My Blockchain in Go

TL;DR;

This post is a personal note to explain how I implemented the same blockchain of previous post in Golang. Nevertheless, it can be used by other people who wants to get more knowledge about developing a blockchain in Go.

The structure of this story follows exactly the one I posted just above. The difference is in the details of each language and on the app structure (which does not differ so much by the way).

The source codes from both the server and the client sides can be found at the Conclusion section. It is available for all those who wants to fork/improve it.



Installing dependencies

In order to make this work, we need to install:

And we have to set the GOPATH variable.

I also suggest to place all the app structure inside the %GOPATH%/src folder (or $GOPATH/src if you are not on Windows).


The application to be developed here

Like in the previous post of my blockchain in Python; a group of people decide to organize a competition of football match betting. Each player will make their bets on the matches Portugal vs. Switzerland; and Netherlands vs. England, valid for the semi-finals of Europe Nations League.

As they do not know themselves very much, they prefer to go for a Blockchain application to register their bets, and like this there will no be no doubts whatsoever about cheating or somebody changing their results randomly. All bets are treated like a transaction and are properly registered in a chain that is shared among all players. Each person has their own copy of all the bets.

So, let’s start the implementation of this Blockchain!


App structure

The structure of our application is a bit more complex than the Python version.

This is the directory structure that must be under the $GOPATH folder.

src
|--
BlockchainBetSportGolang
|--|-- bet
|--| |-- controller.go (where we are going to place the handlers)
|--| |-- model.go (the representation of the objects)
|--| |-- blockchain.go (the blockchain business logic)
|--| |-- router.go (the routes definition)
|--|-- logger
|--| |-- logger.go
|--|-- main.go

Most of the structure and the logic of this application is based on the API that I developed here:


Structure of the blockchain

Each block of our chain will have the following information:

  • the index of the block: an incremental integer
  • a timestamp corresponding to the creation date/time of the block
  • a collection of bets (more details below in this same section)
  • the nonce used to mine the block (more details in the “Mining a block” section)
  • the hash of the block
  • the hash of the previous block
Structure of a block

When creating our Go struct, we put the name and the type of the variable, and on the right we give the name that is going to be sent by the API whenever bet information is sent to any application that calls it.

Each bet in the block contains:

  • the name of the player (the person who is betting)
  • the id of the match
  • the score given by the player to both teams
Structure of a bet

Initialization of the application

In main.go:

App initialization in main.go

When a user launches the application, typing

go run main.go 9000

the main() method is executed; and this is what happens there:

  • the address variable is set to the value input by the user (9000)
  • the routers are initialized (more details in the following sections)
  • the headers are initialized (accepting calls from any origin and working with GET and POST requests)
  • the app starts listening to the port defined in the address variable (9000)

Routing

As we have seen previously, one of the steps during the initialization of the application is the creation of the routes to be called by the client.

In our logic, the router.go file contains the definitions of the routes, and the corresponding functions of controller.go that are called by them.

This is the code of router.go:

router.go: definition of the routes and their creation

The function called by main.go — NewRouter — gets the address of the node (the address variable read in main), sets it to the current URL. In this case, when the user typed

go run main.go 9000

The server application will run in this URL: http://localhost:9000

And finally, we have a loop in the routes array, setting the routes of our server application. This is done via the Gorilla Mux package.

Last but not least, it calls the CreateNewBlock function from the blockchain in order to create the Genesis block (line 108 on the code above). More details about blocks creation later.

controller.blockchain.CreateNewBlock(100, "0", "0")

Get the blockchain

The basic function to test all our functionalities is to get the blockchain.

Basically, we need to set:

  • a route to be called by client in router.go
  • a function to respond to this route in controller.go. This function will return the pointer to the blockchain variable marshalled in JSON format to the client:

Test it

We can quickly test it via Postman. This is how the request and response will look like:


Register a bet in the blockchain

Now we are going to start registering the bets in the blockchain.

We are going to implement it in three steps:

  • add the routes to the routes configuration, in router.go:
  1. RegisterAndBroadcastBet: the route to be called by the client, which will register the bet in current blockchain; and send it to all nodes in the network
  2. RegisterBet: the route to be called by the server after registering the bet in its blockchain to register the bet in the other nodes of the network
  • for each one of these routes, we create a function to respond to them in controller.go. These functions will call the register bet function in blockchain:

Notes:

  1. the function MakeCall is a general function to make calls to other nodes. It is going to be used every time we need to synchronize information among all nodes in the network
  2. the function MakePostCall just invokes MakeCall to make POST requests to other nodes
  • Finally, the implementation of the bet registering inside blockchain.go

Test it

In order to test it, we can try to register a bet and then call the get blockchain logic to check the registered bet in the pending_bets array.

  • Registering the bet of player “john” on the match “NlEn” (Netherlands vs. England). He bets England is going to win 2–1; so the score of team one (Netherlands) will be set to 1; and the score of team two (England) will be set to 2
Posting to http://localhost:9000/bet/broadcast to test the bet registration
  • Checking the pending bet

Next, we are going to see how to mine and create a block containing all the pending bets.


Mining a block

In blockchain, in order to create a block to be registered in the chain, a node needs to pass a proof of work test. It consists of finding a nonce (an integer in our case) that, combined with all the other data in the block, will return a hash code which begins with “0000”.

The first step to accomplish this is to develop the proof of work calculation, in blockchain.go:

The idea is simple: increment the nonce until the SHA256 hash of the block data returns a string starting with “0000”

With this in place, we can move to the mining logic. As usual, we are going to:

  • add the /mine router to the list of routes in router.go, linking to Mine function in controller.go:
/mine route added to routes configuration
  • implement the Mine function in controller.go. This function is going to:
  1. get the last block from the blockchain (calling the GetLastBlock method)
  2. marshal the current block data
  3. encode it to string
  4. call the ProofOfWork function (showed above) to find the nonce of the block
  5. with this nonce, retrieve the block hash to attach to the block to be created (calling the HashBlock method)
  6. with this nonce, create a new block to be added to the chain (calling the CreateNewBlock method)
  7. convert this new block into JSON and send it to the other nodes (via making a POST call to /receive-new-block on each node of the network), so that they can also add this block to their chain
Mining logic in controller.go

The last step is to develop the response to /receive-new-block in the nodes that will receive the mined block

  • add the /receive-new-block to the routes array in router.go
  • create the ReceiveNewBlock in controller.go, which will respond to this route:

This function will:

  1. unmarshall the block that is in JSON format
  2. check the block hash (calling the CheckNewBlockHash of blockchain.go)
  3. if the block is accepted, add it to the chain

Last but not least, we have to implement the CheckNewBlockHash function in blockchain.go:

Logically, here we compare the new block’s previous block hash with the hash of the last block contained in the node’s chain, as well as the indexes.

Test it

We can test the mining logic by:

  • Registering a bet (like in the previous section)
  • Calling the /mine endpoint (it may take a little time)
Test of mining logic
  • Then, we call the get blockchain logic so that we can see that the “pending” bet now is an “official” bet present in a block. Besides this, we can see that the pending_bets array is now empty. You can see also that the hash of the block starts with “0000”:
The blockchain now has a new block with the registered bet

But … how do we do to synchronize all nodes and find a consensus if two or more of them have different versions of the chain?


Register nodes of the network and the consensus logic

Let us suppose we have two nodes, node_1 running in http://localhost:9000

go run main.go 9000

and node_2 running in http://localhost:9001

go run main.go 9001

And each one of them has a different chain registered. How to synchronize their chains into only one?

The first part is that we need to register node_2 into the network of node_1. node_2 will have to call the /register-and-broadcast-node endpoint of node_1.

To do this, we do a POST call to

POST http://localhost:9000/register-and-broadcast-node

passing in its body the node to be registered, in JSON format, like this:

{ "newnodeurl": "http://localhost:9001" }
Please note: newnodeurl must be between quotes, differently from the Python version

Again, we follow the same steps:

  • in router.go, add the following routes to the list:
  1. /register-and-broadcast-node to be called every time a new node has to be added to the network
  2. /register-node to be called on each node already present in the network to also add the newly added node
  3. /register-nodes-bulk that will pass all the current nodes of the network to the new node, so they it will also have them in its internal list of nodes
Register nodes routing
  • in controller.go, we develop the function that will answer to each route:

First: RegisterAndBroadcastNode, which answers to /register-and-broadcast-node

Function that responds to /register-and-broadcast-node

Second: RegisterNode, which answers to /register-node

Function that responds to /register-node

Third: RegisterNodesBulk, which answers to /register-nodes-bulk

Function that responds to /register-nodes-bulk

But… what if node_2 had already a chain that is slightly different from the one of the network of node_1? We need to find a consensus so that both nodes — and then all the network — have the same chains, with the same bets.

Here, we are going to use a very simple solution to find a consensus: the network which contains the longest chain keeps it, forcing the other to drop its chain and get the new one.

This is how we are going to develop the /consensus endpoint

  • adding the route in router.go:
  • adding the function Consensus in controller.go:
  • when a consensus is found, we need to see if the new chain (if the chain is changed) is valid. We do this with the ChainIsValid function in blockchain.go:

For each in the block in the chain, we check if the hashes generated with their nonces correspond, and if the previous block hash is indeed equal to the hash of the previous block.

Test it

Supposing we have our node_1 running in port 9000 with the block of player “john” created in the previous sections in its chain.

We start node_2 in port 9001 with an empty chain.

  • Get blockchain of node 1
  • Get blockchain of node 2
  • Register node 2 into the network of node 1
  • Calling consensus logic in node 2 (chain is replaced)
  • Check that blockchain of node 2 is really changed, and network_nodes array contains node 1:
  • Check that blockchain of node 1 remains the same, and network_nodes array contains node 2

Great! Blockchains in both nodes are equal, and network is synchronized.


Check the bets of a player or a match

In the last part of the server code, we are going to see how to retrieve all bets linked to a player or to a match in special.

We go to the same steps as before:

  • adding the routes in router.go:
  • adding the corresponding functions to controller.go:

Like this, any calls to the endpoint /match/NlEn will call the function GetBetsForMatch passing “NlEn” in the variable “matchId”.

Likewise, any calls to endpoint /player/john will call the function GetBetsForPlayer passing “john” in the variable “playerName”.

  • adding the business logic functions in blockchain.go, in charge of searching for the bets in the chain:

Test it

After registering the bet of player John, and mining the block (remember: we are looking for official, and not pending, bets), we can call http://localhost:9000/player/john to retrieve the bet that John did for the match Netherlands vs. England:

Also, we can call http://localhost:9000/match/NlEn to retrieve all bets done for the match Netherlands vs. England:


Client test application

Besides the steps that I described in the previous sections, another way for you to test this application is by using a very simple client app that registers and sends bets to the Blockchain.

It is downloadable from the link below:

To run it, open a terminal, browse to the path of the downloaded solution, and run the following instruction.

$ npm i && npm start

This will automatically open the test page. Once the page is open, type the name of the player and the scores of the two matches and hit the “Send Bets” button.

Once the bets are sent, you can use Postman to check that the bet is well registered in the pending_bets array.

Then, we call the mine function:

And finally, we can see that the block with the two bets of player Jane are registered:

In the client app, just call http://localhost:3000/player/jane:

Display of page http://localhost/player/jane

Conclusion

This is the Golang version of the bets blockchain that I implemented firstly in Python.

The complete solution is on the link below:

Do not hesitate in forking and improving the solution if you want to. ;)