Using Python and the flask Framework implementation creates a block chain, the workload proved that a consensus algorithm generates network node and a step by step run mining inspection (attached item complete code end of the article)

In this part of the block chain to explain the technical point of view, to achieve a simple block chain systems Python, a better understanding of the structure and principle of block chain.

1, with the proviso

  • You need to understand under the concept of block chain.

    Concept originated in the bit block chain of credits, to its nature is a centralized database of the distributed data storage, point transmission (are P2P), new applications of computer technology consensus pattern mechanism, encryption algorithm (taken from Wikipedia).

  • We need to understand the concept of hash.

    If you do not understand the hash, you can view the contents of know almost at the following address:
    https://www.zhihu.com/question/26762707

  • You need to understand the working principle of HTTP.

    Not understand the words, themselves Baidu or Google.

  • Installation Customer Support HTTP protocol end

    The Postman or cURL, other may be.

  • And other documents required to install Python3.6 +

    Later chapters "5, compiled Python files" will be explained in detail.

  • Source Address

    https://github.com/dvf/blockchain
    

2, create a block chain

Python program can be written in a variety of text editor or IDE, such Subline, EditPlus, PyCharm, VSCode, Atom and the like.

Create a new directory, for the time being named "py_blockchain_demo", written in python to be used to store the file, and then create a 'blockchain.py' file name.

2.1 Description block chain

Create a Blockchainclass constructor creates an empty list initialization (to store our block chain), and another storage transactions. The following are examples of 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

BlockchainClass is responsible for managing the chain data, it stores the transaction and also add a new block to Method chain data. Let's start with more ways to expand.

2.2 Block Structure

Each block has a 索引, a 时间戳(Unix时间戳), a 事务列表, a 校验(稍后详述), and 前一个块的散列.

Here is an example of Block:

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

At this point, a 区块链concept should be obvious - it is contained in each new block before the block therein 散列. This is crucial, because this is the 区块链reason can not be changed: If the attacker is damaged 区块链in an earlier block, all subsequent blocks will contain incorrect hash value.

That make sense? If you have not figured out, take the time to carefully think about - this is the core idea behind the block chain. There are confused I do not know how to learn a school friend Editor's Choice Python in learning learning qun 315 -346- 913 can learn to learn together and progress together! Share free videos

2.3 Add to trading block

We will need to add a transaction to block the way. Our responsibility new_transaction () method is this, and it is 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: <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

new_transaction() Add to the list the transaction method, which returns the index of the transaction will be added to the block --- useful to tell a user submits the transaction for later next mining.

2.4 to create a new block

When our Blockchainback is instantiated, we need to block creation (a no leading block blocks) added to it to go. We also need to add a block of our origins proved that this is the result of mining (or proof of work). We will discuss in detail later mining.

In addition to creating block creation in the constructor, we will complement new_block(), new_transaction()and hash()functions:

import hashlib
import json
from time import time

class Blockchain(object):
    def __init__(self):
        self.current_transactions = []
        self.chain = []

        # 创建创世区块
        self.new_block(previous_hash=1, proof=100)

    def new_block(self, proof, previous_hash=None):
        """
        创建一个新的区块到区块链中
        :param proof: <int> 由工作证明算法生成的证明
        :param previous_hash: (Optional) <str> 前一个区块的 hash 值
        :return: <dict> 新区块
        """

        block = {
            'index': len(self.chain) + 1,
            'timestamp': time(),
            'transactions': self.current_transactions,
            'proof': proof,
            'previous_hash': previous_hash or self.hash(self.chain[-1]),
        }

        # 重置当前交易记录
        self.current_transactions = []

        self.chain.append(block)
        return block

    def new_transaction(self, sender, recipient, amount):
        """
        创建一笔新的交易到下一个被挖掘的区块中
        :param sender: <str> 发送人的地址
        :param recipient: <str> 接收人的地址
        :param amount: <int> 金额
        :return: <int> 持有本次交易的区块索引
        """
        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):
        """
        给一个区块生成 SHA-256 值
        :param block: <dict> Block
        :return: <str>
        """

        # 我们必须确保这个字典(区块)是经过排序的,否则我们将会得到不一致的散列
        block_string = json.dumps(block, sort_keys=True).encode()
        return hashlib.sha256(block_string).hexdigest()

The above code should be straightforward --- To make the code clear, I've added some comments and documentation. We almost completed our block chain. But at this point you must be wondering how the new block is created, forged or mining.

3, the workload proved algorithm

3.1 understand the workload proved

Use the workload proved (PoW) algorithm, to demonstrate how to create a new block or tap on the block chain. PoW's goal is to calculate a numeric meet specific criteria, this figure must be very difficult for everyone concerned in the calculation, but easy to verify. This is the core idea behind the work proved.

We will see a simple example to help you understand:

Suppose integer x is multiplied by a Hash value of the product of another integer y must end in zero, i.e., hash (x * y) = ac23dc ... 0. Set x = 5, find y? Implemented in Python:

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 result is: y = 21. Because, the end of the generated Hash value must be zero.

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

In Bitcoin, the effort to prove the algorithm is called Hashcash , and it is very similar to the above questions, but very difficult to calculate. This is the problem the miners to compete for the right to create blocks and competing computing. In general, proportional to the number of computational difficulty of a particular character string with the target to be met, the miners calculate the result, you get a certain number of Bitcoin reward (transactions).

Verify the results, of course, very easy.

3.2 The effort to prove

Let's implement a similar PoW algorithm. Rules similar to the above examples:

Find a number P, such that it is spliced ​​with a previous proof block Hash value to the beginning of the string of 4 zeros.

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: <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):
        """
        Validates the Proof: Does hash(last_proof, proof) contain 4 leading zeroes?
        :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"

Way to measure complexity of the algorithm is to modify the beginning of the number zero. Use 4 to a demonstration, you will find more than a zero would greatly increase the time required to calculate the results.

Now Blockchain class has basically been completed, the next use HTTP requests to interact.

4, Blockchain API interface as

We will use Python Flask framework, which is a lightweight Web application framework, which will facilitate network request is mapped to Python function, and now we have to make Blockchain run on Flask web based.

We will create three interfaces:

  • / Transactions / new: create a trading and added to the block
  • / Mine: tell the server to tap new block
  • / Chain: returns the entire chain block

4.1 Creating nodes

Our "Flask server" block chain will play a node in the network. Let's add some skeleton code:

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

from flask import Flask

class Blockchain(object):
    ...

# 实例化节点
app = Flask(__name__)

# 为此节点生成一个全球唯一的地址
node_identifier = str(uuid4()).replace('-', '')

# 实例化 Blockchain 类
blockchain = Blockchain()

# 创建 /mine 接口,GET 方式请求
@app.route('/mine', methods=['GET'])
def mine():
    return "We'll mine a new Block"

# 创建 /transactions/new 接口,POST 方式请求,可以给接口发送交易数据
@app.route('/transactions/new', methods=['POST'])
def new_transaction():
    return "We'll add a new transaction"

# 创建 /chain 接口,返回整个区块链
@app.route('/chain', methods=['GET'])
def full_chain():
    response = {
        'chain': blockchain.chain,
        'length': len(blockchain.chain),
    }
    return jsonify(response), 200

# 服务器运行端口 5000
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

4.2 sends the transaction

Sent to the node's structure is as follows:

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

Because we already have ways to add transactions, so to add transaction-based interface is very simple. Let's write a function to add transaction:

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

4.3 mining

It is where the magic of mining, it is very simple to do about three things:

1. Calculate the workload proved PoW
2. miners granted by a new transaction (own) a currency
3. construct a new block and add it to the chain

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 of the transaction is our own server node, we do most of the work is just to interact around Blockchain class method. So far, we block chain even completed, we actually run.

5, compiled Python files

On a Mac compiler Python3 a little trouble here, especially to explain.

5.1 Mac installation Python3

Python were strong, one of the reasons for its wealth of third-party libraries. pip is the third-party libraries python package management tool.
Since the Mac python2 and python3 coexist. Thus python3 corresponding package management tool commandment is pip3.

If you install python3 by Homebrew, then pip3 will be installed. It is proposed to install python3 directly through the homebrew.

# 安装Python3
brew install python3
# 检查Python3版本(即检查是否安装成功)
python3 -V

5.2 Installation Pipenv

Python version of the many, often need to use different versions of Python in development, different projects may also use different versions of third-party libraries, which we need to build more virtual Python environment. pipenv official recommendation tool that allows Python virtual environment more convenient.

# 安装pipenv
pip3 install pipenv 

Create a virtual environment Python 5.3

Python files into the directory, in turn execute the following command

# 创建Python虚拟环境,并指定Python版本
pipenv --python=python3.6
# 安装Flask、requests模块
pipenv install Flask==0.12.2 requests==2.18.4

6, run block chain

You can use cURL or Postman and API to interact.
Specify the port number pipenv (code default port 5000 can be omitted behind "-p 5000"), and start Sever:

pipenv run python blockchain.py -p 5000

The terminal is shown below:

wenzildeiMac:py_blockchain_demo wenzil$ pipenv run python blockchain.py -p 5000
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

Let us request by HTTP: 5000 / Mine: // localhost (GET) to mining:

Mining

 

Initiate a GET request with Postman.

Create a transaction request, request HTTP: // localhost: 5000 / Transactions / new new (POST), as shown:

Create a transaction request

"Headers" add such Key-Value, the report server will return error "500 Internal Server Error".

'content-type':'application/json'

If not using Postman, look at the use of cURL statement is the same:

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

After submitted two requests, require mining (that is, the request "mine" Interface) to make the transaction effective.

 

Again mining Start Trading

In this case, again by requesting http: // localhost: 5000 / chain can get all the information blocks.

{
    "chain": [
        {
            "index": 1,
            "previous_hash": "1",
            "proof": 100,
            "timestamp": 1528705939.274652,
            "transactions": []
        },
        {
            "index": 2,
            "previous_hash": "22efcab1c2990f7d371e5159fe9f753ea4f5b0f9b173f0e41004eb1b6efcd1f7",
            "proof": 24960,
            "timestamp": 1528705943.739656,
            "transactions": [
                {
                    "amount": 1,
                    "recipient": "2aaa370d7d604b708678a510f11da5d7",
                    "sender": "0"
                }
            ]
        },
        {
            "index": 3,
            "previous_hash": "0cfdac7a19302f5d3af7d20ebf7997afadd88b5f4f937ade867c24701fc21158",
            "proof": 9425,
            "timestamp": 1528706168.36694,
            "transactions": [
                {
                    "amount": 5,
                    "recipient": "someone-other-address",
                    "sender": "d4ee26eee15148ee92c6cd394edd974e"
                },
                {
                    "amount": 5,
                    "recipient": "someone-other-address",
                    "sender": "d4ee26eee15148ee92c6cd394edd974e"
                },
                {
                    "amount": 1,
                    "recipient": "2aaa370d7d604b708678a510f11da5d7",
                    "sender": "0"
                }
            ]
        }
    ],
    "length": 3
}

7, consistency (consensus)

We've got a basic block chain can accept deals and mining. But the block chain system should be distributed. Since it is distributed, then take what we actually guarantee that all nodes have the same chain it? This is the consistency that we want to have multiple nodes on the network, it is necessary to achieve a consistency algorithm

7.1 Register the node

Before implementing the consensus algorithm, we need to find a way to make a node knows its adjacent nodes. Each node needs to keep a record containing the other nodes in the network. So let's add a few interfaces:

1, / nodes / register:. The new node receives a list of URL in the form of
2, / nodes / resolve:. Implementation Conformance algorithm, to resolve any conflicts, make sure you have the correct chain node
we modify the init function under Blockchain and provide a registered node method:

...
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 used to set the storage node, which is an easy way to add a node to avoid repetition.

7.2 to achieve consensus algorithm

Like the previous talking about it, when one node to another node has a different chain, it will produce conflict. To solve this problem, we will develop effective longest chain is the most authoritative rule. In other words: In this network the longest chain is the most authoritative. We will use this algorithm to reach a consensus between the 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 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:5000http://localhost:5001

注册一个新节点

 

然后我在节点 2 上挖掘了一些新的块,以确保链条更长。 之后,我在节点1上调用 GET /nodes/resolve,其中区块链数据由一致性算法取代(注:这一步运行结果跟原文有点出入,可以查看原文的结果):

 

验证节点

这是一个包,去找一些朋友一起,以帮助测试你的区块链。

最终完整Python源代码如下:

import hashlib
import json
from time import time
from urllib.parse import urlparse
from uuid import uuid4

import requests
from flask import Flask, jsonify, request


class Blockchain:
    def __init__(self):
        self.current_transactions = []
        self.chain = []
        self.nodes = set()

        # Create the genesis block
        self.new_block(previous_hash='1', proof=100)

    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'
        """

        parsed_url = urlparse(address)
        if parsed_url.netloc:
            self.nodes.add(parsed_url.netloc)
        elif parsed_url.path:
            # Accepts an URL without scheme like '192.168.0.5:5000'.
            self.nodes.add(parsed_url.path)
        else:
            raise ValueError('Invalid URL')


    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
            last_block_hash = self.hash(last_block)
            if block['previous_hash'] != last_block_hash:
                return False

            # Check that the Proof of Work is correct
            if not self.valid_proof(last_block['proof'], block['proof'], last_block_hash):
                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

    def new_block(self, proof, previous_hash):
        """
        Create a new Block in the Blockchain
        :param proof: The proof given by the Proof of Work algorithm
        :param previous_hash: 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
        """

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

    def proof_of_work(self, last_block):
        """
        Simple Proof of Work Algorithm:
         - Find a number p' such that hash(pp') contains leading 4 zeroes
         - Where p is the previous proof, and p' is the new proof

        :param last_block: <dict> last Block
        :return: <int>
        """

        last_proof = last_block['proof']
        last_hash = self.hash(last_block)

        proof = 0
        while self.valid_proof(last_proof, proof, last_hash) is False:
            proof += 1

        return proof

    @staticmethod
    def valid_proof(last_proof, proof, last_hash):
        """
        Validates the Proof
        :param last_proof: <int> Previous Proof
        :param proof: <int> Current Proof
        :param last_hash: <str> The hash of the Previous Block
        :return: <bool> True if correct, False if not.
        """

        guess = f'{last_proof}{proof}{last_hash}'.encode()
        guess_hash = hashlib.sha256(guess).hexdigest()
        return guess_hash[:4] == "0000"


# Instantiate the 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():
    # We run the proof of work algorithm to get the next proof...
    last_block = blockchain.last_block
    proof = blockchain.proof_of_work(last_block)

    # 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


@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


@app.route('/chain', methods=['GET'])
def full_chain():
    response = {
        'chain': blockchain.chain,
        'length': len(blockchain.chain),
    }
    return jsonify(response), 200


@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


if __name__ == '__main__':
    from argparse import ArgumentParser

    parser = ArgumentParser()
    parser.add_argument('-p', '--port', default=5000, type=int, help='port to listen on')
    args = parser.parse_args()
    port = args.port

    app.run(host='0.0.0.0', port=port)



 

Guess you like

Origin blog.csdn.net/weixin_44995023/article/details/92080603