DEV Community

vinayak
vinayak

Posted on • Originally published at itsvinayak.hashnode.dev on

How To Build A Blockchain In Python

Blockchain is a shared, immutable ledger that simplifies the method of recording transactions and tracking assets in a network. It's a constantly growing list of records known as a block. These blocks are connected, creating a chain known as a blockchain.

The fundamental feature of blockchain :

  • Immutable and Unhackable records

  • Distributed ledger technology

  • Persistent in storing data (no loss of data)

Setting up Virtualenv & Installing Dependencies 🔌

create a virtualenv, using python's built-in module called venv. Here env is the name of the environment.

python3 -m venv env

Enter fullscreen mode Exit fullscreen mode

for activating this virtualenv, we need to source it.

source ./env/bin/activate

Enter fullscreen mode Exit fullscreen mode

Installing Dependencies

we need flask as a dependency for serving our blockchain

pip install Flask==2.2.2

Enter fullscreen mode Exit fullscreen mode

Setting up Folder Structure 🗂

  • create a base folder, and name it blockchain

  • inside this folder create a file called blockchain.py which will hold our blockchain code.

  • create another file called server.py this will contain our server code, to server our blockchain.

Creating a Blockchain

Import Dependencies


import datetime
import json
import hashlib
import time

Enter fullscreen mode Exit fullscreen mode

Now, create a class called blockchain , which will hold all our logic and chain itself. Inside this blockchain class, we will have some functions.

  • init : initialize the blockchain, and creates a Genius Block

    def __init__ (self) -> None:
        """
        initialize the blockchain
        """
        self.chain = []
        # create the genesis block
        self.create_block(proof=1, previous_hash="0")

Enter fullscreen mode Exit fullscreen mode
  • create_block : this function creates a new block and adds it to the blockchain, it takes proof and the previous hash as an argument
    def create_block(self, proof, previous_hash):
        """
        add a new block to the blockchain
        """
        block = {}
        block["index"] = len(self.chain) + 1
        block["timestamp"] = str(datetime.datetime.now())
        block["proof"] = proof
        block["previous_hash"] = previous_hash
        self.chain.append(block)
        return block

Enter fullscreen mode Exit fullscreen mode
  • get_previous_block : This function gets the previous block, which is added to the blockchain
    def get_previous_block(self):
        """
        get the previous block
        """
        return self.chain[-1]

Enter fullscreen mode Exit fullscreen mode
  • proof_of_work : proof of work is a Consensus Protocol in blockchain used to define finding a number such that the hash of the number, is hard to find because it takes a lot of time, and computing power.
  def proof_of_work(self, previous_proof):
        start_time = time.time()
        new_proof = 1
        check_proof = False
        while check_proof is False:
            hash_operation = hashlib.sha256(
                str(new_proof **2 - previous_proof** 2).encode()
            ).hexdigest()
            if hash_operation[:4] == "0000":
                check_proof = True
            else:
                new_proof += 1
        elapsed = time.time() - start_time
        print(' time take to get new_proof using pow : ', elapsed)
        return new_proof

Enter fullscreen mode Exit fullscreen mode
  • hash : hash function takes a block and converts it into hash using sha256 , and returns the hash
    def hash(self, block) -> str:
        """
        hash the block using sha256, and return the hash
        """
        encoded_block = str(json.dumps(block, sort_keys=True)).encode('utf-8')
        hash = hashlib.sha256(encoded_block).hexdigest()
        return hash

Enter fullscreen mode Exit fullscreen mode
  • is_chain_valid : check if the blockchain is valid
   def is_chain_valid(self, chain):
        """
        check if the blockchain is valid
        """
        if chain == [] or chain == None:
            # if the chain is empty or None, then the chain is not passed as a parameter
            chain = self.chain

        previous_block = chain[0]
        block_index = 1
        while block_index < len(chain):
            block = chain[block_index]
            if block["previous_hash"] != self.hash(previous_block):
                return False
            previous_proof = previous_block["proof"]
            proof = block["proof"]
            hash_operation = hashlib.sha256(
                str(proof **2 - previous_proof** 2).encode()
            ).hexdigest()
            if hash_operation[:4] != "0000":
                return False
            previous_block = block
            block_index += 1
        return True

Enter fullscreen mode Exit fullscreen mode

Creating a web server

Creating a Flask web server

import os
from flask import Flask, jsonify

# env
PORT = os.getenv('PORT', 8080)
DEBUG = os.getenv('DEBUG', True)

app = Flask( __name__ )

@app.route('/', methods=['GET'])
def home():
    return "<h1>Welcome to the Blockchain</h1>", 200

if __name__ == " __main__":
  app.run(host="0.0.0.0", port=PORT, debug=DEBUG)

Enter fullscreen mode Exit fullscreen mode

Importing our blockchain

importing and initializing blockchain will create Genius Block

from blockchain import Blockchain
blockchain = Blockchain()

Enter fullscreen mode Exit fullscreen mode

Adding mine_block function

This mine_block function helps used to mine a block in a given blockchain

@app.route('/mine_block', methods=['GET'])
def mine_block():
    previous_block = blockchain.get_previous_block()
    previous_proof = previous_block['proof']
    proof = blockchain.proof_of_work(previous_proof)
    previous_hash = blockchain.hash(previous_block)
    block = blockchain.create_block(proof, previous_hash)
    response = {}
    response['message'] = "Blocked is just mined !!"
    response['index'] = block['index']
    response['timestamp'] = block['timestamp']
    response['previous_hash'] = block['previous_hash']
    response['proof'] = block['proof']

    return jsonify(response), 201

Enter fullscreen mode Exit fullscreen mode

Adding get_chain function

This get_chain function will return a JSON list of blocks and its attribute.

@app.route('/get_chain', methods=['GET'])
def get_chain():
    blockchain_clone = blockchain.get_chain()
    return jsonify(blockchain_clone), 200

Enter fullscreen mode Exit fullscreen mode

Adding is_valid function

This function checks if the current blockchain Is valid or not

@app.route('/is_valid', methods=['GET'])
def is_valid():
    is_valid = blockchain.is_chain_valid(blockchain.chain)
    if is_valid:
        response = {}
        response['message'] = "Blockchain is valid"
        return jsonify(response), 200
    else:
        response = {}
        response['message'] = "Blockchain is not valid"
        return jsonify(response), 200

Enter fullscreen mode Exit fullscreen mode

Starting webserver

To start the web server, we will execute the server.py

python3 server.py

Enter fullscreen mode Exit fullscreen mode

All codes with docker files are present on GitHub

Top comments (0)