Lesson 0002: Transaction Structure & the UTXO Model

⏱ ~18 minutes πŸ“… 2026-06-10 🎯 Bottom-Up β€’ Fundamentals
Goal: Understand exactly what a Bitcoin transaction is β€” its binary structure, the UTXO model, how inputs reference outputs, how locking and unlocking scripts work, and why "your balance" is a fiction.

The UTXO Model: There Are No Accounts

Bitcoin does not have accounts or balances. This is the single most important thing to internalize. Instead, Bitcoin uses the UTXO model (Unspent Transaction Output).

UTXO = Unspent Transaction Output. A UTXO is a discrete chunk of bitcoin β€” a specific amount locked to a specific condition (script). When your wallet says you have "5 BTC," it means the sum of all UTXOs you can unlock is 5 BTC. You don't have a balance; you have a collection of unspent outputs.

Analogy: Physical Cash

Imagine you have a $20 bill and a $5 bill in your pocket. You don't have a "$25 account" β€” you have two specific, indivisible notes. To pay $23, you hand over the $20 bill and the $5 bill, receive $2 in change (a new note), and destroy the original two notes. This is exactly how Bitcoin works: UTXOs are indivisible (you must spend them entirely), and change comes back as a new UTXO.

Transaction Structure: The Raw Anatomy

A Bitcoin transaction is a binary message with a well-defined structure. Here's the complete field layout:

Field Size Description
Version 4 bytes Transaction format version (currently 1 or 2). Signals which rules to validate against.
SegWit Flag 0 or 2 bytes Optional. If present, 0x0001 β€” indicates witness data follows (SegWit).
Input Count 1–9 bytes (varint) Number of inputs. Never zero (except coinbase).
Inputs variable Array of TxIn structures (see below). Each input spends one UTXO.
Output Count 1–9 bytes (varint) Number of outputs.
Outputs variable Array of TxOut structures. Each output creates a new UTXO.
Witness Data variable Only if SegWit flag present. One witness stack per input.
Locktime 4 bytes Earliest time/block height the transaction can be included. 0 = immediately.
Source: Bitcoin Wiki β€” tx message; Bitcoin Developer Guide β€” Transactions Introduction

TxIn: The Input Structure

Field Size Description
Previous TxID 32 bytes The hash (txid) of the transaction containing the UTXO being spent.
Output Index (vout) 4 bytes Which output (0-based) in the previous transaction is being spent.
Script Length varint Byte length of the unlocking script.
ScriptSig variable The unlocking script β€” data (signatures, public keys) that satisfies the previous output's locking script.
Sequence 4 bytes Originally for payment channel updating; now used with locktime (set to 0xffffffff to finalize).
The OutPoint (TxID + vout): Together, the 32-byte txid and 4-byte output index form an outpoint β€” a unique pointer to exactly one UTXO. Think of it as a coordinate: "transaction abc123... output #2." Every UTXO in existence has a unique outpoint. An outpoint can only be spent once β€” attempting to spend the same outpoint twice is a double-spend and will be rejected.

TxOut: The Output Structure

Field Size Description
Value 8 bytes Amount in satoshis (1 BTC = 100,000,000 satoshis). A 64-bit signed integer.
Script Length varint Byte length of the locking script.
ScriptPubKey variable The locking script β€” conditions that must be met to spend this output.

Locking Scripts (ScriptPubKey) & Unlocking Scripts (ScriptSig)

This is where Bitcoin's programmability lives. Every output has a locking script (ScriptPubKey) β€” a small program written in Bitcoin Script that defines the conditions for spending. When someone wants to spend that output, they provide an unlocking script (ScriptSig) that satisfies those conditions.

The validation process concatenates the two scripts β€” ScriptSig first, then ScriptPubKey β€” and executes them on a stack machine. If execution completes without error and leaves a true (non-zero) value on the stack, the spend is authorized.

The Most Common Pattern: P2PKH (Pay to Public Key Hash)

Locking Script (ScriptPubKey) β€” set by the sender:

OP_DUP
OP_HASH160
<pubkey-hash>
OP_EQUALVERIFY
OP_CHECKSIG

Unlocking Script (ScriptSig) β€” provided by the spender:

<signature>
<public-key>
Stack execution walkthrough:
Stack: []
  1. Push <sig>        β†’ [sig]
  2. Push <pubkey>      β†’ [sig, pubkey]
  3. OP_DUP              β†’ [sig, pubkey, pubkey]
  4. OP_HASH160          β†’ [sig, pubkey, hash(pubkey)]
  5. Push <pubkey-hash> β†’ [sig, pubkey, hash(pubkey), pubkey-hash]
  6. OP_EQUALVERIFY      β†’ [sig, pubkey]  (fails if hashes don't match)
  7. OP_CHECKSIG         β†’ [true]  (fails if sig doesn't match pubkey)
  β†’ VALID βœ“

The genius of this system: the sender doesn't need to know the recipient's public key β€” just its hash. The recipient reveals their public key only at spending time, providing a layer of privacy. Once spent, the public key is visible on-chain, which is why address reuse is discouraged.

Source: Bitcoin Developer Guide β€” P2PKH Script Validation

The Fee Mechanism: Inputs βˆ’ Outputs = Fee

There is no "fee" field in a transaction. The fee is implicit:

Fee = Ξ£(input values) βˆ’ Ξ£(output values)

Feerate = Fee / (transaction weight / 4) [sat/vB]

The miner who includes the transaction collects this difference. Because UTXOs must be spent in full, you almost always need a change output β€” an output sending the excess back to yourself (to a fresh address).

Example Transaction

Alice wants to pay Bob 0.01 BTC. She has one UTXO worth 0.05 BTC.

Inputs:  1 UTXO (0.05 BTC)         = 5,000,000 sat
Outputs:
  β†’ Bob:       0.01 BTC            = 1,000,000 sat
  β†’ Change:    0.0399 BTC          = 3,990,000 sat
Fee:           0.0001 BTC          =    10,000 sat

5,000,000 βˆ’ (1,000,000 + 3,990,000) = 10,000 sat fee

The Chain of Ownership

Every transaction (except coinbase) consumes UTXOs and creates new ones. This creates a directed graph of ownership, traceable all the way back to the coinbase transactions that originally created the bitcoin. A valid transaction is one where every input's ScriptSig correctly unlocks the ScriptPubKey of the UTXO it references.

Coinbase Tx         Tx A                Tx B (Alice→Bob)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Input:   β”‚       β”‚ Input:   β”‚         β”‚ Input:   β”‚
β”‚  (none)  β”‚       β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”β”‚         β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”β”‚
β”‚          β”‚       β”‚  β”‚CB out││─────────│──│TxA #1β”‚β”‚
β”‚ Output:  │───┐   β”‚  β””β”€β”€β”€β”€β”€β”€β”˜β”‚         β”‚  β””β”€β”€β”€β”€β”€β”€β”˜β”‚
β”‚  50 BTC  β”‚   β”‚   β”‚          β”‚         β”‚          β”‚
β”‚  (UTXO)  β”‚   β”‚   β”‚ Output:  β”‚         β”‚ Output:  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚   β”‚  25 BTC──│─────────│→ 0.01 BTCβ”‚ (Bob's UTXO)
               └───│→(UTXO)   β”‚         β”‚          β”‚
                   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β”‚  24.99──│→ (Change UTXO)
                                        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

🧠 Quick Check

Alice has a 1 BTC UTXO and wants to send 0.3 BTC to Bob with a 0.0001 BTC fee. How much change does she get back?

Coinbase Transactions: The Exception

The coinbase transaction (first transaction in every block) breaks the rules:

Standard Transaction Types (Quick Reference)

Type Locking Script Pattern Used For
P2PKH OP_DUP OP_HASH160 <hash> OP_EQUALVERIFY OP_CHECKSIG Standard payment to a Bitcoin address (legacy, starts with "1")
P2SH OP_HASH160 <redeem-script-hash> OP_EQUAL Payment to a script hash (multisig, SegWit-compatible addresses starting with "3")
P2WPKH OP_0 <witness-program> (20 bytes) Native SegWit v0 (Bech32 addresses starting with "bc1q")
P2TR OP_1 <witness-program> (32 bytes) Taproot (Bech32m addresses starting with "bc1p")
Null Data OP_RETURN <data> Provably unspendable β€” embeds data on-chain without bloating the UTXO set

🧠 Quick Check

What makes the coinbase transaction structurally different from all other transactions?

🧠 Quick Check

In the P2PKH script validation flow, what does OP_EQUALVERIFY check?

Key Takeaways

  1. Bitcoin has no accounts β€” only UTXOs. Your "balance" is the sum of UTXOs you can unlock.
  2. A transaction consumes UTXOs (inputs) and creates new UTXOs (outputs). UTXOs are indivisible β€” you always spend the full amount.
  3. Every output has a locking script (ScriptPubKey). Every input provides an unlocking script (ScriptSig) that must satisfy it.
  4. Fee = inputs βˆ’ outputs. There is no explicit fee field. Change outputs send excess back to the spender.
  5. The coinbase transaction is the sole exception β€” it creates bitcoin from nothing and has no real input.
  6. Addresses encode script conditions β€” "1..." = P2PKH, "3..." = P2SH, "bc1q..." = SegWit v0, "bc1p..." = Taproot.
πŸ”— Primary source for deeper reading: Bitcoin Developer Guide β€” Transactions β€” the complete reference. Also: Chapters 5–7 of Mastering Bitcoin, 2nd Edition (Antonopoulos) for the definitive walkthrough of keys, addresses, transactions, and the UTXO model.
πŸ’¬ Questions? Ask your agent-teacher: "walk me through the P2SH spending flow," "explain the witness data in SegWit," or "why can't I spend part of a UTXO?" Every question deepens the model.

Navigate