Python Blockchain 简明教程

Python Blockchain - Transaction Class

在本章中,让我们创建一个 Transaction 类,以便客户端能够向某人汇款。请注意,客户端既可以是发件人,也可以是收件人。当您希望收款时,其他发件人将创建一个交易并在其内指定您的 public 地址。我们定义一个交易类的初始化如下 −

In this chapter, let us create a Transaction class so that a client will be able to send money to somebody. Note that a client can be both a sender or a recipient of the money. When you want to receive money, some other sender will create a transaction and specify your public address in it. We define the initialization of a transaction class as follows −

def __init__(self, sender, recipient, value):
   self.sender = sender
   self.recipient = recipient
   self.value = value
   self.time = datetime.datetime.now()

init 方法采用三个参数 − 发件人的 public 密钥,收件人的 public 密钥以及要发送的金额。这些存储在实例变量中以供其他方法使用。此外,我们还创建了一个用于存储交易时间的变量。

The init method takes three parameters − the sender’s public key, the recipient’s public key, and the amount to be sent. These are stored in the instance variables for use by other methods. Additionally, we create one more variable for storing the time of transaction.

接下来,我们编写一个名为 to_dict 的实用程序方法,该方法将上述四个实例变量组合在一个字典对象中。这仅仅是为了将整个交易信息放在一个变量中访问。

Next, we write a utility method called to_dict that combines all the four above-mentioned instance variables in a dictionary object. This is just to put the entire transaction information accessible through a single variable.

您从前面的教程中知道,区块链中的第一个块是 Genesis 块。Genesis 块包含区块链创建者发起的第一次交易。此人的身份可能像比特币的情况一样保密。因此,当创建第一次交易时,创建者可能会将他的身份发送为 Genesis 。因此,在创建字典时,我们会检查发件人是否为 Genesis ,如果为真,则我们只为身份变量分配某个字符串值;否则,我们将发件人的身份分配给 identity 变量。

As you know from the earlier tutorial that the first block in the blockchain is a Genesis block. The Genesis block contains the first transaction initiated by the creator of the blockchain. The identity of this person may be kept a secret like in the case of Bitcoins. So when this first transaction is created, the creator may just send his identity as Genesis. Thus, while creating the dictionary, we check if the sender is Genesis and if so we simply assign some string value to the identity variable; else, we assign the sender’s identity to the identity variable.

if self.sender == "Genesis":
   identity = "Genesis"
else:
   identity = self.sender.identity

我们使用以下代码行构建字典

We construct the dictionary using following line of code

return collections.OrderedDict({
   'sender': identity,
   'recipient': self.recipient,
   'value': self.value,
   'time' : self.time})

完整 to_dict 方法的代码如下 −

The entire code for the to_dict method is shown below −

def to_dict(self):
   if self.sender == "Genesis":
      identity = "Genesis"
   else:
      identity = self.sender.identity

   return collections.OrderedDict({
      'sender': identity,
      'recipient': self.recipient,
      'value': self.value,
      'time' : self.time})

最后,我们将使用发件人的私钥对这个字典对象签名。和以前一样,我们使用内置的具有 SHA 算法的 PKI。生成的签名被解码以得到 ASCII 表示以供打印并将其存储到我们的区块链中。 sign_transaction 方法代码显示如下 −

Finally, we will sign this dictionary object using the private key of the sender. As before, we use the built-in PKI with SHA algorithm. The generated signature is decoded to get the ASCII representation for printing and storing it in our blockchain. The sign_transaction method code is shown here −

def sign_transaction(self):
   private_key = self.sender._private_key
   signer = PKCS1_v1_5.new(private_key)
   h = SHA.new(str(self.to_dict()).encode('utf8'))
   return binascii.hexlify(signer.sign(h)).decode('ascii')

我们现在将测试这个 Transaction 类。

We will now test this Transaction class.

Testing Transaction Class

为此,我们将创建两个用户,称为 DineshRamesh 。Dinesh 将向 Ramesh 发送 5 TPCoin。为此,我们首先创建名为 Dinesh 和 Ramesh 的客户端。

For this purpose, we will create two users, called Dinesh and Ramesh. Dinesh will send 5 TPCoins to Ramesh. For this first we create the clients called Dinesh and Ramesh.

Dinesh = Client()
Ramesh = Client()

请记住,当您实例化 Client 类时,将创建客户端唯一的 public and 私钥。由于 Dinesh 要向 Ramesh 发送付款,因此他将需要使用客户端的身份属性获取 Ramesh 的公钥。

Remember that when you instantiate a Client class, the public and private keys unique to the client would be created. As Dinesh is sending payment to Ramesh, he will need the public key of Ramesh which is obtained by using the identity property of the client.

因此,我们将使用以下代码创建交易实例 −

Thus, we will create the transaction instance using following code −

t = Transaction(
   Dinesh,
   Ramesh.identity,
   5.0
)

请注意,第一个参数是发件人,第二个参数是收件人的公钥,第三个参数是要转账的金额。 sign_transaction 方法从第一个参数中检索发件人的私钥以签署交易。

Note that the first parameter is the sender, the second parameter is the public key of the recipient and the third parameter is the amount to be transferred. The sign_transaction method retrieves the sender’s private key from the first parameter for singing the transaction.

交易对象创建后,您将通过调用其 sign_transaction 方法对其进行签名。此方法以可打印的格式返回生成的签名。我们使用以下两行代码生成并打印签名 −

After the transaction object is created, you will sign it by calling its sign_transaction method. This method returns the generated signature in the printable format. We generate and print the signature using following two lines of code −

signature = t.sign_transaction()
print (signature)

当您运行上述代码时,您将看到类似于此的输出 −

When you run the above code, you will see the output similar to this −

7c7e3c97629b218e9ec6e86b01f9abd8e361fd69e7d373c38420790b655b9abe3b575e343c7
13703ca1aee781acd7157a0624db3d57d7c2f1172730ee3f45af943338157f899965856f6b0
0e34db240b62673ad5a08c8e490f880b568efbc36035cae2e748f1d802d5e8e66298be826f5
c6363dc511222fb2416036ac04eb972

现在,由于我们创建客户端和交易的基本基础设施已经就绪,我们现在将像现实生活中一样执行多个客户端和多个交易。

Now as our basic infrastructure of creating a client and a transaction is ready, we will now have multiple clients doing multiple transactions as in a real life situation.