Use Python to pull a blockchain from scratch, and python to start from scratch

Source: Internet
Author: User

Use Python to pull a blockchain from scratch, and python to start from scratch

The author believes that the fastest way to learn blockchain is to create one by yourself. This article will follow the author's instructions in using Python to create a blockchain.

We are new to the rise of digital currencies and want to know the technology behind it-how blockchain is implemented.

However, it is not easy to fully understand blockchain. I like to learn in practice and learn more about the technology by writing code. You can build a blockchain to deepen your understanding of the blockchain.

Preparations

This article requires you to have a basic understanding of Python, read and write basic Python, and a basic understanding of HTTP requests.

We know that blockchain is an immutable and ordered chain structure composed of block records. records can be transactions, files, or any data you want, it is important that they are linked through hashes.

If you are not familiar with hash, read this article.

Environment preparation

Prepare the environment and ensure that Python3.6 +, pip, Flask, and requests are installed.

Installation Method:

pip install Flask==0.12.2 requests==2.18.4

You also need an HTTP client, such as Postman, cURL, or other clients.

Reference Source Code (the original code cannot be run when I translate it. I fork a copy, fixed the error, and added the translation. Thanks to star)

Start creating Blockchain

Create a new blockchain. py file. All the code in this article is written in this file. You can refer to the source code at any time.

Blockchain

First, create a Blockchain class and create two lists in the constructor. One is used to store the Blockchain and the other is used to store transactions.

The following is the Blockchain framework:

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

Blockchain is used to manage the chain. It can store transactions and add new blocks. Next we will further improve these methods.

Block Structure

Each block contains attributes: index, Unix timestamp, transactions, workload proof (explained later), and Hash value of the previous block.

The following is the structure of a block:

block = { 'index': 1, 'timestamp': 1506057125.900785, 'transactions': [  {   'sender': "8527147fe1f5426f9dd545de4b27ee00",   'recipient': "a77f5cdfa2934df3954a5c7c7da5df1f",   'amount': 5,  } ], 'proof': 324984774000, 'previous_hash': "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"}

Here, the concept of blockchain is clear. Each new block contains the Hash of the previous block. This is the key and ensures the immutability of blockchain. If an attacker destroys a previous block, the Hash of all blocks will become incorrect. If you do not understand it, digest it slowly. For details, refer to {% post_link whatbc blockchain technical principles %}

Join transaction

Next we need to add a transaction to improve the new_transaction method.

Class Blockchain (object ):... def new_transaction (self, sender, recipient, amount): "generates new transaction information, which will be added to the next block to be dug: 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, 'reiient ': recipient, 'amount': amount,}) return self. last_block ['index'] + 1

Method to add a transaction record to the List, and return the index of the block to which the record will be added (the next block to be mined), which will be useful when users submit transactions.

Create new block

When Blockchain is instantiated, we need to construct a creation block (the first block without the previous block) and add a proof of work to it.

Each block must be proven by the workload, which is commonly known as mining. We will continue to explain it later.

To construct the creation block, we also need to improve the new_block (), new_transaction (), and hash () methods:

Import hashlibimport jsonfrom time import timeclass 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): "" generate a new block: param proof: <int> The proof given by the Proof Work algorithm: param previus_hash: (Optional) <str> Hash of previous Block: return: <dict> New Block "" block = {'index': len (self. chain) + 1, 'timestamp': time (), 'transactions': self. current_transactions, 'prop': proof, 'previous _ hash': previus_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): "generates new transaction information, which is added to the next block to be dug: 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, 'reiient ': recipient, 'amount': amount,}) return self. last_block ['index'] + 1 @ property def last_block (self): return self. chain [-1] @ staticmethod def hash (block): "generate the block's SHA-256 hash value: param Block: <dict> block: return: <str> "" # 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 ()

Through the above Code and comments, you can have a visual understanding of the blockchain. Next, let's look at how the blockchain is dug out.

Understanding workload proof

The new block is constructed based on the workload proof algorithm (PoW. The goal of PoW is to find a number that meets a specific condition, which is hard to calculate but easy to verify. This is the core idea of workload proof.

For ease of understanding, for example:

Assume that the Hash value of the product of an integer x multiplied by another integer y must end with 0, that is, hash (x * y) = ac23dc... 0. Set the variable x = 5, and find the value of y?

Python is implemented as follows:

From hashlib import sha256x = 5y = 0 # y unknown while sha256 (F' {x * y} '. encode (). hexdigest () [-1]! = "0": y + = 1 print (f'the solution is y = {y }')

The result is y = 21. because:

hash(5 * 21) = 1253e9373e...5e3600155e860

In bitcoin, the workload verification algorithm, known as Hashcash, is similar to the problem above. In order to compete for the right to create a block, the miner is competing for computing results. Generally, the computing difficulty is proportional to the number of characters that the target string must satisfy. After the miner calculates the result, he will receive a bitcoin reward.
Of course, it is very easy to verify this result on the network.

Implementation workload proof

Let's implement a similar PoW algorithm. The rule is: Find a number p so that the Hash value of the string spliced with the proof of the previous block starts with four zeros.

Import hashlibimport jsonfrom time import timefrom uuid import uuid4class Blockchain (object ):... def proof_of_work (self, last_proof): "" Simple Proof of work:-find a p' to make hash (pp ') start with 4 zeros-p is the proof of the previous block, and P' is the proof of the current: param last_proof: <int>: return: <int> "" proof = 0 while self. valid_proof (last_proof, proof) is False: proof + = 1 return proof @ staticmethod def valid_proof (last_proof, proof): "Verification proof: whether to hash (l Ast_proof, proof) starts with four 0? : Param last_proof: <int> Previous Proof: param proof: <int> Current Proof: return: <bool> True if correct, False if not. "guess = f' {last_proof} {proof }'. encode () guess_hash = hashlib. sha256 (guess ). hexdigest () return guess_hash [: 4] = "0000"

The algorithm complexity can be measured by modifying the number starting with zero. Use four for demonstration. You will find that the time required to calculate the result is greatly increased if one is greater than zero.

Now the Blockchain class is basically complete, and then use HTTP requests for interaction.

Blockchain as API Interface

We will use the Python Flask framework, a lightweight Web application framework that maps network requests to Python functions. Now let's run Blockchain on the Flask web.

We will create three interfaces:

  • /Transactions/new create a transaction and add it to the block
  • /Mine tells the server to mine new blocks
  • /Chain returns the entire blockchain

Create a node

Our "Flask server" will act as a node in the blockchain network. Let's first add some framework code:

import hashlibimport jsonfrom textwrap import dedentfrom time import timefrom uuid import uuid4from flask import Flaskclass Blockchain(object): ...# Instantiate our Nodeapp = Flask(__name__)# Generate a globally unique address for this nodenode_identifier = str(uuid4()).replace('-', '')# Instantiate the Blockchainblockchain = 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), 200if __name__ == '__main__': app.run(host='0.0.0.0', port=5000)

Briefly describe the above Code:

Row 3: Create a node.
Row 18th: Creates a random name for the node.
Row 21st: instance Blockchain class.
Line 24-26: Create/mine GET interface.
Line 28-30: Create/transactions/new POST interface to send transaction data to the interface.
Row 32-38: Create/chain interface, return the entire blockchain.
Line 40-41: the service runs on port 5000.

Send transaction

The transaction data structure sent to the node is as follows:

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

There are already methods for adding transactions. It is easy to add transactions based on interfaces.

import hashlibimport jsonfrom textwrap import dedentfrom time import timefrom uuid import uuid4from flask import Flask, jsonify, request...@app.route('/transactions/new', methods=['POST'])def new_transaction(): values = request.get_json() # Chek 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

Mining

Mining is amazing. It is very simple and has done three things:

  1. Proof of computing workload PoW
  2. Grant a miner (himself) a coin by adding a transaction
  3. Construct a new block and add it to the chain
Import hashlibimport jsonfrom time import timefrom uuid import uuid4from flask import Flask, jsonify, request...@app.route ('/mine', methods = ['get']) def mine (): # We run the proof work algorithm to get the next proof... last_block = blockchain. last_block last_proof = last_block ['prop'] proof = blockchain. proof_of_work (last_proof) # reward nodes with proof of workload. # If the sender is "0", it indicates that it is a newly dug coin blockchain. new_transaction (sender = "0", recipient = node_identifier, amount = 1,) # Forge the new Block by adding it to the chain block = blockchain. new_block (proof) response = {'message': "New Block Forged", 'index': block ['index'], 'transactions': block ['transactions'], 'prop': block ['prop'], 'previous _ hash': block ['previous _ hash'],} return jsonify (response), 200

Note that the transaction receiver is our own server node. Most of the work we do is to interact with Blockchain methods. At this point, even if our blockchain is complete, we can actually run it.

Run blockchain

You can use cURL or Postman to interact with APIs.

Start server:

$ python blockchain.py* Runing on http://127.0.0.1:5000/ (Press CTRL+C to quit)

Let's request http: // localhost: 5000/mine for mining.

Add a new transaction using the post request

If Postman is not used, the following cURL statement is also used:

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

After digging twice, there are three blocks. You can obtain all the block information by requesting http: // localhost: 5000/chain.

{ "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}

Consistency (consensus)

We already have a basic blockchain that can accept transactions and mining. However, the blockchain system should be distributed. Since it is distributed, what can we do to ensure that all nodes have the same chain? This is the consistency problem. To have multiple nodes on the network, we must implement a consistent algorithm.

Register nodes

Before implementing the consistency algorithm, we need to find a way to let a node know its adjacent nodes. Each node needs to save a record containing other nodes in the network. So let's add several interfaces:

  1. /Nodes/register: list of new nodes in URL format
  2. /Nodes/resolve executes consistency algorithms to resolve any conflicts and ensure that nodes have the correct chain

Modify the init function of Blockchain and provide a method for registering nodes:

...from urllib.parse import urlparse...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: <str> Address of node. Eg. 'http://192.168.0.5:5000'  :return: None  """  parsed_url = urlparse(address)  self.nodes.add(parsed_url.netloc)

We use set to store nodes, which is a simple method to avoid repeated addition of nodes.

Consensus Algorithms

As mentioned above, conflict means that different nodes have different chains. To solve this problem, the longest and most effective chain is the final chain. In other words, the longest valid chain in the network is the actual chain.

We use the following algorithm to reach consensus in the network.

... Import requestsclass 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 Block is correct if block ['previous _ hash']! = Self. hash (last_block): return False # Check that the Proof Work is correct if not self. valid_proof (last_block ['prop'], block ['prop']): return False last_block = block current_index + = 1 return True def resolve_conflicts (self ): "Consensus algorithms resolve conflicts using the longest chain in the network.: return: <bool> True if the chain is replaced; otherwise, False "neighbors = 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 neighbors: 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 method valid_chain () is used to check whether it is a valid chain and traverse each block to verify the hash and proof.

The resolve_conflicts () method is used to resolve conflicts, traverse all neighboring nodes, and check the validity of the chain using the previous method. If the longer chain is found to be valid, replace the chain.

Let's add two routes, one for registering nodes 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 run nodes on different machines or enable different network ports on one machine to simulate a multi-node network. Here, you can enable different ports on the same machine for demonstration, run the command on different terminals to start two nodes: http: // localhost: 5000 and http: // localhost: 5001.

pipenv run python blockchain.pypipenv run python blockchain.py -p 5001

Then dig two blocks on node 2 to ensure a longer chain, and then access the interface/nodes/resolve on node 1, at this time, the chain of Node 1 will be replaced by the chain of Node 2 through the consensus algorithm.

Summary

The above section describes how to use Python to pull a blockchain from scratch. I hope it will be helpful to you. If you have any questions, please leave a message, the editor will reply to you in a timely manner. Thank you very much for your support for the help House website!

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.