How can you tell a record was changed?
A hash chain is a list of records where each record holds the fingerprint of the one before it. If anybody changes an old record, the fingerprints stop matching, so the change shows.
A shared list of who paid whom has this problem: one person could quietly rub out a line. A hash chain lets everybody check the list for themselves.
By the end of this lesson
Note
I can link blocks with hashes so that a change to an old block is detectable.
Key words
| Word | What it means |
|---|---|
| Hash | a fixed-size fingerprint worked out from some data |
| Block | one group of records, stored with its own hash |
| Previous hash | the hash of the block just before this one |
| Chain | blocks in order, each holding the previous hash |
| Tamper-evident | a change to the data can be seen, even if it cannot be stopped |
The cells students fill in are left blank in this preview.
A block holds records and the previous hash
A block is a group of records. Besides its records, each block stores its own number and the hash of the block before it.
The block's own hash is worked out from all of that together: its number, the previous hash and its records. Block 0 has nothing before it, so its previous hash is a row of zeros.
Build three blocks and print their hashes
docker exec jupyter python3 steps/link.pyShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Read the lines the lab printed
The script printed three lines, one for each block. Each line shows the block number, the first ten characters of its previous hash and the first ten of its own hash.
Look at block 1. Its previous hash is the same ten characters as block 0's own hash. That match is the link. Every hash starts with three zeros because the lab also mines each block, which lesson 2 explains.
A changed old block breaks the chain
To check a chain, you do two things to every block. First, work its hash out again from its contents and compare it with the stored one. Second, check that its previous hash equals the hash of the block before.
If somebody edits block 1, the first check fails at block 1. The tool reports the number of the first bad block.
Change one amount and check the chain
docker exec jupyter python3 steps/tamper.pyShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Worked example: what each check printed
| Step | What the lab printed | What it means |
|---|---|---|
| Before any change | (True, None) | Valid, and no bad block |
| One amount changed in block 1 | (False, 1) | Block 1 no longer matches its hash |
| Block 1's hash faked by hand | (False, 1) | The fake is still not the real hash of its contents |
| Block 1 mined again | (False, 2) | Block 1 is right, but block 2 holds the old hash of block 1 |
The cells students fill in are left blank in this preview.
A common mistake
Warning
Many people think you can repair a changed block by working its hash out again. That repairs block 1 only. Block 2 still holds the old hash of block 1, so the link between them is broken, and so is every later link. To hide a change, you must redo every block after it.
Try it: change a record and compare
import hashlib
def fingerprint(index, previous, data):
text = str(index) + "|" + previous + "|" + data
return hashlib.sha256(text.encode()).hexdigest()
start = "0" * 64
data = ["Asha pays Ben 5", "Ben pays Cara 2"]
first = fingerprint(0, start, data[0])
second = fingerprint(1, first, data[1])
print("block 1 stores:", second[:10])
# Change the first payment, as if somebody edited an old record.
data[0] = "Asha pays Ben 50"
first = fingerprint(0, start, data[0])
second_now = fingerprint(1, first, data[1])
print("block 1 would now be:", second_now[:10])
print("still the same hash:", second_now == second)
# Now change data[1] instead and compare again.