Gist

The blockchain industry is in full swing and the best way to understand how it functions is by creating it yourself. Simplistic examples can be revealing. Below you can find my own 5-cent implementation which helped me grasp the concepts.

A chain is a glorified linked-list with blocks keeping a hash of the previous block. As such one cannot fiddle with the content without cascading the effect down the list. Here a block definition:

import hashlib as hasher
import datetime as date
import requests
import time
import math
import uuid
import random

class Block:
    """
        The basic unit of a blockchain.

    """

    def __init__(self, index, data, previous_hash):
        if index is None or not isinstance(index, int) or index < 0:
            raise Exception("Given index is not acceptable.")

        self.index = index
        self.timestamp = date.datetime.now()
        self.data = data
        self.previous_hash = previous_hash
        sha = hasher.sha256()
        sha.update(str(self.index).encode('utf-8') + str(self.timestamp).encode(
            'utf-8') + str(self.data).encode('utf-8') + str(self.previous_hash).encode('utf-8'))
        self.hash = sha.hexdigest()

You don’t need to encode the whole package in the hash and a good hash is an art on its own.
The chain is really just linking blocks together:


class Chain:
    """
        The basic blockchain.

    """

    def __init__(self):
        self.head = Block(0, "Genesis", "0")
        self.tail = self.head
        self._blocks = [self.tail]

    def __iter__(self):
        return self._blocks.__iter__()

    def append(self, data: str):
        self._blocks.append(Block(self.tail.index + 1,  data, self.tail.hash))
        self.tail = self._blocks[-1]
        return self.tail

    def __str__(self):
        return f"Chain of length {len(self._blocks)}"

    def serialize(self):
        coll = []
        for block in self._blocks:
            coll.append({
                "index": str(block.index),
                "timestamp": str(block.timestamp),
                "data": str(block.data),
                "hash": block.hash
            })
        return coll

    def last(self):
        return self.tail

A node is part of a peer network where each attempts to solve a puzzle. The type and complexity here is a whole topic related to attacks, spamming and balance between protecting and challenge. Let’s say that the puzzle should be fairly difficult and that whoever finds the solution is being rewarded. Note that if you are only after a blockchain storage solution you don’t need to solve any puzzle, the chain’s linked hashing is all you need. Once a peer is rewarded the other peers are notified and get an update. The puzzle is difficult to solve and easy to proof, hence the reason why cryptographic algorithms are perfect. It’s easy to show that a solution is right but it’s tough to find it.


class Node:
    def __init__(self):

        self._address = str(uuid.uuid4())
        self._chain = Chain()
        self._peers = []
        self._transactions = []

    def add_transaction(self, tx):
        self._transactions.append(tx)

    def add_peer(self,url):
        self._peers.append(url)

    def get_peer_chains(self):
        coll = []
        for node_url in self._peers:
            try:
                blocks = requests.get(f"{node_url}/blocks").content
                blocks = json.loads(blocks)
                coll.append(blocks)
            except Exception:
                pass
        return coll

    def get_blocks(self):
        return self._chain.serialize()

    def get_transactions(self):
        return self._transactions
        
    def consensus(self):
        # accept the longest one
        other_chains = self.get_peer_chains()
        longest_chain = self._chain
        for chain in other_chains:
            if len(longest_chain) < len(chain):
                longest_chain = chain

        self._chain = longest_chain

    def proof_of_work(self,last_proof):
        #  compute something intense and return your supposedly good answer to the puzzle
        time.sleep(2)
        return random.randint(1, 1e12)

    def mine(self):
        last_block = self._chain.last()
        last_proof = last_block.data
        proof = self.proof_of_work(last_proof)

        self._transactions.append(
            {
                "from": "network",
                "to": self._address,
                "amount": 1
            }
        )

        self._chain.append(proof)

        return self._chain.last()

The blockchain idea is great, the whole money-making scheme much less. The fact that the (complex) computation is irrelevant and not being used for anything else is a disgrace, a waste or resources and time. If only the CPU cycles would be used to compute protein folding or something alike, but the scheme is purely geared towards enrichment.