从零到区块链的Python--第一部分
欢迎来到 "从零到区块链的Python "系列,在这里我们将建立一个区块链应用程序的实现,特别是一个加密货币从头开始。在整个系列中,我们将建立和改进功能,直到我们有一个功能齐全的演示。
免责声明:请注意,这绝不是为了在真实场景中使用,这里使用的代码仅用于教育目的。
在这一部分,我们将建立以下基本的区块链功能。
- 有可能将区块添加到
- 简单的工作证明(PoW)算法
- 增加交易的可能性
- 挖掘新区块的可能性
- 用一个新的区块链来替换这个区块链的可能性
而我们将为未来的文章保留以下内容。
- 钱包管理
- 签署交易
- 点对点通信
区块链是如何工作的?
在我们直接进入代码之前,你需要对什么是区块链、分布式账本如何工作以及sha256等加密函数的基本概念有一些基本的了解。
让乐趣开始吧
我们现在准备开始逐个模块地开发我们的区块链,在这篇文章中,我将通过代码样本和解释来一步步地指导你,经历我的思考过程和代码实现。为了保持对主要概念的关注,我不会在这里介绍我是如何实现swagger文档或代码测试的,但可以在这里找到完整工作实例的副本。
基本结构
我们需要为我们的区块链讨论的第一件事是区块和我们想在区块中存储的数据。对于我们的目的,我们将存储交易信息,所以像发件人、收件人和金额的数据。为了我们的目的,我们将使用类,这将更容易理解和遵循代码。
这非常简单,我们已经创建了一个validate
函数,我们以后会使用,现在,我们只是不允许任何负数的交易,以防止偷币。接下来是我们的区块定义。
Block = {
index: number
timestamp: number
transactions: [Transactions]
nonce: string
previous_hash: string
hash: string
}
我们的区块也很简单,它包含一个索引,一个时间戳,一个属于该区块的交易列表,一个我们将用作工作证明的nonce,前一个区块的散列和我们区块的散列。
对于区块,事情看起来有点奇怪,所以让我们一步一步来。这个类中的重要函数是hash_block
,它将区块信息(除去哈希属性)序列化,并返回对象的sha256表示。这个表示法随后被用作区块的哈希参数,以后将被用作区块没有被改变的加密证明。
区块链
现在我们需要用所有的区块链逻辑把它粘合起来。我们的区块链也将是一个类,在这里我们要存储所有我们需要监控和运作区块链的信息。
属性
self.__chain = []
self.__current_transactions = []
@property
def last_block(self):
return self.__chain[-1]
@property
def last_transaction(self):
return self.__current_transactions[-1]
@property
def pending_transactions(self):
return self.__current_transactions
@property
def full_chain(self):
return self.__chain
这就是我们托管区块链所需要的一切,至少现在是这样。让我们回顾一下每个属性是什么。
- 区块链(__chain):代表区块链的区块列表 [私有] 。
- __current_transactions:还没有成为区块一部分的交易列表 [private] 。
- last_block:添加到链上的最后一个区块
- last_transaction:添加到链上的最后一笔交易
- pending_transactions: 返回 __current_transactions 属性。
- full_chain: 返回__chain属性。
构造函数
在我们的构造函数中,我们将简单地初始化2个列表,并创建我们的第一个区块,这被称为创世区块。它将没有交易附加到它,没有nonce,它的前一个哈希值将是简单的00
,代表没有前一个哈希。
创建交易
简单地说,就是生成交易对象,验证它是否有效并将其附加到链上。
工作证明
现在我们开始讨论区块链的重头戏,工作证明。工作证明由两个函数组成,一个工作证明生成器,另一个验证器。我们的实现方式是采取最新的区块,并添加一个nonce来满足这个要求。
f`{last_nonce}{last_hash}{nonce}`
用sha256哈希的结果是4个前导零。
找到nonce值的唯一方法是尝试错误,我们将从0开始,每次加1,直到验证函数给出一个正数。这样做的目的是为了防止代理插入或更新被破坏的区块,是一个过程密集型计算。
挖矿
我们现在准备开采我们的第一个区块,让我们看看如何通过检查过程来做到这一点。
- 我们为我们的新区块计算nonce。
- 我们创建一个新的交易,给矿工一个奖励,这个交易的发送者是0,将产生1个币到奖励地址。
- 我们将创建区块并将其添加到链上。
现在让我们研究一下add_block
功能和它所包含的内容。
当我们走到这一步时,validate_block
函数周围的东西开始变得有点奇怪。所有这些if都是什么?这个函数的主要目的是验证该区块属于链,previous_hash
属性与前一个区块相匹配,区块中存储的哈希值与实际计算的哈希值相匹配,并且我们的工作证明是有效的。
替换区块链
这是一个非常重要的步骤,如果对等体之间在区块链上发生冲突,我们需要一个系统来定义哪个是正确的,为此我们将遵循比特币的方法,即投入工作最多的链将是正确的。
目前,工作量将是一个非常简单的计算,它是链上的区块数量。我知道还有改进的余地,我们可以在以后的工作中进行。下面是代码的样子。
很简单,我们比较链的大小,我们确保新的链有所有有效的区块,我们简单地把所有缺失的区块插入我们的区块链中,太好了,除了这个。
# Then we compare each block with its previous one
for x in range(1, len(chain_to_validate)):
if not self.validate_block(chain_to_validate[x], chain_to_validate[x - 1]):
return False
它伤害了你的眼睛吗?每次我们想验证一个传入的链时,我们需要验证该链上的所有区块,一定有更好的方法,特别是如果我们考虑到这些区块中有许多可能是我们自己的链上的。好吧......有一个更好的方法,但现在不会涉及,我们将在未来的文章中进行研究,但如果你有兴趣并想做研究和创建一个PR,欢迎你这样做:)。
祝贺你!
就这样......差不多......你仍然需要把我们讨论的所有方法暴露在某种服务器上,在我的演示项目中,我使用了flask和Swagger,这样你就有一个UI来测试和查看发生了什么。