探索区块链的奥秘:用Python构建你自己的区块链
你是否了解比特币的基石是区块链技术? 今天,我们将从最基础的概念出发,使用Python编程语言构建一个简单的区块链系统。
什么是区块链?
早在2008年,一位化名为中本聪的神秘人物或团体发表了一篇名为比特币白皮书。 这篇论文首次提出了比特币的概念,一种点对点的电子现金系统,允许用户在没有中央机构(如银行)的情况下进行交易。 鲜为人知的是,中本聪在同一篇论文中还阐述了一种去中心化信息存储方法,这就是我们今天所说的区块链。
深入了解区块链技术
简而言之,区块链是一个共享的、不可篡改的数字账本,它通过分布式的计算机网络来存储交易数据。 我们可以把区块链分解为两个核心概念:
- 区块 (Block):这是我们存储交易记录的地方。
- 链 (Chain):这是一系列相互连接的记录。
因此,区块链可以被定义为一系列相互连接的区块,每个区块都包含了按照特定规则进行的交易记录。
每一个新的区块都建立在前一个区块的基础上,形成了一个不可逆的链条。 这意味着每个区块都依赖于它之前的区块,从而构成了一个稳固且不可篡改的系统。 任何拥有适当权限的人都可以查看并验证整个区块链的完整性。
区块链技术带来了一系列引人注目的特性:
- 历史数据的不可变性
- 信息存储的持久性
- 存储数据的零错误率
目前,许多系统都依赖于区块链技术,例如加密货币、资产转移(NFT)等,甚至在不久的将来可能会被应用于投票系统。
值得强调的是,使用Python构建的区块链并不一定是一个包含数千行代码的复杂程序。 它的核心本质上是一个相互关联的交易记录列表。
当然,以上只是一个简单的解释。如果你希望深入了解,我们还为初学者准备了完整的区块链教程,请务必查阅。
事不宜迟,让我们开始使用Python构建一个简单的区块链系统。
用Python构建区块链:实战演练
在开始之前,我们先明确一下本教程的目标:
- 使用Python构建一个简单的区块链系统。
- 在我们的区块链上记录以字符串形式呈现的预先定义好的交易。
- 测试我们区块链的不可篡改性。
在本教程中,我们不会使用JSON格式,而是使用Python列表,这可以简化流程,使我们能够专注于区块链的核心概念。
为了成功完成本教程,你需要:
创建区块类
打开你喜欢的代码编辑器,创建一个名为 `main.py` 的文件。我们所有的代码都将写在这个文件中。
首先,我们需要导入 哈希库,这个库提供创建单向加密消息的功能。 哈希技术是区块链能够安全存储交易记录的关键。
哈希函数是一种算法,它接收任意长度的数据(通常是编码后的字符串)作为输入,并返回一个固定长度的唯一标识符,通常被称为“摘要”或“签名”。 这个特性至关重要,因为即使输入数据只有细微的变化,哈希函数也会产生完全不同的输出。稍后我们将看到这一点。
现在,我们只需要导入Python内置的 `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()` 方法,将编码后的数据转换为十六进制格式的字符串。
我知道这些概念可能有点难以理解,所以让我们在Python交互式环境中实际操作一下 `hashlib` 模块:
In [1]: import hashlib In [2]: message = "Python is great" In [3]: h1 = hashlib.sha256(message.encode()) In [4]: h1 Out[4]: <sha256 ... object @ 0x7efcd55bfbf0> In [5]: h1.hexdigest() Out[5]: 'a40cf9cca ... 42ab97' In [6]: h2 = hashlib.sha256(b"Python is not great") In [7]: h2 Out[7]: <sha256 ... object @ 0x7efcd55bfc90> In [8]: h2.hexdigest() Out[8]: 'fefe510a6a ... 97e010c0ea34'
正如你所看到的,仅仅是输入字符串的细微变化(从 “Python is great” 到 “Python is not great”),就会导致哈希值产生完全不同的结果。 这和区块链的完整性密不可分。 如果你尝试对区块链中的任何数据进行细微的修改,其哈希值就会发生巨大变化。 这就是“你无法破坏区块链”这句话的真正含义。
使用我们的区块类
稍后我们将构建一个完整的区块链类,但现在,让我们使用我们刚刚定义的 `GeekCoinBlock` 类来创建一个区块链(Blockchain)。
在同一个文件中,我们先定义几个简单的字符串变量来代表交易记录,如下所示:
class GeekCoinBlock: ... t1 = "Noah 向 Mark 发送了 5 个 GC" t2 = "Mark 向 James 发送了 2.3 个 GC" t3 = "James 向 Alisson 发送了 4.2 个 GC" t4 = "Alisson 向 Noah 发送了 1.1 个 GC"
当然,这里的GC指的是GeekCoin(极客币)。
现在,我们使用 `GeekCoinBlock` 类来创建我们区块链的第一个区块,并打印出它的属性。 请注意,创世区块(区块链中的第一个区块)的 `previous_hash` 参数通常是一个任意的字符串或者哈希值,在本例中,我们使用 “firstblock” 作为它的 `previous_hash`。
block1 = GeekCoinBlock('firstblock', [t1, t2]) print(f"区块 1 数据: {block1.block_data}") print(f"区块 1 哈希值: {block1.block_hash}")
然后,我们以相同的方式创建第二个区块,但这次我们将第一个区块的哈希值作为 `previous_hash` 参数传递给第二个区块。
block2 = GeekCoinBlock(block1.block_hash, [t3, t4]) print(f"区块 2 数据: {block2.block_data}") print(f"区块 2 哈希值: {block2.block_hash}")
现在,让我们运行这段代码,并分析输出结果。 在你的终端中输入以下命令:
❯ python main.py 区块 1 数据: Noah 向 Mark 发送了 5 个 GC - Mark 向 James 发送了 2.3 个 GC - firstblock 区块 1 哈希值: 087c9f9b6949e45e368e5a08c979060894b3c698f630c0c303c7f07e45853670 区块 2 数据: James 向 Alisson 发送了 4.2 个 GC - Alisson 向 Noah 发送了 1.1 个 GC - 087c9f9b6949e45e368e5a08c979060894b3c698f630c0c303c7f07e45853670 区块 2 哈希值: 27a24759229f87f5d8c1c31c5c9665e9a95b994556049b585a3c80e605789828
目前为止,你看到的只是文字和一些64个字符的哈希值,但这已经初步展示了区块链的工作原理。
区块链从一个创世区块开始,它构成了所有后续区块的基础。
任何人都可以验证区块链的完整性,这正是区块链如此安全可靠的原因。 例如,如果我们稍微修改交易的内容,例如:
t2 = "Mark 向 James 发送了 2.3 个 GC" 改为 t2 = "Mark 向 James 发送了 3.2 个 GC"
我们可以看到,区块的哈希值发生了巨大的变化。
区块 1 数据: Noah 向 Mark 发送了 5 个 GC - Mark 向 James 发送了 3.2 个 GC - firstblock 区块 1 哈希值: 9293a08e65b35730b2027637592d077e15867807c736018457028545b828b3c9 区块 2 数据: James 向 Alisson 发送了 4.2 个 GC - Alisson 向 Noah 发送了 1.1 个 GC - 9293a08e65b35730b2027637592d077e15867807c736018457028545b828b3c9 区块 2 哈希值: 7550ef770d92df75f6f433ab99f36c565c30a61d64b2928c61b609d7a920d596
你可以通过这个GitHub仓库查看当前的完整项目。
编码区块链类
我们的系统目前是手动编码变量来验证其完整性的,这种方式并不理想,所以我们需要一种更有效的方法。
我们已经有了构成区块链的砖块(区块)。现在,是时候创建一个类将它们组合成一条完整的区块链了。
我们先删除之前定义的交易变量和区块对象,然后使用以下代码:
# main.py class Blockchain: def __init__(self): self.chain = [] self.generate_genesis_block() def generate_genesis_block(self): self.chain.append(GeekCoinBlock("0", ['创世区块'])) 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"数据 {i + 1}: {self.chain[i].block_data}") print(f"哈希值 {i + 1}: {self.chain[i].block_hash}n") @property def last_block(self): return self.chain[-1]
这又是一段比较长的代码。让我们来详细分析每一部分:
- `self.chain`:一个列表,用于记录所有区块。我们可以通过列表的索引来访问每一个区块。
- `generate_genesis_block`:将创世区块(区块链中的第一个区块)添加到区块链中。这个区块的 `previous_hash` 被设置为 “0”,并且其交易列表为“创世区块”。
- `create_block_from_transaction`:允许我们仅使用交易列表将新的区块添加到区块链中。如果我们每次要记录交易时都手动创建一个区块会很繁琐。
- `display_chain`:使用 `for` 循环来打印整个区块链。
- `last_block`:一个属性,允许我们访问区块链的最后一个区块。 我们在 `create_block_from_transaction` 方法中使用了这个属性。
现在,让我们来测试一下我们刚刚构建的区块链类:
# main.py import hashlib class GeekCoinBlock: ... class Blockchain: ... t1 = "George 向 Joe 发送了 3.1 个 GC" t2 = "Joe 向 Adam 发送了 2.5 个 GC" t3 = "Adam 向 Bob 发送了 1.2 个 GC" t4 = "Bob 向 Charlie 发送了 0.5 个 GC" t5 = "Charlie 向 David 发送了 0.2 个 GC" t6 = "David 向 Eric 发送了 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: 84b4c7d6a5184f30384dd8a0178c9693346a4299c295e31e137b6509d536e244n 数据 2: George 向 Joe 发送了 3.1 个 GC - Joe 向 Adam 发送了 2.5 个 GC - 84b4c7d6a5184f30384dd8a0178c9693346a4299c295e31e137b6509d536e244 哈希值 2: 345b7b9f4d0a26c724e990e509a08e85a4141c70b9b1a1311439c17278b8704bn 数据 3: Adam 向 Bob 发送了 1.2 个 GC - Bob 向 Charlie 发送了 0.5 个 GC - 345b7b9f4d0a26c724e990e509a08e85a4141c70b9b1a1311439c17278b8704b 哈希值 3: 9b6f825628b8f7f94a0a91d02a2a537f3e0b30281a33968132217294244b4161n 数据 4: Charlie 向 David 发送了 0.2 个 GC - David 向 Eric 发送了 0.1 个 GC - 9b6f825628b8f7f94a0a91d02a2a537f3e0b30281a33968132217294244b4161 哈希值 4: 9a35d7702e52c347f05d466a038760f4e115289910308f43e91e409f8639c9cbn
恭喜! 🙌 你刚刚从零开始构建了一个简单的Python区块链系统。
你现在可以继续完善你的区块链系统,例如使用getter和setter方法来增强区块链的不可变性,或者实现诸如工作量证明(PoW)、挖矿等其他功能。你还可以参考我们之前发布的比特币挖矿基础文章来了解更多概念。
总结
区块链是比特币、以太坊以及其他所有加密货币背后的核心技术。 在本文中,你学习了如何使用Python构建一个区块链,其中涉及了 `sha256` 哈希算法、类和对象等概念。
现在,你可以挑战一下自己,创建一个挖矿系统,或者使用诸如Django或Flask之类的框架通过REST API来实现它。
很多人通过加密货币发家致富。想象一下,如果自己创建一个加密货币,你能实现什么。🤑
继续编码吧!👨💻