How to implement a Blockchain Structure?
We 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:
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.
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.
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.
/tmp/my-first-blockchain folder you’ll find:
› 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.
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
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 firstname.lastname@example.org to email@example.com
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 firstname.lastname@example.org to email@example.com
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.
add function is almost identical to
append. We compare hashes before updating our chain:
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!
I wrote software for large distributed systems, web applications, and even robots.
Now I focus on decentralization, overly-engineered software, and frugal innovation.
I help companies around the world build products through SingularGarden.