6.区块链节点信息同步

作者: 浮云发发 | 来源:发表于2018-04-26 00:09 被阅读33次

区块链节点信息需要同步,本节主要讲一下选取最长的链做为基准链。

NiuCoinBlockChainOne.py

# -*- coding: utf-8 -*-
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
import requests

class NiuCoinBlockChainOne:

    # 构造器
    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_chain(chain):
                    max_length = length
                    new_chain = chain
        if new_chain:
            self.chain = new_chain#将最长的链赋值给自己
            return True
        return False

niucoin = NiuCoinBlockChainOne()
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

@app.route("/new_node",methods=["POST"])#新增一个节点
def new_node():
    values = request.get_json()
    nodes = values.get("nodes")#获得所有节点
    if nodes is None:
        return "数据有问题",400
    for node in nodes:
        niucoin.register_node(node) #加入节点
    response = {
        "message":f"节点已经追加",
        "node":list(niucoin.nodes)
    }
    return jsonify(response),200

@app.route("/node_synchronize")#节点信息同步
def node_refresh():
    replaced = niucoin.resolve_conflicts() #最长的链
    if replaced:
        response={
            "message":"区块链查新为最长区块链",
            "new_chain":niucoin.chain
        }
    else:
        response = {
            "message": "区块链已经是最长的,无需替换",
            "new_chain": niucoin.chain
        }
    return jsonify(response), 200

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

NiuCoinBlockChainTwo.py

# -*- coding: utf-8 -*-
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
import requests

class NiuCoinBlockChainTwo:

    #构造器
    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.path)#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_chain(chain)
                    max_length = length
                    new_chain = chain
        if new_chain:
            self.chain = new_chain#将最长的链赋值给自己
            return True
        return False

niucoin = NiuCoinBlockChainTwo()
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

@app.route("/new_node",methods=["POST"])
def new_node():
    values = request.get_json()
    nodes = values.get("nodes")#获得所有节点
    if nodes is None:
        return "数据有问题",400
    for node in nodes:
        niucoin.register_node(node) #加入节点
    response = {
        "message":f"节点已经追加",
        "node":list(niucoin.nodes)
    }
    return jsonify(response),200

@app.route("/node_refresh")
def node_refresh():
    replaced = niucoin.resolve_conflicts() #最长的链
    if replaced:
        response={
            "message":"区块链查新为最长区块链",
            "new_chain":niucoin.chain
        }
    else:
        response = {
            "message": "区块链已经是最长的,无需替换",
            "new_chain": niucoin.chain
        }
    return jsonify(response), 200

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

NiuCoinBlockChainThree.py

# -*- coding: utf-8 -*-
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
import requests

class NiuCoinBlockChainThree:

    #构造器
    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_chain(chain):
                    max_length = length
                    new_chain = chain
        if new_chain:
            self.chain = new_chain#将最长的链赋值给自己
            return True
        return False

niucoin = NiuCoinBlockChainTwo()
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

@app.route("/new_node",methods=["POST"])
def new_node():
    values = request.get_json()
    nodes = values.get("nodes")#获得所有节点
    if nodes is None:
        return "数据有问题",400
    for node in nodes:
        niucoin.register_node(node) #加入节点
    response = {
        "message":f"节点已经追加",
        "node":list(niucoin.nodes)
    }
    return jsonify(response),200

@app.route("/node_refresh")
def node_refresh():
    replaced = niucoin.resolve_conflicts() #最长的链
    if replaced:
        response={
            "message":"区块链查新为最长区块链",
            "new_chain":niucoin.chain
        }
    else:
        response = {
            "message": "区块链已经是最长的,无需替换",
            "new_chain": niucoin.chain
        }
    return jsonify(response), 200

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

以上用到的库(import),百度一下安装即可;
端口要用5位,我这里四位不行,比如6000;
运行时不要run flask,要配置python的运行环境(在pycharm在右上角可配置flask还是python环境);
代码比较长,先大概理解下代码,跑完程序就理解所有代码了;
有三个节点类,可以模拟三个节点信息同步,为了简单我仅演示两个。

1.准备最长链,节点1

访问『http://127.0.0.1:65531/mine』,执行10次,制造最长链;
访问『http://127.0.0.1:65531/chain』,可以显示有11个区块。

2.准备短链,节点2

访问『http://127.0.0.1:65532/mine』,执行2次,制造最短链;
访问『http://127.0.0.1:65532/chain』,可以显示有3个区块。

3.将所有节点注册

用postman执行『http://127.0.0.1:65532/new_node』,POST方式,内容为『{"nodes":["127.0.0.1:65531","127.0.0.1:65533"]}』,加入节点1与节点3至节点2,这里仅是模拟,不要加入自己(节点2),否则会卡住线程。

4.同步信息,将短的替换为长的

访问『http://127.0.0.1:65532/node_refresh』,同步最长链至当前节点;
至此就完成了简单的节点间信息同步。

相关文章

  • 6.区块链节点信息同步

    区块链节点信息需要同步,本节主要讲一下选取最长的链做为基准链。 NiuCoinBlockChainOne.py N...

  • 了解概念

    一、组成区块链的节点和区块分别是什么? 1.区块链网络有很多节点组成,这些节点在p2p网络里相互同步信息,就沟通了...

  • MAI:人工智能+区块链,跟造假说拜拜

    首先区块链共识协议限制着区块链的发展,因为协议中规定网络中的节点对于信息的处理时,节点都要对数据进行同步,因此区块...

  • [以太坊源码分析][p2p网络07]:同步区块和交易

    同步,也就是区块链的数据的同步。这里分为两种同步方式,一是本地区块链与远程节点的区块链进行同步,二是将交易均匀的同...

  • 区块链分布式技术【点量软件】

    [区块链系统] 区块链是通过分布式节点的存储资源,对全网全节点进行存储同步,并通过相应的共识技术保证内部节点对存储...

  • 24:全节点

    全节点指的是拥有网络中全部的数据的节点。全节点需要同步所有的区块链数据,它能够独立验证区块链上的所有交易并实时更新...

  • 【区块链笔记整理】共识机制种类

    概念: 共识机制是区块链节点就区块信息达成全网一致共识的机制,可以保证最新区块被准确添加至区块链、节点存储的区块链...

  • fabric 2.3 Ledger Snapshot

    Ledger Snapshot 新加入节点可以不用从0号区块开始同步区块,而是直接同步通道的snapshot信息,...

  • iptables 阻止Docker部署的区块链节点同步

    相关术语 热钱包:在线区块链节点,保持区块同步,负责获取链上最新数据、及广播交易等需要互联网的操作冷钱包:离线区块...

  • 2.1 cleos-commands-blockchain

    查询本地节点及链上部分数据的基本信息 1. 获取当前区块链的信息 获取当前区块链的信息。使用方式 cleos ge...

网友评论

    本文标题:6.区块链节点信息同步

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