Building a Blockchain is the easiest way to learn how they function.
You're excited about Cryptocurrencies' growth, and you're curious about how Blockchains work—the underlying technology but not sure where and how to learn blockchain programming. In this article, we will see how a blockchain works and how to create one.
Learning about blockchain programming isn't easy, and it can be best understood by doing. If you follow these steps, you'll have a working Blockchain program and a solid understanding of how they work by the end of this guide.
Before you begin, make sure you have everything you need.
Bear in mind that a blockchain is a chain of immutable, sequential records known as Blocks. They can hold transactions, files, or any other form of data. The important thing is that hashes are used to connect them. If you're not sure what a hash is, let me explain.
A hash function is a function that takes an input value and produces a deterministic output value based on that input value. Whenever you run the hash function, you will always get the same y output value for every x input value. Every input has a predetermined output in this manner. A function is simply something that takes an input and produces an output from it.
f(x)=y
Consequently, a hash function takes an input (which can be any data – numbers, files, etc.) and returns a hash. A hexadecimal number is widely used to describe a hash.
md5(“hello world”)=5eb63bbbe01eeed093cb22bb8f5acdc3
This is the md5 hash function, which produces a 32-character hexadecimal output from any input data. Hash functions are normally irreversible (one-way), which means you can't work out the input unless you try every possible input (this is called a brute-force attack).
Who is the target audience for this guide?
Since we'll be interacting with our Blockchain over HTTP, you should be comfortable reading and writing simple Python. You should also have a basic understanding of how HTTP requests function. We will create our blockchain in python.
What do I require? Make sure you have Python 3.6+ enabled, as well as pip. You'll also want Flask and the fantastic Requests library:
pip install Flask==0.12.2 requests==2.18.4
An HTTP client, such as Postman or cURL, is also needed.
Now that we are ready with the environment let us see how to create the first blockchain program step by step. There are the following steps involved.
1- Creating a Blockchain
2- BlockChain as an API
3- Interacting with Blockchain
4- Problem of Consensus
1- Creating a Blockchain
We'll make a Blockchain class with two constructors: one for storing our blockchain and another for storing transactions. The following is the outline for our class:
class Blockchain(object):
def __init__(self):
self.chain = []
self.current_transactions = []
def new_block(self):
# Creates a new Block and adds it to the chain
pass
def new_transaction(self):
# Adds a new transaction to the list of transactions
pass
@staticmethod
def hash(block):
# Hashes a Block
pass
@property
def last_block(self):
# Returns the last Block in the chain
pass
The Blockchain class is in charge of preserving the chain. It will keep track of transactions and include methods for adding new blocks to the chain. Let's get started on some processes.
What does a block look like?
An index, a timestamp (in Unix time), a list of transactions, a proof (more on that later), and the hash of the previous block are all included in each Block. The following is an example of a single Block:
block = {
'index': 1,
'timestamp': 0106057127.800556,
'transactions': [
{
'sender': "9259847gh2k2549f9dd5565783624jh11",
'recipient': "h88k3jkhh5696jk5654a5cj6kda5df7u",
'amount': 5,
}
],
'proof': 425984974226,
'previous_hash': "b5fe8269fe1ac4328ce45bc30ba6b13305412f17ea9203943d8e6e522bb2792a"
}
The definition of a chain should be clear at this point—each new block contains the hash of the previous block. This is important because it is what guarantees the immutability of blockchains:
If a previous block in the chain is corrupted, all subsequent blocks will have incorrect hashes. Does that make sense to you? If it doesn't, give it some time to sink in—it's the backbone of blockchains.
Incorporating Transactions into a Block:
A way to add transactions to a Block will be needed. This is done by our new transaction() process, which is fairly straightforward:
def new_transaction(self, sender, recipient, amount):
"""
Creates a new transaction to go into the next mined Block
:param sender: Address of the Sender
:param recipient: Address of the Recipient
:param amount: Amount
:return: The index of the Block that will hold this transaction
"""
self.current_transactions.append({
'sender': sender,
'recipient': recipient,
'amount': amount,
})
return self.last_block['index'] + 1
Following the addition of a transaction to the list, new transaction() returns the index of the block to which the transaction will be added—the next block to be mined. This will come in handy for the consumer who submits the transaction later on.
Developing New Blocks:
When we build our Blockchain, we'll need to seed it with a genesis block, which is a block that has no predecessors. Also, we'll need to include a "proof" in our genesis block, which is the product of mining (or proof of work). We'll get into mining a bit more later. We'll flesh out the methods for the new block(), new transaction(), and hash() apart from creating the genesis block in our constructor.
import hashlib
import json
from time import time
class Blockchain(object):
def __init__(self):
self.current_transactions = []
self.chain = []
# Create the genesis block
self.new_block(previous_hash=1, proof=100)
def new_block(self, proof, previous_hash=None):
"""
Create a new Block in the Blockchain
:param proof: The proof given by the Proof of Work algorithm
:param previous_hash: (Optional) Hash of previous Block
:return: New Block
"""
block = {
'index': len(self.chain) + 1,
'timestamp': time(),
'transactions': self.current_transactions,
'proof': proof,
'previous_hash': previous_hash or self.hash(self.chain[-1]),
}
# Reset the current list of transactions
self.current_transactions = []
self.chain.append(block)
return block
def new_transaction(self, sender, recipient, amount):
"""
Creates a new transaction to go into the next mined Block
:param sender: Address of the Sender
:param recipient: Address of the Recipient
:param amount: Amount
:return: The index of the Block that will hold this transaction
"""
self.current_transactions.append({
'sender': sender,
'recipient': recipient,
'amount': amount,
})
return self.last_block['index'] + 1
@property
def last_block(self):
return self.chain[-1]
@staticmethod
def hash(block):
"""
Creates a SHA-256 hash of a Block
:param block: Block
:return:
"""
# We must make sure that the Dictionary is Ordered, or we'll have inconsistent hashes
block_string = json.dumps(block, sort_keys=True).encode()
return hashlib.sha256(block_string).hexdigest()
We're almost done with our blockchain representation. But you're probably wondering how new blocks are made, forged, or mined at this point.
Proof of Work:
New Blocks are generated or mined using a Proof of Work algorithm (PoW) on the blockchain. PoW aims to find a number that solves a dilemma. The number must be difficult to locate but simple to verify (in terms of computation) by anyone on the network. Proof of Work is based on this concept.
To help this sink in, we'll look at a straightforward example. Let’s decide that the hash of some integer x multiplied by another y must end in 0. So,
hash(x * y) = ac23dc...0
And for example, let’s assume:
x = 5
Implementing this as following:
from hashlib import sha256
x = 5
y = 0 # We don't know what y should be yet...
while sha256(f'{x*y}'.encode()).hexdigest()[-1] != "0":
y += 1
print(f'The solution is y = {y}')
The solution is:
y = 21
Since the produced hash ends in 0:
hash(5 * 21) = 1253e9373e...5e3600155e860
Hashcash is the Proof of Work algorithm used in Bitcoin. And it's not too dissimilar from our previous example. Miners compete to solve this algorithm to construct a new block. The number of characters searched for in a string determines the complexity in general. The miners are then rewarded with a coin in a transaction for their solution. The network will quickly test their solution.
Basic Proof of Work implementation
Let's use a similar algorithm to implement our blockchain. The rule we'll use will be identical to the one shown above, which is :
“Find a number p that produces a hash with four leading 0s when hashed with the previous block's solution.”
import hashlib
import json
from time import time
from uuid import uuid4
class Blockchain(object):
...(code removed for brevity)
def proof_of_work(self, last_proof):
"""
Simple Proof of Work Algorithm:
- Find a number p' such that hash(pp') contains leading 4 zeroes, where p is the previous p'
- p is the previous proof, and p' is the new proof
:param last_proof:
:return:
"""
proof = 0
while self.valid_proof(last_proof, proof) is False:
proof += 1
return proof
@staticmethod
def valid_proof(last_proof, proof):
"""
Validates the Proof: Does hash(last_proof, proof) contain 4 leading zeroes?
:param last_proof: Previous Proof
:param proof: Current Proof
:return: True if correct, False if not.
"""
guess = f'{last_proof}{proof}'.encode()
guess_hash = hashlib.sha256(guess).hexdigest()
return guess_hash[:4] == "0000"
We could alter the number of leading zeroes to modify the algorithm's complexity. However, four is adequate. You'll discover that a single leading zero makes a big difference in the amount of time it takes to find a solution. Our class is nearly over, and we're able to start using HTTP requests to connect with it.
2- BlockChain as an API
Here, the Python Flask System will be used. It's a micro-framework that allows mapping endpoints to Python functions easily. This enables us to communicate with our blockchain through HTTP requests over the internet.
We'll formulate three methods:
- To add a new transaction to a block, type /transactions/new.
- To tell our server to mine a new block, form /mine.
- To get the entire Blockchain, select /chain.
Setting up Flask
In our blockchain network, our "server" will function as a single node. Let's start by writing some boilerplate code:
import hashlib
import json
from textwrap import dedent
from time import time
from uuid import uuid4
from flask import Flask
class Blockchain(object):
...(code removed for brevity)
# Instantiate our Node
app = Flask(__name__)
# Generate a globally unique address for this node
node_identifier = str(uuid4()).replace('-', '')
# Instantiate the Blockchain
blockchain = Blockchain()
@app.route('/mine', methods=['GET'])
def mine():
return "We'll mine a new Block"
@app.route('/transactions/new', methods=['POST'])
def new_transaction():
return "We'll add a new transaction"
@app.route('/chain', methods=['GET'])
def full_chain():
response = {
'chain': blockchain.chain,
'length': len(blockchain.chain),
}
return jsonify(response), 200
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
Here's a short rundown of what we've added above:
Line 15: Generates a new instance of our Node
Line 18: Assign our node a random name.
Line 21: Build a new instance of our Blockchain class.
Lines 24–26:Establish the /mine endpoint, which is a GET message.
Lines 28–30:Establish the /transactions/new endpoint, which will be a POST request since we'll be sending data to it.
Lines 32–38:Create the /chain endpoint, which returns the entire Blockchain.
Lines 40–41: The server is started on port 5000.
The Transactions Endpoint:
This is what a transaction request would look like. It's the information that the user sends to the server:
{
"sender": "sender address",
"recipient": "recipient address",
"amount": 5
}
The rest is simply because we already have a class method for adding transactions to a block.
Let's write the transaction-adding function:
import hashlib
import json
from textwrap import dedent
from time import time
from uuid import uuid4
from flask import Flask, jsonify, request
...(code removed for brevity)
@app.route('/transactions/new', methods=['POST'])
def new_transaction():
values = request.get_json()
# Check that the required fields are in the POST'ed data
required = ['sender', 'recipient', 'amount']
if not all(k in values for k in required):
return 'Missing values', 400
# Create a new Transaction
index = blockchain.new_transaction(values['sender'], values['recipient'], values['amount'])
response = {'message': f'Transaction will be added to Block {index}'}
return jsonify(response), 201
The Mining Endpoint:
The magic happens at our mining endpoint, and it's easy. It must achieve three objectives:
- Find out the Proof of Work.
- Add a transaction providing us 1 coin to reward the miner (us).
- Attach the new Block to the chain to forge it.
import hashlib
import json
from time import time
from uuid import uuid4
from flask import Flask, jsonify, request
...(code removed for brevity)
@app.route('/mine', methods=['GET'])
def mine():
# We run the proof of work algorithm to get the next proof...
last_block = blockchain.last_block
last_proof = last_block['proof']
proof = blockchain.proof_of_work(last_proof)
# We must receive a reward for finding the proof.
# The sender is "0" to signify that this node has mined a new coin.
blockchain.new_transaction(
sender="0",
recipient=node_identifier,
amount=1,
)
# Forge the new Block by adding it to the chain
previous_hash = blockchain.hash(last_block)
block = blockchain.new_block(proof, previous_hash)
response = {
'message': "New Block Forged",
'index': block['index'],
'transactions': block['transactions'],
'proof': block['proof'],
'previous_hash': block['previous_hash'],
}
return jsonify(response), 200
It's worth remembering that the mined block's recipient is our node's address. And the bulk of what we've done so far has been to communicate with our Blockchain class's methods. We're done now, and we can start communicating with our blockchain.
3- Interacting with Blockchain
To communicate with our API over a network, you can use cURL or Postman.
Start the server:
$ python blockchain.py
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
Let's see if we can mine a block by sending a GET request to
http://localhost:5000/mine
Let's start by making a POST request to create a new transaction:
http://localhost:5000/transactions/new with transaction structure as following:
Let's look at the whole chain by making a request:
http://localhost:5000/chain
{
"chain": [
{
"index": 1,
"previous_hash": 1,
"proof": 100,
"timestamp": 1596260667.770589,
"transactions": []
},
{
"index": 2,
"previous_hash": "c099cb...bfb9",
"proof": 35293,
"timestamp": 1596260689.717885,
"transactions": [
{
"amount": 1,
"recipient": "b56b9b37ec100ce75342559b8bbca40a",
"sender": "0"
}
]
},
{
"index": 3,
"previous_hash": "eff9a1...102f",
"proof": 35089,
"timestamp": 1596260896.1086553,
"transactions": [
{
"amount": 1,
"recipient": "b56b9b37ec100ce75342559b8bbca40a",
"sender": "0"
}
]
}
],
"length": 3
}
4- Problem of Consensus
This is awesome. We have a simple Blockchain that allows us to mine new Blocks and accept transactions. The point of Blockchains, however, is that they should be decentralized. And how do we ensure that they all represent the same chain if they're decentralized? This is known as the Consensus Problem, and if we want more than one node in our network, we'll need to implement a Consensus Algorithm.
Registering new Nodes
We need a way to let a node know about other nodes on the network before enforcing a Consensus Algorithm. Per node in our network should keep a list of other nodes. As a consequence, we'll need some additional endpoints.
⦁ /nodes/register for accepting a list of new nodes in the URL form.
⦁ /nodes/resolve for implementing our Consensus Algorithm, which resolves any conflicts and ensures a node's chain is right.
We'll need to update the constructor of our Blockchain and add a method for registering nodes:
...(code removed for brevity)
from urllib.parse import urlparse
...(code removed for brevity)
class Blockchain(object):
def __init__(self):
...
self.nodes = set()
...
def register_node(self, address):
"""
Add a new node to the list of nodes
:param address: Address of node. Eg. 'http://192.156.0.4:5000'
:return: None
"""
parsed_url = urlparse(address)
self.nodes.add(parsed_url.netloc)
It's worth remembering that we've used a set() to keep track of the list of nodes. This is a low-cost way to ensure that new node additions are idempotent, ensuring that no matter how many times we add a single node, it only appears once.
Putting the Consensus Algorithm into Operation
As previously described, a dispute arises when one node's chain varies from that of another node. To solve this, we'll apply the rule that the chain with the longest valid chain is the most authoritative. In other words, the de-facto chain is the one with the longest duration on the network. We achieve Consensus among the nodes in our network using this algorithm.
...(code removed for brevity)
import requests
class Blockchain(object)
...(code removed for brevity)
def valid_chain(self, chain):
"""
Determine if a given blockchain is valid
:param chain: A blockchain
:return: True if valid, False if not
"""
last_block = chain[0]
current_index = 1
while current_index < len(chain):
block = chain[current_index]
print(f'{last_block}')
print(f'{block}')
print("\n-----------\n")
# Check that the hash of the block is correct
if block['previous_hash'] != self.hash(last_block):
return False
# Check that the Proof of Work is correct
if not self.valid_proof(last_block['proof'], block['proof']):
return False
last_block = block
current_index += 1
return True
def resolve_conflicts(self):
"""
This is our Consensus Algorithm, it resolves conflicts
by replacing our chain with the longest one in the network.
:return: True if our chain was replaced, False if not
"""
neighbours = self.nodes
new_chain = None
# We're only looking for chains longer than ours
max_length = len(self.chain)
# Grab and verify the chains from all the nodes in our network
for node in neighbours:
response = requests.get(f'http://{node}/chain')
if response.status_code == 200:
length = response.json()['length']
chain = response.json()['chain']
# Check if the length is longer and the chain is valid
if length > max_length and self.valid_chain(chain):
max_length = length
new_chain = chain
# Replace our chain if we discovered a new, valid chain longer than ours
if new_chain:
self.chain = new_chain
return True
return False
The first approach is to use by looping around each block and checking both the hash and the proof, valid chain() decides if a chain is valid.
Resolve conflicts() is a method that loops through all of our neighbours, downloads their chains, and verifies them with the method above. If a valid chain with a length greater than ours is discovered, we replace ours.
Let's add two new endpoints to our API, one for adding neighbours and the other for resolving conflicts:
@app.route('/nodes/register', methods=['POST'])
def register_nodes():
values = request.get_json()
nodes = values.get('nodes')
if nodes is None:
return "Error: Please supply a valid list of nodes", 400
for node in nodes:
blockchain.register_node(node)
response = {
'message': 'New nodes have been added',
'total_nodes': list(blockchain.nodes),
}
return jsonify(response), 201
@app.route('/nodes/resolve', methods=['GET'])
def consensus():
replaced = blockchain.resolve_conflicts()
if replaced:
response = {
'message': 'Our chain was replaced',
'new_chain': blockchain.chain
}
else:.
response = {
'message': 'Our chain is authoritative',
'chain': blockchain.chain
}
return jsonify(response), 200
You can now move to a new computer and start spinning up different nodes on your network. Alternatively, you can run processes on various ports on the same computer. Here, a new node is built on a different port and registered with the current node. As a consequence, we have two nodes:
Then, on node 2, mine some new Blocks to ensure that the chain is longer.
After that, on node 1, use GET /nodes/resolve to replace the chain with the Consensus Algorithm:
Finally
That's what there is to it...Gather a group of friends to assist you in putting your Blockchain to the test. Hope you've been motivated to make something new as a result of this.
Blockchains are exciting because they can affect the way we think about markets, governments, and record-keeping. There's a lot to learn about blockchain programming & ethical hacking languages. Get together with seasoned experts on KoolStories. Download the app now to start your upskilling journey with our micro learning platform!