Browsed by
Tag: Pyhton

Bitcore.js keys for zeros and ones.

Bitcore.js keys for zeros and ones.

Bitcore is an excellent JavaScript library that is in use in many Bitcoin-related websites. Using the tools in this library one can easily achieve almost every Bitcoin functionality. Creating key pairs, parsing blocks, creating and signing transactions and more. In this post, I’ll focus on the use of Bitcore when dealing with key pair.

 

The zero

A beginner web developer can create a simple key pair by just using:

bitcore = require("bitcore-lib");
privateKey = new bitcore.PrivateKey // Generate a random private key
privateKey.toString()
>> "23bc740f87bd68729e794eb48b5137150f17109f855a34512c3c5f93d7498291"

The privateKey comes with ample of build in methods, most of which are more than enough for basic Bitcoin implementation in many web applications.

privateKey.toAddress().toString()
>> "1LY75mCpuD3xPfLLFwbWccBNoQQY4VBeQj"
privateKey.toPublicKey().toString()
>> "0379d42509499082436c89a4e1637ed14a27e56174843bddb980ab6f155f82431c"

This codes can be implemented in a manner of minutes. Bitcoin can be incorporated into many web applications in less than a day. However, those of you with a keen eye to Bitcoin protocol probably noticed that the public key comes in its compressed format. The uncompressed public key will be twice as long (64 bytes + 1 byte) and will have 0x04 as their leading byte.

This is, of course, a non-issue for most use cases, but it might be somewhat counterproductive when learning the relations between private keys, public keys, and address.

To truly understand something, there’s no better way than to get your hands dirty. And when we’re referring to something as crucial to Bitcoin (and blockchains in general) as key pairs, no shortcuts should be made.

 

To one.

During my first experimentation with this library, I received the impression that, as good as this library is, it might not be sufficient to teach and learn the underlying mechanism of the Bitcoin blockchain itself.

However, after more careful examination I came to realize that this library provides much more granular tools than what I expected. In fact, it seems that I can use it in conjunction to the developer documentation on Bitcoin addresses.

This is done thanks to one specific method that returns the numeric value of each point in the public key (don’t forget, the uncompressed public key is just a set of x-y coordinates).

publicKey.point.x
publicKey.point.y

This is highly useful method for a number of reasons:

  1. It creates a big number object in JavaScript, thus saves us from the hassle of working with 32+ bytes (A big drawback in JavaScript is the lack of native support for any number that is 32 bytes and above).
  2. Each point is given independently; as a result, the students are more aware of the real meaning of what a public key is really is (in terms of x-y coordinates). It’s also an excellent opportunity to show the students how one coordinate can be dropped to achieve the compressed address.

Another two very useful methods are:

bitcore.crypto.Hash.sha256ripemd160(pubKey);
bitcore.crypto.Hash.sha256sha256(hashedPublicKey);
The first two methods makes the hashing process really easy to execute. The Bitcoin protocol requires double hashing to be executed at two different locations in order to turn the public key to Bitcoin address. In many other languages (such as Python, which I've been using extensively when teaching this subject), there's a need to import and define each hash function. The process is tedious, and at the end of the day, somewhat messy.

By having these two methods, we save almost 40% in code space, and the students can focus on what’s really important in this lesson.

 

And here’s the final result:

// This code represents a possible approach for teaching Keys
// using JavaScript. 
// Pay attention that even while still using a JS library such as bitcore.js 
// The code still follows all the steps defined in the developers documentation.

bitcore = bitcore = require("bitcore-lib");

privKey = bitcore.PrivateKey.fromString("8c5e5b37ebf1e7a274b9dff4910f9a2004868897f7d845802b77a1b245c26bc7");

pubKey = "04" +
        privKey.publicKey.point.x.toBuffer().toString("hex") +
        privKey.publicKey.point.y.toBuffer().toString("hex");

pubKey = new Buffer(pubKey, "hex");

hashedPublicKey = "00" + bitcore.crypto.Hash.sha256ripemd160(pubKey).toString("hex");

hashedPublicKey = new Buffer(hashedPublicKey, "hex");

checkSum = bitcore.crypto.Hash.sha256sha256(hashedPublicKey).toString("hex").slice(0,8);

checkSum = new Buffer(checkSum, "hex");

binAddress = hashedPublicKey.toString("hex") + checkSum.toString("hex");

binAddress = new Buffer(binAddress, "hex");

address = bitcore.encoding.Base58.encode(binAddress)

 

Now compare to what we might see in Python:

Private_key = bytes.fromhex("BF9795D3FCB4E2181B7B536C2247EA0001397C99BA94D4D4DD62801BB151B091")

import ecdsa

signing_key = ecdsa.SigningKey.from_string(Private_key, curve = ecdsa.SECP256k1)

verifying_key = signing_key.get_verifying_key()

public_key = bytes.fromhex("04") + verifying_key.to_string()

import hashlib

sha256_1 = hashlib.sha256(public_key)

ripemd160 = hashlib.new("ripemd160")
ripemd160.update(sha256_1.digest())

hashed_public_key = bytes.fromhex("00") + ripemd160.digest()

checksum_full = hashlib.sha256(hashlib.sha256(hashed_public_key).digest()).digest()

checksum = checksum_full[:4]

bin_addr = hashed_public_key + checksum

import base58

FINALE_BTC_ADDRESS = base58.b58encode(bin_addr)

In this instance, we can see that the code created with bitcore js is much more straightforward and readable than even the simplest Python code.
This is a clear indication that using JavaScript can be a useful tool when teaching the basics of blockchain development.
The libraries can be used when teaching both web developers as well as more protocol oriented students. The code can be presented in highly simplified manner for beginners while still alluding
to its origin and the logic behind it.

Mixing environments – Creating working environment for blockchain developers

Mixing environments – Creating working environment for blockchain developers

This article is part of a series of articles depicting my experience with creating and conducting an 8 week long blockchain app development course in Brazil.

 

What tools should be used when teaching blockchain

 

The term blockchain is often misused. Very rarely do people use the term blockchain to describe anything beyond a chain of blocks. A lot of the time when people talk about the blockchain and its application, they basically refer to a somewhat wide variety of technologies, architectures, tools and protocols that, once properly combined and implemented, creates that “blockchain” they are referring to.

When I created the course, it was obvious to me that in order to properly teach the students how to work with “the blockchain”, I’ll first need to spend a lot time dealing with many different technologies and tools. There isn’t just one blockchain IDE or concept to examine; rather there are quite a number of them. Take key pair for example; private and public keys are some of the most crucial (and known) features in many crypto-currencies and blockchains, but they are by no means specific to blockchains. Many people use key pairs off chain. The same holds for many concepts that are highly integrated into the common view about blockchains – Hashing functions, signatures (and keys), scripts and stack architecture, byzantine general problem, bytes codes, merkle trees, DAGs and more.

Each feature in the list above represent another tool/approach/use case/concept that stands by itself but is also crucial to creating what is commonly known as “the blockchain”. This fact posed a great challenge for me when I tried to create the course. It was obvious to me that the course is aimed at people who want to learn how to develop their own blockchain applications and solutions, which meant that it will require the students to get their hands somewhat dirty in codes, command line prompt, and different computational tools.

The challenge here lay in choosing the right tools to work with while remembering that each item on the list should be taught in a manner that is  adequate on the one hand, but without going to a level too deep and insignificant for the course on the other hand. It was also important that there should be a clear difference in the relations between the different and individual items.  I knew I wasn’t hired to teach the students how to program or how to work with different environments. However, making the assumption that they had adequate programming knowledge, enough not to require any introduction to that programing language/ environment/ tools seemed quite optimistic at best, and downright stupid at worst. This is even more so when dealing with a variety of different tools and languages.

I decided to do my best to choose the most user friendly working environments – even at the cost of efficiency and future usability.

Numerous developers have their own working environment. However, I was convinced that every code, example and CLI command/tool should be properly tested and documented in a single uniform environment. The last thing I wanted to do was stand in front of the class while in the background, my code failed to compile. The result of this is that I tried  a lot of different environments while always keeping in mind that the environment to be used should fulfill the following requirements;

  1. It needs to support all the tools I require that my students use.
  2. It shouldn’t affect in anyway the students’ computers, working environments, file systems, paths and/or jeopardizes their computer security in any way.
  3. It should be uniform for all the students.
  4. It should be easy and fast to set and reset whenever needed.
  5. It should be as user friendly as possible.

 

After a few experimentations, I decided to work with the following configurations:

 

  1. Cloud9 level 1 IDE environment with the following installations:
    1. Python-pip.
    2. Python-virtualenv.
    3. Virtual environments for Python 2.7 and 3.5
    4. Ethereum SOLC
    5. Tcpdump (for some reasons, not all c9 workspaces had it installed)
    6. The following pip packages (base58, ecdsa)
Cloud 9 was used for running python files and as a uniform terminal.
  1. Digital ocean Ubuntu 16.041 X64 droplet with the following installations:
    1. Nodejs 6
    2. Meteor Javascript framework version 1.3.4 with web3 and bitcore-lib packages.
    3. The following changes were optional for a few students:
      1. Installing ipfs and running ipfs daemon and adding ipfs-api package to their meteor app. (For those who wished to work with IPFS).
      2. Adding swap file of 4 gb. (For those with memory issues).
  • Use openssh. (More IDE flexibility for advanced users).

 

  1. Solidity browser compiler was mostly used for writing and deploying smart contracts. SOLC (installed on c9) was used by a few students who required some more advanced contracts (mostly when containing libraries).

 

  1. The only 2 components the students were required to install on their own machines were:
    1. Chrome/Chromium with metamask addon.
    2. Wireshark.

 

Cloud9 provided a well-tested and easy to configure working environment that was consistent for all students. It was used mainly to run the Python codes the students created, to compile some Solidity codes (using SOLC), to catch some packets using tcpdump (The tcpdump files were later downloaded and examined using wireshark) and to access digital ocean droplet using ssh.

I was very pleased with this working environment as it was quite robust, highly configurable, not local and easy to reset – Basically it was a great playground to get dirty with, without having to worry about damaging the students’ native environment.

 

Digital ocean droplets were used to provide the students with a uniform platform on which they can create their apps. Meteor is a well-documented JavaScript framework. It was obvious to me that if the students were expected to create applications, they should also have access to some JavaScript tools as both Bitcoin and Ethereum have some very powerful tools for app developers – mainly web3 for Ethereum and Bitcore for Bitcoin.

There’s also another npm package for compiling Solidity (similar to SOLC), but unfortunately, I’ve experienced a lot of compatibility issues with that package and decided to ban the students from using it. IPFS-api is another useful tool for more advanced students who are interested in working with IPFS.

It is important to note that although I did discuss IPFS with some students, I didn’t consider it an important part of the course. First, the system is still in a very early stage. Secondly, the main goal of the course was to teach the students how to develop blockchain applications, and not necessarily decentralized applications (although the two might have a lot in common, they’re not mutually the same) and IPFS just didn’t really fit the slot. Besides, I already had an ample amount of topics to focus on and teach my students (And I must admit; I’m not that much of an expert in this platform myself).

Another point to consider is that in a future course, in the case where there’s no promise to create apps, digital ocean might still be used. In this case, JavaScript libraries can be taught by using clean nodeJS interface.

 

Metamask and solidity browser were wonderful and very easy to use tools. In a manner of minutes, the student had yet another playground to play with Solidity and the Ethereum blockchain.

(It’s important to note that I took some time to make sure ALL of the students were using clean metamask installation WITHOUT any of their real wallets imported to it and only on the Ropsten testnet).

 

One last note about truffle

I also feel compelled to justify a little further my decision to exclude the use of truffle and/or embark (with testrpc) during the course and instead choosing to work with solidity browser compiler. The thing is,  at the time, both truffle and embark had some memory issues that forced me to use another swap file (both when tested on Cloud9 and when tested on digital ocean droplet). In addition to that,  most smart contracts required were easy to deploy from the Solidity web compiler. For specific ad hoc contracts that required the use of a more robust compiler, Ethereum SOLC was used on cloud 9 (SOLC didn’t had any memory issues). I do however recognize that truffle and embark are major tools in the industry and I’m defiantly planning to integrate them into future courses.

blockchain related career

blockchain related career

A pleasant call

A few months ago I was approached by the wonderful guys and girls from the Exosphere Academy with the offer to help them build a new blockahin course. They wanted to create a boot camp for people who are interested in blockchain, its implications and possible implementations. I liked the idea. For some time now I believed that one of the major obstacles for bitcoin, ethereum and other blockchain utilities to achieve their potential lies at the high learning curve new users and developers needs to climb. In this blog, and in other forums, I did my best to try and mitigate this learning curve and I was honored by the opportunity to construct a complete and cohesive course for other developers and enthusiasts.

 

My way.

After I took upon myself the task of creating this course, I was approached by a Brazilian magazine who asked me to describe how I became a blockchain developer. The result was the following article at carreirasolo.org. (The original article is in Portuguese). And right here is an English translation for all of those who’re interested in blockchain related carer.


 

The first time I heard about bitcoin.

Six years ago, I read a short article in a financial magazine about a new type of digital coin called bitcoin. Naturally, the article was completely misleading, which isn’t that surprising. At the time, nobody really understood bitcoin. I’m not even sure the article mentioned the word “blockchain”. But I will always remember this article and how I just skimmed it and completely disregarded the idea as just another scam – thus forfeiting my chance to become a millionaire by downloading a piece of software to my computer. A few years later, in 2012, when I was (slightly) older and wiser, I read another article about bitcoin, this time in a tech magazine. Although it wasn’t completely accurate, the article provided a great service to its audience. The reporter was not only informed about bitcoin, but he also put a lot of effort work into understanding his readers – their technical background and how well informed they were about economics, web architecture, computer science, etc. The result was the first ever bitcoin article I read that dealt with it in terms, analogies and examples that conveyed the actual ideas behind the coin.

After that, I was hooked. The protocol’s promise is one of the most ambitious projects I’ve ever encountered in the digital world. It’s not just another cool app, video game or social network where we can show off pictures to our friends and family. Bitcoin challenges us to literally rethink, remodel and rebuild some of the most central elements of human society – from financial systems, government bodies, bureaucracies, health care, sources of information and much more. All of these can benefit from implementing at least some of the tools presented in the bitcoin protocol. I knew that I wanted to be a part of it.

Baby steps

Initially, I didn’t have much coding experience. At the time I was finalizing my BSC in chemistry and environmental studies. I wrote some very basic Java code to help me in my work, but nothing more than that, so I knew I had to work on my coding skills – sooner rather than later. I decided to study Python for many reasons: it was easy to use, well documented, and already had a (relatively) large selection of bitcoin-related libraries and implementations. I was actually amazed at how well it went. Python turned out to be an extremely easy language to learn, but what was even more encouraging was that while learning the basic concepts of the programing language, I also gained many valuable insights into computer architecture and protocols. All this was very useful when I tried to figure out how Bitcoin worked.

After I felt reasonably competent with Python, I decided to look more into app development. Luckily, at the time, many JavaScript bitcoin-related libraries started to appear. JavaScript was easy enough to learn (especially when all you care about is the bitcoin part, and not the user experience). HTML and CSS were somewhat more confusing, but I soon managed to create some decent-looking interfaces for my bitcoin apps.

During this time, I was constantly reading bitcoin-related news stories, articles, blogs and forums, almost daily. This also provided me with a great feedback loop, as it always helped me focus on the spects of the programming language I was working with (Python and JavaScript).

Introducing ethereum

By the time Vitalik Buterin – who, by the way, was already highly respected In the bitcoin community – introduced his vision for Ethereum, I was already head over heels into Bitcoin and blockchains. I found the approach presented by Vitalik very compelling and promising, and I discovered that by learning how Ethereum works, I could enhance my own understanding of the bitcoin protocol by comparing the similarities and differences between the two.

The big leap

Meanwhile, I started to work on my Master’s degree and took few more advanced courses in algorithms and machine learning to amp up my computer skills. But I wasn’t pleased with the courses. The level at which we learned was high, no doubt about that, but none of the courses offered me any truly useful tools to work with. So I started to study by myself again.

I looked into assembly code, which helped me a lot in my understanding of the Ethereum Virtual Machine (or EVM for short). At this time, I decided to take a leap of faith and turn my passion to blockchains into a full-time career. At first, I started by creating simple videos that explained the basics of bitcoin. Then I showed some implementations for key features using Python. The initial exposure I received was very modest – but it did the job, and almost immediately I started to receive calls from professionals from a variety of industries who asked for my help and advice. Many of them wanted to use the power of bitcoin and the blockchain in their respective industries, and I was thrilled to be at the epicenter of such a great revolution in so many different and unique fields. Many of the people I worked with were genuinely looking for ways to revise their services and models to accommodate the needs of the 21st century. Many have the potential to empower millions (if not billions) of people in developing countries that might finally get direct access to many of the services we take for granted, like banking, medical insurance, pensions, legal frameworks to settle disputes, transparent government … the list goes on and on.

In the meanwhile

Blockchain architecture and computer decentralization is really not the scary thing most people think it is. The protocols are quite well documented, and once you’ve made some mental leaps, it will all start to make sense. You just need to learn it in steps. First, you need to understand what really sets blockchains apart from many other solutions. Then, using some basic coding and IT skills, you can easily familiarize yourself with many of its features and inner workings. The next step is to create some basic code that mimics a few of the more common blockchain-related features. Finally, putting it all together, you can start to create your own blockchain applications and decentralized solutions.

I’m biased. I’m in love with the vision that Bitcoin, Ethereum and blockchain architecture bring to the world. My fingers itch, and my appetite is insatiable. For years I’ve been working diligently to see this revolution spread from the computer geeks and mathematicians to the masses, where it’s really needed. So you’d better take my enthusiasm with a pinch of salt and look for the many blockchain-related projects that will now start to grow – and watch how they’re planning to literally change our world. Then you’ll feel the same way I do. I’m sure of it!

Neat Ethereum tricks. The transaction nonce.

Neat Ethereum tricks. The transaction nonce.

Whenever a user deploys a new contract to the Ethereum blockchain, that contract receives its own Ethereum address.

User 0x0a Deploying contract Reclaim –> contract address 0x0a1

As it turns out, these contract addresses ARE NOT a random address. The address of every contract we’ll deploy depends on two parameters:

  1. The Ethereum address from which the contract is being deployed.
  2. The nonce of the transaction.

 

What do we mean by nonce

The nonce of the transaction! Not to be confused with the nonce used in the mining process. In Ethereum, every transaction have a nonce associated with it. The nonce is one of the tools that helps to index and process transactions in the right order. The nonce itself IS NOT a random value. It grows by scalar one with every transaction we transmit to the blockchain. For the Ethereum test-net, the nonce begins with 0x100000 (1048576).

 

Calculating the new contract address

The new contract address can be computed in the following way:

def mk_contract_address(sender, nonce):
    return sha3(rlp.encode([normalize_address(sender), nonce]))[12:]

 

sha3 and rlp and encryption functions. The only two variables are the address of the sender and the nonce (basically the transaction number for that particular address).

I’ve installed the pyethereum library on ubuntu 16.04. and changed dir to directory cd /pyethereum/ethereum . There I launched python 2.7.12 and imported the utils.

$ cd /pyethereum/ethereum

$ python

>> import utils

Than I used the function utils.mk_contract_address(sender address, nonce) to get the addresses of my future contracts.

For the sender address: 0x43CCFE27708381164Fd079556C7Ef158A6d409Dc I can check for what the address of the next deployed contract will be.

nonce1 = 1048576 =>; 0x7930935a32ee489bd102002c2598602ff79c24fd

nonce2 = 1048577 =>; 0x0d7d52f686f54e44f604a6253857d5b119cb1da8

nonce3 = 1048578 =>; 0x9ddbce5eb6d16bd73e9256e091f9b39647daf026

I can continue this way on and on till I cover all the address space for the sender address.

 

What does it mean?

The first thing I did was to try and send transactions to future address. I sent 0.01 Eth from 0x43cc... to  0x7d47... (nonce = 1048584. You can use the code above to calculate the full address). The ether was sent without any problem. I can easily send the ethers to any valid ether address. The ethers, of course, can’t be reclaimed at this point since there’s no private key or code that is associated with that address.

Then I tried to deploy a contract to a particular pre-determined address (0x7d47...). I’ve used a basic meteor app with web3 library to deploy the contract.

Template.hello.events({
  'click button': function(event) {
    
    myContract = web3.eth.contract(newABI);
    myContract.new({
      from: web3.eth.accounts[0],
      data: newData,
      nonce: 1049856
     // to: "0x7D47BcC72D9c7758a3021B0A393af6aa2BE66F58"
    }, function(err, res){
      if(err){
        console.log(err);
      }else{}
      console.log(res);
    })
  },
});

The contract is a simple contract that allows reclaiming the ethers stored at the address 0x7d47....

contract Reclaim{
    
    address public owner = msg.sender;
    
    function kill(){
        suicide(owner);
    }
}

And I’m happy to say that the experiment went smoothly. As long as when deploying the contract to claim the coins, the nonce is set so that utils.mk_contract_address(sender address, nonce) = required address, the coins can be reclaimed!

You can watch the transactions I’ve created over here.

A list of the last three transactions.
A list of the last three transactions.

That made me think about few ways in which this trick can be utilized. From sending funds with higher anonymity to issuing assets and token BEFORE their contract code was even completed and I guess there’re much more options.

But there are limitations

Since the nonce is correlated with the number of transactions (and increases by one with each transaction) we need to make sure that when we deploying the Reclaim contract, we’ll do so when the next nonce matches the required address. otherwise we might lose our window of opportunity and the coins might be lost forever! When I tried to send the coins and then claim them back using a contract with a too high nonce, I failed to do so. It seems that the transaction stays in the transactions pool for 50 blocks, if by the time 50 blocks have passed we won’t transmit enough transactions to cover the gap in the nonce, our transaction will be dropped out.

	 	
nonce1 = 1048578  
nonce2 = 1048579  
***This gap needs to be filled within 50 blocks or the transaction will be dropped***
nonce150 = 1048728 
nonce151 = 1048529  
Scripts and stacks

Scripts and stacks

Personal note, Many things happened in past two months the required my full attention. I hope to resume a steady flow of posts in coming days.

Review

In the last post we’ve talked about one the biggest bitcoin misconception – The idea that transaction actually moves coins from one wallet to another. The truth is that transactions are nothing more that statements. These statements always points to a previous statement (that in turn point to an even older statement and so on), and usually these statement also specify an amount of coins that the current owner is wishing to transfer. The statement also contains a riddle, or an equation that needs to be proofed, and mostly, the key to proof this equation will require the use of the private_key that is associated with the recipient bitcoin address.

level3

Pay attention, even though Bob will be required to use his own private_key to proof that he indeed can solve this problem, the private_key still won’t be available to any one.

 

Now let’s look for a second at this transaction message. We’ve already learned how to create a bitcoin message (see this section about Version message and this one about headers). We just need to make sure that all of the fields are filled in accordance the protocol rules. Just like filling a form. You can find a complete list of the fields that needs to be filled in the bitcoin developers documentation.

 

 

Most of the fields are quite straight foreword. I might still create another post in the future with detail instructions on how to fill all the fields, but this isn’t really the topic of this post. This post deals with one of bitcoin more fascinating aspects – The riddle that Alice place in her statement. The riddle that only Bob can solve -The script.

 

(You just can’t wait to create your own transaction? you’re more than welcome to watch my videos on creating bitcoin transaction)

Scripts, what is it?

Scripts is a computer language. In more detail, it’s a set of predefined words that are agreed upon. Every node that follows the rules specified in the bitcoin protocol will know how to read, interpret and implement these words. Because bitcoin messages are basically nothing more then a string on bytes, these words are not written in plain English, rather are translated to OP_CODEs. That way, we can send our message as a string of bytes, and the receiving node will know that these bytes represent some instructions. (Important note, The receiving node will only treat this bytes as instructions only if they appear inside one of the script field.)

Here’re selected few:

Word Opcode Hex Input Output Description
OP_1ADD 139 0x8b in out  1 is added to the input.
OP_1SUB 140 0x8c in out 1 is subtracted from the input.
N/A 1-75 0x01-0x4b (special) data The next opcode bytes is data to be pushed onto the stack
OP_MIN 163 0xa3 a b out  Returns the smaller of a and b.
 OP_SHA256  168  0xa8  in  hash The input is hashed using SHA-256
OP_EQUAL 135 0x87 x1 x2 True / false Returns 1 if the inputs are exactly equal, 0 otherwise.

The original list included around 200 of these words, but currently most nodes will only support few dozes of these words. Using these few words we can create many “riddles” or state many conditions to claim the coins in our transaction message.

For example I can add the following string of bytes as my script.

0x01 0x8b 0x87 0x02 0x87

<1> <OP_1ADD> <2> <OP_EQUAL>
  1. It will take the number 1.
  2. Use the OP_CODE OP_1ADD to add 1 to it -> The output of this OP_CODE will be 2.
  3. Use the OP_CODE OP_EQUAL to make sure if the result is equal to 2. -> The output of this OP_CODE will be True.

A word of caution though, most nodes not only refuse to accept most of these OP_CODEs, they will even refuse to accept most non-standard  scripts, mainly because they want users to use standard transactions. Many nodes will not only refuse to accept a transaction with a non standard script, they’ll also refuse to transmit these transactions to other nodes.

 

Stacks

You might’ve already noticed that this script language can only be written as a list of operations. Unlike other high level languages (such as python for example) Scripts can only be used in a predefined order. This type of structure is called stack, because we’re stacking variables and data on top of each other. But not only we’re stacking them, using the stack structure also means that they’ll be processed in accordance to the order in which they were stacked.

In our previous example, the integer 1 was the first item in our stack. Then came the operation OP_1ADD which took that item as its input, processed this item by adding 1 to it, and than giving the output 2. Now the number 2 is stacked BELLOW the integer 2.

<1> <OP_1ADD> <2> <OP_EQUAL>

<2> <2> <OP_EQUAL>

The node recognize the OP_CODE <0x02> as the integer 2, so it moves on to the next item in our stack – the OP_CODE OP_EQUAL. This operation input is the two items that are directly bellow it and compere the two. If both are equal, it will return True.

<True>

 

This example code can’t be used with a standard bitcoin transaction, it’s only meant to give you a general feel on how scripts works.

You can find an example of a real transaction over here:

 

 

Give it a try with bitpy

One of bitpy newest feature is the ability to create stacks and see them in action in real time. Mind you, only few OP_CODES are currently implemented, but it might still give you a feel on how stacks works.

Example of stack using bitpy
Example of stack using bitpy

 

Simple stack architecture with python

Stack architecture can easily be implemented using arrays. After all, it’s nothing than an array of objects (variables, operations, results etc’).

In our bitpy project, under Utils/OpCodes/Codes.py I’ve created a stack class. In its most basic form, this class will only create and empty array upon initialization, followed by  2 methods only.

class Stack():

    def __init__(self):
        self.items = []

    def push(self, item):
        self.items.append(item)

    def pop(self):
        elm = self.items.pop()
        return elm
  1. push(item) append new item to the array
  2. pop(item) remove the topmost item in my array.

This should be enough to create a very basic stack class. Still, I’ve added few more methods.

class Stack():

    def __init__(self):
        self.items = []

    def isEmpty(self):
        return self.items == []

    def push(self, item):
        self.items.append(item)

    def pop(self):
        elm = self.items.pop()
        return elm

    def size(self):
        return len(self.items)

    def printStack(self):
        display = ""
        for items in self.items:
            items = str(items)
            if len(items) > 5:
                display += " " + "<"+ items[:5] + "..." + ">"
            else:
                display += " " + "<" + items + ">"
        return display

    def clear(self):
        self.items.clear()

The isEmpty method will check if our stack array is empty.

The size method will give us the size of the array.

The printStack will provide us with a visual representation of our array. Pay attention that I’ve limited the size of each item to only 5 characters so that items such as hashed messages, bitcoin addresses, keys etc’ won’t take the all screen.

The clear method will remove all items from our array.

Using this methods we can easily start implementing more advanced OP_CODE to our stack array.

def OP_DUP(self):
    elm = self.pop()
    self.items.append(elm)
    self.items.append(elm)

def OP_HASH160(self): #saved as string!
    self.push(Utils.keyUtils.keys.generate_hashed_public_key_string(self.pop()))

def OP_EQUAL(self):
    elm1 = self.pop()
    elm2 = self.pop()

    if elm1 == elm2:
        self.push(1)
    else:
        self.push(0)

def OP_VERIFY(self):
    top = self.pop()
    if top == 1:
        self.push(1)
    else:
        self.push(0)

def OP_RETURN(self, input):
    self.push(input)

 

Transaction part one – The misconceptions about the block chain

Transaction part one – The misconceptions about the block chain

Three levels of abstractification.

The are three level to understand the way the Bitcoin block chain works.

The first level
One of the most simple Bitcoin block chain abstractification

In the first level, we got those who just heard about Bitcoin for the first time. People usually thinks that the coins are just associated with the Bitcoin address. Whenever Alice sends Bob coins, she just place a statement (or transaction) in the block chain specifying that the X coins that were associated with Alice address, should now be associated with Bob address. This is of course wrong since this representation contains only 3 thing: the sender address, the receiver address and the amount of coins to be transferred. But this level of abstraction is usually the first thought most people have when first presented with the idea of the block chain.

The second level
Points to previous transacions

In the second level, people starts to understand that each transaction also contains the origin of each coin. So if Alice wants to send 5 BTC to bob, she first needs to show where she got these 5 BTC from, That is, she also needs to provide a way to point to older translations on the block chain, transactions which proves that Alice is indeed the rightful owner of these five BTC. So now what we have starts to look more like a chain. It’s no longer just a table containing the address and the current BTC balance,  rather the block chain needs to contain a list of all previous transactions. This depiction is more accurate, but still it isn’t complete – introducing the third level.

The third level
Points at previous transaction and set the condition for claiming the coins.

In the third level, people learns that a transaction is more then just a simple statement in the block chain. Transaction contains more then just information about the origin of the coins (the input), the address of the receivers (the outputs) and the amount of coins to be transferred. Rather, the transaction also contains a riddle in it, and only by solving this riddle, can the coins be claimed and transferred. So when Alice send 5 BTC to Bob, she doesn’t only pointing at the transaction from which Alice got the coins, it also solves the riddle specified in that transaction to prove that Alice is allowed to claim those coins, but that’s not the end of it, in the transaction that Alice publish on the block chain she’s also inserting another riddle, a riddle that only Bob can answer. So if Bob would like to use this coins in the future, he’ll have to solve that riddle which was provided to him by Alice. And the process goes on and on and on.

I love riddles! Or, how to solve the riddle and prove that I’m allowed to claim the coins?

A quick reminder. Signing messages and key pair.

In the previous post we’ve talked about mathematical trapdoors and hashing functions. We’ve saw how we can use these types of function so sign a message with a private key and how these signed message can be verified with the corresponding public key.

F("My name is Alice", Alice's_private_key) = signed message.

Verify(signed message, "My name is Alice", Alice's_public key) = true.

Change any component in the Verify statement, and we’ll receive false. This way we can easily prove that the message “My name is Alice” was indeed signed by Alice and that no one tempered with that message.

Pay attention! We cannot sign a message with the public key, it simply wont work! the public key can only be used to verify a message, not to sign it!

So, Alice can now publish a message in the block chain that contains the input (origin of the coins) and the output (the address of the receiver). This is the original message, public for anyone to see and check as he or she pleases. Alice can also now specify the following rules in that public message:

  1. This message is the original message.
  2. Within this message I’ve included Bob’s_public_key (In hashed format – We’ll get there in a second).
  3. Take your public key and hash it. If your hashed public key matches the hashed public key from step 2, you may move to the next step.
  4.  Take this original message, and sign it with your own private key.
    F(This message, Bob’s_private_key) = signed message.
  5. The signed message should be verified only against the public key that is specified in this message.
    Verify(signed message, This message, Bob’s_public_key) = true.
  6. If the verification indeed yield true, you may claim the coins in this transaction

 Getting Bob’s public key

When Alice specify Bob as the recipient of a transaction, she does so by inserting Bob’s hashed public key. The hashed public key (as we already saw in the post dealing with keys) can be deducted from Bob’s Bitcoin address.

The public key is hashed and then added to the final Bitcoin address.
The public key is hashed and then added to the final Bitcoin address.

So basically, knowing Bob’s Bitcoin address is equal to knowing Bob’s hashed public key. All we need to do is to convert the address back from base 58, and remember that out of the 25 bytes of the binary address, we need to omit the first byte and the last 4 bytes.

Scrips – the beginning

As we’ve already saw many times in the past, Bitcoin message is no more then a string of bytes that follow a predefined order. That means that in order to specify conditions and rules like the one Alice is using in her transaction message, we also need all parties to agree on a predefined field that will contain the conditions, and we also need to agree on a way to translate the bytes in that field into a set of rules, or instructions. For this purpose, a scripting language was created for Bitcoin, this langue allocate predefined operation to a predefined byte. For example, the byte 0x8b means “plus 1”, the byte 0x8c means “minus 1”, the byte 0xa9 means “hash the public key. First with SHA-256 and then with RIPEMD-160”, and so on. There’re many more of these operators (also called OP-codes) and these OP-codes helps us to specify the rules that needs to be fulfilled. These rules are transparent and are publicly visible on the block chain. Whenever a node verify a transaction, the nodes follows these rules and make sure that they eventually do yield a true statement.

We’ll talk more about these OP-codes and scrips in the next sections, when we’ll also see a real example of valid transaction script.

 

Connection part three – Receiving messages

Connection part three – Receiving messages

In the previous posts, all that we’ve done was to construct and send messages to another node on the network. In this post, we’ll see what happens to incoming messages.

First stop – The ReceiverManager:

class ReceiverManager(Thread):
    def __init__(self, sock):
        Thread.__init__(self)
        self.sendingQueue = Utils.globals.sendingQueue
        self.sock = sock
        self.ping = ""

        self.outfile = open("data_received_from_node.txt", 'w')

    def run(self):
        while True:
            try:

                # get only the header's message
                header = self.sock.recv(24)

                if len(header) <= 0:
                    raise Exception("Node disconnected (received 0bit length message)")

                headerStream = BytesIO(header)
                parsedHeader = HeaderParser(headerStream)

                # get the payload
                payload = self.recvall(parsedHeader.payload_size)
                payloadStream = BytesIO(payload)

                self.manager(parsedHeader, payloadStream)

            except Exception as e:
                print(e)
                break

        print("Exit receiver Thread")

The receivermanager always runs in the background, checking our Thread for any incoming packets. Once it receives a packet, it will immediately cut its first 24 bytes.

header = self.sock.recv(24)

The first 24 bytes are the header. If you remember from this post, every Bitcoin message will starts with header, and the header is always exactly 24 bytes long.

 

The first 24 bytes are the header. The rest is the payload
The first 24 bytes are the header. The rest is the payload.

This header is now parsed as a string of bytes and passed to the HeaderParser class in Bitpy/Network/HeaderParser.py

headerStream = BytesIO(header)
parsedHeader = HeaderParser(headerStream)

 

Second stop – The HeaderParser class:

The HeaderParser class takes the first 24 bytes as a long string of bytes, and then it reads them in the same order that we’ve seen before.

Size (Bytes) Name Data type Description
4 Start string char[4]  The network identifier
12 Command name char[12]  The name of the command.
4 Payload size uint32 Len(payload)
4 Checksum char[4]  SHA256(SHA256(payload))[:4]

First 4 bytes for the Start string (or Magic number), another 12 bytes for Command name, the next 4 bytes are the Payload size and the last 4 bytes are the checksum.

4 bytes for starting string. 12 for command name. 4 for payload size and 4 for checksum
4 bytes for starting string. 12 for command name. 4 for payload size and 4 for checksum
class HeaderParser:
    def __init__(self, header):  # Packets is a stream

        self.magic = read_hexa(header.read(4))
        self.command = header.read(12)
        self.payload_size = read_uint32(header.read(4))
        self.checksum = read_hexa(header.read(4))

        self.header_size = 4 + 12 + 4 + 4

    def to_string(self):
        display = "\n-------------HEADER-------------"
        display += "\nMagic:\t %s" % self.magic
        display += "\nCommand name	:\t %s" % self.command
        display += "\nPayload size	:\t %s" % self.payload_size
        display += "\nChecksum	:\t\t %s" % self.checksum
        display += "\nheader Size:\t\t %s" % self.header_size
        display += "\n"
        return display

We’ve also defined the to_string function which basically makes it easier to print a human readable version of the message header.

You might’ve noticed that currently our code just accept the checksum field from the received message without checking it. This is of course a security flaw in our code. The checksum filed is there to help us verify the authenticity of the message. That is one of the ways we can make sure that no one tempered or changed the message on its way from the sender node to our node. But for the time being we’ll assume that the message is indeed authentic and we’ll accept the checksum as is.

 

Third stop – Back to the ReceiverManager:

Now that we have our header, it’s time to get the payload. The size of the payload was defined in the header of the message. We need to cut that amount of bytes from our incoming packets, just as we cut the first 24 bytes of the header. There’s however one extra step in our code. Instead of using the built in sock.recv function (as we did for the header) we’ve decided to implement our own recevall function. The rational was that since we have no way to predetermine the size of the payload, and since the built in sock.recv can’t handle large packets of unknown size, it would be wiser to break the payload into smaller parts and append them together. This has nothing to do with the Bitcoin protocol, it’s only our way to make sure that the code will properly handle large messages.

def recvall(self, length):
    parts = []

    while length > 0:
        part = self.sock.recv(length)
        if not part:
            raise EOFError('socket closed with %d bytes left in this part'.format(length))

        length -= len(part)
        parts.append(part)

    return b''.join(parts)

So now, after we’ve cut the required amount of bytes that represents the payload of our message, and we have both our header (which was already parsed) and our payload (yet to be parsed), we’ll pass them both to the receivermanager manager function.

 

Forth stop – Manager:

    
def manager(self, parsedHeader, payloadStream):

    command = parsedHeader.command.decode("utf-8")
    message = {"timestamp": time.time(), "command": command, "header": parsedHeader.to_string(), "payload": ""}


    if command.startswith('ping'):
        ping = Ping.DecodePing(payloadStream)

        pong = Pong.EncodePong(ping.nonce)
        packet = PacketCreator(pong)
        self.sendingQueue.put(packet.forge_packet())

        message["payload"] = str(ping.nonce)
        self.display(message)

    elif command.startswith('inv'):
        inv = Inv.DecodeInv(payloadStream)
        message["payload"] = inv.get_decoded_info()
        self.display(message)

    elif command.startswith('addr'):
        addr = Addr.DecodeAddr(payloadStream)
        message["payload"] = addr.get_decoded_info()
        self.display(message)

    elif command.startswith('pong'):
        pong = Pong.DecodePong(payloadStream)
        message["payload"] = pong.get_decoded_info()
        self.display(message)

    elif command.startswith('version'):
        version = Version.DecodeVersion(payloadStream)
        message["payload"] = version.get_decoded_info()
        self.display(message)

The manager function does a very simple thing. It checks the command of the message (the command is part of the header) and then it sends the message payload to be parsed by the corresponding functions. For example. If the manager sees that the command is «pong», it will use the decodepong method in Bitpay/Packets/control_messages/pong.py to extract the desire fields out of it. (You can read more about «pong», «ping» and «verack» messages in this post.).

 

Divergence

We have our pared message, both its header and payload. And now we need to decide what to do with them. For some messages this might be the end of the line. There’s nothing more we can do with them. Some might require us to act. «ping» message should be answered by a «pong» message, transactions should be checked and relayed (We’ll talk about transactions in later posts), «version» messages should be acknowledged by sending back a «verack» message.

A major part of learning the Bitcoin protocol is learning how each and every message should be dealt with. Which fields of information it contains and what is the meaning of this information. We’ve already talked about some of the messages in previous posts  (see here for «ping», «pong» and «verack» messages, and here for «version» message.) and as our project will have more features implemented, so we’ll discuss other type of messages and how to deal with them.

User interface

User interface

The best way to make our code really useful is to add user interface to it. There is a lot of this that can only be taught and understood by looking at the code itself, bu there are also many things that the average user can learn about the Bitcoin protocol that can be explained in a more “human friendly” way. An that is way Alexis and I have decided to add a Graphical User Interface (GUI) to our project in hope that in the future we can create a full Bitcoin graphical environment.

We’ve added a new folder to hold our GUI files, the UI folder. This folder contains 3 implementations. The first one uses the Tkinter module, the second uses the pyQt module and the third is a simple command line interface (And this is why we’re calling this folder UI and not GUI). We still haven’t decided on the final implementation bu we believe that we’ll eventually go with only the pyQt implementation, basically because this one looks the best!

 

This is what it looks like at the moment:

Bitcoin graphical environment
The user interface of bitpy.

This is our basic design, At the bottom there’s a list of all the messages you can send: «version», «verack» and «ping»   (More messages will be added soon). The left side keeps a record of all of the incoming messages, in the order in which they were received. Once we choose one of these messages, we can see at the right panel a display of the parsed message. The header and the payload.

Remember! this is just our first draft, but we’re quite proud of it. Little by little our project shows more and more potential.

 

installing dependencies

Because we’re using pyQt5, you might need to install the pyQt5 module on your machine. The easiest way to do so will be to use the commend:

pip install pyqt

 

 

 

Messages part two – Payloads and version message

Messages part two – Payloads and version message

In the previous posts we’ve talked a little bit about messages. We know that a message is nothing more than a string of bytes, it has an header and a body (payload), and it must maintain its predefined format. We’ve seen the format of the header, but every message body (payload) will contain different information, according to the message type. We’ll start by constructing the “version” message.

The version message is used when trying to establish a connection with the remote node. Alice will send the version message to Bob, and only after Bob have approved this version message, and replay with his own version message, only then the connection between the two nodes can be established. No other message will be accepted before both nodes have exchanged this version message. So it’s no surprise that we choose to construct this message first, since this is the first message that we’ll send, and the first one we’ll receive.

 

The fields that are required in our version message (From the developer reference):

 

Size (Bytes) Name Data type Description
4 version int32 What is the latest version of the protocol that the transmitting node (our node) understands. In this example this number is 70012
8 services uint64
Not full node 0x00
Full node 0x01
8 timestamp int64 Current timestamp
8 addr_recv services uint64 What type of services OUR receiving node can support?
16 addr_recv IP address char The IP address of OUR receiving node
2 addr_recv port uint16 The port of OUR receiving node
8 addr_trans services uint64 What type of services OUR transmitting node can support?
16 addr_trans IP address char The IP address of OUR transmitting node
2 addr_trans port uint16 The port of OUR transmitting node
8 nonce uint64 A random number that helps the receiving node to detect and index our connection
Varies user_agent bytes CompactSize This field varies in size, but it tells the other node what should be the size of the next field
Varies user_agent string This field is used to display the name of our node, like licence plates. We can call our node whatever we want, “core”, “classic”, “my_cool_bitcoin_thingy”.
4 start_height int32 The highest block that the transmitting node knows of.
1 relay bool
True The transmitting node can relay messages to the rest of the network
False The transmitting node can’t relay messages to the rest of the network
  • Pay attention that in the “version” message, when asking for both the receiving and the transmitting  services, IP address and ports, we’re asked about our own machine, our own node. In our case both incoming and outgoing messages will be dealt in a similar manner, but some implementations might include more advanced routing.

Code implementation

Alexis and I decided that every message will have it’s own file in which the payload of the message will be both created (For messages that our node will send) and parsed (For incoming messages).

import random
import time
from io import BytesIO
from Utils.config import version_number, latest_known_block
from Utils.dataTypes import *


class EncodeVersion:
    def __init__(self):
        self.command_name = "version"

        self.version = to_int32(version_number)
        self.services = to_uint64(0)
        self.timestamp = to_int64(time.time())

        self.addr_recv_services = to_uint64(0)
        self.addr_recv_ip = to_big_endian_16char("127.0.0.1")
        self.addr_recv_port = to_big_endian_uint16(8333)

        self.addr_trans_services = to_uint64(0)
        self.addr_trans_ip = to_big_endian_16char("127.0.0.1")
        self.addr_trans_port = to_big_endian_uint16(8333)

        self.nonce = to_uint64(random.getrandbits(64))
        self.user_agent_bytes = to_uchar(0)
        self.starting_height = to_int32(latest_known_block)
        self.relay = to_bool(False)

    def forge(self):
        return self.version + self.services + self.timestamp + \
               self.addr_recv_services + self.addr_recv_ip + self.addr_recv_port + \
               self.addr_trans_services + self.addr_trans_ip + self.addr_trans_port + \
               self.nonce + self.user_agent_bytes + self.starting_height + \
               self.relay


class DecodedVersion:
    def __init__(self, payload):
        self.version = read_int32(payload.read(4))
        self.services = read_uint64(payload.read(8))
        self.timestamp = read_int64(payload.read(8))

        self.addr_recv_services = read_uint64(payload.read(8))
        self.addr_recv_ip = parse_ip(payload.read(16))
        self.addr_recv_port = read_big_endian_uint16(payload.read(2))

        self.addr_trans_services = read_uint64(payload.read(8))
        self.addr_trans_ip = parse_ip(payload.read(16))
        self.addr_trans_port = read_big_endian_uint16(payload.read(2))

        self.nonce = read_uint64(payload.read(8))

        self.user_agent_bytes = read_compactSize_uint(BytesIO(payload.read(1)))
        self.user_agent = read_char(payload.read(self.user_agent_bytes), self.user_agent_bytes)

        self.starting_height = read_int32(payload.read(4))
        self.relay = read_bool(payload.read(1))

    def get_decoded_info(self):
        display = "\n-----Version-----"
        display += "\nversion                :\t\t %s" % self.version
        display += "\nservices  	         :\t\t %s" % self.services
        display += "\ntimestamp              :\t\t %s" % self.timestamp

        display += "\naddr_recv_services	 :\t\t %s" % self.addr_recv_services
        display += "\naddr_recv_ip           :\t\t %s" % self.addr_recv_ip
        display += "\naddr_recv_port         :\t\t %s" % self.addr_recv_port

        display += "\naddr_trans_services  	:\t\t %s" % self.addr_trans_services
        display += "\naddr_trans_ip         :\t\t %s" % self.addr_trans_ip
        display += "\naddr_trans_port	    :\t\t %s" % self.addr_trans_port

        display += "\nnonce                 :\t\t %s" % self.nonce

        display += "\nuser_agent_bytes  	:\t\t %s" % self.user_agent_bytes
        display += "\nuser_agent            :\t\t %s" % self.user_agent
        display += "\nstarting_height	    :\t\t %s" % self.starting_height
        display += "\nrelay	                :\t\t %s" % self.relay

        return display

Because this code is used both for incoming and outgoing messages, it has both the class EncodeVersion, which is used to build the payload of the version message, and the class DecodedVersion which is used to parse the payload of any incoming version message.

The function forge will just append and return all the fields in the right order – this is the finale payload.

 

EncodeVersion

Because we haven’t established connection yet, we first need to create the payload of our version message using the EncodeVersion class. The class won’t take any argument (except for self) and will just assign every field with the right value and the right data type.

The variables version_number and last_known_block are imported from Bitpy/Utils/config.py and are set to:

version_number = 70012
latest_known_block = 416419  # june 2016

Our node is not a full node so the services will be set to 0x00. For that reason we’ll also set our relay field to be False.

In our own node, both incoming and outgoing messages will be dealt by the same machine so both receiving and transmitting machines are the same:

self.addr_recv_services = to_uint64(0)
self.addr_recv_ip = to_big_endian_16char("127.0.0.1")
self.addr_recv_port = to_big_endian_uint16(8333)

self.addr_trans_services = to_uint64(0)
self.addr_trans_ip = to_big_endian_16char("127.0.0.1")
self.addr_trans_port = to_big_endian_uint16(8333)

 

We’re using the function random.getrandbits(64) in order to populate or nonce field with 8 bytes long random number.

We’re also not adding any vanity name to our node at the time so we’re setting the user_agent_bytes to be 0. That means that there’s no user_agent_bytes field.

 

 

DecodedVersion

This class is quite straightforward, it receives the payload of the incoming message from Bitpy/Manager/ReceiverManager.py.

It uses the builtin function read  and our data types functions to assign each field with the proper value, for example the first 4 bytes are the version number in uint32 format, the next 8 bytes are the services field in uint64 format and so on.

The only thing that is really unique is the user_agent field:

self.user_agent_bytes = read_compactSize_uint(BytesIO(payload.read(1)))
self.user_agent = read_char(payload.read(self.user_agent_bytes), self.user_agent_bytes)

This is the first example of the varying CompactSize data type in use. The field user_agent_bytes doesn’t have a fixed size. The Bitcoin protocol defines the variable data type CompactSize to deal with such fields (you can read more about this data type in the data types section). We’re using the function BytesIOin in order to send this argument as a string of bytes to theread_CompactSize_unit function and receives back the Uint that matches the size of the next field, the, the user_agent field. Then we’re using the data type function read_char which requires two arguments. The first is the string of bytes itself (payload.read(self.user_agent_bytes)) and the second is the size of the total string (self.user_agent_bytes).

Once we’ve finished parsing out version message we can use the get_decode_info function in order to display the information about the remote node (currently, we aren’t doing anything with this information except to dump it as a text file).

—–Version—–
version : 70012
services : 5
timestamp : 1467293151
addr_recv_services : 1
addr_recv_ip : ��^�V�
addr_recv_port : 30373
addr_trans_services : 5
addr_trans_ip : ��
addr_trans_port : 8333
nonce : 1755461931592560680
user_agent_bytes : 16
user_agent : /Classic:0.12.0/
starting_height : 418653
relay : True

 

Edit (4-Jul-2016): Python 2.5 to 3.5 migration

Please read the general notes about the transition from Python 2.5 to 3.5 over here. And the complete github change log for the migration over here.

The code for the <Version> message remind fairly untouched, only few adjustments were required:
class EncodeVersion:
///
self.timestamp = to_int64(int(time.time()))
///
self.addr_recv_ip = to_big_endian_16char(b“127.0.0.1”)
///
self.addr_trans_ip = to_big_endian_16char(b“127.0.0.1”)
///
class DecodedVersion:
///
self.user_agent = read_chars(payload.read(self.user_agent_bytes), self.user_agent_bytes)
///