Part VI ยท Protocol Layer Chapter 19

Ordinals and Inscriptions

"This document defines a scheme for assigning serial numbers to sats."โ€”Casey Rodarmor, Ordinal Numbers

Every previous chapter has treated satoshis as interchangeable. A sat is a satโ€”1/100,000,000 of a bitcoin, fungible by design. Ordinal theory upends this assumption: by assigning a unique serial number to every satoshi ever mined and tracking transfers via a deterministic first-in-first-out rule, it turns each sat into a distinct, identifiable object.

Inscriptions build on this foundation. Using a Taproot script-path spend (Chapter 13), arbitrary dataโ€”images, text, HTML, even programsโ€”can be embedded in the witness of a reveal transaction. The inscription is permanently bound to a specific sat, which can then be transferred, sold, or held like any other UTXO.

This chapter examines both the numbering scheme and the transaction anatomy that makes inscriptions possible.โ€ 

19.1Ordinal Theory: Numbering Every Sat

19.1.1The Assignment Algorithm

Every sat receives a serial number based on the order in which it is mined. The whole algorithm is two short functions โ€” together they answer "given a block height, what are the ordinal numbers of the sats that block minted?" The algorithm is purely interpretive: no consensus rule changes, no extra bytes on chain, no new transaction field. Any node can recompute every ordinal from chain history.

Ordinal Assignment Algorithm โ€” fully annotated
# โ”€โ”€ Constants โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
SATS_PER_BTC     = 100_000_000        # 1 BTC = 10^8 sats
HALVING_INTERVAL = 210_000            # blocks per halving epoch (~4 yrs)
INITIAL_SUBSIDY  = 50 * SATS_PER_BTC  # 5,000,000,000 sats (block 0's reward)

# โ”€โ”€ 1. How many sats does block <height> mint? โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
def subsidy(height):
    halvings = height // HALVING_INTERVAL    # 0 in epoch 0, 1 in epoch 1, ...
    return INITIAL_SUBSIDY >> halvings         # halve `halvings` times (>> 1 โ‰ก รท 2)

# โ”€โ”€ 2. What ordinal is the FIRST sat of block <height>? โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
def first_ordinal(height):
    total = 0
    for h in range(height):       # sum every prior block's reward
        total += subsidy(h)
    return total                    # picks up where block (height-1) left off

That's it. Five active lines once you strip the comments. Let's actually run it on real heights so the abstraction stops being abstract:

Walking the algorithm โ€” concrete values

subsidy(h) โ€” the per-block reward at four landmark heights:

heighthalvings = height // 210,00050e8 >> halvings= sats= BTC
005,000,000,000 >> 05,000,000,00050
209,99905,000,000,000 >> 05,000,000,00050
210,00015,000,000,000 >> 12,500,000,00025 โ† first halving
840,00045,000,000,000 >> 4312,500,0003.125 โ† 4th halving (Apr 2024)

first_ordinal(h) โ€” the ordinal of the first sat of each landmark block. (At each halving boundary the per-block step shrinks because the subsidy halved.)

heightfirst_ordinal(h)meaning
00the mythic genesis sat
15,000,000,000= subsidy(0); first sat of block 1
210,000,000,000= subsidy(0) + subsidy(1)
210,0001,050,000,000,000,000= 210,000 ร— 5e9; first epic sat (start of epoch 1)
420,0001,575,000,000,000,000+ 210,000 ร— 2.5e9 (epoch 1 added 525e12 sats)
840,0001,968,750,000,000,000start of epoch 4 (3.125 BTC subsidy)

No memorization required. The point: a single 64-bit integer per sat, computed by a 5-line algorithm from public chain history.

The same data, grouped by halving epoch:

EpochBlocksSubsidyFirst Ordinal of Epoch
00โ€“209,99950 BTC0
1210,000โ€“419,99925 BTC1,050,000,000,000,000
2420,000โ€“629,99912.5 BTC1,575,000,000,000,000
3630,000โ€“839,9996.25 BTC1,837,500,000,000,000
4840,000โ€“1,049,9993.125 BTC1,968,750,000,000,000

19.1.2Transfer: First-In-First-Out

Once a sat exists, where it ends up after a transaction is also fully determined by a simple rule: FIFO. Stack all the input sats in order (input 0's sats first, then input 1's, then input 2'sโ€ฆ), then pour them into the outputs in order until each output is full. Any sats left over after every output is full constitute the fee and are claimed by the miner via the block's coinbase transaction.

Interactive: Watch the FIFO pour

A 2-input / 2-output transaction. Inputs total 150 sats; outputs total 130; the difference is a 20-sat fee that goes to the miner via the block's coinbase. Click Step to pour the input sats into the outputs one batch at a time. The colors track which input each output's sats came from.

Inputs (150 sats โ€” flow direction โ†’)
stream
Outputs & fee (150 sats โ€” same total)
bins
output 0 ยท 60 sats
output 1 ยท 70 sats
fee โ†’ miner ยท 20 sats
step 0 / 4

Color key: input 0 sats came from input 0 (ordinals 1000โ€“1099); input 1 sats came from input 1 (ordinals 2000โ€“2049). Same color = same source โ€” at a glance you can see which input contributed which slice of each output.

Why this matters in practice. The fee bin in step 4 contains ordinals 2030โ€“2049. If ordinal 2040 was an inscription Alice cared about, she just paid it as a fee โ€” it now belongs to whoever mined this block. Standard ("non-ordinal-aware") wallets treat sats as interchangeable and routinely make this mistake. Ordinal-aware wallets work backwards from "where do I want ordinal N to land?" and then choose input order and output sizes so FIFO routes N to the intended output. Try moving back to step 0 and re-running โ€” the FIFO rule is fully deterministic, so the only way to change the destination of any specific ordinal is to change the inputs or outputs.

No Protocol Change Required

Ordinal theory is purely interpretiveโ€”it requires no changes to Bitcoin's consensus rules, transaction format, or network protocol. Any node can independently compute the ordinal number of any sat by replaying the blockchain. Ordinals exist in the same sense that block height exists: as a deterministic function of the chain's history.

19.1.3Rarity

Bitcoin's periodic events create natural rarity tiers:

RarityDefinitionTotal Supply
CommonAny sat not first in its block2.1 quadrillion
UncommonFirst sat of each block (excl. higher tiers)6,926,535
RareFirst sat of each difficulty adjustment3,432
EpicFirst sat of each halving epoch27
LegendaryFirst sat of each cycle (6 halvings)5
MythicFirst sat of the genesis block1

A cycle is the period between conjunctions of a halving and a difficulty adjustment (\(6 \times 210,000 = 1,260,000\) blocks, 24 years). The first conjunction has not yet occurred.

19.2The Inscription Envelope

Inscriptions embed data inside a Taproot witness script using a construct called an envelope: an OP_FALSE OP_IF block that is syntactically valid but never executed.

Inscription Envelope Structure

OP_FALSE

OP_IF

OP_PUSH "ord" protocol tag

OP_PUSH 1 content-type tag

OP_PUSH "<MIME type>" e.g., "image/png"

OP_PUSH 0 body separator

OP_PUSH <data> content (may span multiple pushes)

OP_ENDIF

Key design properties:

A common misconception is that the inscription data "runs" on-chain. It does not. The OP_FALSE ensures the OP_IF branch is never entered. The data pushes inside the envelope are parsed by indexers (like ord) but ignored by Bitcoin's script interpreter. The actual spending conditionโ€”typically a simple <pubkey> OP_CHECKSIGโ€”appears before the envelope.

19.3The Commit/Reveal Pattern

Inscriptions require a two-phase process because Taproot script-path spends can only be made from existing Taproot outputs. You cannot create and spend a Taproot output in the same transaction.

19.3.1Phase 1: Commit

The commit transaction creates a P2TR output whose internal key or script tree commits to the inscription content. From the outside, this looks like an ordinary Taproot outputโ€”nothing reveals the inscription until the output is spent.

19.3.2Phase 2: Reveal

The reveal transaction spends the commit output via script-path (Chapter 13). The witness contains:

  1. A signature satisfying the script's spending condition.
  2. The tapscript containing the envelope (the full inscription data).
  3. The control block (parity byte + internal public key + Merkle proof).

The inscription content becomes visible on-chain only in the reveal transaction's witnessโ€”permanently recorded in the blockchain.

Commit Tx
P2TR output
Looks like normal P2TR
spends โ†’
Reveal Tx
Script-path spend
Envelope in tapscript
witness data โ†’
On-Chain
Inscription visible
Reveal Transaction Witness Stack
Item 0: <Schnorr signature> 64 bytes
Item 1: Tapscript (the envelope)
OP_FALSE OP_IF
OP_PUSH "ord"
OP_PUSH 01 โ† content type tag
OP_PUSH "image/png"
OP_PUSH 00 โ† data separator
OP_PUSHDATA2 <image data...>
OP_ENDIF
Item 2: <control block> 33+ bytes

19.4Specimen: Inscription #0

The very first Ordinals inscription โ€” a 100×100 pixel skull image โ€” was inscribed by Casey Rodarmor on December 14, 2022 at 20:32 UTC in block 767,430. Two transactions in two blocks: a commit that creates a P2TR output, then a reveal that spends it script-path with the inscription embedded in the witness.

Commit transaction
block 767,429 โ€” looks like any other P2TR send
txid274bda66โ€ฆ 6358
InputP2WPKH ยท 111,794 sats
Output 0P2TR ยท 10,000 sats (the inscription commit)
Output 1P2WPKH ยท 101,531 sats (change)
Fee263 sats (234 B / 153 vB)
Reveal transaction
block 767,430 โ€” the inscription appears in the witness
txid6fb976abโ€ฆ 2799
Inputspends commit Output 0 ยท P2TR script-path
OutputP2WPKH ยท 9,678 sats
Fee322 sats (1,040 B / 322 vB โ†’ 1 sat/vB)
nSequence0xFFFFFFFD (RBF-signaling)
Witness3 items, ~953 bytes โ†“

Below is the full reveal-transaction hex โ€” hover any byte for a field tooltip:

Where the bytes come from

Any Bitcoin node will serve the raw transaction bytes for any confirmed txid. Three common ways to fetch them: bitcoin-cli getrawtransaction <txid> against your own node, the mempool.space API (or the mempool.space โ†— link in the header of the hex widget below), or any Esplora-compatible block-explorer endpoint. All three return the same 1,040-byte hex string โ€” chain state is deterministic, and so is the byte representation of a tx in it.

The bulk of those 1,040 bytes is a single witness element โ€” the tapscript, witness item 1, which carries both the spending condition and the inscription. Below is its anatomy.

19.4.1The Witness: Three Items

Item 0
64 bytes
Schnorr signature
Satisfies the <pubkey> OP_CHECKSIG inside the tapscript.
Item 1 โ€” Tapscript
853 bytes
Spending condition + inscription envelope
This is where the PNG lives. Decomposed below โ†“
Item 2
33 bytes
Control block
Leaf version 0xc0 + 32-byte internal pubkey. No Merkle proof (single-leaf tree).

19.4.2Tapscript Anatomy โ€” Color-Coded

The 853-byte tapscript splits into seven distinct regions. Each row below shows the actual hex from this specimen, the opcode interpretation, byte count, and purpose:

SPENDING CONDITIONauthorizes the spend
20 4a3ca2cf 35f7902d f1215f82 3d977df1 1740 48b0 62e03a44 f71c2ee7 36a60cc5 ac
OP_PUSHBYTES_32 <32-byte pubkey> OP_CHECKSIG
34 bytes
offset 0โ€“33
ENVELOPE OPENdead code โ€” never executes
00 63
OP_FALSE OP_IF  โ€” pushes 0, branches on it, jumps straight to OP_ENDIF
2 bytes
offset 34โ€“35
PROTOCOL MARKER"ord" โ€” this is an inscription
03 6f 72 64
OP_PUSHBYTES_3 "ord"  โ€” disambiguates from other uses of OP_FALSE OP_IF
4 bytes
offset 36โ€“39
CONTENT-TYPE TAGtag 1 = MIME type
01 01 09 69 6d 61 67 65 2f 70 6e 67
OP_PUSHBYTES_1 0x01 (tag id)   OP_PUSHBYTES_9 "image/png"
12 bytes
offset 40โ€“51
BODY SEPARATORtag 0 โ€” content starts now
00
OP_0  โ€” sentinel marking the start of the inscription body
1 byte
offset 52
PAYLOAD โ€” Chunk 1first 520 bytes of the PNG
4d 08 02 89 50 4e 47 0d 0a 1a 0a โ€ฆ (520 bytes total)
OP_PUSHDATA2 length=520   "โ€ฐPNG\r\n\x1a\n" โ€” the PNG magic number
523 bytes
offset 53โ€“575
PAYLOAD โ€” Chunk 2remaining 273 bytes (ends in IEND)
4d 11 01 09 b1 6c 4b 96 0a โ€ฆ 49 45 4e 44 ae 42 60 82
OP_PUSHDATA2 length=273   โ€ฆ"IEND" + CRC โ€” the PNG end-of-file marker
276 bytes
offset 576โ€“851
ENVELOPE CLOSEjumped to from OP_IF
68
OP_ENDIF  โ€” the only opcode actually executed in this section (a no-op once we got here)
1 byte
offset 852

Color key: spending condition · envelope no-op · protocol marker · content-type tag · body separator · payload

Three things the visualization makes obvious
  1. The spending condition is just 34 bytes. The other 819 bytes of the tapscript exist purely to carry data โ€” none of it affects whether the spend is valid.
  2. The PNG is whole. Look at chunk 1: bytes 89 50 4e 47 0d 0a 1a 0a are the standard PNG file header (you can paste them into any hex editor and the OS will recognize the file). Look at chunk 2's tail: 49 45 4e 44 ae 42 60 82 is "IEND" + CRC โ€” the PNG end-of-file marker. The image is bit-for-bit identical to the file Casey inscribed.
  3. The 520-byte split is forced by Script. Each individual push must be โ‰ค520 bytes (BIP 342). The PNG is 793 bytes total, so the encoder must split: 520 + 273. There is nothing semantically special about the boundary โ€” it is purely a serialization constraint.

Why the dead-code trick works. The Bitcoin script interpreter sees OP_FALSE OP_IF, evaluates the top-of-stack as zero, and jumps to the matching OP_ENDIF without parsing the contents. Everything between them is bytes the interpreter never reads as opcodes. The OP_PUSHDATA2 520 <520 bytes> would otherwise consume 520 bytes from the script stream and push them as a stack item โ€” but inside OP_FALSE OP_IF โ€ฆ OP_ENDIF, the interpreter is skipping, not executing. The data is therefore stored on chain without ever touching the script semantics. Ordinals indexers (like ord) parse the same bytes as data, not script โ€” that's the entire trick.

19.4.3Reading PNG Out of the Witness

How did we know to look up 6fb976abโ€ฆ2799?

Inscriptions have a human-friendly identifier called the inscription ID (formally defined in ยง19.7.1):

<reveal_txid>i<index>

For Inscription #0 specifically, the ID is 6fb976abโ€ฆ2799i0 โ€” strip the i0 suffix and you have the reveal txid. To get from a name like "Inscription #0" to that ID, query any indexer that has scanned the chain for envelopes:

Indexers do exactly what ยง19.4.2 documents โ€” scan every Taproot script-path spend for an OP_FALSE OP_IF "ord" envelope and record the txid + index. The ID is a deterministic function of chain state; any two indexers produce identical results for the same chain tip.

Once you have the reveal txid, the procedure to recover the inscribed image from on-chain bytes alone is:

  1. Fetch the reveal transaction 6fb976abโ€ฆ2799 via any of the routes above (bitcoin-cli getrawtransaction, mempool.space, Esplora).
  2. Take witness item 1 (the tapscript), 853 bytes.
  3. Skip the first 34 bytes (spending condition).
  4. Skip 00 63 (envelope open).
  5. Skip 03 6f 72 64 (the "ord" marker).
  6. Skip 01 01 09 69 6d 61 67 65 2f 70 6e 67 (the content-type tag).
  7. Skip 00 (the body separator).
  8. For each remaining push, read OP_PUSHDATA2 + length + payload bytes. Concatenate the payloads.
  9. Stop at OP_ENDIF.

The concatenated bytes are the literal contents of the PNG file. Save them to inscription_0.png, double-click, see the skull.

19.5Why Taproot Makes This Possible

Inscriptions exploit three properties of the Taproot upgrade that converge to make on-chain data storage economical:

19.5.1The Witness Discount

Witness data is counted at 1 WU per byte (vs. 4 WU per byte for non-witness data). For inscription #0:

Non-witnessWitness
Bytes82958
Weight contribution\(82 \times 4 = 328\) WU\(958 \times 1 = 958\) WU
Total weight1,286 WU (322 vB)

Without the witness discount, the same 1,040 bytes would cost \(1,040 \times 4 = 4,160\) WU (1,040 vB)โ€”more than three times the actual cost. The witness discount provides a 69% fee reduction for data-heavy transactions like inscriptions.

19.5.2No Script Size Limit (BIP 342)

Pre-Taproot scripts were limited to 10,000 bytes (the MAX_SCRIPT_SIZE consensus rule). BIP 342 (Tapscript) removed this limit for Taproot script-path spends. The only remaining constraint is the 4,000,000 WU block weight limitโ€”a single inscription can theoretically consume nearly an entire block.

19.5.3Unexecuted Branches Are Valid

Because OP_FALSE OP_IF โ€ฆ OP_ENDIF is never entered during script execution, the data inside the envelope is not subject to script-execution rules (like the stack element size limit for operations). The 520-byte push limit still applies at the serialization level, but arbitrarily large content can be split across multiple pushes.

19.6The Storage Debate

Inscriptions reignited a long-standing argument about what data belongs on the Bitcoin blockchain. The technical reality is more nuanced than either side typically acknowledges.

19.6.1The Seven Layers of Pruning

"Pruning" in Bitcoin is not a single operation โ€” it operates at several distinct layers, each discarding different data with different trade-offs:

LayerWhat gets discardedWho does itUser-facing?
Block file pruningOld blk*.dat and rev*.dat files after validation-prune=N flagYes โ€” the primary meaning of "pruned node"
UTXO pruningOP_RETURN outputs โ€” provably unspendable, never enter the UTXO setEvery node, automaticallyNo โ€” invisible to the operator
Mempool pruningLowest-feerate unconfirmed transactions when mempool exceeds -maxmempool (default 300 MB)Every node, automaticallyNo โ€” happens silently under load
Manual pruningBlocks below a specified height via pruneblockchain RPCOperator via RPC callYes โ€” fine-grained control
Ultraprune (v0.8.0)The old BerkeleyDB database โ€” replaced with a lean UTXO-only LevelDBPieter Wuille, 2013No โ€” architectural prerequisite that made all other pruning possible
UTXO set pruning (Utreexo, proposed)The UTXO set itself โ€” replaced with a cryptographic accumulator; transactions carry their own existence proofsNot yet implementedWould eliminate the ~8 GB in-memory UTXO database
Witness pruning (never built)Witness data stripped from blocks while keeping block structureNot yet implementedWould allow selective deletion of inscription data

The common thread: at each layer, the question is what data can the node discard and still validate fully? Block pruning discards historical evidence. UTXO pruning discards provably dead outputs. Mempool pruning discards low-priority unconfirmed transactions. Utreexo would discard the UTXO set itself. Witness pruning would discard signatures and inscription data. They are all "pruning," but they operate on completely different data structures โ€” and only the first is available as a user setting today.

19.6.2What "Prunable" Actually Means

"Prunable" is used loosely in the Bitcoin community, but it refers to two completely different operations that happen at different layers:

Two Meanings of "Prunable"

With this distinction, the storage picture becomes more precise:

ComponentWhere it livesUTXO-set pruned?Block-file pruned?
Inscription content (image, text)Witness field in blk*.datN/A โ€” never in UTXO setOnly if -prune is on (deletes whole block)
OP_RETURN metadataOutput script in blk*.datYes โ€” automatically excluded, every nodeOnly if -prune is on (deletes whole block)
Fake P2WSH output (data as script hash)UTXO set + blk*.datNo โ€” appears spendable, permanentOnly if -prune is on (but UTXO entry remains)
Inscription output (carries the inscribed sat)UTXO set + blk*.datNo โ€” persists until spentOnly if -prune is on (but UTXO entry remains)

When gmaxwell says OP_RETURN data is "completely prunable and pruned," he means UTXO-set pruning โ€” the output never enters the expensive in-memory database. The raw bytes still sit in blk*.dat on every archive node's disk. On a pruned node, those bytes eventually disappear when the entire block is deleted โ€” but that's not special to OP_RETURN; every byte in the block goes with it.

The real advantage of OP_RETURN is not that the data vanishes from disk. It's that the data never touches the UTXO set. Block files are cheap sequential storage. The UTXO set is a live database queried on every transaction validation, held in RAM or fast SSD, growing permanently with every unspent output. An OP_RETURN output creates zero burden on this critical resource. A fake P2WSH output creates a permanent entry that every full node on the network must maintain โ€” forever, or until someone "spends" it (which, for a fake script hash, is never).

19.6.3The Costs That Pruning Does Not Eliminate

19.6.4The Witness Discount Mismatch

The 75% witness discount (1 WU per witness byte vs. 4 WU per non-witness byte) was designed to incentivize SegWit adoption. The economic rationale: witness data is prunable and does not affect the UTXO set, so it should be cheaper. The discount assumed witness data would consist of signatures (64โ€“73 bytes per input). Inscriptions exploit the same discount to store megabytes of arbitrary content at one-quarter the effective fee rate โ€” an application the discount's designers did not anticipate.

19.6.5Can Node Operators Selectively Prune Inscription Data?

Not with Bitcoin Core's current tools. The -prune flag operates at the block level โ€” it discards entire old blocks after validation, keeping only the most recent blocks (the value is a disk budget in MiB; the 550 minimum keeps roughly a day or two of blocks). There is no option to selectively strip witness data while preserving the rest of the block.

The options available to a node operator are:

  1. Full pruned node (-prune=550): Discards block data beyond the disk budget (~1โ€“2 days of blocks at the 550 MiB minimum). Disk usage stays around 5โ€“10 GB. All inscription witness data is eventually deleted โ€” but so is everything else. The node cannot serve historical blocks to peers.
  2. Full archive node (default): Keeps every byte ever confirmed โ€” currently 650+ GB and growing. No selective deletion is possible.

There is no middle option in Bitcoin Core. A node operator who wants to validate the full chain and serve blocks to peers, but does not want to store hundreds of gigabytes of inscription images, has no recourse.

19.6.6Could You Build Selective Pruning?

Short answer: not without modifying Bitcoin Core's storage layer or rewriting the entire blockchain on disk. The block-serialization format interleaves witness data inside each transaction (not appended at the end), so removing a witness shifts every byte offset that follows in the file, which invalidates every subsequent block's index entry. The full code-level walk-through โ€” the actual BlockManager::WriteBlock() source, the FlatFilePos index structure, and the two architectures (external post-processor / separate witness files) that could make selective pruning practical โ€” lives in Appendix G.

Appendix G โ€” Selective Witness Pruning: the C++ code, the storage format, the two architectures โ†’Design Memo โ€” Expiring Witness-Discounted Outputs: miniscript & covenant approaches โ†—

Appendix G addresses the chain-bytes side of the question (can we delete the data?). The design memo addresses the UTXO-set side (can we make the spending claim expire?). They're sister rabbit holes from the same concern about long-term storage cost.

19.6.7Inscriptions Are Door 2

Chapter 15 introduces the Three Doors framework developed by the BitcoinTalk user d5000 during the 2025 debate over Bitcoin Core 30's OP_RETURN change. The framework ranks on-chain data-embedding methods by how much harm they do to the network: Door 1 is fake public keys (permanent UTXO pollution), Door 2 is Taproot witness embedding (moderate, theoretically prunable, never actually pruned), Door 3 is OP_RETURN (never enters the UTXO set).

Inscriptions are Door 2. An inscription envelope lives in the Taproot script-path witness; the actual reveal output is a normal P2TR UTXO (~43 bytes of UTXO-set weight) that eventually gets spent or sits in limbo. The content itself rides on the witness discount (1 WU per byte instead of 4) and is not counted against any per-tx relay cap โ€” the only brake on inscription size is the 4 MB block weight limit itself.

The key observation from the v30 debate, echoed by Greg Maxwell and d5000, is that Door 2 is architecturally the strangest of the three: its data is theoretically deletable (the coinbase's witness commitment, ยง14.4.3, proves the witness existed even after the bytes are gone), but no Bitcoin client has ever implemented selective witness pruning. The witness discount was priced on a prunability that was never built. So while inscriptions sound cleaner than OP_RETURN ("it's in the witness, it doesn't hit the UTXO set"), in practice every archive node stores every inscription byte forever. If the goal is truly prunable on-chain data, Door 3 โ€” not the witness โ€” is where it belongs. That is precisely the argument that carried Bitcoin Core 30 across the line.

19.6.8Interrogating the Arguments

The debate around on-chain data storage is full of claims that sound technical but collapse under scrutiny. A rigorous reader should challenge each one:

ClaimReality
"OP_RETURN data is fully prunable"Half true. It is automatically excluded from the UTXO set (the expensive part). But the raw bytes persist in blk*.dat on every archive node forever. Only full block pruning (-prune=N) removes them โ€” and that removes everything else too. There is no way to selectively delete OP_RETURN data while keeping the block.
"Witness data is prunable"Theoretically. The witness commitment in the coinbase makes it architecturally safe to delete witness data. But no Bitcoin client has ever implemented selective witness pruning. The only way to "prune" witness data today is to prune entire blocks. The discount was priced on a prunability that was never built.
"Inscriptions don't affect the UTXO set because the data is in the witness"The inscription content doesn't affect the UTXO set. But every inscription creates at least one spendable output โ€” the UTXO that carries the inscribed sat. That output entry (~43 bytes) sits in the UTXO set of every full node on the planet until it is spent. Millions of abandoned inscriptions mean millions of permanent UTXO entries.
"Just run a pruned node if you don't want the data"Pruned nodes cannot serve historical blocks to peers. If everyone prunes, new nodes cannot sync. The network requires a sufficient number of archive nodes. Pruning shifts the burden โ€” it doesn't eliminate it.
"Miners already filter transactions they don't like"Miners can choose not to include data transactions, but they cannot prevent other miners from including them. And rational miners will include any transaction that pays a sufficient fee. Filtering is a unilateral decision with no network effect โ€” it just means the filtering miner earns less revenue.
"The 80-byte OP_RETURN limit protects the network"It protects the network from 80+ byte OP_RETURN outputs. It does not protect the network from data storage โ€” it merely redirects embedders to the witness (Door 2) or fake outputs (Door 1), both of which are more harmful. The limit displaces the problem; it does not solve it.

The honest conclusion: there is no free lunch. Every method of embedding data on-chain has costs. The question is not whether data storage should be prevented (it can't be โ€” the bytes are valid transactions) but which costs are acceptable and who bears them. OP_RETURN imposes the least cost (no UTXO burden, block-file only). Witness inscriptions impose moderate cost (UTXO entry + block-file data). Fake outputs impose the highest cost (permanent UTXO entry + block-file data, with no way to ever remove the UTXO entry). The tooling to prune witness data โ€” the middle option โ€” was never built, despite the witness discount being justified by its theoretical prunability.

The Irony of OP_RETURN

OP_RETURN was explicitly designed as the "clean" way to put data on-chain: unspendable, no UTXO entry, prunable. But its long-standing 80-byte standardness default (a policy rule, not consensus) made it useless for large content until Core 30.0 lifted the default (ยง19.6.7). Inscriptions bypass this limit entirely by using the witness, which has no standardness cap and gets the 75% discount. If inscriptions used OP_RETURN, they would be limited to 80 bytes โ€” no images, no HTML, no games. The protocol that was designed for data storage is too small; the field that was designed for signatures is used instead.

19.7Inscription Identity and Transfer

19.7.1Inscription IDs

Each inscription is identified by its reveal transaction's txid and an index:

6fb976ab49dcec017f1e201e84395983204ae1a7c2abf7ced0a85d692e442799i0

The i0 suffix indicates this is the first (index 0) inscription in the reveal transaction. A single transaction can contain multiple inscriptions across its inputs.

19.7.2Ordinal-Aware Transfer

The inscription is bound to the first sat of the reveal transaction's first input. From that point, the sat (and its inscription) follows the FIFO transfer rule through subsequent transactions.

Ordinal-aware wallets must carefully control input/output ordering to avoid accidentally sending an inscribed sat to an unintended recipientโ€”or worse, losing it to fees. A standard (non-ordinal-aware) wallet treats all sats as fungible and may inadvertently relinquish a valuable inscribed sat.

19.8What We Learned

19.8.1Looking Ahead

Inscriptions use the witness to embed non-fungible contentโ€”one inscription per sat. Chapter 20 examines Runes, a protocol that uses OP_RETURN to create fungible tokens on Bitcoin, with an entirely different transaction anatomy.

Exercises

Litmus (L)

  1. How are ordinal numbers assigned to satoshis?
  2. What does the "ord" marker in an inscription envelope signify?
  3. Why does the inscription protocol use a two-phase commit/reveal pattern?
  4. What is the maximum size of a single data push in a Taproot script?
  5. What happens to sats that are not claimed by any output (i.e., the fee)?

Hands-On (H)

  1. Calculate the ordinal number of the first sat mined in block 767,430 (Inscription #0's block). Show your work by epoch.
  2. A "Hello, world!" text inscription (13 bytes of content, MIME type text/plain;charset=utf-8) is revealed in a transaction with 82 bytes of non-witness data. Estimate the total witness size and the transaction's weight.
  3. In Inscription #0's reveal transaction, the stripped size is 82 bytes and the total size is 1,040 bytes. Verify the weight (1,286 WU) and vsize (322 vB) using the BIP 141 weight formula.

Proofs and Reasoning (P)

  1. Explain why OP_FALSE OP_IF โ€ฆ OP_ENDIF is a no-op in Bitcoin Script. Why is this property essential for inscriptions?
  2. Why did BIP 342's removal of the 10,000-byte script size limit have a larger practical impact on inscriptions than the witness discount?
  3. The ordinal transfer rule is FIFO. Construct a scenario where a 3-input, 2-output transaction results in an inscribed sat ending up in the fee (lost to the miner).

Connections (C)

  1. Taproot dependency. Compare the inscription mechanism (Taproot script-path, witness envelope) with the OP_RETURN data embedding from Chapter 15. Why can't inscriptions use OP_RETURN? What are the size and cost tradeoffs?
  2. Block weight economics. A 400,000-byte JPEG inscription fills nearly an entire block's witness budget. Calculate its weight and the percentage of the 4,000,000 WU block limit it consumes. What does this imply for other transactions in that block?

Bridge (B)

  1. Chapter 20 covers Runes (fungible tokens via OP_RETURN). Compare the on-chain footprint of an inscription (witness data) vs. a Rune etching (OP_RETURN). Which is more efficient per byte of protocol data, and why?
  2. Could the inscription envelope format work with pre-Taproot transaction types (e.g., P2WSH)? What consensus or relay-policy constraints would prevent it?

Solutions

L1. Ordinals are assigned sequentially in the order sats are mined. The first sat of the genesis block is ordinal 0. Each block's subsidy adds the next batch. The first sat of block \(h\) has ordinal \(\sum_{i=0}^{h-1} \texttt{subsidy}(i)\).

L2. The "ord" marker (0x6f7264) disambiguates Ordinals inscriptions from other potential uses of the OP_FALSE OP_IF envelope pattern. It is the first push inside the envelope and identifies the protocol.

L3. Taproot script-path spends can only be made from existing Taproot outputs. The commit transaction creates the P2TR output that commits to the script tree containing the inscription. The reveal transaction then spends it, exposing the tapscript (and the embedded data) in the witness. You cannot create and spend a Taproot output in the same transaction.

L4. 520 bytes. This is a Taproot consensus rule inherited from the original script push limit. Larger content is split across multiple pushes within the envelope.

L5. Unclaimed sats (the transaction fee) flow to the coinbase transaction of the block. In ordinal theory, the coinbase has implicit inputs for fees, so these sats are assigned to the miner's coinbase outputs following the standard FIFO rule.

H1. Block 767,430 is in epoch 3 (blocks 630,000โ€“839,999).

EpochSats ContributedCalculation
01,050,000,000,000,000\(210,000 \times 5,000,000,000\)
1525,000,000,000,000\(210,000 \times 2,500,000,000\)
2262,500,000,000,000\(210,000 \times 1,250,000,000\)
3 (partial)85,893,750,000,000\(137,430 \times 625,000,000\)
Total1,923,393,750,000,000

The first sat of block 767,430 is ordinal 1,923,393,750,000,000. The 137,430 partial-epoch blocks come from \(767,430 - 630,000\).

H2. The tapscript contains:

Tapscript total: \(34 + 35 + 14 = 83\) bytes. Add Schnorr signature (64 bytes) and control block (33 bytes). Witness items with varints: \(1 + 64 + 1 + 83 + 1 + 33 = 183\) bytes. Add witness item count (1 byte) and marker+flag (2 bytes): total transaction \(\approx 82 + 2 + 1 + 183 = 268\) bytes.

Weight: \(82 \times 3 + 268 = 246 + 268 = 514\) WU, or \(\lceil 514/4 \rceil = 129\) vB.

H3. Weight \(= \text{stripped\_size} \times 3 + \text{total\_size} = 82 \times 3 + 1{,}040 = 246 + 1{,}040 = 1{,}286\) WU.

vsize \(= \lceil 1{,}286 / 4 \rceil = \lceil 321.5 \rceil = 322\) vB.

Fee rate: \(322 \div 322 \approx 1\) sat/vB.

P1. In Bitcoin Script, OP_IF pops the top stack element and executes the following code only if the element is nonzero (true). OP_FALSE pushes zero, so OP_IF always takes the "else" branchโ€”which, in the absence of an OP_ELSE, means jumping directly to OP_ENDIF. All data pushes between OP_IF and OP_ENDIF are parsed but never executed. This is essential because inscription data (binary images, HTML, etc.) would cause script failures if executedโ€”they are not valid opcodes or stack elements in an execution context. The envelope ensures the data is recorded on-chain (in the witness) but ignored by the script interpreter.

P2. The witness discount reduces the cost per byte of inscription data by 75% (1 WU vs. 4 WU). But the 10,000-byte script limit would have capped inscription size to 10 KB regardless of cost. BIP 342's removal of this limit changed the maximum possible size from 10 KB to 4 MB (the entire block weight budget). Without the size limit removal, inscriptions would be limited to small text or tiny images. The discount makes large inscriptions affordable; the size limit removal makes them possible.

P3. Suppose Alice holds three UTXOs: input 0 has 5,000 sats (with an inscription on sat 0), input 1 has 3,000 sats, input 2 has 2,000 sats. Total: 10,000 sats. She creates a transaction with output 0 = 4,000 sats and output 1 = 5,500 sats, paying a 500-sat fee.

FIFO assignment: output 0 gets the first 4,000 sats from input 0 (ordinals 0โ€“3,999). Output 1 gets the remaining 1,000 from input 0 (ordinals 4,000โ€“4,999), then 3,000 from input 1, then 1,500 from input 2. The last 500 sats from input 2 are the fee.

The inscription (on sat 0 of input 0) ends up in output 0. Now change the outputs: output 0 = 4,000 sats, output 1 = 5,000 sats, fee = 1,000. If Alice carelessly sets output 0 = 0 sats and output 1 = 9,000 sats, then the first 9,000 sats fill output 1 and the final 1,000 sats (from input 2) are the fee. The inscribed sat (sat 0 of input 0) goes to output 1.

For the sat to be lost to the fee, its position in the combined input stream must exceed the total output value. Put the inscription late in the stream: inputs = [5,000, 3,000, 2,000] with the inscription on sat 1,500 of input 2 โ€” stream position \(5{,}000 + 3{,}000 + 1{,}500 = 9{,}500\). Set output 0 = 4,000 sats and output 1 = 5,000 sats, fee = 1,000. FIFO: output 0 takes positions 0โ€“3,999, output 1 takes 4,000โ€“8,999, and positions 9,000โ€“9,999 โ€” including the inscribed sat at 9,500 โ€” fall into the fee. The ordinal protocol treats fee sats as flowing to the block's coinbase: the inscription now belongs to the miner.

C1. OP_RETURN (Chapter 15) embeds data in a scriptPubKey output, which is non-witness data (4 WU/byte). Maximum: 80 bytes of data. Inscriptions embed data in the witness, which costs 1 WU/byte, and have no practical size limit beyond the block weight.

Tradeoffs: OP_RETURN is 4\(\times\) more expensive per byte but creates a provably unspendable output (no UTXO bloat). Inscriptions are 4\(\times\) cheaper per byte but require a spendable Taproot output, increasing UTXO set pressure. OP_RETURN is limited to 80 bytes; inscriptions can store megabytes. For small metadata (transaction timestamps, proof anchors), OP_RETURN is simpler and cheaper in absolute terms. For large data (images, media), only inscriptions are feasible.

C2. A 400,000-byte JPEG in the witness, with 82 bytes of non-witness data:

Weight \(= 82 \times 3 + (82 + 2 + 400,000 + overhead) \approx 246 + 400,200 \approx 400,446\) WU.

As a fraction of the 4,000,000 WU block limit: \(400,446 / 4,000,000 \approx 10.0\%\). A single large inscription consumes roughly 10% of a block's capacity, leaving 90% for other transactions. A 4 MB inscription (the theoretical maximum) would consume the entire block.

B1. Inscriptions store data in the witness at 1 WU/byte. Rune etchings store protocol data in OP_RETURN outputs at 4 WU/byte. Per byte of protocol data, inscriptions are 4\(\times\) more weight-efficient. However, Rune protocol messages are small (typically \(<\)80 bytes), so the absolute weight difference is modest. Inscriptions are designed for large payloads (images, media); Runes are designed for compact token operations (etch, mint, transfer) where the total data is tiny.

B2. The OP_FALSE OP_IF envelope is syntactically valid in any script context, so it could appear in a P2WSH witness script. However, pre-Taproot scripts have a 10,000-byte MAX_SCRIPT_SIZE consensus limit, capping inscription size to 10 KB. Additionally, P2WSH witness data still receives the SegWit discount (1 WU/byte), but the script size limit makes it impractical for anything beyond small text. BIP 342 (Tapscript) removed this limit specifically for Taproot script-path spends, which is why inscriptions require Taproot.

โ† Ch. 18 Ch. 20 โ†’