来源 https://zhuanlan.zhihu.com/p/142136802
此区块链教程将详细介绍区块链背后的理论。区块链是数字货币比特币的基本构建块,此教程将讨论比特币的复杂性,全面解释区块链架构,并建立我们自己的区块链。
本教程将介绍如何构建上述系统,并在市场上推出自己的数字货币。整个区块链项目开发包括3个主要部分:客户(Client)、矿工(Miners)、区块链(Blockchain)。
多个客户进行的交易在系统中排队; 矿工从此队列中提取交易并将其添加到区块中。 然后他们将开采该区块,获胜的矿工将拥有将该区块添加到区块链中的特权,从而为自己赚钱。
我们将在后续讨论区块链创建时描述此挖掘过程。 在编写多个交易代码之前,添加一个函数用来打印给定交易的内容。
display_transaction
函数接受交易类型的单参数。 接收到交易中的字典对象被复制到一个名为tsdict
的临时变量中,并使用字典键打印对应的值。
def display_transaction(transaction): tsdict = transaction.to_dict() print("sender: " + tsdict['sender']) print('-' * 20) print("recipient: " + tsdict['recipient']) print('-' * 20) print("value: " + str(tsdict['value'])) print('-' * 20) print("time: " + str(tsdict['time'])) print('-' * 20)
下面我们定义一个交易队列存储交易对象。
为了创建一个队列,我们声明一个名为transactions
的全局列表变量:
transactions = []
我们简单地将每个新创建的交易添加到此队列。 注意:为简单起见,本教程中不实现队列管理逻辑。
我们将开始创建交易。 首先创建4个客户,他们为从他人那里获得各种服务或商品而互相汇款。
Dinesh = Client() Ramesh = Client() Seema = Client() Vijay = Client()
至此,我们有4个客户,分别是Dinesh,Ramesh,Seema和Vijay。 假设每个客户钱包中都持有一些TPCoin可以用于交易。 这些客户的身份将通过这些对象的identity属性来指定。
现在执行第一个交易:
t1 = Transaction(Dinesh, Ramesh.identity, 5.0)
在这个交易中,Dinesh将5个TPCoins发送给Ramesh。 为了使交易成功,必须确保Dinesh钱包中有足够的钱来进行这次付款。 注意:我们需要一个初始(genesis
)交易来启动系统中TPCoin的流通。
我们使用Dinesh的私钥签署此交易,并将其添加到交易队列中:
t1.sign_transaction() transactions.append(t1)
Dinesh完成第一个交易后,我们将在不同客户间创建更多的交易。
现在创建更多交易,每笔交易都会向对方转移一些TPCoins。 当有人花钱时,他不必检查钱包中是否有足够的余额。在发起交易时,矿工将验证每个交易发送方所拥有的余额。
余额不足时,矿工将此交易标记为无效,并且不会将其添加到该区块中。
以下代码将创建9个交易并将其添加到我们的队列中。
t2 = Transaction(Dinesh, Seema.identity, 6.0) t2.sign_transaction() transactions.append(t2) t3 = Transaction(Ramesh, Vijay.identity, 2.0) t3.sign_transaction() transactions.append(t3) t4 = Transaction(Seema, Ramesh.identity, 4.0) t4.sign_transaction() transactions.append(t4) t5 = Transaction(Vijay, Seema.identity, 7.0) t5.sign_transaction() transactions.append(t5) t6 = Transaction(Ramesh, Seema.identity, 3.0) t6.sign_transaction() transactions.append(t6) t7 = Transaction(Seema, Dinesh.identity, 8.0) t7.sign_transaction() transactions.append(t7) t8 = Transaction(Seema, Ramesh.identity, 1.0) t8.sign_transaction() transactions.append(t8) t9 = Transaction(Vijay, Dinesh.identity, 5.0) t9.sign_transaction() transactions.append(t9) t10 = Transaction(Vijay, Ramesh.identity, 3.0) t10.sign_transaction() transactions.append(t10)
作为区块链管理者,你可能喜欢定期查看交易队列的内容。 为此,可以使用display_transaction
函数。 要将所有交易转储到队列中,只需迭代交易列表;然后为每个交易调用display_transaction
函数:
for transaction in transactions: display_transaction(transaction) print ('-' * 20)
由于交易会定期添加到区块中,因此你通常只希望查看尚未开采的交易清单,需要创建适当的for循环来遍历尚未挖掘的交易。
到目前为止,你已经学习了如何创建客户,允许客户之间进行交易,维护待挖掘的未完成的交易队列。
一个区块由不同数量的交易组成。 为简单起见,假设该块由固定数量的交易组成,示例中为3个交易。 由于该块需要存储3个交易的列表,我们声明一个实例变量authenticated_transactions
:
self.verified_transactions = []
我们将此变量命名为verify_transactions
,表示只有经过验证的有效交易才会被添加到该区块中。 每个块还保留前一个块的哈希值,因此块链变得不可变。
为了存储先前的哈希,声明一个实例变量:
self.previous_block_hash = ""
最后,声明一个变量Nonce
,用于存储矿工在采矿过程中创建的随机数。
self.Nonce = ""
Block类的定义为:
class Block(): def __init__(self): self.verified_transactions = [] self.previous_block_hash = "" self.Nonce = ""
由于每个块需要前一个块的哈希值,声明一个last_block_hash
的全局变量:
last_block_hash = ""
下面在区块链中创建第一个块。假设TPCoins的发起者最初向一个已知客户Dinesh发送500个TPCoins。 为此创建一个Dinesh实例:
Dinesh = Client()
然后我们创建初始(genesis)交易,并向Dinesh的公共地址发送500 TPCoins。
t0 = Transaction("Genesis", Dinesh.identity, 500.0)
创建一个Block类的实例:
block0 = Block()
将previous_block_hash
和once
实例变量初始化为None,因为这是存储在区块链中的第一笔交易。
block0.previous_block_hash = None Nonce = None
将t0
交易添加到块中的verified_transactions
列表中。
block0.verified_transactions.append(t0)
此时,该块完成初始化,可以添加到我们的区块链中。 我们将为此创建区块链。 在将区块添加到区块链之前,我们将对区块进行哈希处理并将其值存储在之前声明的last_block_hash
变量中。 该值将由下一个矿工在其区块中使用。
通过如下代码哈希区块并存储其值:
digest = hash(block0) last_block_hash = digest
区块链包含彼此链接的区块列表。 为了存储整个列表,创建一个列表变量TPCoins
:
TPCoins = []
dump_blockchain
方法用于转储整个区块链的内容。 首先打印区块链的长度,以便确定当前区块链中存在多少个区块。
def dump_blockchain(self): print("Number of blocks in the chain: " + str(len(self)))
随着时间的推移,区块链中的块数可能很多。 当打印区块链的内容时,需要确定要检查的范围。 示例中打印了整个区块链,因为在当前示例不会添加太多块。为了遍历整个链,设置了一个for循环:
for x in range (len(TPCoins)): block_temp = TPCoins[x] print ("block # " + str(x))
每个引用的块都复制到临时变量block_temp
中。
将块号作为每个块的标题。 注意:数字将从零开始,第1个块是编号为1的初始块。
在每个块中,已经将3个交易(初始块除外)的列表存储在变量verified_transactions
中。 在for循环中迭代此列表,调用display_transaction
显示交易明细。
for transaction in block_temp.verified_transactions: display_transaction (transaction)
dump_blockchain
方法全部代码为:
def dump_blockchain(self): print("Number of blocks in the chain: " + str(len(self))) for x in range(len(TPCoins)): block_temp = TPCoins[x] print("block # " + str(x)) for transaction in block_temp.verified_transactions: display_transaction(transaction) print('-' * 10) print('=' * 40)
现在已经创建了一个用于存储块的区块链,一个任务是创建块并将其添加到区块链中。 为此,将添加之前已经创建的初始块。
向区块链添加一个块涉及到将创建的块追加到TPCoins
列表中。
TPCoins.append(block0)
注意:与系统中其余的块不同,初始块仅包含一个由TPCoins系统的发起者发起的交易。通过调用函数dump_blockchain
转储区块链的内容:
dump_blockchain(TPCoins)
至此,区块链系统就可以使用了。我们将通过为感兴趣的客户提供挖掘功能,使他们成为矿工。