一.区块链中节点间的通信
区块链网络
- 公有链区块链网络
- 私有链区块链网络
- 联盟链区块链网络
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共识算法的区块链网络
- 构建区块(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验证