Here is the basic blueprint of the Python class we’ll use for creating the blockchain:
1
class Block(object):
2
3
def __init__():
4
5
pass
6
7
#initial structure of the block class
8
9
def compute_hash():
10
11
pass
12
13
#producing the cryptographic hash of each block
14
15
class BlockChain(object):
16
17
def __init__(self):
18
19
#building the chain
20
21
def build_genesis(self):
22
23
pass
24
25
#creating the initial block
26
27
def build_block(self, proof_number, previous_hash):
28
29
pass
30
31
#builds new block and adds to the chain
32
33
@staticmethod
34
35
def confirm_validity(block, previous_block):
36
37
pass
38
39
#checks whether the blockchain is valid
40
41
def get_data(self, sender, receiver, amount):
42
43
pass
44
45
# declares data of transactions
46
47
@staticmethod
48
49
def proof_of_work(last_proof):
50
51
pass
52
53
#adds to the security of the blockchain
54
55
@property
56
57
def latest_block(self):
58
59
pass
60
61
#returns the last block in the chain
Now, let’s explain how the blockchain class works.
Initial Structure of the Block Class
Here is the code for our initial block class:
1
import hashlib
2
3
import time
4
5
class Block(object):
6
7
def __init__(self, index, proof_number, previous_hash, data, timestamp=None):
8
9
self.index = index
10
11
self.proof_number = proof_number
12
13
self.previous_hash = previous_hash
14
15
self.data = data
16
17
self.timestamp = timestamp or time.time()
18
19
@property
20
21
def compute_hash(self):
22
23
string_block = "{}{}{}{}{}".format(self.index, self.proof_number, self.previous_hash, self.data, self.timestamp)
24
25
return hashlib.sha256(string_block.encode()).hexdigest()
As you can see above, the class constructor or initiation method ( __init__()) above takes the following parameters:
self — just like any other Python class, this parameter is used to refer to the class itself. Any variable associated with the class can be accessed using it.
index — it’s used to track the position of a block within the blockchain.
previous_hash — it used to reference the hash of the previous block within the blockchain.
data—it gives details of the transactions done, for example, the amount bought.
timestamp—it inserts a timestamp for all the transactions performed.
The second method in the class, compute_hash , is used to produce the cryptographic hash of each block based on the above values.
As you can see, we imported the SHA-256 algorithm into the cryptocurrency blockchain project to help in getting the hashes of the blocks.
Once the values have been placed inside the hashing module, the algorithm will return a 256-bit string denoting the contents of the block.
So, this is what gives the blockchain immutability. Since each block will be represented by a hash, which will be computed from the hash of the previous block, corrupting any block in the chain will make the other blocks have invalid hashes, resulting in breakage of the whole blockchain network.
Building the Chain
The whole concept of a blockchain is based on the fact that the blocks are “chained” to each other. Now, we’ll create a blockchain class that will play the critical role of managing the entire chain.
It will keep the transactions data and include other helper methods for completing various roles, such as adding new blocks.
Let’s talk about the helper methods.
Adding the Constructor Method
Here is the code:
1
class BlockChain(object):
2
3
def __init__(self):
4
5
self.chain = []
6
7
self.current_data = []
8
9
self.nodes = set()
10
11
self.build_genesis()
The __init__() constructor method is what instantiates the blockchain.
Here are the roles of its attributes:
self.chain — this variable stores all the blocks.
self.current_data — this variable stores information about the transactions in the block.
self.build_genesis() — this method is used to create the initial block in the chain.
Building the Genesis Block
The build_genesis() method is used for creating the initial block in the chain, that is, a block without any predecessors. The genesis block is what represents the beginning of the blockchain.
To create it, we’ll call the build_block() method and give it some default values. The parameters proof_number and previous_hash are both given a value of zero, though you can give them any value you desire.
Here is the code:
1
def build_genesis(self):
2
3
self.build_block(proof_number=0, previous_hash=0)
4
5
def build_block(self, proof_number, previous_hash):
6
7
block = Block(
8
9
index=len(self.chain),
10
11
proof_number=proof_number,
12
13
previous_hash=previous_hash,
14
15
data=self.current_data
16
17
)
18
19
self.current_data = []
20
21
self.chain.append(block)
22
23
return block
Confirming Validity of the Blockchain
The confirm_validity method is critical in examining the integrity of the blockchain and making sure inconsistencies are lacking.
As explained earlier, hashes are pivotal for realizing the security of the cryptocurrency blockchain, because any slight alteration in an object will result in the creation of an entirely different hash.
Thus, the confirm_validity method utilizes a series of if statements to assess whether the hash of each block has been compromised.
Furthermore, it also compares the hash values of every two successive blocks to identify any anomalies. If the chain is working properly, it returns true; otherwise, it returns false.
Here is the code:
1
def confirm_validity(block, previous_block):
2
3
if previous_block.index + 1 != block.index:
4
5
return False
6
7
elif previous_block.compute_hash != block.previous_hash:
8
9
return False
10
11
elif block.timestamp <= previous_block.timestamp:
12
13
return False
14
15
return True
Declaring Data of Transactions
The get_data method is important in declaring the data of transactions on a block. This method takes three parameters (sender’s information, receiver’s information, and amount) and adds the transaction data to the self.current_data list.
Here is the code:
1
def get_data(self, sender, receiver, amount):
2
3
self.current_data.append({
4
5
'sender': sender,
6
7
'receiver': receiver,
8
9
'amount': amount
10
11
})
12
13
return True
Effecting the Proof of Work
In blockchain technology, Proof of Work (PoW) refers to the complexity involved in mining or generating new blocks on the blockchain.
For example, the PoW can be implemented by identifying a number that solves a problem whenever a user completes some computing work. Anyone on the blockchain network should find the number complex to identify but easy to verify — this is the main concept of PoW.
This way, it discourages spamming and compromising the integrity of the network.
In this article, we’ll illustrate how to include a Proof of Work algorithm in a blockchain cryptocurrency project.
Finalizing With the Last Block
Finally, the latest_block() helper method is used for retrieving the last block on the network, which is actually the current block.
Here is the code:
1
def latest_block(self):
2
3
return self.chain[-1]
Implementing Blockchain Mining
Now, this is the most exciting section!
Initially, the transactions are kept in a list of unverified transactions. Mining refers to the process of placing the unverified transactions in a block and solving the PoW problem. It can be referred to as the computing work involved in verifying the transactions.
If everything has been figured out correctly, a block is created or mined and joined together with the others in the blockchain. If users have successfully mined a block, they are often rewarded for using their computing resources to solve the PoW problem.
Here is the mining method in this simple cryptocurrency blockchain project:
1
def block_mining(self, details_miner):
2
3
self.get_data(
4
5
sender="0", #it implies that this node has created a new block
6
7
receiver=details_miner,
8
9
quantity=1, #creating a new block (or identifying the proof number) is awarded with 1
10
11
)
12
13
last_block = self.latest_block
14
15
last_proof_number = last_block.proof_number
16
17
proof_number = self.proof_of_work(last_proof_number)
18
19
20
21
last_hash = last_block.compute_hash
22
23
block = self.build_block(proof_number, last_hash)
24
25
26
27
return vars(block)
28
29
Summary
Here is the whole code for our crypto blockchain class in Python:
1
import hashlib
2
3
import time
4
5
class Block(object):
6
7
def __init__(self, index, proof_number, previous_hash, data, timestamp=None):
8
9
self.index = index
10
11
self.proof_number = proof_number
12
13
self.previous_hash = previous_hash
14
15
self.data = data
16
17
self.timestamp = timestamp or time.time()
18
19
@property
20
21
def compute_hash(self):
22
23
string_block = "{}{}{}{}{}".format(self.index, self.proof_number, self.previous_hash, self.data, self.timestamp)
24
25
return hashlib.sha256(string_block.encode()).hexdigest()
26
27
def __repr__(self):
28
29
return "{} - {} - {} - {} - {}".format(self.index, self.proof_number, self.previous_hash, self.data, self.timestamp)
30
31
class BlockChain(object):
32
33
def __init__(self):
34
35
self.chain = []
36
37
self.current_data = []
38
39
self.nodes = set()
40
41
self.build_genesis()
42
43
def build_genesis(self):
44
45
self.build_block(proof_number=0, previous_hash=0)
46
47
def build_block(self, proof_number, previous_hash):
48
49
block = Block(
50
51
index=len(self.chain),
52
53
proof_number=proof_number,
54
55
previous_hash=previous_hash,
56
57
data=self.current_data
58
59
)
60
61
self.current_data = []
62
63
self.chain.append(block)
64
65
return block
66
67
@staticmethod
68
69
def confirm_validity(block, previous_block):
70
71
if previous_block.index + 1 != block.index:
72
73
return False
74
75
elif previous_block.compute_hash != block.previous_hash:
76
77
return False
78
79
elif block.timestamp <= previous_block.timestamp:
80
81
return False
82
83
return True
84
85
def get_data(self, sender, receiver, amount):
86
87
self.current_data.append({
88
89
'sender': sender,
90
91
'receiver': receiver,
92
93
'amount': amount
94
95
})
96
97
return True
98
99
@staticmethod
100
101
def proof_of_work(last_proof):
102
103
pass
104
105
@property
106
107
def latest_block(self):
108
109
return self.chain[-1]
110
111
def chain_validity(self):
112
113
pass
114
115
def block_mining(self, details_miner):
116
117
self.get_data(
118
119
sender="0", #it implies that this node has created a new block
120
121
receiver=details_miner,
122
123
quantity=1, #creating a new block (or identifying the proof number) is awared with 1
124
125
)
126
127
last_block = self.latest_block
128
129
last_proof_number = last_block.proof_number
130
131
proof_number = self.proof_of_work(last_proof_number)
132
133
last_hash = last_block.compute_hash
134
135
block = self.build_block(proof_number, last_hash)
136
137
return vars(block)
138
139
def create_node(self, address):
140
141
self.nodes.add(address)
142
143
return True
144
145
@staticmethod
146
147
def get_block_object(block_data):
148
149
return Block(
150
151
block_data['index'],
152
153
block_data['proof_number'],
154
155
block_data['previous_hash'],
156
157
block_data['data'],
158
159
timestamp=block_data['timestamp']
160
161
)
162
163
blockchain = BlockChain()
164
165
print("GET READY MINING ABOUT TO START")
166
167
print(blockchain.chain)
168
169
last_block = blockchain.latest_block
170
171
last_proof_number = last_block.proof_number
172
173
proof_number = blockchain.proof_of_work(last_proof_number)
174
175
blockchain.get_data(
176
177
sender="0", #this means that this node has constructed another block
178
179
receiver="LiveEdu.tv",
180
181
amount=1, #building a new block (or figuring out the proof number) is awarded with 1
182
183
)
184
185
last_hash = last_block.compute_hash
186
187
block = blockchain.build_block(proof_number, last_hash)
188
189
print("WOW, MINING HAS BEEN SUCCESSFUL!")
190
191
print(blockchain.chain)
Now, let’s try to run our code to see if we can generate some digital coins...