5.区块链挖矿与交易实现

本段代码将实现:1.区块链挖矿;2.挖矿后获得记账权;3.将链中的交易打包进区块。

NiuCoinBlockChain.py

from typing import Any,Dict,List,Optional
import time
import hashlib
from uuid import uuid4
import json
from flask import Flask
from flask import jsonify
from urllib.parse import urlparse
from flask import request

class NiuCoinBlockChain:

    #构造器
    def __init__(self):
        self.current_transcations=[]#缓存交易列表,在没有新区块前放在这里,产生新区块后,会被加入到新区块
        self.chain=[]#区块链管理多个区块
        self.nodes=set()#保存网络中的其它节点
        self.new_block(pre_hash="1",proof=100)#创世区块

    #新增一个新区块
    def new_block(self,pre_hash:Optional[str],proof:int)->Dict[str,Any]:
        block = {
            "index":len(self.chain)+1, #索引
            "timestamp":time.time(),
            "transcations":self.current_transcations,#将临时缓存的交易放在区块中
            "proof":proof,#工作量要记下来,校验区块时需要这个证明
            "pre_hash":pre_hash or self.chain[-1]["hash"]
        }
        block["hash"] = self.hash(block)
        self.current_transcations=[]#交易被打包成区块后,要清空
        self.chain.append(block)

    #新增一个新的交易
    def new_transcations(self,sender:str,recer:str,amount:int)->int:
        self.current_transcations.append({
            "sender":sender,
            "recer":recer,
            "amount":amount,
        })
        return self.last_block()["index"]+1

    # 获得最后一个区块
    def last_block(self)->Dict[str,Any]:
        return self.chain[-1]

    # 整个区块hash
    @staticmethod
    def hash(block:Dict[str,Any])->str:
        blockstring = json.dumps(block,sort_keys=True).encode()
        return hashlib.sha256(blockstring).hexdigest()

    # 不断修改值,进行hash碰撞,起到算出结果为止(即拿到证明)
    def proof_of_work(self,last_proof:int)->int:
        proof = 0
        while self.do_proof(last_proof,proof) is False:
            proof+=1
        return proof

    # 进行hash碰撞
    @staticmethod
    def do_proof(last_proof:int,proof:int)->bool:
        guess=f'{last_proof*proof}'.encode()
        guess_hash = hashlib.sha256(guess).hexdigest()
        return guess_hash[:4]=="0000"#难度可调
"""
    # 校验整个链是否正确
    def valid_chain(self,chain:List[Dict[str,Any]]):
        #用当前区块与前一个区块进行校验,循环至最后一个
        pre_block = chain[0]
        current_index = 1
        while current_index<len(chain):
            block = chain[current_index]
            if block["pre_hash"]!=self.hash(pre_block): #校验是否被篡改,hash要能对上
                return False
            if not self.valid_proof(pre_block["proof"],block["proof"]):#校验工作量正确
                return False
            pre_block = block
            current_index+=1
        return True

    # 节点注册,追加节点
    def register_node(self,addr:str)->None:
        now_url=urlparse(addr)#将addr转成对象,能取出schame或port等
        self.nodes.add(now_url.netloc)#netloc='www.cwi.nl:80'

    #节点同步:查找所有的节点,如果附近的节点比自己多,将邻居节点的链赋值给自己节点
    def resolve_conflicts(self)->bool:
        neighbours=self.nodes
        new_chain=None
        max_length=len(self.chain)
        for node in neighbours:#从邻居中取最长的链,赋值给new_chain
            response = requests.get(f"http://{node}/chain") #node的域名与端口都不一样
            if response.status_code==200:
                length = response.json()[length]
                chain = response.json()[chain]
                if length > max_length and self.valid_proof(chain):
                    max_length = length
                    new_chain = chain
        if new_chain:
            self.chain = new_chain#将最长的链赋值给自己
            return True
        return False
"""

niucoin = NiuCoinBlockChain()
node_id = str(uuid4()).replace("-","")
print("当前节点钱包地址:",node_id)

app = Flask(__name__)
@app.route("/")
def index_page():
    return "欢迎呵呵"

@app.route("/chain")
def chain():#输出区块链
    response={
        "chain":niucoin.chain,
        "length":len(niucoin.chain),
    }
    return jsonify(response),200

@app.route("/mine")#挖矿,系统奖励比特币
def index_mine():
    last_block = niucoin.last_block()
    last_proof = last_block["proof"]
    proof = niucoin.proof_of_work(last_proof) #挖矿,挖到矿才往下走

    niucoin.new_transcations("0",node_id,200) #获得奖励

    niucoin.new_block(None,proof)
    response={
        "message":"新的区块产生",
        "index":niucoin.last_block()["index"],
        "transcations":niucoin.last_block()["transcations"],
        "proof":niucoin.last_block()["proof"],
        "pre_hash":niucoin.last_block()["pre_hash"]
    }

    return jsonify(response),200

@app.route("/new_transcations",methods=["POST"])#交易
def new_transcations():
    values = request.get_json()
    required = ["payer","recer","amount"]
    if not all(key in values for key in required):
        return "数据不完整",400
    index = niucoin.new_transcations(values["payer"],values["recer"],values["amount"])
    response = {
        "message":f"交易加入到区块{index}"
    }
    return jsonify(response),200


if __name__ == "__main__":
    app.run("127.0.0.1",port=5000)

用flask输出区块链

先运行该类,在网址中输入『http://127.0.0.1:5000/chain

体验挖矿生成新区块,并获得区块奖励

先运行『http://127.0.0.1:5000/mine』两次;
再运行『http://127.0.0.1:5000/chain』即可看到创世区块后面追加了两个新区块,这两个新区块都有币的奖励

体验挖矿生成新区块,并获得区块奖励,并将未入区块的交易打包进区块

先运行『http://127.0.0.1:5000/mine』一次;
再用postman(其它http工具也行)运行『http://127.0.0.1:5000/new_transcations』两次;
再运行『http://127.0.0.1:5000/mine』一次;
查看结果:刚交易的数据被打包进了新区块。

    原文作者:浮云发发
    原文地址: https://www.jianshu.com/p/cdea966c89a0
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞