美文网首页区块链研习社
迷你区块链代码详解

迷你区块链代码详解

作者: Andytl的世界 | 来源:发表于2018-08-04 23:30 被阅读13次

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

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

    相关文章

      网友评论

        本文标题:迷你区块链代码详解

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