如何使用Python创建区块链?
你知道比特币是建立在区块链之上的吗?今天我们将用Python从零开始构建一个区块链。
什么是区块链?
在2008年,一个名叫Satoshi Nakamoto的未知个体或团体发布了 Bitcoin paper。比特币是一种点对点的电子现金版本,允许在不通过中央机构(银行)的情况下进行交易。大多数人不知道的是,在同一篇论文中,Satoshi定义了一种分布式的信息存储方式,现在被称为 Blockchain。
简单来说,区块链是一个共享的、不可变的数字分类帐,它在一个去中心化的计算机网络上存储交易。
我们可以将区块链分为两个简单的术语:
- 块:存储交易的空间
- 链:一组链接记录
这定义了区块链为一系列链接的块,每个块都存储具有特定参数的交易。
每个块都建立在另一个块之上,创建了一个不可逆转的块链。换句话说,每个块都依赖于另一个块。这就成为一个强大且不可变的系统,权限正确的任何人都可以审查完整性。
区块链引入了一套有趣的特性:
- 历史不可变性
- 信息持久性
- 存储数据无错误
许多系统目前依赖于区块链,如 cryptocurrencies、资产转移 (NFTs),可能在不久的将来还包括投票。
值得一提的是,一个 Python 区块链不必是一个有成千上万行代码的复杂程序。在其核心,它只是一个彼此链接的交易列表。
当然,这只是一个简短的解释,但如果你想要一个完整的指南,我们已经制作了一份有关 Blockchain for beginners 的完整教程。一定要查看。
不多说了,让我们用Python构建一个简单的区块链。
使用Python构建区块链
在开始之前,让我们定义一下这个教程中要做的事情:
- 使用Python构建简单的区块链系统
- 使用预先设定的字符串代表的交易来使用我们的区块链
- 测试我们的区块链的不可变性
我们将不使用 JSON 而是使用Python列表。这将使我们简化过程,并专注于应用区块链的关键概念。
以下是你需要遵循本教程的内容:
- 理解 classes and methods in 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区块链。
您的挑战是创建一个挖矿系统,为什么不使用像Django或Flask这样的框架通过REST API实现呢。
许多人正在从加密货币中获得财富。想象一下,如果您自己创建了一个加密货币,您可以做些什么。🤑
继续编码!👨💻