Codementor Events

WebAssembly to run blockchain using Go - Part 2

Published Sep 24, 2019
WebAssembly to run blockchain using Go -  Part 2

In this article I aim at making an attempt to demystify blockchain by presenting an implementation using Go programming language.
In part 1 of this article, the application has been presented as a scenario between two actors Alice and Bob.

Objectives of this article

  • Gain an insight over the inner-workings of blockchain.
  • How to create a blockchain in Go.
  • Consider the distributed aspect of the app carrying out the blockchain operations.

Blockchain can be seen as a distributed database in which consensus algorithms are provided to allow adding new entries while these entries are ensured to be valid without the need of a central authority to ensure that.

Proof of Work (PoW)

PoW is required to be a hard problem so that one node can not consistently solve it hence delivers a proof for group consensus.
Suppose SS: event that one node finds the nonce that solves the hash in a time not exceeding ten minutes.
Assume for one node we have p(S)p(S): probability of event SS taking place = 0.0010.001 which is a very insignificant probability.
Let's now define SnS_n: event that at least one node solves the hash within the ten minutes in a pool of n number of nodes, accordingly p(Sn)=1(1p(S))np(S_n) = 1-(1-p(S))^n.
prob diagram.png
Substituting for two values of n number of nodes in the network p(S1000)=0.6323p(S_{1000}) = 0.6323, p(S10000)=0.99995p(S_{10000}) = 0.99995
Therefore, it is concluded that with a big enough number of contributing nodes, the value jumps significantly from 0.001 to 0.6323 to nearly one!
It is worth noting that the probability model that describes this scenario should be more complex than that. But the point is to make sense of the fact that the likelihood of getting the block created becomes significant if many nodes exist in the network hence it prevents a malicious node from introducing fake transactions into the chain.

It is required to have a level of control on the time in which the nodes take to create a new block. A harder PoW in turn requires more time, hence we need to control the difficulty of PoW. In this article difficulty diff is the number of leading zeros in which the hash is required to have for the block to be considered valid.
leading zeros.png

Mining

Mining is the Work in Proof of Work as nodes loop through nonce values until the valid hash is found.
mining-process-as-dapp.png
In this application nonce values looped through are not incrementally increasing. This to allow different nodes in the network to go through different nonces.
In this article a SHA256 hash is used in an array byte represented in little-endian.

What's little endian vs big endian !
Endiannes is about the order in which bytes of a datatype is placed in memory. For little endian, the least significant byte of a datatype is placed first in memory followed by the more signficant bytes until reaching the most significant one while big endian follows the opposite order.

If we want to enforce the leading zeros condition upon the hex 0xAB0300, it is first converted to 0x0003AB from which we count the number of leading zeros.

Code

Now let's get into the exciting job, in the previous part of this article, a walkthrough on the usage of the application is presented along with the WebAssembly bindings written. In this part, blockchain and the networking portion in it is presented.

Transaction

First I define what a transaction is

find code here

In a real blockchain application transaction most proabably is required to contain more attributes but the bare minimum which I choose to present is to have the sender From of the transaction, the reciever To and the amount of crypsys Amount being transferred. I also allow the transaction to be represented in json format since it is being propagated through network.

Block

The block fields:

Block
id
previous hash
nonce
payload (transaction)
difficulty
timestamp
this block hash

Represented in the struct of this code from the file block.go which belongs to package blockchain.

find code here

For this snippet,

find code here

I create a struct for the part of the block to be hashed which is basically all the attributes of the block except for the hash. In lines 11-15 , these fields are filled then converted to a string. Then in line 18 the string is hashed and copied into the hash attribute of the created block instance.

As for function hashValid, checking the validity of the hash is simply checking the number of leading zeros.

find code here

But considering the endiannes things shall require a bit more work than just counting zeros. I start by taking the last 8 bytes of the hash array that is under check. It is worth noting that taking only those 8 bytes is not functionally wrong as long as the difficulty is no more than 64 (8*8) bits .
In line 7 I shift the last byte of the array to take the place of the most significant byte of a new uint64 number (hashAsInt) while the first byte of array forms the least significant byte of the new number. The rest of array bytes form the remaining bytes of hashAsInt accordingly in that order. After finishing that for loop in lines 6-8, I am retreiving back the most significant 64-bits of the hash in the form in which they existed before getting represented in little-endian as array. Hence now we can validate those bytes accordingly whether they pass difficulty check in lines 9-10 or not.

Blockchain

In this file blockchain.go, the blockchain structure and methods are defined.

find code here

For this application Blockchain struct contains only one attribute chain which is an array of Block.
The first function NewBlockchain() constructs an instance of Blockchain. It first invokes GetObserver() where this initializes the underlying networking operations. By creating a new blockchain the first block is created rightaway where in blockchain terms it is called "genesis block" and it does not contain any relevant transaction info but its creation is essential for other blocks to follow.
In line 25 I set a callback, this callback is later called by the underlying network when a message is received by the node notifying it that there is a new transaction requested. The receiving node then might contribute by mining the transaction or ignore it and just add the new block. In this article it is assumed that nodes always mine transaction when they are asked for it. In line 9 the listener() converts the serialized message msg received into a predefined struct.
After that it invokes a new thread that starts mining to create a new block in line 11 while the transaction information of the block to be created is just extracted priorly from msg. At the end, the chain is mutated by adding that new block to it.

RequestTransaction() method insitigates the creation of new transactions. At first it sends a message to the network in line 35 to notify other nodes about a newly requested block that needs to be created then it tries to mine for that new block by itself.

Networking

Node struct reflects the networking aspect of the blockchain as it comprises features of the network.

find code here

First are the destination ip address toIP and port toPort of the running server in file tracker.js which is written in nodejs. Attribute response holds messages received from the tracker. While ws points at the websocket connection. Finally, newTransactionCallback is a callback that is called once the node received a request for a new transaction to be created.

At this point I fill the Connect() procedure first to establish connection with tracker then to register event listeners.

find code here

First I get the websocket object from the javascript global scope running on the web browser.
From this object, New() is invoked passing the url to connect to as an argument, in this case the url is "ws://127.0.0.1:8081/ws"
In line 9, I register the necessary event listener that is called once a message is received. The Go func callback is wrapped inside a js.FuncOf() which converts Go func into a function to be used by javascript.
This is also mentioned in part 1 of this article. The message is received and parsed then it branches to two cases either it be a transaction request or be it a response. In the first case the newTransactionCallback is invoked on the transaction, this in turn invokes the listener() in blockchain.go. response holds the value of a nonce during the mining process which solves the nonce to achieve the required hash. This is the value which is being checked upon when mine() executes in block.go.

I wish you felt excited about blockchains after reading this article, hopefully the code in my repository helps you in your subequent Go blockchain projects.

Discover and read more posts from beber89
get started