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.
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.
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. |
| 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).
|
| 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. |
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.
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: [] 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 ValidationThere 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).
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
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)
ββββββββββββ
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?
The coinbase transaction (first transaction in every block) breaks the rules:
0xffffffff).
| 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 |
What makes the coinbase transaction structurally different from all other transactions?
In the P2PKH script validation flow, what does OP_EQUALVERIFY check?