挑战杯 python区块链实现 - proof of work工作量证明共识算法-2 快速实现一个区块链

时间:2024-02-16 07:01:06

2.1 什么是区块链

区块链是一个不可变得,有序的被称之为块的记录链,它们可以包含交易、文件或者任何你喜欢的数据,但最重要的是,它们用hash连接在一起。

2.2 一个完整的快包含什么

一个索引,一个时间戳,一个事物列表,一个校验, 一个前快的散链表

2.3 什么是挖矿

挖矿其实非常简单就做了以下三件事:

1、计算工作量证明poW
2、通过新增一个交易赋予矿工(自已)一个币
3、构造新区块并将其添加到链中

2.4 工作量证明算法:

使用该算法来证明是如何在区块上创建和挖掘新的区块,pow的目标是计算出一个符合特定条件的数字,这个数字对于所有人而言必须在计算上非常困难,但易于验证,这就是工作证明背后的核心思想计算难度与目标字符串需要满足的特定字符串成正比。

2.5 实现代码



    import hashlib
    import json
    import requests
    from textwrap import dedent
    from time import time
    from uuid import uuid4
    from urllib.parse import urlparse
    from flask import Flask, jsonify, request
    
    class Blockchain(object):
        def __init__(self):
            ...
            self.nodes = set()
            # 用 set 来储存节点,避免重复添加节点.
            ...
            self.chain = []
            self.current_transactions = []
    
            #创建创世区块
            self.new_block(previous_hash=1,proof=100)
    
        def reister_node(self,address):
            """
            在节点列表中添加一个新节点
            :param address:
            :return:
            """
            prsed_url = urlparse(address)
            self.nodes.add(prsed_url.netloc)
    
        def valid_chain(self,chain):
            """
            确定一个给定的区块链是否有效
            :param chain:
            :return:
            """
            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")
                # 检查block的散列是否正确
                if block['previous_hash'] != self.hash(last_block):
                    return False
                # 检查工作证明是否正确
                if not self.valid_proof(last_block['proof'], block['proof']):
                    return False
    
                last_block = block
                current_index += 1
            return True

        def ressolve_conflicts(self):
            """
            共识算法
            :return:
            """
            neighbours = self.nodes
            new_chain = None
            # 寻找最长链条
            max_length = len(self.chain)
    
            # 获取并验证网络中的所有节点的链
            for node in neighbours:
                response = requests.get(f'http://{node}/chain')
    
                if response.status_code == 200:
                    length = response.json()['length']
                    chain = response.json()['chain']
    
                    # 检查长度是否长,链是否有效
                    if length > max_length and self.valid_chain(chain):
                        max_length = length
                        new_chain = chain
    
            # 如果发现一个新的有效链比当前的长,就替换当前的链
            if new_chain:
                self.chain = new_chain
                return True
            return False
    
        def new_block(self,proof,previous_hash=None):
            """
            创建一个新的块并将其添加到链中
            :param proof: 由工作证明算法生成证明
            :param previous_hash: 前一个区块的hash值
            :return: 新区块
            """
            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):
            # 将新事务添加到事务列表中
            """
            Creates a new transaction to go into the next mined Block
            :param sender:发送方的地址
            :param recipient:收信人地址
            :param amount:数量
            :return:保存该事务的块的索引
            """
            self.current_transactions.append({
                'sender':sender,
                'recipient':recipient,
                'amount':amount,
            })
    
            return  self.last_block['index'] + 1

        @staticmethod
        def hash(block):
            """
            给一个区块生成 SHA-256 值
            :param block:
            :return:
            """
            # 必须确保这个字典(区块)是经过排序的,否则将会得到不一致的散列
            block_string = json.dumps(block,sort_keys=True).encode()
            return hashlib.sha256(block_string).hexdigest()
    
        @property
        def last_block(self):
            # 返回链中的最后一个块
            return self.chain[-1]

        def proof_of_work(self,last_proof):
            # 工作算法的简单证明
            proof = 0
            while self.valid_proof(last_proof,proof)is False:
                proof +=1
            return proof
    
        @staticmethod
        def valid_proof(last_proof,proof):
            # 验证证明
            guess =  f'{last_proof}{proof}'.encode()
            guess_hash = hashlib.sha256(guess).hexdigest()
            return guess_hash[:4] =="0000"


    # 实例化节点
    app = Flask(__name__)
    
    # 为该节点生成一个全局惟一的地址
    node_identifier = str(uuid4()).replace('-','')
    
    # 实例化Blockchain类
    blockchain = Blockchain()
    
    # 进行挖矿请求
    @app.route('/mine',methods=['GET'])
    def mine():
        # 运行工作算法的证明来获得下一个证明。
        last_block = blockchain.last_block
        last_proof = last_block['proof']
        proof = blockchain.proof_of_work(last_proof)
    
        # 必须得到一份寻找证据的奖赏。
        blockchain.new_transaction(
            sender="0",
            recipient=node_identifier,
            amount=1,
        )
    
        # 通过将其添加到链中来构建新的块
        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_transactions():
        values = request.get_json()
    
        # 检查所需要的字段是否位于POST的data中
        required = ['seder','recipient','amount']
        if not all(k in values for k in request):
            return 'Missing values',400
    
        #创建一个新的事物
        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__':
        app.run(host='0.0.0.0',port=5000)

代码弄好启动你的项目以后打开Postman 完成以下操作

在这里插入图片描述

学长通过请求 http://localhost:5000/mine进行采矿

在这里插入图片描述