上一篇介绍了迷你区块链的实现过程,仔细阅读代码很容易掌握区块链中一些基本概念,如区块、哈希计算、工作量证明、共识算法等。为了深入理解迷你区块链,下面贴出源代码和注释。看完代码我们再看看它的问题。
from flask import Flask#导入flask模块用于创建http服务
from flask import request
import json#导入json模块用于表示交易结构
import requests#导入request模块用于响应http请求
import hashlib as hasher#导入hashlib模块用于进行哈希运算
import datetime as date#导入datetime模块用于读取时间
node = Flask(__name__)#启动一个http服务实例
# 定义区块
class Block:
def __init__(self, index, timestamp, data, previous_hash):#区块的信息包括索引、时间戳、数据、前一个区块的哈希值
self.index = index
self.timestamp = timestamp
self.data = data
self.previous_hash = previous_hash
self.hash = self.hash_block()
def hash_block(self):#获取区块哈希值
sha = hasher.sha256()
sha.update(str(self.index) + str(self.timestamp) + str(self.data) + str(self.previous_hash))
return sha.hexdigest()
# 产生创世区块
def create_genesis_block():
# 人为设置索引为0,前一区块哈希为0
return Block(0, date.datetime.now(), {
"proof-of-work": 9,
"transactions": None
}, "0")
# 为节点分配任意地址
miner_address = "q3nf394hjg-random-miner-address-34nf3i4nflkn3oi"
# 生成本节点的区块链
blockchain = []
blockchain.append(create_genesis_block())
# 保存交易记录在本节点的列表中
this_nodes_transactions = []
#保存网络中其他节点的url,以便通信
peer_nodes = []
# 是否为挖矿节点设置
mining = True
#客户端以txion命令发送交易
@node.route('/txion', methods=['POST'])
def transaction():
#每次收到post请求,抽取交易数据
new_txion = request.get_json()
# 把交易数据添加到列表中
this_nodes_transactions.append(new_txion)
# 成功接收到一个交易记录就显示在控制台上
print "New transaction"
print "FROM: {}".format(new_txion['from'].encode('ascii','replace'))
print "TO: {}".format(new_txion['to'].encode('ascii','replace'))
print "AMOUNT: {}\n".format(new_txion['amount'])
# 返回客户端成功信息
return "Transaction submission successful\n"
#客户端以blocks命令读取区块
@node.route('/blocks', methods=['GET'])
def get_blocks():
chain_to_send = blockchain
#把区块链转化为字典格式,方便后面以json对象发送
for i in range(len(chain_to_send)):
block = chain_to_send[i]
block_index = str(block.index)
block_timestamp = str(block.timestamp)
block_data = str(block.data)
block_hash = block.hash
chain_to_send[i] = {
"index": block_index,
"timestamp": block_timestamp,
"data": block_data,
"hash": block_hash
}
chain_to_send = json.dumps(chain_to_send)
return chain_to_send
#发现新区块链
def find_new_chains():
# 从其他节点获得新区块链
other_chains = []
for node_url in peer_nodes:
# 从其他节点以get方式读取区块链
block = requests.get(node_url + "/blocks").content
#转换json对象为python字典格式
block = json.loads(block)
# 把字典格式的区块链加入列表中
other_chains.append(block)
return other_chains
#共识算法
def consensus():
# 从其他节点获得区块链
other_chains = find_new_chains()
# 如果本节点区块链在所有区块链中不是最长的则保存最长链
longest_chain = blockchain
for chain in other_chains:
if len(longest_chain) < len(chain):
longest_chain = chain
# 以最长链为本节点区块链
blockchain = longest_chain
#工作量证明方法
def proof_of_work(last_proof):
#设置一个变量(证明数)用于工作量证明
incrementor = last_proof + 1
#变量一直递增,直到变量可以被9和上一区块的证明数整除
while not (incrementor % 9 == 0 and incrementor % last_proof == 0):
incrementor += 1
#找到符合规则的证明数就可以返回工作量证明了
return incrementor
#客户端以mine命令挖矿
@node.route('/mine', methods = ['GET'])
def mine():
#获取上一区块的证明数
last_block = blockchain[len(blockchain) - 1]
last_proof = last_block.data['proof-of-work']
# 计算工作量证明就是在挖矿
# 程序可能卡在这里,直到工作量证明完成
proof = proof_of_work(last_proof)
# 当完成工作量证明,也就是到了矿,就奖励矿工1枚币
this_nodes_transactions.append(
{ "from": "network", "to": miner_address, "amount": 1 }
)
# 打包区块数据
new_block_data = {
"proof-of-work": proof,
"transactions": list(this_nodes_transactions)
}
new_block_index = last_block.index + 1
new_block_timestamp = this_timestamp = date.datetime.now()
last_block_hash = last_block.hash
# 清空本节点交易记录,因为已经写到区块了
this_nodes_transactions[:] = []
# 产生新的区块并链接到原区块链上
mined_block = Block(
new_block_index,
new_block_timestamp,
new_block_data,
last_block_hash
)
blockchain.append(mined_block)
# 告知客户端,区块被挖到了,也就是交易记录已经打包到区块链了
return json.dumps({
"index": new_block_index,
"timestamp": str(new_block_timestamp),
"data": new_block_data,
"hash": last_block_hash
}) + "\n"
#运行节点
node.run()
迷你区块链的问题
1、共识算法没有使用,迷你区块链“蛇链”功能还不够完善,作者没有写完整。目前还无法实现分布式计算。
2、共识算法中未验证其他节点区块链的合法性。可添加以下代码:
def verify_proof_of_work(proof, last_proof):
return (proof > last_proof
and proof % 9 == 0
and proof % last_proof == 0)
3、无法监听其他节点区块链状态。可添加以下代码:
@node.route('/add_peer', methods=['GET'])
def add_peer():
host = request.args['host'] if 'host' in request.args else 'localhost'
port = request.args['port']
peer = host + ':' + port
peer_nodes.append(peer)
print("Peer added: %s" % peer)
return ""
4、工作量证明算法太简陋,证明数很有规律9、18、36、72、144 ......。工作量证明算法可以改成寻找一个证明数使得“前一区块哈希+证明数”哈希值前几位数为0,这样计算量可以通过0的个数控制,而且证明数没有规律。代码如下:
def proof_of_work(previous_hash, number_of_leading_zeroes=5):
"""
Uses `previous_hash` to solve for a `nonce`, where the resulting
hash starts with a number of zero bits ( number_of_zeroes ).
Returns
nonce : int
"""
nonce = None
incrementor = 0
leading_zeroes = '0' * number_of_leading_zeroes
while not nonce:
sha = hashlib.sha256()
sha.update(
str(previous_hash).encode('utf-8') +
str(incrementor).encode('utf-8')
)
challenge_hash = sha.hexdigest()
if str(challenge_hash[:number_of_leading_zeroes]) == leading_zeroes:
nonce = incrementor
else:
incrementor += 1
return nonce, number_of_leading_zeroes
后记:github是个好东西,‘蛇链’代码的评论区很多高质量留言,比如有人改进了‘蛇链’代码(增加了节点发现其他节点功能,采用类似比特币的工作量证明算法),有人分享了其他迷你区块链代码(可视化web形式表现区块链基本概念)。
网友评论