区块链开发2

一.区块链中节点间的通信

区块链网络

  • 公有链区块链网络
  • 私有链区块链网络
  • 联盟链区块链网络

1.基于python Networkx工具基础

安装Networkx:

pip install networkx

创建图形

import networkx as nx
G = nx.Graph()

 添加节点

G.add_node(1)
#添加2,3节点
G.add_node_from([2,3])

添加边

G.add_edge(1,2)

e = (2,3)
G.add_edge(*e)

也可以通过可迭代对象添加
G.add_edges_from([(1,2),(1,3)])

2.私有链网络图像


import networkx as nx
import matplotlib.pyplot as plt

#创建图形
G = nx.Graph()
#形成中心节点
G.add_node(0)
#形成外部节点
for i in range(1,30):
    G.add_node(i)
    # 每个节点与中心节点相连
    G.add_edge(0,i)

#配置节点大小为50
options = {
    'node_size': 50,
}
nx.draw(G,**options)
plt.show()

3.联盟链网络图像

import networkx as nx
import matplotlib.pyplot as plt

#创建图形
G = nx.Graph()
#创建中心节点
G.add_node(0)
G.add_node(1)
G.add_node(2)
G.add_node(3)
G.add_node(4)
G.add_node(5)
#连接中心节点
G.add_edge(0,1)
G.add_edge(1,2)
G.add_edge(2,3)
G.add_edge(3,4)
G.add_edge(4,5)
G.add_edge(5,0)

#为每个中心节点创建节点
for i in range(0,6):
    for j in range(0,5):
        sub_node = f'{i}{j}'
        G.add_node(sub_node)
        #连接每个外部节点与中心节点
        G.add_edge(i,sub_node)
#设置节点大小
options = {
    'node_size': 50,
}

nx.draw(G,**options)
plt.show()

4.公有链网络图像


import networkx as nx
import matplotlib.pyplot as plt

G = nx.gnp_random_graph(50,0.08)
options = {
    'node_size': 50,
}
nx.draw(G,**options)
plt.show()

 

p2p网络通信 

1.p2p概念

对等式网络,又称点对点技术,是无中心服务器,依靠用户群交换信息的互联网体系,作用是减低以往网络传输中的节点,降低资料遗失的风险。

2.socket通信

基于python实现p2p通信

创建socket服务端

注意需要下载pip install flask-socketio


from flask import Flask,request
import flask_socketio
app = Flask(__name__)
#定义变量名my_socketio
# cors_allowed_origins='*'配置内容表示允许跨域
my_socketio = flask_socketio.SocketIO(app,cors_allowed_origins='*')
# 创建以message为标识的socket接口
@my_socketio.on('message')
def message(message):
    print(f'receive message:{message}')
    

if __name__ == '__main__':
    my_socketio.run(app,host='0.0.0.0',port=5001,debug=True)

创建socket客户端

需要下载pip install "python-socketio[client]"


import socketio
import time
sio = socketio.Client()
sio.connect('http://localhost:5001')

for i in range(0,10):
    sio.emit("message",'hello,this is client')
    time.sleep(1)

服务端将出现

 运用socket构建p2p通信

 socker1文件


from flask import Flask,request
import flask_socketio
import socketio
import time

app = Flask(__name__)

#创建Socket服务端
my_socketio = flask_socketio.SocketIO(app,cors_allowed_origins='*')
@my_socketio.on('message')
def message(message):
    print(f"receive message:{message}")

@app.route('/send',methods=['POST'])
def send_message():
    body = request.json
    #创建Socket客户端
    sio = socketio.Client()
    # 连接socket2的服务端,端口号为5001
    sio.connect('http://localhost:50001')
    # 发送数据
    sio.emit("message",body['data'])
    time.sleep(3)
    # 断开数据
    sio.disconnect()
    return "ok"

if __name__ == '__main__':
    # 节点1(socket1),配置端口为5000
    my_socketio.run(app,host='0.0.0.0',port=5000)

socker2文件


from flask import Flask,request
import flask_socketio
import socketio
import time
app = Flask(__name__)

# 创建socket服务端
my_socketio = flask_socketio.SocketIO(app,cors_allowed_origins='*')
@my_socketio.on('message')
def message(message):
    print(f"receive message:{message}")

@app.route('/send',methods=['POST'])
def send_message():
    body = request.json
    # 创建socket客户端
    sio = socketio.Client()
    # 连接socket1的服务端,端口号为5000
    sio.connect('http://localhost:5000')
    sio.emit("message",body['data'])
    time.sleep(3)
    # 断开连接
    sio.disconnect()
    return 'ok'

if __name__ == '__main__':
    # 节点socket2,配置端口号为5001
    my_socketio.run(app,host='0.0.0.0',port=50001)

 

 

区块链网络的数据传播方式 

1.Gossip协议

基于Flask-APScheduler定时器


from flask import Flask
import datetime
from flask_apscheduler import APScheduler
class Config(object):
    """
    创建定时器的配置内容,需要加载进入Flask进程
    """
    # 执行任务配置内容,这里以间隔的方式实现
    JOBS = [
        {
            'id':'job1',
            'func':'scheduler1:task1',
            'args':(1,2),
            'trigger':'interval',
            'seconds':10

        }
    ]
    # 用于启动定时器,True表示启动
    SCHEDULER_API_ENABLED = True

#定义间隔执行任务时执行的函数
def task1(a,b):
    print(f'{datetime.datetime.now()} execute simple task a+b is {a}+{b}={a+b}')
    
if __name__ == '__main__':
    # 第一步:创建flask执行对象app
    app = Flask(__name__)
    # 第二步:在Flask对象中加载定时任务的配置
    app.config.from_object(Config())
    # 第三步:创建APScheduler调渡器
    scheduler = APScheduler()
    # 第四步:将Flask执行对象和调渡器绑定
    scheduler.init_app(app)
    # 第五步:启动调渡器
    scheduler.start()
    # 第六步:启动flask进程
    app.run(port=8001)

以装饰器的方式创建定时器


from flask import Flask
from flask_apscheduler import APScheduler
import datetime

# 第一步:创建flask执行对象app
app = Flask(__name__)
# 第二步:创建APScheduler调渡器
scheduler = APScheduler()
# 第三步:配置flask app进程,打开调渡器
class Config(object):
    SCHEDULER_API_ENABLED = True
    # 第四步:在flask对象中加载配置
app.config.from_object(Config())
# 第五步:将flask执行对象和调渡器绑定
scheduler.init_app(app)

# 第六步:创建定时启动的任务
@scheduler.task('interval',id='job1',seconds=5,misfire_grace_time=900)
def job():
    print(str(datetime.datetime.now()) + 'executed job!')

if __name__ == '__main__':
    # 第七步:启动定时器
    scheduler.start()
    # 第八步:启动falsk进程
    app.run(port=8002)

2.搭建基于gossip协议的区块链系统

(1) 创建区块链网络(Network)、节点(Peer)以及消息(Message)对象模型。

创建models.py:

import matplotlib.pyplot as plt   
import networkx as nx
import socketio
class Network(object):
    def __init__(self,name):
        """
        初始化区块链网络
        :param name:
        """
        # 网络中存在的节点
        self.peers = []
        # 网络名称
        self.name = name
        # 网络中定义的networkx网络拓扑
        self.G = nx.Graph()

    def add_peer(self,peer):
        """
        在网络中新增的节点
        """
        self.peers.append(peer)
        self.G.add_node(peer.name,host=peer.host,port=peer.port)

    def add_edge(self,s_peer,e_peer):
        """
        在网络中新增节点的边
        """
        e = (s_peer,e_peer)
        self.G.add_edge(*e)

    def del_peer(self,peer_name):
        """
        删除指定名称的节点
        """
        for i,peer in enumerate(self.peers):
            if peer_name == peer.name:
                del self.peers[i]
        self.G.remove_node(peer_name)

    def draw_network(self):
        """
        绘制网络
        """
        pos = nx.spring_layout(self.G,iterations=100)
        nx.draw(self.G,pos,with_labels=True)
        plt.show()

class Peer(object):
    def __init__(self,name,host,port):
        """
        初始化节点
        :param name:节点名称
        :param host:节点的主机ip
        :param port:节点的端口
        """
        self.name = name
        self.host = host
        self.port = port
        # 节点当前最新的数据版本号
        self.version = 0
        # 节点存贮数据的数据池
        self.pool = []
        self.sio = socketio.Client()

    def add_message(self,message):
        """
        在数据池中添加信息
        :param message:传入的message对象
        """
        self.pool.append(message)

class Message(object):
    def __init__(self,data,c_time):
        """
        初始化消息对象
        :param data:传递的数据
        :param c_time:创建的时间
        """
        self.data = data
        self.c_time = c_time
        # 消息的版本号,用与跟踪最新消息
        self.version = int(c_time.timestamp())

    def to_dict(self):
        """
        将消息转化为字典
        :return:消息的字典对象
        """
        return {
            'data':self.data,
            'c_time':self.c_time.strftime("%Y-%m-%d %H:%M:%S"),
            'version':self.version
        }




(2)定义通用返回

创建http_res.py


# HTTP响应
# 空数据响应
empty_res = {'code':404,'data':'empty data'}
# 成功响应
success_res = {'code':200,'data':'ok'}

(3)定义通用处理函数

services.py

import networkx as nx
import models
from datetime import datetime
import random
from flask import jsonify
import http_res

def generate_network(network_name,peer_list):
    """
    生成区块链网络,初始化Networkx实体,以及在实体中加入节点和边
    :param network_name:网络名称
    :param peer_list:以生成的节点列表
    :return:生成的区块链网络实体对象

    """
    g_network = models.Network(network_name)
    for index,peer in enumerate(peer_list):
        g_network.add_peer(peer)
        if index == len(peer_list) - 1:
            # 如果时最后一个节点,那就让最后一个节点和第一个节点首尾相连
            g_network.add_edge(peer.name,peer_list[0].name)
        else:
            # 否则,建立本节点与下一个节点的边
            g_network.add_edge(peer.name,peer_list[index+1].name)

    return g_network

def new_msg_service(body,c_peer):
    """
    HTTP接口处理函数,添加新消息处理函数
    :param body:HTTP POST请求体内容
    :param c_peer:当前节点对象
    """
    if 'data' not in body:
        return jsonify(http_res.empty_res)
    # 创建新的消息对象
    msg = models.Message(body['data'],datetime.now())
    # 将消息对象存贮与当前节点中
    c_peer.add_message(msg.to_dict())
    c_peer.version = msg.version
    return jsonify(http_res.success_res)

def send_version(peer,network):
    """
    socket客户端处理函数,随机发送最新数据版本服务
    :param peer:当前节点
    :param network:当前区块链网络
    :return:
    """
    print('start to send version!')
    peer_name = peer.name
    neighbours = list(network.G.adj[peer_name])
    rand_index = random.randint(0,len(neighbours)-1)
    neighbour_peer_name = neighbours[rand_index]
    neighbour_peer = network.G.nodes()[neighbour_peer_name]
    req_url = f"http://{neighbour_peer['host']}:{neighbour_peer['port']}"
    res_url = f"http://{peer.host}:{peer.port}"
    print(f'connect to peer {req_url}')
    peer.sio.connect(req_url)
    send_msg = {
        'version':peer.version,
        'url':res_url
    }
    peer.sio.emit('peer-version',send_msg)
    peer.sio.disconnect()

def peer_version_services(rec_msg,c_peer,sio):
    """
    用于接收socket客户端请求,message中包含节点版本
    :param rec_msg:key-value形式
    :param c_peer:当前服务端节点
    :param sio :当前服务端节点的客户端
    :return:
    """
    version = rec_msg['version']
    url = rec_msg['url']
    print(f'receive message:{version}')
    # 如果请求的版本号小于本届点的最新版本号,则需要取出两版本号之前所有的数据
    res_arr = []
    send_msg = {}
    if version < c_peer.version:
        # 倒叙遍历
        for i in range(len(c_peer.pool) - 1,-1,-1):
            get_msg = c_peer.pool[i]
            if version < get_msg['version']:
                res_arr.insert(0,get_msg)

        # 按固定格式返回数据
        send_msg = {
            'code':1,
            'data':res_arr
        }
    else:
        # 查询不到数据,则返回空数据
        send_msg = {
            'code':0,
            'data':'empty'
        }
        sio.connect(url)
        sio.emit('peer_message',send_msg)
        sio.disconnect()

def peer_message_service(msg_dict,c_peer):
    """
    socket服务端接受数据服务,如果code为0表示没有新消息,code为1表示有新消息
    :param msg_json:接收消息
    :param c_peer:当前服务端节点
    :reurn:
    """
    if 'code' not in msg_dict or 'data' not in msg_dict:
        return
    # code :0表示没有新数据不做任何操作
    # code:1表示有新数据加入数据池
    if msg_dict['code'] == 0:
        return
    if msg_dict['code'] == 1:
        for get_msg in msg_dict['data']:
            msg = models.Message(get_msg['data'],datetime.strptime(get_msg['c_time'],"%Y-%m-%d %H:%M:%S"))
            c_peer.pool.append(msg.to_dict())
        c_peer.version = msg_dict['data'][-1]['version']
        

(4)创建gossip网络实体

entity.py

import services
import models
# 创建节点和网络实体
peer0 = models.Peer('peer0','localhost',5000)
peer1 = models.Peer('peer1','localhost',5001)
peer2 = models.Peer('peer2','localhost',5002)
peer3 = models.Peer('peer3','localhost',5003)
peer4 = models.Peer('peer4','localhost',5004)
peer_list = [peer0,peer1,peer2,peer3,peer4]
network = services.generate_network('test',peer_list)



(5)创建节点执行主体

app0.py,app1.py,app2.py,app3.py,app4.py

from flask import Flask,request,jsonify
import flask_socketio
import services
import entity
from flask_apscheduler import APScheduler

network = entity.network
c_peer = entity.peer0
http_port = 5000

app = Flask(__name__)

scheduler = APScheduler()
class Config(object):
    SCHEDULER_API_ENABLED = True
app.config.from_object(Config())
scheduler.init_app(app)

@scheduler.task('interval',id='send_message',seconds=5,misfire_grace_time=900)
def send_message():
    services.send_version(c_peer,network)

peer_socketio = flask_socketio.SocketIO(app,cors_allowed_origins='*')
@peer_socketio.on('peer-version')
def peer_version(rec_msg):
    services.peer_version_services(rec_msg,c_peer,c_peer.sio)

@peer_socketio.on('peer_message')
def peer_message(msg_dict):
    services.peer_message_service(msg_dict,c_peer)

# 创建HTTP接口处理函数
@app.route('/new_msg',methods=['POST'])
def new_msg():
    body = request.json
    return services.new_msg_service(body,c_peer)

@app.route('/get_pool',methods=['GET'])
def get_pool():
    return jsonify({
        'code':200,
        'data':c_peer.pool
    })
if __name__ == '__main__':
    print(f"{'*'*20}Starting peer0!{'*'*20}")
    scheduler.start()
    peer_socketio.run(app,host='0.0.0.0',port=http_port,debug=False)
    

二. 区块链中的共识算法

1.共识算法(pow)

models.py


import hashlib
class Block(object):
    def __init__(self,index,prev_hash,data,timestamp,bits):
        """
        区块的初始化方法,在创建一个区块需传入包括索引号等信息
        :param index:区块索引号
        :param prev_hash:前一区块的哈希值
        :param data:区块中需保存的记录
        :param timestamp:区块生成的时间戳
        :param bits:区块需传入的比特值
        
        """
        self.index=index
        self.prev_hash = prev_hash
        self.data = data
        self.timestamp = timestamp
        self.difficult_bits = bits
        self.nonce = 0
        # 计算新区快的默克尔跟
        self.merkle_root = self.calc_merkle_root()
        # 计算区块的哈希值
        self.block_hash = self.calc_block_hash()

    def calc_merkle_root(self):
        """
        计算默克尔树的根
        :return:
        """
        calc_txs = [tx for tx in self.data]
        if len(calc_txs) == 1:
            return calc_txs[0]
        while len(calc_txs) > 1:
            if len(calc_txs) % 2 == 1:
                calc_txs.append(calc_txs[-1])
            sub_hash_roots = []
            for i in range(0,len(calc_txs),2):
                join_str = "".join(calc_txs[i:i + 2])
                sub_hash_roots.append(hashlib.sha256(join_str.encode()).hexdigest())
            calc_txs = sub_hash_roots
        return calc_txs[0]

    def calc_block_hash(self):
        """
        生成区块对应的哈希值
        :return:
        """
        blockheader = str(self.index) + str(self.prev_hash) \
                    + str(self.data) + str(self.timestamp) + \
                    hex(self.difficult_bits)[2:] + str(self.nonce)
        h = hashlib.sha256(blockheader.encode()).hexdigest()
        self.block_hash = h
        return h


pow.py

from models import Block
from datetime import datetime
# 1.定义区块难度
DIFFICULT_BITS = 0x1e11ffff
#2.定义示例区块
my_block = Block(1,"0" * 32,['123456'],datetime.now(),DIFFICULT_BITS)
# 3.定义目标值的生成函数
def generate_target(difficult_bits):
    """
    基于区块难度生成对应的目标值
    :param difficult_bits:区块难度
    :return:
    """ 
    # 取区块难度的前两位作为指数
    exponent = int(difficult_bits / 16 ** 6)
    # 取区块难度的后6位作为系数
    coefficient = int(difficult_bits % 16 ** 6)
    print(f'exponent is {hex(exponent)}')
    print(f'coefficient is {hex(coefficient)}')
    # 按照共识计算目标值
    target = coefficient * 2 ** (8 * (exponent - 0x03))
    print(f'target_hex is {target}')
    # 将目标值转化为16进制表示的值
    target_hex = hex(target)[2:].zfill(64)
    print(f'target_hex is {target_hex}')
    return target

# 4.定义pow算法
def pow_alg(block):
    # 获取指定区块的难度
    difficult_bits = block.difficult_bits
    # 生成目标值
    target = generate_target(difficult_bits)

    # 通过循环方式反复生成区块头的哈希值并与目标值比较
    # 设置计算次数位2的32次方
    # 每次循环将区块的随机值累加1,并生成新的哈希值并于目标值比较
    for n in range(2 ** 32):
        block.nonce = block.nonce + n
        block.calc_block_hash()
        # print(f'block_hash hex is {hex(int(block.block_hash,16))}')
        if int (block.block_hash,16) < target:
            print(f'{"*" * 20}完成计算!{"*" * 20}')
            print(f'总共计算了:{block.nonce}次')
            print(f'target hex值为:{hex(target)[2:].zfill(64)}')
            print(f'区块哈希值为:{hex(int(block.block_hash,16))[2:].zfill(64)}')
            return
pow_alg(my_block)

2.搭建基于pow共识算法的区块链网络

  1. 构建区块(Block)、区块链(Blockchain)、(Network)网络、(Peer)节点模型。

models.py

import hashlib
from datetime import datetime
import networkx as nx
import matplotlib.pyplot as plt
#1.定义区块难度
DIFFICULT_BITS = 0x1e11ffff

class Block(object):
    def __init__(self,index,prev_hash,data,timestamp,bits):
        """
        区块的初始化方法,在创建一个区块需传入包括索引号等相关信息
        :param index: 区块索引号
        :param prev_hash: 前一区块的哈希值
        :param data: 区块中需保存的记录
        :param timestamp: 区块生成的时间戳
        :param bits: 区块需传入的比特值(预留)
        """
        self.index = index
        self.prev_hash = prev_hash
        self.data = data
        self.timestamp = timestamp
        self.difficult_bits= bits
        self.nonce = 0
        # 计算新区块的默克根
        self.merkle_root = self.calc_merkle_root()
        # 计算区块的哈希值
        self.block_hash = self.calc_block_hash()

    def to_json(self):
        """
        将区块内容以JSON的形式输出
        :return:
        """
        return {
            "index": self.index,
            "prev_hash": self.prev_hash,
            "merkle_root": self.merkle_root,
            "data": self.data,
            "timestamp": self.timestamp.strftime('%Y/%m/%d %H:%M:%S'),
            'bits': hex(self.difficult_bits)[2:].rjust(8, "0"),
            'nonce': hex(self.nonce)[2:].rjust(8, "0"),
            'block_hash': self.block_hash
        }

    def calc_merkle_root(self):
        """
        计算默克树的根(Merkle Root)
        :return:
        """
        calc_txs = [tx for tx in self.data]
        if len(calc_txs) == 1:
            return calc_txs[0]
        while len(calc_txs) > 1:
            if len(calc_txs) % 2 == 1:
                calc_txs.append(calc_txs[-1])
            sub_hash_roots = []
            for i in range(0, len(calc_txs), 2):
                join_str = "".join(calc_txs[i:i+2])
                sub_hash_roots.append(hashlib.sha256(join_str.encode()).hexdigest())
            calc_txs = sub_hash_roots
        return calc_txs[0]
    def calc_block_hash(self):
        """
        生成区块对应的哈希值
        :return:
        """
        blockheader = str(self.index) + str(self.prev_hash) \
                      + str(self.data) + str(self.timestamp) + \
                      hex(self.difficult_bits)[2:] + str(self.nonce)
        h = hashlib.sha256(blockheader.encode()).hexdigest()
        self.block_hash = h
        return h

#区块链对象
class Blockchain(object):
    def __init__(self):
        self.chain = []
        #用于记录不同节点按index顺序获取区块记账权的信息
        self.peer_block = {}
        self.create_genesis_block()

    def add_block(self, block):
        self.chain.append(block)

    def add_peer_block(self,name,block_index):
        """
        向peer_block中添加peer->block_index记录
        :param name:节点名称
        :param block_index区块索引值
        """

        if name in self.peer_block:
            self.peer_block[name].append(block_index)
        else:
            self.peer_block[name]= [block_index]
    
    
    def query_peer_block(self,name):
        """
        查询peer_block内容
        :param name:节点名称
        """
        return self.peer_block[name]
    
    def query_block_info(self, index=0):
        """
        通过索引值查询区块链chain中的区块信息
        """
        int_index = int(index)
        block_json = self.chain[int_index].to_json()
        return block_json
    
    def create_genesis_block(self):
        """
        创建创世区块,在这里定义区块难度,这将被之后所有的区块引用
        """
        genesis_block = Block(0,
                              "0" * 64,
                              ["hello world"],
                              datetime.now(),
                              DIFFICULT_BITS)
        self.add_block(genesis_block)

# 模拟的节点
class Peer:
    def __init__(self,name):
        self.name = name
        self.last_block = 1

#区块链网络
class Network(object):
    def __init__(self, name):
        """
        初始化区块链网络
        :paeam name:
        """
        self.peers = []  #网络存在节点
        self.name = name    #网络名称
        self.G = nx.Graph()   #网络中的定义的network网络拓扑

    def add_peer(self, peer):
        """
        在网络中新增节点
        """
        self.peers.append(peer)
        self.G.add_node(peer.name)

    def add_edge(self, s_peer, e_peer):
        """
        在网络中新增节点间的边
        """
        e = (s_peer, e_peer)
        self.G.add_edge(*e)

    def del_peer(self, peer_name):
        """
        删除指定名称的peer节点
        """
        for i, peer in enumerate(self.peers):
            if peer_name == peer.name:
                del self.peers[i]
        self.G.remove_node(peer_name)

    def draw_network(self):
        """
        绘制网络
        """
        pos = nx.spring_layout(self.G, iterations=100)
        nx.draw(self.G, pos, with_labels=True)
        plt.show()

创建项目实体

entity.py

import models

# 用于创建节点和网络实体
peer0 = models.Peer('peer0')
peer1 = models.Peer('peer1')
peer2 = models.Peer('peer2')
peer3 = models.Peer('peer3')
peer4 = models.Peer('peer4')
peer_list = [peer0, peer1, peer2, peer3, peer4]

#创建区块链
blockchain = models.Blockchain()


 创建pow算法实现模块

pow.py

#3.定义目标值的生成函数
def generate_target(difficult_bits):
    """
    基于区块难度生成对应的目标值
    :param difficult_bits:区块难度
    :return:
    """
    #取区块难度(16进制)的前2位作为指数
    exponent = int(difficult_bits / 16 ** 6)
    #取区块难度(16进制)的前6位作为系数
    coefficient = int(difficult_bits % 16 ** 6)
    print(f'exponent is {hex(exponent)}')
    print(f'coefficient is {hex(coefficient)}')

    #按照共识计算目标值
    target = coefficient * 2 ** (8 * (exponent - 0x03))
    print(f'target is {target}')
    #将目标值转换成16进制表示的值
    target_hex = hex(target)[2:].zfill(64)
    print(f'target_hex is {target_hex}')
    return target

#4.定义pow算法
def pow_alg(block):
    #获取指定区块的难度
    difficult_bits = block.difficult_bits
    #生成目标值
    target = generate_target(difficult_bits)

    #通过循环的方式反复生成区块头的哈希值并与目标值比较
    #设置计算次数为2的32次方
    #每次循环将区块中的“随机值”累加1,并生成新的哈希值与目标值比较
    for n in range(2 ** 32):
        block.nonce = block.nonce + n
        block.calc_block_hash()
        # print(f'block_hash hex is {hex(int(block.block_hash, 16))}')
        if int(block.block_hash, 16) < target:
            print(f'{"*" * 20}完成计算!{"*" * 20}')
            print(f'总共计算了:{block.nonce}次')
            print(f'target hex值为{hex(target)[2:].zfill(64)}')
            print(f'区块哈希值为:{hex(int(block.block_hash, 16))[2:].zfill(64)}')
            return block
        

生成services处理模块

services.py

import models
import entity
import pow
from datetime import datetime


def generate_network(network_name, peer_list):
    """
    生成区块链网络,初始化Network实体,以及在Network实体中加入节点(node)和边(node)
    :param network_name:网络名称
    :param peer_list:已生成的节点列表
    :return:生成的区块链网络实体对象
    """
    g_network = models.Network(network_name)
    for index, peer in enumerate(peer_list):
        g_network.add_peer(peer)
        if index == len(peer_list)-1:
            #如果是最后一个节点,那就让最后一个节点和第一个节点首位相连
            g_network.add_edge(peer.name, peer_list[0].name)
        else:
            #否则,建立本节点与下一个节点的边
            g_network.add_edge(peer.name, peer_list[index+1].name)
    return g_network

def exe_pow(data,peer_name):
    """
    供节点循环执行pow算法
    :param data:区块数据
    ;param peer_name:节点名称
    """

    #1.首先获得区块链中最新区块
    last_block = entity.blockchain.chain[-1]
    #2.获取last_block区块的索引值
    index = last_block.index + 1
    #3.生成新的区块
    g_block = models.Block(last_block.index + 1, last_block.prev_hash,data,datetime.now(),last_block.difficult_bits)
    #4.将区块扔进pow算法中进行计算,在得到区块头后返回区块信息
    c_block = pow.pow_alg(g_block)
    #判断区块链内的内容,如果当前区块链中没有新数据产生,则将产生的区块加入区块链中。
    if len (entity.blockchain.chain) <= index:
        entity.blockchain.add_block(c_block)
        entity.blockchain.add_peer_block(peer_name,index)
    else:
        #如果计算的区块索引已存在,则说明其他节点已抢先计算完成,则计算失败不能将结果保存至区块链
        print(f'区块索引<{index}>,已存在!{peer_name}节点计算失败')
    

创建程序执行模块

 app.py

from flask import Flask, request
from flask_apscheduler import APScheduler
import services
from datetime import datetime
import entity

app = Flask(__name__)


network = services.generate_network('test',entity.peer_list)
#创建定时任务
scheduler = APScheduler()
class Config(object):
    SCHEDULER_API_ENABLED = True
app.config.from_object(Config())
scheduler.init_app(app)

#设置统一的间隔执行任务时间
interval_seconds = 20

#创建节点0(peer0),进行pow计算任务
@scheduler.task('interval', 
                id='peer0-calc', 
                seconds=interval_seconds, 
                misfire_grace_time=900)
def send_message():
    #设置统一的区块数据
    data = f'{entity.peer0.name}-{datetime.now().strftime("%Y-%m-%d %H:%M:%S")} '
    services.exe_pow(data=data,peer_name=entity.peer0.name)

#创建节点1(peer1),进行pow计算任务
@scheduler.task('interval', 
                id='peer1-calc', 
                seconds=interval_seconds, 
                misfire_grace_time=900)

def send_message():
    data = f'{entity.peer1.name}-{datetime.now().strftime("%Y-%m-%d %H:%M:%S")} '
    services.exe_pow(data=data,peer_name=entity.peer1.name)

#创建节点2(peer2),进行pow计算任务
@scheduler.task('interval', 
                id='peer2-calc', 
                seconds=interval_seconds, 
                misfire_grace_time=900)

def send_message():
    data = f'{entity.peer2.name}-{datetime.now().strftime("%Y-%m-%d %H:%M:%S")} '
    services.exe_pow(data=data,peer_name=entity.peer2.name)

#创建节点3(peer4),进行pow计算任务
@scheduler.task('interval', 
                id='peer3-calc', 
                seconds=interval_seconds, 
                misfire_grace_time=900)

def send_message():
    data = f'{entity.peer3.name}-{datetime.now().strftime("%Y-%m-%d %H:%M:%S")} '
    services.exe_pow(data=data,peer_name=entity.peer3.name)

#创建节点4(peer4),进行pow计算任务
@scheduler.task('interval', 
                id='peer2-calc', 
                seconds=interval_seconds, 
                misfire_grace_time=900)

def send_message():
    data = f'{entity.peer4.name}-{datetime.now().strftime("%Y-%m-%d %H:%M:%S")} '
    services.exe_pow(data=data,peer_name=entity.peer4.name)

@app.route('/peer_block_query',methods = ['GET'])
def peer_block_query():
    """
    获取所有节点及记录区块的索引值
    """
    return entity.blockchain.peer_block

@app.route('/block_query',methods = ['GET'])
def block_query():
    """
    查询指定区块索引值(高度)
    """

    index = request.args['id']
    return entity.blockchain.query_block_info(index)

if __name__ == '__main__':
    scheduler.start()
    app.run()

postman验证

 

 

猜你喜欢

转载自blog.csdn.net/m0_74421072/article/details/134460743