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

作者: 浮云发发 | 来源:发表于2018-04-20 14:12 被阅读32次

    本段代码将实现: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』一次;
    查看结果:刚交易的数据被打包进了新区块。

    相关文章

      网友评论

        本文标题:5.区块链挖矿与交易实现

        本文链接:https://www.haomeiwen.com/subject/tzwakftx.html