Easier to read with cream paper, a tint, more contrast or larger text? Choose your colours and text, once, for every page.

Free lesson

How a ledger stops double spending

After this lesson: I can work out balances from a list of transactions and refuse an overspend.

60 min lesson1 commandBlockchain lab: a toy chain in Python to read, break, mine and sign

How do you know who has what?

A ledger is a list of every transaction in the order it happened. Nobody stores a balance. You work each balance out by replaying the list from the start.

A double spend is an attempt to use the same funds twice. A ledger that replays in one agreed order refuses the second.

By the end of this lesson

Note

I can work out balances from a list of transactions and refuse an overspend.

Key words

WordWhat it means
Ledgeran ordered list of every transaction
Transactionone payment from one account to another
Balancewhat an account holds after the list so far
Replayto go through the list again from the start
Double spendusing the same funds in two payments

The cells students fill in are left blank in this preview.

Balances are worked out by replaying payments

A ledger stores only transactions, such as "Asha pays Ben 4". To find a balance, start from the opening balances and apply the transactions one at a time, in order.

Nobody can quietly edit a stored balance, because none is stored. If the list is the same, every copy of the ledger gives the same balances.

Replay four payments in the lab

Command
docker exec jupyter python3 steps/balances.py

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Worked example: the lab's four payments

StepPaymentBalances afterwardsResult
StartnoneAsha 10, Ben 5, Cara 0Opening balances
1Asha pays Ben 4Asha 6, Ben 9, Cara 0Accepted
2Ben pays Cara 6Asha 6, Ben 3, Cara 6Accepted
3Cara pays Asha 8Asha 6, Ben 3, Cara 6Refused, Cara has only 6
4Ben pays Cara 3Asha 6, Ben 0, Cara 9Accepted

The cells students fill in are left blank in this preview.

A double spend uses the same funds twice

Dev holds 10 and sends 8 to Eli. Dev also sends 8 to Fay. Both payments look fine on their own, because each one is less than 10. Together they need 16.

A ledger replays in order. The first payment leaves Dev with 2, so the second is refused. The order decides which one is real.

Try it: replay and swap the order

Code: python
start = {"Dev": 10, "Eli": 0, "Fay": 0}
payments = [["Dev", "Eli", 8], ["Dev", "Fay", 8], ["Eli", "Fay", 3]]
money = {}
for name in start:
    money[name] = start[name]
for p in payments:
    if money[p[0]] >= p[2]:
        money[p[0]] = money[p[0]] - p[2]
        money[p[1]] = money[p[1]] + p[2]
        print("accepted:", p)
    else:
        print("refused:", p)
print(money)
# Swap the first two payments and run again.

A common mistake

Warning

Many people think a valid chain stops an overspend by itself. It does not. A chain only shows that no block was changed. A refusal needs a ledger rule that checks the sender's balance before it accepts a payment. Keep the two jobs apart: was it changed, and is it allowed.

The chain gives everybody one agreed order

The second payment is refused only if everybody replays the two in the same order. If one computer saw Fay's payment first, it would refuse Eli's instead.

A chain fixes the order. A payment that is in an earlier block counts first. This is why an agreed order is the real problem a shared ledger solves.

About this lab and its source: Blockchain lab: a toy chain in Python to read, break, mine and sign

Teaching a class? Set this module for your students with a teacher guide, marked assignments and a lab for every student.