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
python3 -m venv env
python3 -m venv env

Enter fullscreen mode Exit fullscreen mode

for activating this virtualenv, we need to source it.

source ./env/bin/activate
source ./env/bin/activate
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
pip install Flask==2.2.2
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
import datetime
import json
import hashlib
import time
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")
    def __init__ (self) -> None:
        """
        initialize the blockchain
        """
        self.chain = []
        # create the genesis block
        self.create_block(proof=1, previous_hash="0")
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
    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
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]
    def get_previous_block(self):
        """
        get the previous block
        """
        return self.chain[-1]
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
  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
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
    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
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
   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
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)
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)
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()
from blockchain import Blockchain
blockchain = Blockchain()
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
@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
@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
@app.route('/get_chain', methods=['GET'])
def get_chain():
    blockchain_clone = blockchain.get_chain()
    return jsonify(blockchain_clone), 200
@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
@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
@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
python3 server.py
python3 server.py

Enter fullscreen mode Exit fullscreen mode

All codes with docker files are present on GitHub

原文链接:How To Build A Blockchain In Python

© 版权声明
THE END
喜欢就支持一下吧
点赞9 分享
Do not give in to fear
别在恐惧面前低下你的头
评论 抢沙发

请登录后发表评论

    暂无评论内容