构建区块链 python(一)

构建区块链

前言

小编认为学习区块链如何工作的最快方法是建立一个区块链。虽然网上有很多教程或视频,小编也一一浏览过,但是觉得那些示例效果…小编喜欢边做边学,小编希望在看过这篇文章之后您将拥有一个运行正常的区块链,并对它们的工作原理有扎实的了解。

请记住!!!区块链是一个不变的顺序记录链,称为块。它们可以包含事务,文件或您真正喜欢的任何数据。但是重要的是,它们使用哈希值链接在一起。

前期准备

pip install Flask==0.12.2  requests==2.18.4 

开始流程

步骤1:建立区块链

打开你最喜欢的文本编辑器或IDE,我个人❤️ PyCharm。创建一个新文件,名为blockchain.py(代表区块链)。

创建一个区块链类

小编在这里创建一个 Blockchain类,其构造函数创建一个初始的空列表(用于存储我们的区块链),并创建另一个用于存储事务。

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类负责管理链。它将存储事务,并具有一些用于将新块添加到链中的辅助方法。

块看起来像什么?

每个Block都有一个索引,一个时间戳(以Unix时间表示),一个事务列表,一个证明以及前一个Block的哈希值。
这是单个块的外观示例:

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

链的概念应该很明显每个新块本身都包含前一个块的哈希。这是至关重要的,因为这是赋予区块链不变性的原因:如果攻击者破坏了链中较早的区块,则所有后续区块将包含不正确的哈希。这么有意义吗?如果不是做,则需要花一些时间让它沉没-这是区块链背后的核心思想。

将交易添加到区块

将交易添加到区块,我们需要一种将交易添加到区块的方法。我们的new_transaction() 方法对此负责,这很简单:

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():

import hashlib
import json
from time import time


class Blockchain(object):
    def __init__(self):
        self.current_transactions = []
        self.chain = []

        # Create the genesis block
        self.new_block(previous_hash=1, proof=100)

    def new_block(self, proof, previous_hash=None):
        """
        Create a new Block in the Blockchain
        :param proof: <int> The proof given by the Proof of Work algorithm
        :param previous_hash: (Optional) <str> Hash of previous Block
        :return: <dict> New Block
        """

        block = {
            'index': len(self.chain) + 1,
            'timestamp': time(),
            'transactions': self.current_transactions,
            'proof': proof,
            'previous_hash': previous_hash or self.hash(self.chain[-1]),
        }

        # Reset the current list of transactions
        self.current_transactions = []

        self.chain.append(block)
        return block

    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

    @property
    def last_block(self):
        return self.chain[-1]

    @staticmethod
    def hash(block):
        """
        Creates a SHA-256 hash of a Block
        :param block: <dict> Block
        :return: <str>
        """

        # We must make sure that the Dictionary is Ordered, or we'll have inconsistent hashes
        block_string = json.dumps(block, sort_keys=True).encode()
        return hashlib.sha256(block_string).hexdigest()

代表区块链几乎完成了。但是在这一点上,您一点想知道如何创建,开采新块。

了解工作量证明

工作量证明算法(PoW)是在区块链上创建或挖掘新区块的方式。PoW的目标是发现可以解决问题的数字。从数字上来说, 该数字必须很难找到,但要易于被网络上的任何人验证。这是工作量证明的核心思想。
我们将看一个非常简单的示例来帮助解决这个问题。
让我们决定某个整数x乘以另一个y 的哈希必须以0结尾。hash(x * y) = ac23dc…0。对于这个简化的示例,让我们修复x = 5。在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。由于产生的哈希值以0结尾:

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

在比特币中,工作量证明算法称为Hashcash。而且与我们上面的基本示例并没有太大不同。这是矿工竞相解决以创建新区块的算法。通常,难度由字符串中搜索的字符数决定。然后,通过在交易中获得硬币,矿工将获得奖励,以奖励他们的解决方案。

实施基本的工作证明
让我们为区块链实现类似的算法。我们的规则将类似于上面的示例:
找出一个数字 p ,该数字与前一个块的解决方案进行哈希运算时,会导致4个前导0被生产。

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就足够了。您会发现,添加单个前导零将使找到解决方案所需的时间产生巨大差异。

发布了77 篇原创文章 · 获赞 5 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_39682037/article/details/105460583