• Python创建区块链


    Step 1: 创建一个区块链

    打开你最喜欢的文本编辑器或者IDE, 我个人比较喜欢 PyCharm. 新建一个名为blockchain.py的文件。 我们将只用这一个文件就可以。但是如果你还是不太清楚, 你也可以参考 源码.

    描述区块链

    我们要创建一个 Blockchain 类 ,他的构造函数创建了一个初始化的空列表(要存储我们的区块链),并且另一个存储交易。下面是我们这个类的实例:

    
    blockchain.py
    
    
    class Blockchain(object):
    
        def __init__(self):
    
            self.chain = []
    
            self.current_transactions = []
    
    
        def new_block(self):
    
            # Creates a new Block and adds it to the chain
    
            pass
    
    
        def new_transaction(self):
    
            # Adds a new transaction to the list of transactions
    
            pass
     
    
        @staticmethod
    
        def hash(block):
    
            # Hashes a Block
    
            pass
     
    
        @property
    
        def last_block(self):
    
            # Returns the last Block in the chain
    
            pass
    

    我们的 Blockchain 类负责管理链式数据,它会存储交易并且还有添加新的区块到链式数据的Method。让我们开始扩充更多Method

    块是什么样的 ?

    每个块都有一个 索引,一个 时间戳(Unix时间戳),一个事务列表, 一个 校验(稍后详述) 和 前一个块的散列 。

    下面是一个Block的例子 :

    
    blockchain.py
    
     
    
    block = {
    
        'index': 1,
    
        'timestamp': 1506057125.900785,
    
        'transactions': [
    
            {
    
                'sender': "8527147fe1f5426f9dd545de4b27ee00",
    
                'recipient': "a77f5cdfa2934df3954a5c7c7da5df1f",
    
                'amount': 5,
    
            }
    
        ],
    
        'proof': 324984774000,
    
        'previous_hash': "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
    
    }
    

    在这一点上,一个 区块链 的概念应该是明显的 - 每个新块都包含在其内的前一个块的 散列 。 这是至关重要的,因为这是 区块链 不可改变的原因:如果攻击者损坏 区块链 中较早的块,则所有后续块将包含不正确的哈希值。

    这有道理吗? 如果你还没有想通,花点时间仔细思考一下 - 这是区块链背后的核心理念

    添加交易到区块

    我们将需要一个添加交易到区块的方式。我们的 new_transaction()方法的责任就是这个, 并且它非常的简单:

    blockchain.py
    
     
    
    class Blockchain(object):
    
        ...
    
     
    
        def new_transaction(self, sender, recipient, amount):
    
            """
    
            Creates a new transaction to go into the next mined Block
    
            :param sender: <str> Address of the Sender
    
            :param recipient: <str> Address of the Recipient
    
            :param amount: <int> Amount
    
            :return: <int> The index of the Block that will hold this transaction
    
            """
    
     
    
            self.current_transactions.append({
    
                'sender': sender,
    
                'recipient': recipient,
    
                'amount': amount,
    
            })
    
     
    
            return self.last_block['index'] + 1
    
    

    new_transaction() 方法添加了交易到列表,它返回了交易将被添加到的区块的索引---讲开采下一个这对稍后对提交交易的用户有用。

    创建新的区块

    当我们的 Blockchain 被实例化后,我们需要将 创世 区块(一个没有前导区块的区块)添加进去进去。我们还需要向我们的起源块添加一个 证明,这是挖矿的结果(或工作证明)。 我们稍后会详细讨论挖矿。

    除了在构造函数中创建 创世 区块外,我们还会补全 new_block() 、 new_transaction() 和 hash() 函数:

    blockchain.py
    
     
    
    import hashlib
    
    import json
    
    from time import time
    
     
    
    class Blockchain(object):
    
        def __init__(self):
    
            self.current_transactions = []
    
            self.chain = []
    
     
    
            # 创建创世区块
    
            self.new_block(previous_hash=1, proof=100)
    
     
    
        def new_block(self, proof, previous_hash=None):
    
            """
    
            创建一个新的区块到区块链中
    
            :param proof: <int> 由工作证明算法生成的证明
    
            :param previous_hash: (Optional) <str> 前一个区块的 hash 值
    
            :return: <dict> 新区块
    
            """
    
     
    
            block = {
    
                'index': len(self.chain) + 1,
    
                'timestamp': time(),
    
                'transactions': self.current_transactions,
    
                'proof': proof,
    
                'previous_hash': previous_hash or self.hash(self.chain[-1]),
    
            }
    
     
    
            # 重置当前交易记录
    
            self.current_transactions = []
    
     
    
            self.chain.append(block)
    
            return block
    
     
    
        def new_transaction(self, sender, recipient, amount):
    
            """
    
            创建一笔新的交易到下一个被挖掘的区块中
    
            :param sender: <str> 发送人的地址
    
            :param recipient: <str> 接收人的地址
    
            :param amount: <int> 金额
    
            :return: <int> 持有本次交易的区块索引
    
            """
    
            self.current_transactions.append({
    
                'sender': sender,
    
                'recipient': recipient,
    
                'amount': amount,
    
            })
    
     
    
            return self.last_block['index'] + 1
    
     
    
        @property
    
        def last_block(self):
    
            return self.chain[-1]
    
     
    
        @staticmethod
    
        def hash(block):
    
            """
    
            给一个区块生成 SHA-256 值
    
            :param block: <dict> Block
    
            :return: <str>
    
            """
    
     
    
            # 我们必须确保这个字典(区块)是经过排序的,否则我们将会得到不一致的散列
    
            block_string = json.dumps(block, sort_keys=True).encode()
    
            return hashlib.sha256(block_string).hexdigest()
    
    

    上面的代码应该是直白的 --- 为了让代码清晰,我添加了一些注释和文档说明。 我们差不多完成了我们的区块链。 但在这个时候你一定很疑惑新的块是怎么被创建、锻造或挖掘的。

    工作量证明算法

    使用工作量证明(PoW)算法,来证明是如何在区块链上创建或挖掘新的区块。PoW 的目标是计算出一个符合特定条件的数字,这个数字对于所有人而言必须在计算上非常困难,但易于验证。这是工作证明背后的核心思想。

    我们将看到一个简单的例子帮助你理解:

    假设一个整数 x 乘以另一个整数 y 的积的 Hash 值必须以 0 结尾,即 hash(x * y) = ac23dc...0。设 x = 5,求 y ?用 Python 实现:

    from hashlib import sha256
    
    x = 5
    
    y = 0  # We don't know what y should be yet...
    
    while sha256(f'{x*y}'.encode()).hexdigest()[-1] != "0":
    
        y += 1
    
    print(f'The solution is y = {y}')
    

    结果是: y = 21。因为,生成的 Hash 值结尾必须为 0。

    hash(5 * 21) = 1253e9373e...5e3600155e860
    

    在比特币中,工作量证明算法被称为 Hashcash ,它和上面的问题很相似,只不过计算难度非常大。这就是矿工们为了争夺创建区块的权利而争相计算的问题。 通常,计算难度与目标字符串需要满足的特定字符的数量成正比,矿工算出结果后,就会获得一定数量的比特币奖励(通过交易)。

    验证结果,当然非常容易。

    实现工作量证明

    让我们来实现一个相似 PoW 算法。规则类似上面的例子:
    找到一个数字 P ,使得它与前一个区块的 proof 拼接成的字符串的 Hash 值以 4 个零开头。

    blockchain.py
    
     
    
    import hashlib
    
    import json
    
     
    
    from time import time
    
    from uuid import uuid4
    
     
    
    class Blockchain(object):
    
        ...
    
     
    
        def proof_of_work(self, last_proof):
    
            """
    
            Simple Proof of Work Algorithm:
    
             - Find a number p' such that hash(pp') contains leading 4 zeroes, where p is the previous p'
    
             - p is the previous proof, and p' is the new proof
    
            :param last_proof: <int>
    
            :return: <int>
    
            """
    
     
    
            proof = 0
    
            while self.valid_proof(last_proof, proof) is False:
    
                proof += 1
    
     
    
            return proof
    
     
    
        @staticmethod
    
        def valid_proof(last_proof, proof):
    
            """
    
            Validates the Proof: Does hash(last_proof, proof) contain 4 leading zeroes?
    
            :param last_proof: <int> Previous Proof
    
            :param proof: <int> Current Proof
    
            :return: <bool> True if correct, False if not.
    
            """
     
    
            guess = f'{last_proof}{proof}'.encode()
    
            guess_hash = hashlib.sha256(guess).hexdigest()
    
            return guess_hash[:4] == "0000"
    

    衡量算法复杂度的办法是修改零开头的个数。使用 4 个来用于演示,你会发现多一个零都会大大增加计算出结果所需的时间。

    现在 Blockchain 类基本已经完成了,接下来使用 HTTP requests 来进行交互。

    Step 2: Blockchain 作为 API 接口

    我们将使用 Python Flask 框架,这是一个轻量 Web 应用框架,它方便将网络请求映射到 Python 函数,现在我们来让 Blockchain 运行在基于 Flask web 上。

    我们将创建三个接口:
    /transactions/new 创建一个交易并添加到区块
    /mine 告诉服务器去挖掘新的区块
    /chain 返回整个区块链

    创建节点

    我们的“Flask 服务器”将扮演区块链网络中的一个节点。我们先添加一些框架代码:

    blockchain.py
    
     
    
    import hashlib
    
    import json
    
    from textwrap import dedent
    
    from time import time
    
    from uuid import uuid4
    
     
    
    from flask import Flask
    
     
    
    class Blockchain(object):
    
        ...
    
     
    
    # Instantiate our Node
    
    app = Flask(__name__)
    
     
    
    # Generate a globally unique address for this node
    
    node_identifier = str(uuid4()).replace('-', '')
    
     
    
    # Instantiate the Blockchain
    
    blockchain = Blockchain()
    
     
    
    @app.route('/mine', methods=['GET'])
    
    def mine():
    
        return "We'll mine a new Block"
    
     
    
    @app.route('/transactions/new', methods=['POST'])
    
    def new_transaction():
    
        return "We'll add a new transaction"
    
     
    
    @app.route('/chain', methods=['GET'])
    
    def full_chain():
    
        response = {
    
            'chain': blockchain.chain,
    
            'length': len(blockchain.chain),
    
        }
    
        return jsonify(response), 200
    
     
    
    if __name__ == '__main__':
    
        app.run(host='0.0.0.0', port=5000)
    

    简单的说明一下以上代码:
    第 15 行:实例化节点。阅读更多关于 Flask 内容。
    第 18 行:为节点创建一个随机的名称。.
    第 21 行:实例化 Blockchain 类。
    第 24--26 行:创建 /mine 接口,GET 方式请求。
    第 28--30 行:创建 /transactions/new 接口,POST 方式请求,可以给接口发送交易数据。
    第 32--38 行:创建 /chain 接口,返回整个区块链。
    第 40--41 行:服务器运行端口 5000 。

  • 相关阅读:
    Oracle 查询表空间容量脚本
    C#保留小数位的方法集合
    asp.net c# 去掉字符串中重复项并将结果遍历出来算法
    汇总sql server数据库所有表名、列数、行数
    Web表单设计之注册表单
    精简高效的CSS命名准则和方法
    MSSQL查看和解除表锁
    XML通用操作类
    Ajax学习笔记一(xmlHttpRequest对象)
    SQL Server无法生成FRunCM线程|FRunCM 线程|FRunCM
  • 原文地址:https://www.cnblogs.com/sms369/p/14677313.html
Copyright © 2020-2023  润新知