From 0-1 to quickly build a block chain

Recent hot block chain back, if you want to learn more block chain, then look at this article, taught you how to build your own block of a chain.

 

The fastest way to understand the chain of blocks - Construction of a person

 

See this article, indicating that you are also interested in the rise of encryption money, and want to know the technical principles behind how to run block chain works.

 

But I want to get to know the block chain is not easy. I have been studying many of the video, followed by flawed course, experiencing frustration because too few block chain related cases arising.

 

I like to learn from the action. It forced me to deal with the problem from the code level to solve the problem. If you're like me to do, then at the end of this guide, you will have a functioning chain block, they work and have a deeper understanding.

 

Ready to get started

 

Remember, the block chain is an immutable, continuous record chain, referred to as block. They may include transactions, documents or any data you like. But it is important that they are linked together by using a hash.

 

If you are unsure what a hash value, please refer here.

 

Tutorial for the crowd?

 

You can easily read and write some basic Python, and understand the work of the HTTP request, because this article will communicate via HTTP and block chain.

 

What is required?

 

Make sure that you have installed Python 3.6 + (and pip). You also need to install Flask and great Requests library:

 

pip install Flask==0.12.2 requests==2.18.4

 

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

 

Source code is available here.

 

Step 1: Construction of a block chains

 

Open your favorite text editor or IDE, I personally like PyCharm. Create a new file called blockchain.py of. We will only use a file, but if you are confused, you can always refer to the source code.

 

Display block chain

 

We will create a Blockchain class, its constructor creates an initial empty list (for storing our block chain) and the other for storage transactions. This is the script:

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 class 的demo

 

Our Blockchain class is responsible for the management chain. It stores things, and has a number of blocks to add new helper chain. Let's try some new approaches it.

What Block like?

 

Each Block has the following contents:

 

  • An index,

  • A time stamp (Unix time),

  • A list of transactions,

  • A proof (there will be more explained later)

  • The hash value of the previous block.

 

Single Block Example:

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

At this point, the concept of the chain should be very clear - each new block itself contains a hash value of the previous block. This is crucial because it gives not tamper resistance block chain: if the attackers destroyed the chain earlier block, then all subsequent blocks will contain incorrect hash value.

 

Do not know if you can understand Well, please take the time to understand it - this is the core idea of ​​the block chain.

 

Add things to the block

 

We need a method to add something to block. Our new_transaction () method is effective, but also very simple:

class Blockchain(object):  
...  
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

Add new_transaction () a new deal to the list, it will return to the transaction will be added to it, the index is about to be mined blocks. This user submitted after the transaction is very useful.

 

Create a new block

 

When we Blockchain is instantiated, we need to use a block to seed it genesis - a pre-processing block no. Also you need to add a "proof" to the creation of our block, as a result of excavation (working or proof) of. We will discuss in detail later mining.

 

In addition to creating genesis block in the constructor, we will enrich new_block (), new_transaction () and hash () method:

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()

The above content should be very simple - I added some comments and documentation strings to help keep clear. Told block chain is almost complete. But this time, you will want to know how to create, forging or digging a new block.

 

Learn workload prove

 

Work algorithm (PoW) is created or digging new block on the way to block chain. PoW's goal is to find numbers may solve the problem. From the figures, it is difficult to find this number, but can easily be used by anyone on the network for verification. This is the core ideological work to prove.

 

We will look at a very simple example to help understand.

 

Let us decide an integer X multiplied by Y another hash must be zero-terminated. Thus, for this simplified example, let's fix. Implemented in Python: xy0hash (x * y) = ac23dc ... 0x = 5

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}')

Solution is y = 21. Because, the generated hash value to 0 at the end:

 

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

 

In Bitcoin, the work proved algorithm called Hashcash. And with our example above is not much different. This is a miner in order to create a new block while competing solving algorithms. In general, the difficulty is determined by the number of characters in the string search. Then, by obtaining coins in the transaction, the miners will take the reward.

 

The network can easily verify their solutions.

 

The basic working examples prove

 

Let us achieve a similar algorithm block chain. Our rules will be similar to the example above:

 

Find a number p, when the digital hashing a block on the solution, to produce 4 4 ​​preamble with a hash of 0.

import hashlib  
import json  
from time import time  
from uuid import uuid4  
class Blockchain(object):  
...  
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"

To adjust the difficulty of the algorithm, we can modify the number of leading zeros. But 4 is enough. You will find that adding a single leading zeros can significantly shorten the time needed to find a solution.

 

Our class is almost complete, and we're ready to start using an HTTP request to interact with it.

 

Step 2: Our block chain as an API

 

We will use Python Flask framework. This is a micro-frame can be easily mapped to the endpoint Python function. This allows us to use the HTTP requests to communicate with the web through the block chain.

 

We will create three ways:

 

  • / Transactions / new to create a new trading blocks.

  • / Mine told our server digging a new block.

  • / Chain returns the full block chain.

 

Flask Set

 

Our "server" will be formed in a single node in the network our block chain. Let's create a demo:

import hashlib  
import json  
from textwrap import dedent  
from time import time  
from uuid import uuid4  
from flask import Flask  
class Blockchain(object):  
...  
# 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)

A brief description:

 

  • Line 15: Example of our node; the Flask for more information .

  • Line 18: Create a random name for the node.

  • Line 21: Blockchain class instantiated.

  • Line 24-26: Create / mine endpoint, which is a GET request.

  • Line 28-30: Create / transactions / new endpoints, this is a POST request, because we will send it data.

  • Line 32-38: Create / chain endpoint, which returns the full block chain.

  • 40-41 Line: Run the server on port 5000.

 

Trading endpoint

 

This is the way the transaction request. This is what the user is sent to the server:

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

Since we have to add the transaction to the block class methods, thus remaining operation is very simple. Let's 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

Create a method of trading

 

Mining endpoint

 

Our mining end is where the magic happens, it is very easy to use.

 

It must do three things:

 

  1. Computational effort to prove

  2. Reward miners (we) give us a coin by adding a transaction

  3. The chain on the new block 

import hashlib  
import json  
from time import time  
from uuid import uuid4  
from flask import Flask, jsonify, request  
...  
@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

 

Note that the recipient has been mined block is the address of our node. Furthermore, most of the work we do here is just to interact with the methods of Blockchain class. So far, we have completed, you can begin to interact with the block chain.

 

Step 3: block chains to interact with the

 

You can use plain old cURL or Postman interaction via a network with our API.

 

Start the server:

 

$ Python blockchain.py * Running on http://127.0.0.1:5000/ (Exit Press CTRL + C)

 

Let us try to http: // localhost: 5000 / mine: a GET request to tap a block:

 

 

Use a GET request postman Let's create a new transaction, by sending a request to http POST: // localhost: 5000 / transactions / new, its body contains our business structure:

 

 

Use POST request issued postman

 

If you do not use Postman, you can use cURL issue an equivalent request:

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  
}

步骤4:共识

 

我们目前已经拥有一个基本的区块链,可以接受交易并允许我们挖掘新的区块。但是区块链的重点在于它们应该去中心化。而且,如果它们是去中心,我们如何确保它们都反映相同的链?这叫做共识问题,如果我们要在网络中拥有多个节点,就必须实现共识算法。

 

注册新节点

 

在实现共识算法之前,我们需要一种让节点知道网络上相邻节点的方法。我们网络上的每个节点都应保留网络上其他节点的注册表。

 

因此,我们将需要更多的端点:

 

  1. /nodes/register 接受URL形式的新节点列表。

  2. /nodes/resolve 实现我们的共识算法,该算法可以解决所有冲突-确保节点具有正确的链。

 

我们需要修改区块链的构造函数,并提供一种注册节点的方法:

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

一种将相邻节点添加到网络的方法

 

请注意,我们使用了a set()来保存节点列表。这是一种廉价方法,它确保添加新节点是幂等,这意味着无论我们添加特定节点多少次,它都将只出现一次。

 

实施共识算法

 

如上所述,当一个节点与另一节点具有不同的链时会发生冲突。为了解决这个问题,我们规定最长的有效链是具有最高权威的。换句话说,网络上最长的链是事实链。使用此算法,我们可以在网络中的节点之间达成共识。

...  
import requests  
class Blockchain(object)  
...  
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

第一种方法valid_chain()负责通过检查每个块并验证哈希和检验链是否有效。

 

resolve_conflicts()是一种方法,它会检查我们所有的相邻节点,下载它们的链并使用上述方法验证它们。如果找到有效链,其长度大于我们的长度,我们将替换它。

 

让我们将两个端点注册到我们的API,一个端点用于添加相邻节点,另一个端点用于解决冲突:

@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

此时,您可以根据需要使用其他计算机,并在网络上启动不同的节点。或使用同一台计算机上的不同端口启动进程。我在机器上的另一个端口上旋转了另一个节点,并将其注册到当前节点。因此,我有两个节点:http://localhost:5000和http://localhost:5001。

 

 

注册新节点

 

然后,我在节点2上挖到了一些新区块,以确保链更长。之后,对GET  /nodes/resolve在节点1上进行了调用,在该节点上,该链被共识算法替换:

 

 

工作中的共识算法

 

目前为止已经接近成功;可以去找一些朋友一起帮助测试您的区块链。

原文标题:Learn Blockchains by Building One,作者:Daniel van Flymen

Guess you like

Origin www.cnblogs.com/coolyouguo/p/11791482.html