Transaction Anatomy
How Ladder Script transactions are structured, byte by byte
Transaction version 4 signals a TX_MLSC. Nodes without Ladder Script treat it as a standard transaction (soft fork compatibility). The version routes validation to VerifyRungTx instead of VerifyScript.
The funding input is a standard Bitcoin input: P2PKH, P2WPKH, P2TR, or any existing type. The wallet signs it normally. Ladder Script only governs the output side.
Each output is exactly 8 bytes: the value in satoshis. There is no per-output script. Conditions are defined once per transaction via the shared conditions_root (PLC model).
One 0xDF prefix + 32-byte Merkle root shared across all outputs. The root defines a condition tree (PLC model) where outputs are mapped to conditions via the output() wrapper. A creation proof in the witness validates the root is protocol-derived.
| 0xDF | TX_MLSC prefix (1 byte) |
| root | SHA-256 Merkle root of conditions, relays, and coil (32 bytes) |
The per-input witness stack has exactly 2 elements:
The serialised rung with all blocks and their witness fields (signatures, pubkeys, preimages), plus coil metadata and relay definitions.
The Merkle proof linking the revealed conditions to the conditions_root. Contains the rung index, revealed conditions, and sibling hashes.
The creation proof is a separate per-transaction blob (not a per-input witness element). It validates that the conditions_root is protocol-derived from valid typed structure. It is carried after all per-input witness stacks in the TX_MLSC wire format (flag byte 0x02).
Each block starts with a single byte. Values 0x00–0x3E are micro-headers that encode the block type via a lookup table. Fields use the implicit layout, so no field count or type bytes are needed. Values 0x80/0x81 are escape codes for full 2-byte type + explicit fields.
| 0x00 | SIG |
| 0x01 | MULTISIG |
| 0x03 | CSV |
| 0x0A | CTV |
| 0x3E | OUTPUT_CHECK |
| 0x80 | Escape (full type follows) |
| 0x81 | Escape + inverted |
Every field has a declared type with enforced size. No arbitrary data is possible.
| Type | Size | Used for |
|---|---|---|
| PUBKEY | 1–2,048 B | Public keys (Schnorr 33B, PQ up to 2KB) |
| SIGNATURE | 1–50,000 B | Signatures (Schnorr 64B, PQ up to 49KB) |
| HASH256 | 32 B | SHA-256 commitments |
| NUMERIC | 1–4 B | Thresholds, timelocks, counts |
| SCHEME | 1 B | Signature scheme selector |
| PREIMAGE | 32 B | Hash preimage (max 2 per witness) |
Defines what happens when a rung is satisfied.
| coil_type | UNLOCK (0x01) or UNLOCK_TO (0x02). All other values rejected. |
| attestation | INLINE (0x01). All other values rejected. |
| scheme | SCHNORR, ECDSA, or PQ scheme |
| address_hash | 0 or 32 bytes (destination for UNLOCK_TO) |
| rung_destinations | Per-rung destination overrides |
Input: any standard Bitcoin output
Output: 8 bytes (value only) per output
Conditions root: 0xDF + 32-byte Merkle root (one per tx)
Witness: standard Bitcoin witness + creation proof
The funding wallet needs the Ladder Script library (or the engine/RPC) to compute the conditions_root from the desired conditions. Each output is just 8 bytes; the shared root is 33 bytes per transaction.
Input: references the TX_MLSC output
Output: another TX_MLSC output (8 bytes value only)
Witness: ladder witness + MLSC proof + creation proof
The node verifies the Merkle proof, merges conditions with witness, and evaluates the ladder.
1. Node sees tx version 4, input spending a TX_MLSC output
2. Routes to VerifyRungTx
3. Validates outputs are value-only (8 bytes each) with one conditions_root per tx
4. Deserialises witness stack[0] as LadderWitness
5. Deserialises witness stack[1] as MLSCProof
6. Validates the per-transaction creation proof (root is protocol-derived)
7. Extracts pubkeys from witness blocks (merkle_pub_key)
8. Verifies Merkle proof against conditions_root
9. Merges conditions with witness into single structure
10. Evaluates the ladder (AND within rung, OR across rungs)
11. If SATISFIED, the input is valid