Runes

Implementer reference

Reference

Terminology, the indexer's view of the chain, and the decisions an implementation has to get right. Grounded in ord 0.29.0: src/index/updater/rune_updater.rs, src/index/entry.rs, src/index/reorg.rs, src/lib.rs, and the ordinals crate.

Terminology

Runestone
The protocol message: an OP_RETURN output beginning OP_RETURN OP_13, whose data pushes concatenate into a payload of varints.
Artifact
The result of deciphering a transaction. Either a well-formed runestone or a cenotaph. A transaction with no matching output has no artifact at all, which is different from having an empty one.
Cenotaph
A malformed runestone. Burns input runes, makes an etched rune unmintable, and burns mint output while still counting the mint against the cap.
Flaw
The named reason a runestone is a cenotaph. Ten exist; the reference implementation reports the first one found.
Etching
The act of creating a rune and permanently fixing its name, divisibility, symbol, spacers, premine, and terms.
Rune ID
BLOCK:TX: the height of the etching block and the etching transaction's index within it. Assigned once, never reused.
Edict
An instruction inside a runestone: allocate an amount of one rune to one output.
Pointer
The output index that receives unallocated runes, overriding the first non-OP_RETURN output default.
Premine
Units allocated to the etching transaction itself, outside the mint.
Terms
The conditions of an open mint: amount per mint, cap, and height or offset windows.
Turbo
A flag on the etching declaring that the rune opts in to future protocol changes. It carries no meaning under the current rules.
Atomic unit
The indivisible unit of a rune. Display value is the atomic amount shifted by the rune's divisibility.
Unallocated pool
Per transaction: input balances, plus a successful mint, plus a premine. Edicts draw from it; the remainder follows the pointer.
Reserved name
A name at or above 6402364363415443603228541259936211926. Unetchable directly; assigned by the indexer to etchings that omit a name.
Commitment
The tapscript data push in an input's witness proving the etcher claimed the name at least 6 blocks earlier.

Indexer pipeline

Per-transaction indexing order Six carved steps in order: gather unallocated balances from spent inputs; apply the mint if terms allow; apply the etching and its premine; process edicts in order; assign the remainder via pointer or first non-OP_RETURN output; then record burns, including everything if the artifact is a cenotaph. 123 456 Drain rune balances from every spent input into the unallocated pool Apply the mint: if terms hold, increment mint count, add the amount Apply the etching: validate name, commitment, uniqueness; add the premine Process edicts in order, clamping each amount to the remaining balance Send the remainder to the pointer output, else the first non-OP_RETURN output Record burns: OP_RETURN allocations, or everything if the artifact is a cenotaph
Order matters. A mint's output is available to the same transaction's edicts, and a premine can be distributed by an edict with rune ID 0:0.

Two consequences worth internalizing. First, the cenotaph check happens after allocation is computed, and it discards all of it: allocations are replaced wholesale by burns of the entire unallocated pool. Second, an unsuccessful mint is invisible. It leaves no trace in the index, no event, and no error, and it never counts against the cap unless the transaction is a cenotaph for some other reason.

Terms evaluation

A mint at height h succeeds when the rune exists, has terms, and all of the following hold:

Because start takes the maximum and end takes the minimum, giving both an absolute height and an offset narrows the window rather than widening it. Amount is taken as 0 when absent, which produces successful mints that create nothing while still consuming cap.

Supply accounting: supply = premine + mints × amount and max supply = premine + cap × amount. Burned units are tracked separately and are not deducted from supply.

Confirmation and mempool

Reorg behavior

Rune state is fully derived from the chain, so a reorg is handled by rewinding rather than by patching. The reference indexer keeps periodic database savepoints (by default one every 10 blocks, retaining 2) and, on detecting that a stored block hash no longer matches the chain, restores the oldest savepoint and re-indexes forward. A reorg deeper than the retained savepoints is reported as unrecoverable and requires re-indexing.

Practical consequences for anything built on rune data:

Sizes and fees

Runestones are small. These are exact script sizes in bytes from the reference implementation's own size assertions:

Encoded runestone script sizes, bytes
RunestoneSize
Empty (OP_RETURN OP_13 only)2
Etching, shortest name, no other fields7
Etching, longest name, no other fields25
Etching with every field at maximum89
One edict, amount 014
One edict, maximum amount32
Two edicts, maximum amounts54
Three edicts, maximum amounts76
Five edicts, u64-sized amounts75

Relay policy, not the protocol, sets the practical ceiling. The reference wallet refuses to build a runestone whose script exceeds 83 bytes, the standard OP_RETURN size it compiles in, unless explicitly overridden, and it enforces the 400,000 weight unit standard transaction limit. Neither is a consensus rule and neither is part of the Runes specification: a miner-included runestone above those sizes is valid and will be indexed. The payload is emitted as a single data push in practice, since chunking only begins above 4 GiB.

The dominant cost is rarely the runestone. It is the outputs: every recipient of a rune balance needs a spendable output above the dust threshold, so a transfer to n recipients costs n outputs plus change plus the OP_RETURN. Sweeps (amount 0) and splits (output index equal to the output count) exist to keep the runestone itself short.

Limitations

Security considerations

Implementation checklist

  1. Search outputs in order for OP_RETURN OP_13. Take the first match; skip unparseable and non-matching outputs without erroring.
  2. Concatenate all data pushes. Treat any non-pushdata opcode as flaw Opcode and any unparseable script as InvalidScript.
  3. Decode the whole payload as LEB128 varints with the 19-byte limit and the 19th-byte overflow mask. Any failure is flaw Varint.
  4. Parse tag and value pairs until tag 0; then parse edicts in groups of four. Handle TruncatedField and TrailingIntegers.
  5. Accumulate edict rune IDs by delta, rejecting overflow and block 0 with nonzero tx (EdictRuneId), and range-check outputs against the output count, allowing equality as a split (EdictOutput).
  6. Consume flags and fields in the reference implementation's order, leaving values in place when a range check fails, so that odd tags degrade and even tags become UnrecognizedEvenTag.
  7. Check premine + cap × amount for u128 overflow (SupplyOverflow) and confirm no flag bits remain set (UnrecognizedFlag).
  8. Enforce the etching preconditions: minimum name at height, not reserved, not already etched ignoring spacers, and a valid taproot tapscript commitment with at least 6 confirmations.
  9. Apply the pipeline in order: unallocated, mint, etch and premine, edicts, pointer remainder, burns. Clamp every allocation to the remaining balance.
  10. Burn everything on a cenotaph, count the mint, and record the etched rune as unmintable with default properties.
  11. Persist balances per outpoint and per rune, and derive account views from them. Never treat an address as the unit of ownership.
  12. Handle reorgs by rewinding to a savepoint and re-indexing. Key caches by block hash.
  13. Verify against the test vectors, including every cenotaph case, before indexing real value.