Python Blockchain - how to Develop Client
A client is somebody who holds TPCoins and transacts those for goods/services from other vendors on the network including his own.
We should define a Client class for this purpose. To create a globally unique identification for the client, we use PKI (Public Key Infrastructure). In this chapter, let us talk about this in detail.
The client should be able to send money from his wallet to another known person. Similarly, the client should be able to accept money from a third party.
For spending money, the client would create a transaction specifying the sender’s name and the amount to be paid.
For receiving money, the client will provide his identity to the third party − essentially a sender of the money.
We do not store the balance amount of money the client holds in his wallet. During a transaction, we will compute the actual balance to ensure that the client has sufficient balance to make the payment.
To develop the Client class and for the rest of the code in the project, we will need to import many Python libraries. These are listed below −
# import libraries import hashlib import random import string import json import binascii import numpy as np import pandas as pd import pylab as pl import logging import datetime import collections
In addition to the above standard libraries, we are going to sign our transactions, create hash of the objects, etc. For this, you will need to import the following libraries −
# following imports are required by PKI import Crypto import Crypto.Random from Crypto.Hash import SHA from Crypto.PublicKey import RSA from Crypto.Signature import PKCS1_v1_5
Now, let us talk about client class
The Client class generates the private and public keys by using the built-in Python RSA algorithm. The interested reader may refer to this tutorial for the implementation of RSA. During the object initialization, we create private and public keys and store their values in the instance variable.
self._private_key = RSA.generate(1024, random) self._public_key = self._private_key.publickey()
Note that you should never lose your private key. For record keeping, the generated private key may be copied on a secured external storage or you may simply write down the ASCII representation of it on a piece of paper.
The generated public key will be used as the client’s identity. For this, we define a property called identity that returns the HEX representation of the public key.
@property def identity(self): return binascii.hexlify(self._public_key.exportKey(format='DER')) .decode('ascii')
The identity is unique to each client and can be made publicly available. Anybody would be able to send virtual currency to you using this identity and it will get added to your wallet.
The full code for the Client class is shown here −
class Client: def __init__(self): random = Crypto.Random.new().read self._private_key = RSA.generate(1024, random) self._public_key = self._private_key.publickey() self._signer = PKCS1_v1_5.new(self._private_key) @property def identity(self): return binascii.hexlify(self._public_key.exportKey(format='DER')).decode('ascii')
Testing Client
Now, we will write code that will illustrate how to use the Client class −
Dinesh = Client() print (Dinesh.identity)
The above code creates an instance of Client and assigns it to the variable Dinesh. We print the public key of Dinesh by calling its identity method. The output is shown here −
30819f300d06092a864886f70d010101050003818d0030818902818100b547fafceeb131e07 0166a6b23fec473cce22c3f55c35ce535b31d4c74754fecd820aa94c1166643a49ea5f49f72 3181ff943eb3fdc5b2cb2db12d21c06c880ccf493e14dd3e93f3a9e175325790004954c34d3 c7bc2ccc9f0eb5332014937f9e49bca9b7856d351a553d9812367dc8f2ac734992a4e6a6ff6 6f347bd411d07f0203010001
Now, we let us move on to create a transaction
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()
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.
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.
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})
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})
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')
We will now test this Transaction class.
Testing Transaction Class
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()
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 )
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.
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
Comments
Post a Comment