Skip to content

Anatomy of a Transaction

A Bitcoin transaction is, at heart, a short, rigid data structure that says: “consume these existing coins, and create these new ones.” Nothing more. There is no “from” address, no “amount sent” field, no memo. Everything you think of as a payment is reconstructed from this skeleton. Once you can read the skeleton, raw transaction hex stops being intimidating — it’s just a handful of labelled fields.

TRANSACTION
├── version : which consensus rules this tx expects (usually 1 or 2)
├── inputs[] : the coins being SPENT (each points at a prior output)
├── outputs[] : the coins being CREATED (value + lock)
├── witness : signatures/scripts for SegWit inputs (separated since 2017)
└── locktime : "not valid until" block height or timestamp (often 0)

Two of these — version and locktime — are single scalars wrapping the transaction. The action is in the two lists: inputs (what’s consumed) and outputs (what’s made). Let’s open each.

Inputs — references to coins you’re spending

Section titled “Inputs — references to coins you’re spending”

An input does not contain money. It contains a pointer to an output created by some earlier transaction, plus the proof that you’re allowed to spend it.

INPUT
├── previous output
│ ├── txid : the id of the transaction that created the coin
│ └── vout : which output of that tx (the index, 0-based)
├── scriptSig : the unlocking script (legacy) — the "key" to the lock
├── nSequence : a 4-byte field: RBF signaling + relative timelocks
└── (witness) : the unlocking data for SegWit inputs, stored separately

The pair (txid, vout) is an outpoint — it uniquely names exactly one UTXO in the whole ledger. By referencing it, the input says “I am spending that specific coin.” A validating node looks the outpoint up in the UTXO set; if it’s missing (already spent, or never existed), the transaction is invalid. This is the double-spend defense in action.

The scriptSig (and, for modern inputs, the witness) is the satisfaction of the prior output’s lock — typically a signature and a public key. We dissect locking vs unlocking on its own page.

nSequence is a 4-byte field with a tangled history: it now does double duty as the opt-in RBF signal and as the relative timelock mechanism (BIP 68).

Outputs — the new coins you’re creating

Section titled “Outputs — the new coins you’re creating”

An output is the simplest object in Bitcoin: an amount and a lock.

OUTPUT
├── value : amount in SATOSHIS (integer; 1 BTC = 100,000,000 sats)
└── scriptPubKey : the locking script — the spending condition

Bitcoin stores no fractional float for value — everything is an integer count of satoshis, which avoids rounding ambiguity entirely (every node computes the exact same number). The scriptPubKey is the cryptographic lock placed on the coin: usually “spendable by whoever can produce a signature for public key K.” When this output is later spent, it becomes some future input’s referenced outpoint.

Here is a typical 2-input, 2-output payment, drawn as one structure:

tx (version 2)
├─ inputs
│ ├─ in[0] prevout = (txid_A, 1) scriptSig/witness = <sig><pubkey>
│ └─ in[1] prevout = (txid_B, 0) scriptSig/witness = <sig><pubkey>
├─ outputs
│ ├─ out[0] value = 50,000,000 sat scriptPubKey = <lock to recipient>
│ └─ out[1] value = 24,900,000 sat scriptPubKey = <lock back to YOU (change)>
└─ locktime = 0

Read it as a sentence: “Using consensus rules v2, consume coin (txid_A,1) and coin (txid_B,0) — here are the keys — and create a 0.5 BTC coin for the recipient and a ~0.249 BTC coin for myself; no time restriction.” The fee is whatever the inputs total minus the outputs total — it is never written down explicitly.

  • version signals which validation rules apply. Version 2 is required to use BIP 68 relative timelocks; otherwise the difference is mostly historical.
  • locktime lets a transaction declare itself invalid until a given block height or Unix time. Even ordinary wallets set it to roughly the current height as an anti-fee-sniping measure (see Timelocks & HTLCs).

How does this rigid structure help untrusting strangers agree on one ledger? Because there is nothing to interpret. Every node parses the exact same fields, looks up the exact same outpoints, checks the exact same scripts, and sums the exact same integers. A payment isn’t a claim that must be believed — it’s a structure that is either well-formed and spends real, unspent coins with valid proofs, or it isn’t. The format’s rigidity is the agreement: there’s no room for two honest nodes to read the same transaction differently.

  1. List the five top-level fields of a transaction and say in one phrase what each does.
  2. What does an input actually contain — and why does it hold no money itself?
  3. What is an outpoint (txid, vout), and what does a node do with it during validation?
  4. Why are output values stored as integer satoshis rather than decimal BTC?
  5. Why was witness data separated from scriptSig, and what problem did that solve?