如何使用Python创建区块链?

你知道比特币是建立在区块链之上的吗?今天我们将用Python从零开始构建一个区块链。

什么是区块链?

在2008年,一个名叫Satoshi Nakamoto的未知个体或团体发布了 Bitcoin paper。比特币是一种点对点的电子现金版本,允许在不通过中央机构(银行)的情况下进行交易。大多数人不知道的是,在同一篇论文中,Satoshi定义了一种分布式的信息存储方式,现在被称为 Blockchain

区块链技术

简单来说,区块链是一个共享的、不可变的数字分类帐,它在一个去中心化的计算机网络上存储交易。

我们可以将区块链分为两个简单的术语:

  • 块:存储交易的空间
  • 链:一组链接记录

这定义了区块链为一系列链接的块,每个块都存储具有特定参数的交易。

每个块都建立在另一个块之上,创建了一个不可逆转的块链。换句话说,每个块都依赖于另一个块。这就成为一个强大且不可变的系统,权限正确的任何人都可以审查完整性。

区块链引入了一套有趣的特性:

  • 历史不可变性
  • 信息持久性
  • 存储数据无错误

许多系统目前依赖于区块链,如 cryptocurrencies、资产转移 (NFTs),可能在不久的将来还包括投票。

值得一提的是,一个 Python 区块链不必是一个有成千上万行代码的复杂程序。在其核心,它只是一个彼此链接的交易列表。

当然,这只是一个简短的解释,但如果你想要一个完整的指南,我们已经制作了一份有关 Blockchain for beginners 的完整教程。一定要查看。

不多说了,让我们用Python构建一个简单的区块链。

使用Python构建区块链

在开始之前,让我们定义一下这个教程中要做的事情:

  • 使用Python构建简单的区块链系统
  • 使用预先设定的字符串代表的交易来使用我们的区块链
  • 测试我们的区块链的不可变性

我们将不使用 JSON 而是使用Python列表。这将使我们简化过程,并专注于应用区块链的关键概念。

以下是你需要遵循本教程的内容:

创建Block类

打开你喜欢的代码编辑器并创建一个名为 main.py 的文件。这将是我们要使用的文件。

现在,导入 hashlib,一个让我们创建单向加密消息的模块。类似哈希的密码学技术使得区块链创建安全的交易。

哈希函数是一种算法,它接受一些数据(通常是编码后的字符串)并返回一个唯一的标识符,通常称为“摘要”或“签名”。这最后一部分是至关重要的;使用哈希函数,输入的微小差异会产生完全不同的标识符作为输出。稍后我们会看到这一点。

目前,只需导入内置的模块hashlib:

# main.py文件
"""
一个简单的Python区块链
"""

import hashlib

该模块包括大多数您需要的哈希算法。只需记住我们将使用 hashlib.sha256() 函数。

现在,让我们进入GeekCoinBlock,我们完全原创的区块链名称。

class GeekCoinBlock:

def __init__(self, previous_block_hash, transaction_list):

self.previous_block_hash = previous_block_hash
self.transaction_list = transaction_list

self.block_data = f”{‘ – ‘.join(transaction_list)} – {previous_block_hash}”
self.block_hash = hashlib.sha256(self.block_data.encode()).hexdigest()

我知道这可能会导致代码很笨重。让我们在下一节中逐个解释每个部分。

GeekCoinBlock 解释

首先,我们创建了一个名为GeekCoinBlock的类,它是具有特定特征(属性)和行为(方法)的对象的包装器。

然后,我们定义了__init__方法(也称为构造函数),它在每次创建 GeekCoinBlock 对象时被调用。

这个方法有三个参数:

  • self(每个对象的实例)
  • previous_block_hash(对前一个块的引用)
  • transaction_list(当前块中的交易列表)

我们存储先前的哈希和交易列表,并创建一个名为 block_data 的实例变量作为字符串。这在真实的加密货币中是不会发生的,因为我们会将这种类型的数据存储为另一个哈希,但为了简单起见,我们将每个数据块都存储为字符串。

最后,我们创建了 block_hash,其他块将使用它来继续链条。这就是 hashlib 发挥作用的地方;我们不需要创建自定义哈希函数,可以使用预先构建的 sha256 来创建不可变的区块。

该函数接收编码后的字符串(或字节)作为参数。这就是为什么我们使用 block_data.encode() 方法。之后,我们调用 hexdigest() 将编码数据返回为十六进制格式。

我知道这一切可能令人不知所措,让我们在 hashlib on a Python shell 中试一试。

In [1]: import hashlib

In [2]: message = "Python is great"

In [3]: h1 = hashlib.sha256(message.encode())

In [4]: h1
Out[4]: 

In [5]: h1.hexdigest()
Out[5]: 'a40cf9cca ... 42ab97'

In [6]: h2 = hashlib.sha256(b"Python is not great")

In [7]: h2
Out[7]: 

In [8]: h2.hexdigest()
Out[8]: 'fefe510a6a ... 97e010c0ea34'

正如你所见,输入中的微小变化(如“Python is great”到“Python is not great”)可以产生完全不同的哈希。这与区块链的完整性有关。如果在区块链中引入一些小的变化,它的哈希将发生巨大变化。这就是为什么“你无法破坏区块链”的说法是正确的。

使用我们的 Block 类

我们稍后将构建一个完整的 Blockchain 类,但现在,让我们使用我们的 Block 类来创建一个区块链(链条)。

在同一个文件中,创建一些由简单字符串组成的交易,并存储在变量中,例如:

class GeekCoinBlock:
    ...

t1 = "Noah sends 5 GC to Mark"
t2 = "Mark sends 2.3 GC to James"
t3 = "James sends 4.2 GC to Alisson"
t4 = "Alisson sends 1.1 GC to Noah"

当然,GC 指的是 GeekCoin

现在,使用 GeekCoinBlock 类构建我们的区块链的第一个块,并打印其属性。请注意,创世块(先于其他块的第一个块)的 previous_hash 参数将始终是某个任意的字符串或哈希,例如“firstblock”。

block1 = GeekCoinBlock('firstblock', [t1, t2])

print(f"Block 1 data: {block1.block_data}")
print(f"Block 1 hash: {block1.block_hash}")

然后,我们使用第一个块的哈希作为previous_hash参数,对第二个块进行相同的操作。

block2 = GeekCoinBlock(block1.block_hash, [t3, t4])

print(f"Block 2 data: {block2.block_data}")
print(f"Block 2 hash: {block2.block_hash}")

让我们运行并分析从这段代码中得到的输出。再次在终端中键入:

❯ python main.py
Block 1 data: Noah sends 5 GC to Mark - Mark sends 2.3 GC to James - firstblock
Block 1 hash: 01e4e15242a9601725f4a86ca01fbddaaec7105b442955bb0efcadbfc759806d
Block 2 data: James sends 4.2 GC to Alisson - Alisson sends 1.1 GC to Noah - 01e4e15242a9601725f4a86ca01fbddaaec7105b442955bb0efcadbfc759806d
Block 2 hash: 448c4306caf7f6937b0307f92f27fbea3bb73b3470363dee5026a1209dadcfa8

目前,你只能看到文本和一些64个字符的哈希值,但这基本上概述了区块链的机制。

你从一个创世块开始,也就是所有其他块的基础。

任何人都可以验证链的完整性,这就是为什么区块链是一个如此安全的系统。例如,如果我们稍微修改交易的内容,比如:

t2 = "Mark sends 2.3 GC to James" -> t2 = "Mark sends 3.2 GC to James" 

我们会看到块哈希的巨大变化。

Block 1 data: Noah sends 5 GC to Mark - Mark sends 3.2 GC to James - firstblock
Block 1 hash: 7a990bf1d70230bf2dad6160496c0b3046da7a17b1281fd1d4c63d4eac58e78c
Block 2 data: James sends 4.2 GC to Alisson - Alisson sends 1.1 GC to Noah - 7a990bf1d70230bf2dad6160496c0b3046da7a17b1281fd1d4c63d4eac58e78c
Block 2 hash: 569b977306ce88b53e001dca7ba00c03a51c60d6df4650e7657dcd136f2da0ac

你可以在此链接_10上查看当前项目。

编写一个区块链

把我们的系统完整性基于手动编码的变量上并不聪明,所以我们需要另一种方法。

我们有了块。现在是时候建立一个类,将它们组合成一个区块链了。

让我们首先删除之前的交易和块对象,然后使用下面的代码。

# main.py

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

    def generate_genesis_block(self):
        self.chain.append(GeekCoinBlock("0", ['Genesis Block']))
    
    def create_block_from_transaction(self, transaction_list):
        previous_block_hash = self.last_block.block_hash
        self.chain.append(GeekCoinBlock(previous_block_hash, transaction_list))

    def display_chain(self):
        for i in range(len(self.chain)):
            print(f"Data {i + 1}: {self.chain[i].block_data}")
            print(f"Hash {i + 1}: {self.chain[i].block_hash}n")

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

这又是一段庞大的代码。让我们解释一下每个部分:

  • self.chain — 记录所有块的列表。我们可以通过列表索引访问每个块。
  • generate_genesis_block — 将创世块或第一个块追加到链中。块的前一哈希是“0”,交易列表只是“Genesis Block”。
  • create_block_from_transaction — 这允许我们只使用交易列表将块追加到链中。如果我们每次要记录一笔交易都要手动创建一个块,那将非常麻烦。
  • display_chain — 使用循环打印块链。
  • last_block — 允许我们访问链的最后一个元素的属性。我们在create_block_from_transaction方法中使用了它。

让我们测试一下这个区块链。

# main.py

import hashlib

class GeekCoinBlock:
    ...


class Blockchain:
    ...

t1 = "乔治发送3.1 GC给乔"
t2 = "乔发送2.5 GC给亚当"
t3 = "亚当发送1.2 GC给鲍勃"
t4 = "鲍勃发送0.5 GC给查理"
t5 = "查理发送0.2 GC给大卫"
t6 = "大卫发送0.1 GC给埃里克"

myblockchain = Blockchain()

myblockchain.create_block_from_transaction([t1, t2])
myblockchain.create_block_from_transaction([t3, t4])
myblockchain.create_block_from_transaction([t5, t6])

myblockchain.display_chain()

现在,运行main.py文件。

数据1:创世块 - 0
哈希1:39331a6a2ea1cf31a5014b2a7c9e8dfad82df0b0666e81ce04cf8173cc5aed3e

数据2:乔治发送3.1 GC给乔 - 乔发送2.5 GC给亚当 - 39331a6a2ea1cf31a5014b2a7c9e8dfad82df0b0666e81ce04cf8173cc5aed3e
哈希2:98cf363aecb33989aea0425a3c1287268bd86f63851bc08c0734a31db08506d5

数据3:亚当发送1.2 GC给鲍勃 - 鲍勃发送0.5 GC给查理 - 98cf363aecb33989aea0425a3c1287268bd86f63851bc08c0734a31db08506d5
哈希3:6f1cfcc3082488b97db8fdf8ed33f9ac7519be3e285a37a6fcc2f1904f373589

数据4:查理发送0.2 GC给大卫 - 大卫发送0.1 GC给埃里克 - 6f1cfcc3082488b97db8fdf8ed33f9ac7519be3e285a37a6fcc2f1904f373589
哈希4:869df2f03c9860767d35b30a46233fbeea89a3000ae5019d1491e3829d1ab929

恭喜!🙌 您刚刚从头开始创建了一个简单的Python区块链。

您现在可以通过使用getter和setter加强区块链的不可变性,并实现其他功能,如工作证明、mining或我们在Bitcoin Mining fundamentals article中解释的任何其他概念。

结论

区块链是比特币、以太坊和其他所有加密货币背后的技术。在本文中,您学会了如何使用哈希算法(如sha256)、类和对象来创建Python区块链。

您的挑战是创建一个挖矿系统,为什么不使用像DjangoFlask这样的框架通过REST API实现呢。

许多人正在从加密货币中获得财富。想象一下,如果您自己创建了一个加密货币,您可以做些什么。🤑

继续编码!👨‍💻

类似文章