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.†
Every sat receives a serial number based on the order in which it is mined. The algorithm is remarkably simple (from the BIP, in pseudocode):
def subsidy(height):
return 50 * 100_000_000 >> height // 210_000
def first_ordinal(height):
start = 0
for h in range(height):
start += subsidy(h)
return start
The first sat of block 0 is ordinal 0. The first sat of block 1 is ordinal 5,000,000,000 (the Genesis block's full 50 BTC subsidy). Each halving epoch shifts the numbering:
| Epoch | Blocks | Subsidy | First Ordinal of Epoch |
|---|---|---|---|
| 0 | 0–209,999 | 50 BTC | 0 |
| 1 | 210,000–419,999 | 25 BTC | 1,050,000,000,000,000 |
| 2 | 420,000–629,999 | 12.5 BTC | 1,575,000,000,000,000 |
| 3 | 630,000–839,999 | 6.25 BTC | 1,837,500,000,000,000 |
| 4 | 840,000–1,049,999 | 3.125 BTC | 1,968,750,000,000,000 |
When sats move through a transaction, ordinals are assigned to outputs in FIFO order: the sats from input 0 fill output 0 first, then output 1, and so on. Any sats left over (the fee) flow to the coinbase transaction of the block.
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.
Bitcoin's periodic events create natural rarity tiers:
| Rarity | Definition | Total Supply |
|---|---|---|
| Common | Any sat not first in its block | 2.1 quadrillion |
| Uncommon | First sat of each block (excl.\ higher tiers) | 6,926,535 |
| Rare | First sat of each difficulty adjustment | 3,432 |
| Epic | First sat of each halving epoch | 27 |
| Legendary | First sat of each cycle (6 halvings) | 5 |
| Mythic | First sat of the genesis block | 1 |
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.
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.
OP_FALSE
OP_IF
OP_PUSH "ord" protocol tag
OP_PUSH 1 content-type tag
OP_PUSH " e.g., "image/png"
OP_PUSH 0 body separator
OP_PUSH <data> content (may span multiple pushes)
OP_ENDIF
Key design properties:
OP_FALSE OP_IF …\ OP_ENDIF is never entered during script execution. The envelope does not affect the spending condition—it can be combined with any locking script.0x6f7264 (ASCII "ord") disambiguates inscriptions from other uses of envelopes.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.
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.
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.
The reveal transaction spends the commit output via script-path (Chapter 13). The witness contains:
The inscription content becomes visible on-chain only in the reveal transaction's witness—permanently recorded in the blockchain.
The very first Ordinals inscription—a 100\(\times\)100 pixel skull image—was inscribed by Casey Rodarmor on December 14, 2022 at 20:32 UTC in block 767,430.
0.5em
| Field | Value |
|---|---|
| txid | 274bda66… 6358 |
| Input | 1 (P2WPKH, 111,794 sats) |
| Output 0 | P2TR, 10,000 sats (inscription commit) |
| Output 1 | P2WPKH, 101,531 sats (change) |
| Fee | 263 sats |
| Size / Weight / vsize | 234 B / 609 WU / 153 vB |
Output 0 is a standard-looking P2TR address. Nothing in the commit transaction reveals the inscription content.
0.5em
| Field | Value |
|---|---|
| txid | 6fb976ab… 2799 |
| Version | 1 |
| nLockTime | 0 |
| Input | 1 (spends commit output, P2TR script-path) |
| Output | 1 (P2WPKH, 9,678 sats) |
| Fee | 322 sats |
| nSequence | 0xFFFFFFFD (RBF-signaling) |
| Size | 1,040 bytes |
| Weight | 1,286 WU |
| vsize | 322 vB |
| Feerate | 1 sat/vB |
The reveal transaction's witness contains three items:
| Item | Content | Size |
|---|---|---|
| 0 | Schnorr signature | 64 bytes |
| 1 | Tapscript (spending condition + envelope) | 856 bytes |
| 2 | Control block (0xc0 + internal pubkey) | 33 bytes |
The tapscript (witness item 1) contains both the spending condition and the inscription envelope:
OP_PUSHBYTES_32 <pubkey> 33 bytes
OP_CHECKSIG spending condition
OP_0 OP_FALSE
OP_IF begin envelope
OP_PUSHBYTES_3 6f 72 64 "ord"
OP_PUSHBYTES_1 01 tag 1: content type
OP_PUSHBYTES_9 69 6d 61 67 65 2f 70 6e 67 "image/png"
OP_0 tag 0: body begins
OP_PUSHDATA2 08 02 89 50 4e 47 … 520 bytes (PNG data)
OP_PUSHDATA2 XX XX 09 b1 6c 4b … remaining PNG data
OP_ENDIF end envelope
<pubkey> OP_CHECKSIG) comes first. The Schnorr signature in witness item 0 satisfies it.OP_0 OP_IF opens the envelope. Since the top of the stack is zero, the OP_IF branch is never entered—the script interpreter jumps straight to OP_ENDIF.89 50 4e 47 0d 0a 1a 0a (the standard PNG file header). It is split across two OP_PUSHDATA2 pushes because each push is limited to 520 bytes.0xc0: the Tapscript leaf version byte (BIP 342 defines 0xc0 as the Tapscript leaf version; the low bit encodes even output-key parity), followed by the 32-byte internal public key. No Merkle proof is needed because this is the only leaf in the script tree.Inscriptions exploit three properties of the Taproot upgrade that converge to make on-chain data storage economical:
Witness data is counted at 1 WU per byte (vs. 4 WU per byte for non-witness data). For inscription #0:
| Non-witness | Witness | |
|---|---|---|
| Bytes | 82 | 958 |
| Weight contribution | \(82 \times 4 = 328\) WU | \(958 \times 1 = 958\) WU |
| Total weight | 1,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.
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.
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.
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.
"Pruning" in Bitcoin is not a single operation — it operates at several distinct layers, each discarding different data with different trade-offs:
| Layer | What gets discarded | Who does it | User-facing? |
|---|---|---|---|
| Block file pruning | Old blk*.dat and rev*.dat files after validation | -prune=N flag | Yes — the primary meaning of "pruned node" |
| UTXO pruning | OP_RETURN outputs — provably unspendable, never enter the UTXO set | Every node, automatically | No — invisible to the operator |
| Mempool pruning | Lowest-feerate unconfirmed transactions when mempool exceeds -maxmempool (default 300 MB) | Every node, automatically | No — happens silently under load |
| Manual pruning | Blocks below a specified height via pruneblockchain RPC | Operator via RPC call | Yes — fine-grained control |
| Ultraprune (v0.8.0) | The old BerkeleyDB database — replaced with a lean UTXO-only LevelDB | Pieter Wuille, 2013 | No — 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 proofs | Not yet implemented | Would eliminate the ~8 GB in-memory UTXO database |
| Witness pruning (never built) | Witness data stripped from blocks while keeping block structure | Not yet implemented | Would 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.
Inscription data lives in three distinct places, each with different storage properties:
| Component | Where it lives | Prunable? | UTXO set impact |
|---|---|---|---|
| Inscription content (image, text) | Witness field | Yes — discarded by pruned nodes after validation | None |
| OP_RETURN metadata (Runes, etc.) | Output script | Yes — unspendable, never enters UTXO set | None |
| Inscription output (the UTXO carrying the inscribed sat) | UTXO set | No — persists in every full node's database until spent | ~43 bytes per inscription |
The inscription's content — the JPEG, the HTML page, the game — is entirely in the witness, which pruned nodes discard. The inscription's existence as a spendable output is a UTXO entry that every full node must maintain indefinitely.
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.
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 (minimum 550, approximately 4 days). There is no option to selectively strip witness data while preserving the rest of the block.
The options available to a node operator are:
-prune=550): Discards all block data older than ~4 days. 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.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.
There is no configuration option, no RPC call, and no plugin system for custom pruning rules. Building selective witness pruning would require modifying Bitcoin Core's source code — or writing an external tool that operates on the block files directly.
The relevant code lives in src/node/blockstorage.cpp, where blocks are serialized to and read from the blk*.dat files on disk. A selective pruning implementation would need to:
OP_RETURN output in the coinbase transaction) to prove the witness data existed. This commitment is already computed and stored in every post-SegWit block — verification works even after the witness is deleted.The hard part is not the deletion itself — it is the storage format. Bitcoin Core packs transactions contiguously in blk*.dat files. Stripping the witness from a single transaction changes its serialized size, which shifts every subsequent byte offset in the file. The block index (blocks/index/, a LevelDB database that maps block hashes to file positions) would need to be rebuilt.
A more practical approach would be a post-processing tool that operates outside of Core entirely: read the blk*.dat files, strip witness data from blocks older than some threshold, rewrite the files with updated offsets, and rebuild the LevelDB index. This would not require modifying any consensus code. But no one has built and maintained such a tool for production use.
The Bitcoin Knots client (Luke Dashjr's fork of Core) has explored some transaction filtering options. There have also been periodic mailing list proposals for witness pruning and for Utreexo — a cryptographic accumulator that would allow nodes to verify UTXO existence without storing the full UTXO set. These proposals address different facets of the storage problem but none have reached mainline Core. As of 2026, the choice for node operators remains binary: keep everything, or prune entire blocks.
In the BitcoinTalk thread "Why Bitcoin 30 Will Probably Not Lead to More Spam in the Blockchain" (September 2025), developer d5000 framed the data embedding problem as a choice between three doors — each representing a method of putting arbitrary data on-chain, ranked by harm to the network:
OP_FALSE OP_IF envelopes. Creates a UTXO (the inscription output) but data is prunable. Second most harmful — UTXO entry persists, but data can be discarded.d5000's argument: you cannot eliminate the impulse to store data on-chain. But you can channel it toward the least destructive method. The 80-byte OP_RETURN limit keeps Door 3 too small, forcing data embedders through Door 2 (inscriptions) or worse, Door 1 (fake outputs that pollute the UTXO set permanently). Opening Door 3 wider would reduce harm to the network, not increase it.
Greg Maxwell made the same point in the "Removing OP_RETURN Limits" thread (April 2025, 341+ replies): the 80-byte limit is "actively harmful" because it pushes embedders toward fake P2WSH outputs that "permanently pollute the UTXO set." OP_RETURN data, by contrast, is "completely prunable and pruned."
The Three Doors framework reveals a gap in Bitcoin's tooling. Door 2 (witness data) is theoretically prunable — the witness commitment in the coinbase transaction allows verification that witness data existed even after deletion. The witness discount was partly justified by this prunability. But no one has formally proposed "witness pruning" as a BIP or implemented it in any mainline client. The discount exists; the pruning capability it was premised on does not. Until selective witness pruning is built, Door 2 data (inscriptions) imposes the full storage burden on every archive node and every new node performing initial sync — despite being architecturally deletable.
OP_RETURN was explicitly designed as the "clean" way to put data on-chain: unspendable, no UTXO entry, prunable. But its 80-byte standardness limit (a policy rule, not consensus) makes it useless for large content. 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.
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.
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.
OP_FALSE OP_IF …\ OP_ENDIF....i0) and are bound to the first sat of the reveal input.Inscriptions use the witness to embed non-fungible content—one inscription per sat. Chapter 19 examines Runes, a protocol that uses OP_RETURN to create fungible tokens on Bitcoin, with an entirely different transaction anatomy.
*Exercises
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.OP_FALSE OP_IF …\ OP_ENDIF is a no-op in Bitcoin Script. Why is this property essential for inscriptions?*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).
| Epoch | Sats Contributed | Calculation |
|---|---|---|
| 0 | 1,050,000,000,000,000 | \(210,000 \times 5,000,000,000\) |
| 1 | 525,000,000,000,000 | \(210,000 \times 2,500,000,000\) |
| 2 | 262,500,000,000,000 | \(210,000 \times 1,250,000,000\) |
| 3 (partial) | 85,893,750,000,000 | \(137,430 \times 625,000,000\) |
| Total | 1,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:
<pubkey>) + 1 byte (OP_CHECKSIG) = 34 bytesOP_0(1) + OP_IF(1) + push "ord"(1+3) + push tag 1(1+1) + push MIME(1+24) + OP_0(1) + OP_ENDIF(1) = 36 bytesOP_PUSHBYTES_13)Tapscript total: \(34 + 36 + 14 = 84\) bytes. Add Schnorr signature (64 bytes) and control block (33 bytes). Witness items with varints: \(1 + 64 + 1 + 84 + 1 + 33 = 184\) bytes. Add witness item count (1 byte) and marker+flag (2 bytes): total transaction \(\approx 82 + 2 + 1 + 184 = 269\) bytes.
Weight: \(82 \times 3 + 269 = 246 + 269 = 515\) WU, or \(\lceil 515/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.
=1000 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: Alice must set total outputs such that the inscribed sat's position exceeds the sum of all output values. For example: inputs = [5,000, 3,000, 2,000] (inscription on sat 0), output 0 = 0 sats is impossible (dust). A practical scenario: output values sum to 4,999 sats (below the inscribed sat's position of sat 5,000 from input 1). Actually the inscription is on input 0, sat 0—the very first sat. It can only be lost to fees if no output exists (all value goes to fees), which is pathological.
A more realistic scenario: the inscription is on sat 4,999 of input 0 (the last sat). Output 0 = 4,999 sats, output 1 = 4,500 sats, fee = 501. FIFO: output 0 gets sats 0–4,998 from input 0. Output 1 gets sat 4,999 from input 0 plus 3,000 from input 1 plus 1,500 from input 2. The inscribed sat lands in output 1. For it to fall into the fee: outputs must sum to fewer sats than the inscribed sat's ordinal position in the combined input stream. If the inscription is on the last sat of the last input, and the fee is large enough, it can be lost.
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.