Create your own blockchain using Python (pt. 6)

The network

Guillaume Belanger
5 min readJul 18, 2021

Together we built three things: a blockchain, a node and a wallet. The blockchain contains blocks and each block contains transaction data, a timestamp and a hash of the previous block. The node stores the blockchain and validates new transactions. The wallet builds new transactions and is capable of sending those to the node. As of now, all of that beautiful code we built is central: it runs on your PC and nobody except you is able to make transactions. Let’s go back to Wikipedia (our great oracle) and continue reading the blockchain definition:

Blockchains are typically managed by a peer-to-peer network for use as a publicly distributed ledger.

This is where things get more complicated (and interesting frankly). In this section, we will start implementing code that will involve having our transactions being broadcasted to the network.

The blockchain network

Inside of Satoshi Nakamoto’s white paper on Bitcoin, the author defines the transaction process like this:

  1. New transactions are broadcast to all nodes.
  2. Each node collects new transactions into a block.
  3. Each node works on finding a difficult proof-of-work for its block.
  4. When a node finds a proof-of-work, it broadcasts the block to all nodes.
  5. Nodes accept the block only if all transactions in it are valid and not already spent.
  6. Nodes express their acceptance of the block by working on creating the next block in the chain, using the hash of the accepted block as the previous hash.

This means that instead of having the ledger stored centrally, we have a network of nodes that hold copies of the blockchain. They work with each other in a competitive manner to process transactions and ultimately maintaining the ledger.

Transaction validation

Transaction validation is the first item in the transaction process. Transactions are sent by the wallet and received by the bitcoin nodes that validate that they are valid.

We need to make adjustments to our Python code to accommodate remote transaction validation. Let’s start with modifying our wallet code to allow it to send HTTP requests to a node. We create two new classes in our wallet:

# wallet/wallet.pyimport requestsclass Node:
def __init__(self):
ip = "127.0.0.1"
port = 5000
self.base_url = f"http://{ip}:{port}/"

def send(self, transaction_data: dict) -> requests.Response:
url = f"{self.base_url}transactions"
req_return = requests.post(url, json=transaction_data)
req_return.raise_for_status()
return req_return


class Wallet:
def __init__(self, owner: Owner):
self.owner = owner
self.node = Node()

def process_transaction(self, inputs: [TransactionInput], outputs: [TransactionOutput]) -> requests.Response:
transaction = Transaction(self.owner, inputs, outputs)
transaction.sign()
return self.node.send({"transaction": transaction.transaction_data})

Not that we are adding a new library requirement called requests which helps form and send HTTP requests. As a user of those classes you would create and send a transaction like so:

utxo_0 = TransactionInput(transaction_hash="whatever_hash",
output_index=0)
output_0 = TransactionOutput(public_key_hash=b"whatever_public_key", amount=5)
your_wallet.process_transaction(inputs=[utxo_0], outputs=[output_0])

We also need to modify our node’s code so that it can receive HTTP requests (i.e. we want our node to have an API). To achieve this easily, we will use the very popular Flask framework to build a restful API. I won’t go into details on the framework itself and I’ll assume that you are familiar with it. If you’re not, you can use this simple quickstart guide to get your feet wet.

We create a main.py file that takes care of accepting HTTP requests and routing them to the correct methods. We create a method validate_transaction that is executed for each POST to the /transactions endpoint. Inside of this method, we simply call our node’s validate and validate_funds methods. We return status code 200 if there is no execution error and status code 400 if there’s any error.

# main.pyfrom flask import Flask, request

from node.node import NodeTransaction, TransactionException
from initialize_blockchain import blockchain

app = Flask(__name__)

blockchain_base = blockchain()


@app.route("/transactions", methods=['POST'])
def validate_transaction():
content = request.json
try:
node = NodeTransaction(blockchain_base)
node.receive(transaction=content["transaction"])
node.validate()
node.validate_funds()
node.broadcast()
except TransactionException as transaction_exception:
return f'{transaction_exception}', 400
return "Transaction success", 200

This simple Flask app can be started from your terminal like this:

export FLASK_APP=src/main.py
flask run

Note that you can change the HTTP port that your flask app listens on by adding the —- port option to flask run command. Example: flask run —-port 5002. This can also enable you to create multiple instances of the app on your laptop if each has a different port.

After the node validates the transaction, it sends it to the other nodes that it knows about.

Part of our node code, we create a new class to define node interactions:

# node/node.pyclass OtherNode:
def __init__(self, ip: str, port: int):
self.base_url = f"http://{ip}:{port}/"

def send(self, transaction_data: dict) -> requests.Response:
url = f"{self.base_url}transactions"
req_return = requests.post(url, json=transaction_data)
req_return.raise_for_status()
return req_return

We also add a new broadcast method in our NodeTransaction class that takes care of broadcasting transaction to other nodes. This method is called right after transactions are validated.

class NodeTransaction:
def broadcast(self):
node_list = [OtherNode("127.0.0.1", 5001), OtherNode("127.0.0.1", 5002)]
for node in node_list:
try:
node.send(self.transaction_data)
except requests.ConnectionError:
pass

Well that was fun! We are now able to send transactions from a wallet to a node via HTTP, have that transaction validated by the node and broadcasted to other nodes. Those two elements (wallet and node) don’t have to be on the same laptop anymore. They can be anywhere in the world as long as the wallet can reach the node via HTTP.

pow pow

For a while now I have been mentioning Proof-of-Work without really explaining what it is. Proof-of-Work (PoW) is one of the main components of bitcoin and most cryptocurrencies. Simply put, it involves having nodes solve computational problem in order to create new blocks. In the next section we will finally deep-dive into Proof-of-Work and learn about how it secures the blockchain network.

Code repository

Create your own blockchain using Python

References

--

--

Guillaume Belanger

Guillaume is a software developer from Montreal who writes about bip bop stuff.