Foundations of Blockchain
上QQ阅读APP看书,第一时间看更新

An example implementation of Proof of Work

In the previous section, we covered how Proof of Work used a hashing algorithm. We also looked at computing a target hash to solve the hashing puzzle. We're now going to implement a Proof of Work algorithm using the SHA-256 algorithm in order to analyze how hashing and probability contribute to this consensus algorithm.

Since the main intention of the Proof of Work algorithm is to find a nonce that, when attached to the blockchain header, results in the required target hash value, the task here is to randomly guess a nonce value and establish the digest value of the block. Thanks to the properties of hash functions, which make guessing the nonce really hard and non-deterministic, the only way to find the nonce is to actually try out each nonce using the hash function and find a nonce that will satisfy the target hash value. Although the solution is non-deterministic, due to the properties of hash functions, Proof of Work is affected by probability. Although finding the solution depends on luck, the puzzle is often solved by the miner node that has done the most work. This is due to the fact that the probability of finding the nonce increases with the amount of work done.

Each puzzle solved in the Proof of Work has a difficulty level that decides the target hash value to be created. The difficulty level is decided by the number of zero bits required at the beginning of the resulting hash value. The puzzle's difficulty level is increased by increasing the required number of 0 bits in the hash values. This is again due to the fact that the probability of finding a small hash value is lower than the probability of finding any hash values including the large hash values due to the smaller sample space.

This example implementation of Proof of Work will illustrate the role of probability in this consensus algorithm:

from Crypto.Hash import SHA256 
 
text = "I am Satoshi Nakamoto" 
 
 
for nonce in range(20): 
 
    input_data = text + str(nonce) 
 
    hash_data = SHA256.new(input_data.encode()).hexdigest() 
 
    print(input_data, '=>', hash_data) 
The code to demonstrate nonce is inspired by the code snippet from Mastering Bitcoin – First Edition by Andreas M. Antonopoulos.

The preceding code snippet is a simple example of generating hashes to solve the Proof of Work hashing puzzle. The nonce is created in an incremental fashion and appended to the input data. The hash value is computed using the SHA-256 algorithm, and this is repeated for all the nonce values.

The program will generate the following hashes for the nonce-appended data:

I am Satoshi 
Nakamoto0=>a80a81401765c8eddee25df36728d732acb6d135... I am Satoshi
Nakamoto1=>f7bc9a6304a4647bb41241a677b5345fe3cd30db... I am Satoshi
Nakamoto2=>ea758a8134b115298a1583ffb80ae62939a2d086... I am Satoshi
Nakamoto3=>bfa9779618ff072c903d773de30c99bd6e2fd70b... I am Satoshi
Nakamoto4=>bce8564de9a83c18c31944a66bde992ff1a77513... I am Satoshi
Nakamoto5=>eb362c3cf3479be0a97a20163589038e4dbead49... I am Satoshi
Nakamoto6=>4a2fd48e3be420d0d28e202360cfbaba410bedde... I am Satoshi
Nakamoto7=>790b5a1349a5f2b909bf74d0d166b17a333c7fd8... I am Satoshi
Nakamoto8=>702c45e5b15aa54b625d68dd947f1597b1fa571d... I am Satoshi
Nakamoto9=>7007cf7dd40f5e933cd89fff5b791ff0614d9c60... I am Satoshi
Nakamoto10=>c2f38c81992f4614206a21537bd634af7178964... I am Satoshi
Nakamoto11=>7045da6ed8a914690f087690e1e8d662cf9e56f... I am Satoshi
Nakamoto12=>60f01db30c1a0d4cbce2b4b22e88b9b93f58f10... I am Satoshi
Nakamoto13=>0ebc56d59a34f5082aaef3d66b37a661696c2b6... I am Satoshi
Nakamoto14=>27ead1ca85da66981fd9da01a8c6816f54cfa0d... I am Satoshi
Nakamoto15=>394809fb809c5f83ce97ab554a2812cd901d3b1... I am Satoshi
Nakamoto16=>8fa4992219df33f50834465d30474298a7d5ec7... I am Satoshi
Nakamoto17=>dca9b8b4f8d8e1521fa4eaa46f4f0cdf9ae0e69... I am Satoshi
Nakamoto18=>9989a401b2a3a318b01e9ca9a22b0f39d82e48b... I am Satoshi
Nakamoto19=>cda56022ecb5b67b2bc93a2d764e75fc6ec6e6e...

Although each input for the preceding hash values differs by only the last two digits, the hash output values are completely different due to the properties of hash functions. This is why it is infeasible to detect a nonce that would produce the target hash value and therefore solve the puzzle.