• Learn Blockchains by Building One: The fastest way to Learn how Blockchains work is to build One
  • Originally written by Daniel Van Flymen
  • The Nuggets translation Project
  • Permanent link to this article: github.com/xitu/gold-m…
  • Translator: cdpath
  • Proofreader: Atuooo Dubuqingfeng

Readers of this article are as excited about the rise of cryptocurrencies as I am about how the blockchain behind them works.

But blockchain is not easy to understand, and I struggle to understand it anyway. I watched a lot of hard to understand videos, learned a lot of buggy tutorials, found a few examples to try, and was disappointed.

I like to learn by doing. It forced me to fix something that was critical at the code level, and that’s where it got sticky. If you’re like me, by the end of this article you can build a working blockchain and have a solid understanding of how it works.

Background…

Remember that blockchains are immutable, ordered chains of records, also known as blocks. Blocks can contain transactions, files, or any other data you can think of. Crucially, though, they are linked together by the hash value ****.

If you don’t know what a hash is, read this article first.

Who is the target audience for this article? You should be able to read and write basic Python code, and have a basic understanding of how HTTP requests work, as the blockchain implementation in this article relies on HTTP.

What environment is required? Python version no less than 3.6, with PIP installed. You also need to install Flask and the awesome Requests library:

PIP install Flask = = 0.12.2 requests = = 2.18.4Copy the code

Oh, and you have to have an HTTP client, like Postman or cURL. Anything will do.

Where is the code? The source code is here.

Stands for blockchain

Create the Blockchain class, whose constructor creates two initially empty lists, one to store the Blockchain and the other to store transaction information. Class design is as follows:

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
Copy the code

Design of the Blockchain class

The Blockchain class is responsible for managing the chain. It is used to store transaction information and there are also helper methods for adding new blocks to the chain. So let’s implement some methods.

Adds transaction information to the block

In addition, you need a way to add transaction information to the block. To do this with the new_transaction() method, the code is pretty straightforward:

class Blockchain(object):
    ...
    
    def new_transaction(self, sender, recipient, amount):
        """
        Creates a new transaction to go into the next mined Block
        :param sender: <str> Address of the Sender
        :param recipient: <str> Address of the Recipient
        :param amount: <int> Amount
        :return: <int> 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
Copy the code

New_transaction (), after adding a new transaction to the list, returns the index of the block to which the transaction was added, pointing to the next block to be mined. We’ll see later that this is useful for users who submit transactions later.

Understand proof of workload

Proof-of-work algorithms (PoW) describe how new blocks in a blockchain are created or dug up. The purpose of PoW is to find numbers that conform to certain rules. For anyone in the network, that number must be hard to find and easy to verify from a computational standpoint. This is the core idea behind the proof-of-work algorithm.

Here is a very simple example to help understand.

We can stipulate that the hash of some integer x times another y must end in 0. Hash (x * y) = ac23dc… 0. For this example, you might as well make x = 5. Python is implemented as follows:

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}')Copy the code

The solution is y is equal to 21. Because you get a hash that ends in 0:

hash(5 * 21) = 1253e9373e... 5e3600155e860Copy the code

Bitcoin’s workload algorithm is called Hashcash. It is very similar to the example given above. Miners scramble to solve the algorithm to create new blocks. In general, the difficulty depends on how many specific characters are to be found in the string. Miners get paid in bitcoins in exchange for their answers.

And the Internet can easily verify the answer.

Step 2: Use Blockchain as an API

This article uses the Python Flask framework. Flask is a microframework that makes it easy to map network endpoints to Python functions. This makes it easy to interact with the blockchain over the network with HTTP requests.

Three methods need to be created:

  • /transactions/newAdd a transaction to the block
  • /mineNotifies the server to mine a new node
  • /chainReturns the complete blockchain

Trading side

Here is the content of the transaction request, which is sent to the server:

{
 "sender": "my address",
 "recipient": "someone else's address",
 "amount": 5
}
Copy the code

Since there are already class methods to add transactions to the block, the rest is simple. Write a function to add transactions:

import hashlib
import json
from textwrap import dedent
from time import time
from uuid import uuid4

from flask import Flask, jsonify, request

...

@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
Copy the code

Methods to create transactions

Step 3: Interact with Blockchain

You can use cURL or Postman to interact with the blockchain via an API over the network.

Start the server:

$python blockchain.py * Running on [http://127.0.0.1:5000/](http://127.0.0.1:5000/) (Press CTRL+C to quit)Copy the code

Through the GET request to http://localhost:5000/mine try to dig a new block.

Through a POST request to http://localhost:5000/transactions/new to create a New Deal, the POST data to include the following structure:

You can also use the equivalent cURL command to delete something:

$ curl -X POST -H "Content-Type: application/json" -d '{
 "sender": "d4ee26eee15148ee92c6cd394edd974e",
 "recipient": "someone-other-address",
 "amount": 5
}' "[http://localhost:5000/transactions/new](http://localhost:5000/transactions/new)"
Copy the code

After rebooting the server, you now have three blocks, along with the two newly mined blocks. By requesting http://localhost:5000/chain to view all chain blocks:

{"chain": [{"index": 1, "previous_hash": 1, "proof": 100, "timestamp": 1506280650.770839, "transactions": []}, {"index": 2, "previous_hash": "c099bc...bfb7", "proof": 35293, "timestamp": 1506280664.717925, "transactions": [ { "amount": 1, "recipient": "8bbcb347e0634905b0cac7955bae152b", "sender": "0" } ] }, { "index": 3, "previous_hash": "Eff91a...10f2", "proof": 35089, "timestamp": 1506280666.1086972, "transactions": [{"amount": 1," Recipient ": "8bbcb347e0634905b0cac7955bae152b", "sender": "0" } ] } ], "length": 3 }Copy the code

Step 4: Consensus

Pretty cool, right? We have built a basic blockchain that not only supports transactions, but also mines. But the core of blockchain is decentralization. But if you want to decentralize, how do you know that every block is in the same chain? That’s the consensus problem. If there’s more than one node in the network, you have to implement a consensus algorithm.

Implementing consensus networks

As mentioned above, conflict is the difference between one node’s chain and another node’s chain. To resolve conflict, we have a rule: the longest chain of validity is authority. In other words, the longest chain in the network is the one that is actually correct. With this algorithm, consensus can be achieved among multiple nodes in the network.

. import requests class Blockchain(object) ... def valid_chain(self, chain): """ Determine if a given blockchain is valid :param chain: <list> A blockchain :return: <bool> 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: <bool> 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 FalseCopy the code

The first method, valid_chain(), checks the validity of the chain by iterating through each block, verifying the hash and proof of work.

The resolve_Conflicts () method iterates through all neighboring nodes, downloading their chains, and verifies using the method above. If a valid chain is found that is longer than the local chain, the local chain is replaced.

Then register the two interfaces with the API, one to add neighbor nodes and the other to resolve 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
Copy the code

At this point, you can use another computer, if you like, to start different nodes in the network. Or use a different port on the same computer to start the process and join the network. I chose to register the new node with a different port on the same computer, so there are two nodes: http://localhost:5000 and http://localhost:5001.

I dug a new block at node 2 to make the chain longer at node 2. Then call /nodes/resolve of node 1 with GET to see that the chain has been replaced by the consensus algorithm:

And then we’re almost done. Ask some friends to try out your blockchain.

I hope this tutorial inspires you to build something new. I’m obsessed with digital cryptocurrencies because I believe blockchain technology will rapidly change the way we think about economics, government and the way we record information.

Update: I intend to continue with the second part of this article, continuing to expand the blockchain implemented in this article to cover transaction verification mechanisms and discuss how to productize blockchain.

If you enjoyed this tutorial, or have suggestions or questions, feel free to comment. If you find any bugs, feel free to contribute code here!


The Nuggets Translation Project is a community that translates quality Internet technical articles from English sharing articles on nuggets. The content covers Android, iOS, React, front-end, back-end, product, design and other fields. If you want to see more high-quality translation, please continue to pay attention to the Project, official Weibo, Zhihu column.