Think of your money as a pocketful of coins
Imagine you buy a NT$130 lunch with cash. You don't have a single NT$130 note — you hand the cashier a NT$100 note and a NT$50 note, NT$150 in all, and you get NT$20 back as change. Notice what you never do: you never shave NT$30 off the edge of the NT$100 note. Physical money moves in whole pieces. You combine notes to cover the bill, and you receive fresh notes as change.
Bitcoin tracks money in almost exactly this way. Its 'notes' are called UTXOs — Unspent Transaction Outputs — and every payment combines some of them and produces brand-new ones. Once you grasp this one idea, a whole pile of Bitcoin's behaviour stops looking strange.
The ledger has no balances, only unspent coins
Here is the part that surprises most newcomers: Bitcoin stores no balances. A bank database has a row saying *"Account 123: $500"*. Bitcoin has no such row anywhere. Instead, every full node keeps the UTXO set — the complete collection of every coin that currently exists and has not yet been spent — and each coin is tagged with a lock saying who is allowed to spend it.
So what is your balance? It is a number your wallet computes, not one the chain stores. The wallet scans the UTXO set for every output it can unlock with your keys and adds them up. If you control three UTXOs worth 0.6, 0.7, and 0.05 BTC, your wallet shows 1.35 BTC — but on-chain those are three separate coins, not a single balance you can edit.
A worked payment: Alice pays Bob 1 BTC
Alice controls exactly two UTXOs: UTXO_A = 0.6 BTC and UTXO_B = 0.7 BTC. She wants to pay Bob 1.0 BTC. Neither coin alone is enough, so — just like our cash example — she must combine both. Here is what her wallet builds:
- Pick the inputs. The wallet selects UTXO_A (0.6) and UTXO_B (0.7), totalling 1.3 BTC — enough to cover 1.0 plus a small fee.
- Create Bob's output. An output of 1.0 BTC, locked to Bob's address so only Bob can later spend it.
- Create the change output. The leftover can't just vanish, so the wallet makes a second output — the change — of 0.2999 BTC, locked back to an address Alice controls.
- The fee is whatever's left. inputs − outputs = 1.3 − (1.0 + 0.2999) = 0.0001 BTC. There is no explicit fee field; the miner who includes the transaction simply keeps the difference.
- Sign and broadcast. Alice signs each input with her private key, proving she may unlock those coins, then sends the transaction to her peers.
{
"txid": "f5d8e1...c92a", // id of THIS transaction
"vin": [ // inputs: pointers to coins being spent
{ "txid": "a1b2...", "vout": 0 }, // UTXO_A, worth 0.6 BTC
{ "txid": "c3d4...", "vout": 1 } // UTXO_B, worth 0.7 BTC
],
"vout": [ // outputs: brand-new coins created
{ "value": 1.0000, "scriptPubKey": "<lock to Bob's address>" },
{ "value": 0.2999, "scriptPubKey": "<lock to Alice's change address>" }
]
}
// fee = (0.6 + 0.7) - (1.0 + 0.2999) = 0.0001 BTC, kept by the minerNotice the asymmetry: the inputs carry no amounts. Each input is just a pointer to an earlier output — which transaction (`txid`) and which output of it (`vout`). The value 0.6 and 0.7 lives in the outputs being referenced, and a validator looks each one up to learn what it's worth.
Inputs, outputs, and the lock on every coin
Each output has two parts: an amount, and a locking condition — in Bitcoin, a tiny script called the `scriptPubKey`. The common lock says, in effect, "whoever can produce a valid signature from the private key behind this address may spend me."
Each input also has two parts: a pointer to the previous output it spends (`txid:vout`), and an unlocking proof — a signature (the `scriptSig`/witness) that satisfies that output's lock. A node runs the lock and the unlock together as one little stack program; if it evaluates to true, the input is authorized.
# Output lock (scriptPubKey) - pay-to-public-key-hash, the common case:
DUP HASH160 <PubKeyHash> EQUALVERIFY CHECKSIG
# Input unlock (scriptSig / witness) supplied by the spender:
<signature> <publicKey>
# A node runs unlock + lock as ONE stack program. It passes only if:
# 1. hash160(publicKey) == <PubKeyHash> -> right key for this coin
# 2. CHECKSIG verifies <signature> over this tx using publicKeyThat signature is made with ECDSA over the secp256k1 curve, and crucially it covers the contents of this transaction. So you can't grab Alice's signed input and re-attach it to a different payment — that would change what was signed, and the signature would no longer verify.
Spending edits the UTXO set in place: consumed coins are removed, new ones are added. But the history never changes — old blocks stay exactly as written. The set shrinks and grows over time, while the chain behind it stays append-only, which is the root of the ledger's immutability.
Why build it this way? Double-spend detection and parallel validation
Now the payoff. Because every coin is a distinct entry in the UTXO set, spending one is a structural event: the validator looks it up, and if it's there, removes it. If a coin isn't in the set, the spend is rejected outright — it either never existed or was already spent. Here is essentially the whole validation rule:
def validate(tx, utxo_set):
in_sum = 0
for inp in tx.inputs:
utxo = utxo_set.get(inp.txid, inp.vout)
if utxo is None:
reject("input missing: already spent or never existed")
if not verify_signature(inp, utxo.lock, tx):
reject("bad signature: spender not authorized")
in_sum += utxo.value
out_sum = sum(o.value for o in tx.outputs)
if out_sum > in_sum:
reject("outputs exceed inputs: cannot mint money")
fee = in_sum - out_sum
# commit: consume the inputs, create the new outputs
for inp in tx.inputs:
utxo_set.remove(inp.txid, inp.vout)
for i, o in enumerate(tx.outputs):
utxo_set.add(tx.txid, i, o)Double-spending — trying to spend the same coin twice — becomes a direct conflict. The first transaction removes UTXO_A from the set; a second transaction that also points at UTXO_A fails the `get` and is rejected. Honest nodes drop the conflicting transaction from their mempool before it ever reaches a block.
The second win is parallel validation. Because each input names exactly the coins it touches, two transactions over disjoint UTXOs cannot interfere, so a node can verify their signatures on different CPU cores at once — Bitcoin Core really does this. There is no single shared 'balance' counter that every transaction must update in order. Contrast the account model you'll meet next, where two transfers from the same account must be applied in strict nonce order against one mutable balance.
The wallet's hidden work: coin selection, change, and the trade-offs
All of this means a wallet is doing far more than it shows. Choosing which UTXOs to feed into a payment is a real algorithm called coin selection, and it's a genuine optimisation problem with real costs on either side.
- Cover the amount plus the fee using as few inputs as possible — every extra input makes the transaction bigger, and fees are charged per byte, not per bitcoin.
- Prefer combinations that leave clean change, or ideally no change at all, to avoid creating dust — coins so tiny they may cost more in fees to spend than they're worth.
- Send the change to a fresh address, not back to an input address, so an observer can't trivially tell which output is the payment and which is the change — a privacy practice.
Sending change to a new address is also why a wallet quietly manages many addresses behind one balance, and why reusing an address is discouraged. Even so, chain-analysis heuristics — like assuming all inputs to one transaction share an owner — can often re-link them. UTXO privacy is better than the account model's, but it is far from perfect.
The UTXO model buys you natural parallelism, dead-simple double-spend rules, and better privacy — but it pays for those gains in complexity. There's no tidy 'account balance' to read; wallets must track a whole set of coins; and writing rich, stateful programs is awkward, because there is no persistent mutable account in which a contract can keep its data. That is exactly why Ethereum chose the account model you'll meet in the next guide — and why Bitcoin scaling layers like the Lightning Network build payment channels on top of UTXOs rather than rewriting how the base layer keeps score.