From Zero to Blockchain in Python - Part 1

Feature Image

Welcome to the series “From Zero to Blockchain in Python” where we will build an implementation of a blockchain application, specifically a cryptocurrency from scratch. Throughout the series, we will build and improve the functionalities until we have a fully functional demo.

Disclaimer: Please note that this is by no means intended to be used in a real scenario, the code used here is for educational purposes only.

In this part we will build the following basic blockchain functionality:

  • Possibility to add blocks to the
  • Simple Proof of Work (PoW) algorithm
  • Possibility to add transactions
  • Possibility to mine new blocks
  • Possibility to replace the chain with a new one

And we will keep the following for future posts:

  • Wallet management
  • Sign transactions
  • Peer to Peer communication

How does a blockchain work?

Before we jump right into the code you would need to have some basic understanding on what a blockchain is, how a distributed ledger works and basic ideas of cryptographic functions like sha256, if you are quite not there yet or you simply want to reinforce your knowledge please take a look into my article But how does bitcoin actually work?

Let the fun begin

We are now ready to start developing our blockchain module by module, In this article I’ll guide you step by step with code samples and explanations, going through my thought process and the code implementation. To stay focus on the main concepts, I’ll not cover here how I implemented swagger documentation or tests for code, but a copy of the full working example can be found here:

https://github.com/livecodestream/blockchainpy/tree/part_1

Basic Structures

The first things we need to discuss for our blockchain are blocks and the data we want to store in our blocks. For our purposes, we will be storing transaction information, so data like sender, recipient and amount. For our purposes we will use classes, it will be easier to understand and follow the code.

This is extremely simple, and we already created a validate function we will use later on, for now, we just won’t allow any transactions with negative amounts to prevent stealing coins. Next our Block definition:

Block = {
    index: number
    timestamp: number
    transactions: [Transactions]
    nonce: string
    previous_hash: string
    hash: string
}

Our block is also simple, it contains an index, a timestamp, a list of transactions that belong to the block, a nonce which we will use as the proof of work, the hash to the previous block and the hash for our block.

With the blocks, things look a bit weird, so let’s go step by step. The important function in this class is the method hash_block which serializes the block information (minus the hash attributes) and returns a sha256 representation of the object. This representation is then used as the hash parameter of the block and will later be used as cryptographic proof that the block hasn’t been changed.

Blockchain

Now we need to glue it together with all the blockchain logic. Our blockchain will also be a class, where we are going to store all the information we need to monitor and function the blockchain.

Properties

self.__chain = []
self.__current_transactions = []

@property
def last_block(self):
    return self.__chain[-1]

@property
def last_transaction(self):
    return self.__current_transactions[-1]

@property
def pending_transactions(self):
    return self.__current_transactions

@property
def full_chain(self):
    return self.__chain

This is all we need to host our blockchain, at least for now. Let’s review what each one is all about:

  • __chain: A list of Blocks representing the blockchain [private]
  • __current_transactions: The list of transactions which are not yet part of a block [private]
  • last_block: The last block added to the chain
  • last_transaction: The last transaction added to the chain
  • pending_transactions: returns the __current_transactions attribute
  • full_chain: returns the __chain attribute

Constructor

In our constructor, we will simple initialize the 2 lists and create our first block, which is called the genesis block. it will have no transactions attached to it, no nonce, and it’s previous hash will be simple 00 to represent that there is no previous hash.

Creating Transactions

Simply as generating the transaction object, validating if it’s valid and attaching it to the chain.

Proof of Work

Now we start with the heavy-duty of blockchains, the proof of work. The proof of work consists of 2 functions, one proof of work generator, and another validator. The way our implementation works is by taking the latest block and add a nonce such to satisfy that:

f`{last_nonce}{last_hash}{nonce}`

hashed with sha256 will result in 4 leading zeroes.

The only way to find our nonce value is by try an error, we will start with the value 0, and adding 1 at a time until the validation function gives a positive. This is intended to be a process intensive calculation to prevent agents from inserting or updating corrupted blocks.

Mine

We are now ready to mine our first block, let’s see how to do that by examine the process:

  1. We calculate the nonce for our new block
  2. We create a new transaction to give the miner a reward, this transaction will have 0 as the sender and will generate 1 coin to the reward address
  3. We will create the block and add it to the chain

Let’s now examine the add_block function and what it entails:

As we get now to this point things start looking a bit strange around the validate_block function. What are all those ifs? The main purpose of this function is to validate that the block belongs to the chain, that the previous_hash attributes matches with the previous block, that the hash stored in the block matches the actually calculated hash and that our proof of work is valid.

Replacing the Blockchain

This is a very important step, in case of a conflict on the blockchain among peers, we need a system to define which is the correct one, for that we will follow the bitcoin approach saying that the chain with the most work put into will be the right one, as we covered in the previous post

The amount of work will be a very simple calculation for now, and it’s the number of blocks on the chain. I know there’s room for improvement, and we can work on that later on. Here is how the code looks like:

Simple, we compare the sizes of the chains, we make sure the new chain has all valid blocks and we simply insert into our blockchain all the missing blocks, wonderful, except for this:

# Then we compare each block with its previous one
for x in range(1, len(chain_to_validate)):
    if not self.validate_block(chain_to_validate[x], chain_to_validate[x - 1]):
        return False

Does it hurt your eyes? Every time we want to validate an incoming chain we need to validate all the blocks on the chain, there has to be a better approach especially if we consider many of those blocks we probably have on our own chain. Well… there is a better way, but it won’t be covered now, we will take a look into that in a future post, but if you are intrigued and want to do the research and create a PR you are welcome to do so :), just take a look at Merkle Trees.

Congrats!

That’s it… pretty much… you still need to expose all the methods we discussed on a server of some sort, in my demo project I’m using flask and Swagger so that you have a UI to test and see what’s going on. All the information to run the project is on the README file.

There is still a lot more work to be done, like creating node management and synchronization, signing transactions, adding merkle trees, etc. I’m going to continue working on the project and posting regularly here the updates, so stay tuned!

Thanks so much for staying with me so long, hope this project has been interesting. If you want to know more, or if you want me to work on a specific topic, please email me at jc@livecodestream.dev, I’ll be happy to support.

Happy coding!

Join the Free Newsletter

A free, weekly e-mail with the best new articles.

We won't send you spam. Unsubscribe at any time.

Contribute

If you like this article and you want to support my work, you can: