Creating a blockchain in 60 lines of Python
Tags: python, javascript, tutorial, programming
Published: 2021-11-05 23:27:12

When I read the [document](https://dev.to/freakcdev297/creating-a-blockchain-in-60-lines-of-javascript-5fka) written by [Phu Minh](https://dev.to/freakcdev297), I was curious about learning different concepts about blockchain. Once I started to read the code, I wanted to match it with Python to understand also the differences with JavaScript.

The objective of this post is finding the differences in both languages and serve as the *Python* appendix of the [original](https://dev.to/freakcdev297/creating-a-blockchain-in-60-lines-of-javascript-5fka) post.

Even though the original document comes from a [Python](https://www.activestate.com/blog/how-to-build-a-blockchain-in-python/) example, I wanted to have an exact match with the `JavaScript` code to compare.

Let's also fit the `python` code in the promised 60 lines.

## Blockchain

Although the idea is to mimic the entire post and use the same sections to follow the code,

For the Blockchain definition, I prefer the following:

Blockchain is a **system of recording information in a way that makes it difficult or impossible to change**, hack, or cheat.

## Setup

We are using Python for this project, so be sure to install it if you haven't.

As I have said, a block is just an object that has some information on it, so we should have a Block class like this:

```python
class Block:

    def __init__(self, timestamp=None, data=None):
        self.timestamp = timestamp or time()
        # this.data should contain information like transactions.
        self.data = [] if data is None else data
```

The class definition is quite similar in both languages. In Python, we use `self` instead of `this` and __init__ is a `constructor` method.

Comments are also similar in both languages. In Python, we use `#` to comment vs. `//` in javascript.

Fot the `sha256` algorithn, I will use the [hashlib](https://docs.python.org/3/library/hashlib.html) library vs the `crypto` package in javascript.

```python
from hashlib import sha256

class Block:

    def __init__(self, timestamp=None, data=None):
        self.timestamp = timestamp or time()
        self.data = [] if data is None else data
        self.hash = self.getHash()
        self.prevHash = None # previous block's hash

    def getHash(self):
        hash = sha256()
        hash.update(str(self.prevHash).encode('utf-8'))
        hash.update(str(self.timestamp).encode('utf-8'))
        hash.update(str(self.data).encode('utf-8'))
        return hash.hexdigest()
```

In the getHash method, from an empty hash, we update it with the rest of components. The hash is the result of the concatenation of the previous hash, the timestamp and the data. All of then with the `.encode('utf-8')` to convert the string to bytes.

## The blockchain

Let's move over to the blockchain class.

```python
class Blockchain:
    def __init__(self):
        # This property will contain all the blocks.
        self.chain = []
```

Again, the class definition is similar in both languages.

To create the genesis block, we just call the Block with the current timestamp using time. To do that, we need to import the time library.

The string conversion is done with `str` instead of `toString`.

```python
from time import time

class Blockchain:
    def __init__(self):
        # Create our genesis block
        self.chain = [Block(str(int(time())))]
```

And the method to get the latest block is similar. We use `len` to get the length of the chain instead of `length` in javascript.

```python
    def getLastBlock(self):
        return self.chain[len(self.chain) - 1]
```

To add the block to the blockchain, we just call the `addBlock` method. The code is almost the same except the `append` (`push` in javascript).

```python
def addBlock(self, block):
        # Since we are adding a new block, prevHash will be the hash of the old latest block
        block.prevHash = self.getLastBlock().hash
        # Since now prevHash has a value, we must reset the block's hash
        block.hash = block.getHash()
        self.chain.append(block)
```

### Validation

In the validation method, we start using `range` as a big difference. Also, because we don't use constants in Python, we just use normal variables.

For the conditional, python uses `or` instead of `||` in javascript.

```python
def isValid(self):
    # Iterate over the chain, we need to set i to 1 because there are nothing before the genesis block, so we start at the second block.
    for i in range(1, len(self.chain)):
        currentBlock = self.chain[i]
        prevBlock = self.chain[i - 1]

        # Check validation
        if (currentBlock.hash != currentBlock.getHash() or prevBlock hash != currentBlock.prevHash):
            return False

    return True
```

## Proof-of-work

We can implement this system by adding a `mine` method and a `nonce` property to our block. Be careful because `nonce` must be declared before calling the `self.getHash()` method. If not, you will get the error `AttributeError: 'Block' object has no attribute 'nonce'`.

```python
class Block:

    def __init__(self, timestamp=None, data=None):
        self.timestamp = timestamp or time()
        self.data = [] if data is None else data
        self.prevHash = None # previous block's hash
        self.nonce = 0
        self.hash = self.getHash()

    # Our hash function.
    def getHash(self):

        hash = sha256()
        hash.update(str(self.prevHash).encode('utf-8'))
        hash.update(str(self.timestamp).encode('utf-8'))
        hash.update(str(self.data).encode('utf-8'))
        hash.update(str(self.nonce).encode('utf-8'))
        return hash.hexdigest()

    def mine(self, difficulty):
        # Basically, it loops until our hash starts with
        # the string 0...000 with length of <difficulty>.
        while self.hash[:difficulty] != '0' * difficulty:
            # We increases our nonce so that we can get a whole different hash.
            self.nonce += 1
            # Update our new hash with the new nonce value.
            self.hash = self.getHash()
```

To create the difficulty property:

```python
self.difficulty = 1
```

And the `addBlock` method:

```python
    def addBlock(self, block):
        block.prevHash = self.getLastBlock().hash
        block.hash = block.getHash()
        block.mine(self.difficulty)
        self.chain.append(block)
```

## Testing out the chain

First, import the module and use the `Blockchain` class the same way using JeChain object:

```python
from blockchain import Block
from blockchain import Blockchain
from time import time

JeChain = Blockchain()

# Add a new block
JeChain.addBlock(Block(str(int(time())), ({"from": "John", "to": "Bob", "amount": 100})))
# (This is just a fun example, real cryptocurrencies often have some more steps to implement).

# Prints out the updated chain
print(JeChain)
```

It should looks like this:

```python
[
    {
        "data": [],
        "timestamp": "1636153236",
        "nonce": 0,
        "hash": "4caa5f684eb3871cb0eea217a6d043896b3775f047e699d92bd29d0285541678",
        "prevHash": null
    },
    {
        "data": {
            "from": "John",
            "to": "Bob",
            "amount": 100
        },
        "timestamp": "1636153236",
        "nonce": 14,
        "hash": "038f82c6e6605acfcad4ade04e454eaa1cfa3d17f8c2980f1ee474eefb9613e9",
        "prevHash": "4caa5f684eb3871cb0eea217a6d043896b3775f047e699d92bd29d0285541678"
    }
]
```

but only after adding the `__repr__` method to the Blockchain class:

```python
import json

    def __repr__(self):
        return json.dumps([{'data': item.data, 'timestamp': item.timestamp, 'nonce': item.nonce, 'hash': item.hash, 'prevHash': item.prevHash} for item in self.chain], indent=4)
```

## Updated bonus: Difficulty and block time

For the blockTime just:

```python
self.blockTime = 30000
```

Have a look to the ternary used for the difficulty system. In Python, the ternary operator is `(if_test_is_false, if_test_is_true)[test]`, resulting in:

```python
    def addBlock(self, block):
        block.prevHash = self.getLastBlock().hash
        block.hash = block.getHash()
        block.mine(self.difficulty)
        self.chain.append(block)

        self.difficulty += (-1, 1)[int(time()) - int(self.getLastBlock().timestamp) < self.blockTime]
```

The final python code (Without proper formatting) in 60 lines is:

```python
# -*- coding: utf-8 -*-

from hashlib import sha256
import json
from time import time


class Block:

    def __init__(self, timestamp=None, data=None):
        self.timestamp = timestamp or time()
        self.data = [] if data is None else data
        self.prevHash = None
        self.nonce = 0
        self.hash = self.getHash()

    def getHash(self):

        hash = sha256()
        hash.update(str(self.prevHash).encode('utf-8'))
        hash.update(str(self.timestamp).encode('utf-8'))
        hash.update(str(self.data).encode('utf-8'))
        hash.update(str(self.nonce).encode('utf-8'))
        return hash.hexdigest()

    def mine(self, difficulty):
        while self.hash[:difficulty] != '0' * difficulty:
            self.nonce += 1
            self.hash = self.getHash()

class Blockchain:

    def __init__(self):
        self.chain = [Block(str(int(time())))]
        self.difficulty = 1
        self.blockTime = 30000

    def getLastBlock(self):
        return self.chain[len(self.chain) - 1]

    def addBlock(self, block):
        block.prevHash = self.getLastBlock().hash
        block.hash = block.getHash()
        block.mine(self.difficulty)
        self.chain.append(block)

        self.difficulty += (-1, 1)[int(time()) - int(self.getLastBlock().timestamp) < self.blockTime]

    def isValid(self):
        for i in range(1, len(self.chain)):
            currentBlock = self.chain[i]
            prevBlock = self.chain[i - 1]

            if (currentBlock.hash != currentBlock.getHash() or prevBlock.hash != currentBlock.prevHash):
                return False

        return True

    def __repr__(self):
        return json.dumps([{'data': item.data, 'timestamp': item.timestamp, 'nonce': item.nonce, 'hash': item.hash, 'prevHash': item.prevHash} for item in self.chain], indent=4)
```

Hopefully you will enjoy and learn with both posts!