Why does adding a block take work?
Proof of work is a rule that a block counts only if somebody did a lot of trying to make it. Finding the answer is slow, but checking it takes one hash.
This is what makes an old block costly to change. You will mine a block yourself and see how the work grows.
By the end of this lesson
Note
I can explain why mining a block costs work while checking it is cheap.
Key words
| Word | What it means |
|---|---|
| Nonce | a number you change until the hash is acceptable |
| Difficulty | how many zeros the hash must start with |
| Mining | trying nonces until a block's hash meets the difficulty |
| Proof of work | a block whose hash shows that the trying was done |
| Hex digit | one of 16 symbols, 0 to 9 and a to f |
The cells students fill in are left blank in this preview.
A nonce is the number you keep changing
A block's hash depends on its contents. To get a different hash without changing the records, the block carries one more field, the nonce. It is just a whole number.
Mining means trying nonce 0, then 1, then 2, and so on. After each try you work out the hash. You stop when it starts with enough zeros.
Mine one block at four difficulties
docker exec jupyter python3 steps/mine.pyShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Worked example: tries at each difficulty
| Difficulty | Zeros wanted | Average tries (16 to the power) | Tries the lab needed |
|---|---|---|---|
| 1 | 1 | 16 | 15 |
| 2 | 2 | 256 | 835 |
| 3 | 3 | 4,096 | 7,992 |
| 4 | 4 | 65,536 | 109,028 |
The cells students fill in are left blank in this preview.
Each extra zero is 16 times more work
A hash is written in hexadecimal. Each hex digit has 16 possible values, and only one of them is a zero. So one chance in 16 gives a first zero, and one in 256 gives two zeros.
Each extra zero multiplies the average work by 16. Real tries vary. The lab needed 835 for two zeros where the average is 256, which is luck, not a fault.
Try it: mine a block yourself
import hashlib
def mine(data, difficulty):
nonce = 0
while True:
text = data + str(nonce)
digest = hashlib.sha256(text.encode()).hexdigest()
if digest.startswith("0" * difficulty):
return nonce, digest
nonce = nonce + 1
nonce, digest = mine("Asha pays Ben 5", 3)
print("nonce:", nonce)
print("tries:", nonce + 1)
print("hash starts:", digest[:8])
# Change 3 to 2 and run again, then to 4.
Checking a block takes one hash
Finding a good nonce took thousands of tries. Checking one takes a single hash: work the hash out from the block and the nonce, then look at its first characters.
This difference is the whole idea. Mining is slow for the one who adds a block. Checking is quick for everybody else, so everybody can afford to verify.
Check a nonce with one hash
import hashlib
def good(data, nonce, difficulty):
digest = hashlib.sha256((data + str(nonce)).encode()).hexdigest()
return digest.startswith("0" * difficulty)
print(good("Asha pays Ben 5", 1864, 3))
print(good("Asha pays Ben 5", 1865, 3))
# One hash decides each answer. Try nonce 1863.
A common mistake
Warning
Many people think difficulty 4 is only a little harder than difficulty 3, or twice as hard. It is about 16 times harder. Each zero is one more hex digit that must come out right, and a hex digit has 16 values. Count the zeros, then multiply by 16 for each one.
Changing an old block means mining again
When a block is edited, its hash changes, so it no longer starts with zeros. You must mine it again. That also changes its hash, which breaks the link in the next block, so that one must be mined again too.
A block that is ten places back means ten blocks to mine again, while everybody else keeps adding new ones.
Worked example: blocks to mine again
| Chain length | Block edited | Blocks to mine again |
|---|---|---|
| 10 | The newest, block 9 | 1 |
| 10 | Block 6 | 4 |
| 10 | Block 0 | 10 |
The cells students fill in are left blank in this preview.