How to implement a Blockchain Structure?
16 October 2017We saw the use of Blockchain Structures in Decentralized Consensus Systems. And we even detailed how these structures prevent data tampering.
But how to implement a Blockchain in real life?
Let’s take a break from concepts & algorithms to describe actual code. We’re going to define three core functions to implement a Blockchain Structure: init
, append
and add
.
This article is the first in a series that’ll describe the implementation for each of the [3 pillars] of Blockchain: blockchain, P2P, and Proof Of. Maybe you have read one of the other excellent articles on the subject, like Building Blockchain in Go or Let’s Build the Tiniest Blockchain. In that case, just register to our mailing list, we’ll send you the follow-up articles!
You can find the whole project on github. This project is a educational project with as many comments as possible. Don’t hesitate to share your feedbacks on the Issues page.
The following uses Python code but it is using only features that any javascript / java / ruby / C / C# developer is familiar with.
Init
First we initialize a new instance of our blockchain:
I’ll skip implementation details like metadata format and storage. Refer to github for these.
We initialize a new folder with a blockchain:
This code creates an initial block, the genesis, which has a NULL parent.
The make_block
function contains the core of our Blockchain Structure:
hash_ = sha3(previous_hash_bytes, payload)
This line produces a cryptographic fingerprint of the state of the chain. It relies on the fingerprint of the previous state and the current operation. This recursive process protects us from data tampering.
A demo with Ouroboros:
we use the /tmp/my-first-blockchain
folder to hold our blockchain data:
› python main.py init \
--root /tmp/my-first-blockchain \
--payload "this is my genesis block"
e9838c2163a98514c45c7d2524446399e4e3c9f7a...
e9838c...
is the fingerprint of the block we created. Use this hash to compare the chain with other members.
In the /tmp/my-first-blockchain
folder you’ll find:
The description:
› cat /tmp/my-first-blockchain/blockchain.desc
GENESIS: e9838c2163a98514c45c7d2524446399...
HEAD: e9838c2163a98514c45c7d2524446399e4e...
We have a reference to the head of the chain and a reference to the tail. These are equals for now.
The first Block:
› cat /tmp/my-first-blockchain/e9838c2163a98514c4....blck
00000000000000000000000000000000000000000...
this is my genesis block
It contains a reference to the previous block, zeros for “NOTHING.” And the payload.
Note that the Blockchain doesn’t enforce a payload format. If there’s a cryptographic fingerprint for it, you’re good to go.
Append
We add a new block:
We prepare a new block by attaching it to the current block:
new_block = make_block(current_block_hash, payload)
This line shows the Chain part. We attach each block to the previous one.
Demo with Ouroboros:
› python main.py append \
--root /tmp/my-first-blockchain \
"ALICE SENDS 1 ETHER TO CHUCK"
13ad91ad3ed5fbcefdd39801b3b7200eb54594e6c...
We get the hash of the last block. Again, use this Hash to compare your chain with other participants.
Ouroboros updated the description file with a new head:
› cat /tmp/my-first-blockchain/blockchain.desc
GENESIS: e9838c2163a98514c45c7d2524446399...
HEAD: 13ad91ad3ed5fbcefdd39801b3b7200eb54...
The new block contains a reference to the previous block
› cat /tmp/my-first-blockchain/13ad91ad3ed5fbcefd...blck
e9838c2163a98514c45c7d2524446399e4e3c9f7a...
ALICE SENDS 1 ETHER TO CHUCK
Add
Let’s see a case of data tampering! We’ll reproduce the example from the article on data tampering.
Chuck sends a mail to Bob:
from [email protected] to [email protected]
Hi Bob, Add the following payload to your blockchain: CHUCK SEND 1 ETHER TO BOB The Hash: e7ed781fa5e07bf078cb825a51291491273665d458…
Bob uses the add
functions that append a new block IF the proposed hash matches the one we find locally:
› python main.py add \
--root /tmp/my-first-blockchain \
e7ed781fa5e07bf078cb825a51291491273665d458788... \
"CHUCK SEND 1 ETHER TO BOB"
e7ed781fa5e07bf078cb825a51291491273665d458...
It works, which means that Chuck provided a hash that matches Bob’s previous state and the payload.
Then Alice sends a mail:
from [email protected] to [email protected]
Hi Bob, Add the following payload to your blockchain: ALICE SEND 1 ETHER TO BOB The Hash: 6647327c55df3a628086cfb64255c8daea8ddf5c18…
Bob goes on and add
the new transaction:
› python main.py add \
--root /tmp/my-first-blockchain \
6647327c55df3a628086cfb64255c8daea8ddf5c180c1... \
"ALICE SEND 1 ETHER TO BOB"
FAILED:
Traceback (most recent call last):
File "main.py", line 1, in <module>
from ouroboros import cli
...
raise HashDoNotMatchException()
ouroboros.blockchain.HashDoNotMatchException
Bob knows immediately that Alice provided a Hash that doesn’t match the combination of his previous state and the payload. He knows their blockchain his diverged.
Thanks to the Blockchain Structure, they found that someone cheated. And they didn’t have to share the whole history to detect it. All the checks happened on their local machine, efficient.
The add
function is almost identical to append
. We compare hashes before updating our chain:
Finally
with approx. 50 lines of code and three functions you’ve seen the basics to implement a Blockchain! We’ve seen that this is no more than a linked list with a cryptographic hash function.
We are one step closer to a working Distributed Consensus. We still need two more components: a peer-to-peer protocol and a mechanism to pick new blocks.
Subscribe to our mailing list below, or join us on Twitter to receive the follow up articles!
Laurent Senta
I wrote software for large distributed systems, web applications, and even robots.
These days I focus on making developers, creators, and humans more productive through IPDX.co.