区块链研习社

迷你区块链代码详解

2018-08-04  本文已影响13人  Andytl的世界

上一篇介绍了迷你区块链的实现过程,仔细阅读代码很容易掌握区块链中一些基本概念,如区块、哈希计算、工作量证明、共识算法等。为了深入理解迷你区块链,下面贴出源代码和注释。看完代码我们再看看它的问题。

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形式表现区块链基本概念)。

上一篇下一篇

猜你喜欢

热点阅读