Invariants / DC-MEM-09

DC-MEM-09

DC derived enforced

The authoritative UTxO lookup interface returns OWNED values (Option), never a borrow into storage. This is the precondition for a swappable UTxO backend (DC-MEM-05): a resolved output is materialized BY VALUE, so an on-disk backend can serve it without leaking storage lifetimes into the validity rules. Changing the lookup to owned MUST NOT alter any verdict, fingerprint, or failure shape.

Source

MEM-OPT-UTXO-DISK S1 (docs/clusters/MEM-OPT-UTXO-DISK/S1-interface.md); DC-MEM-05

Introduced in
MEM-OPT-UTXO-DISK

Enforcement trace

Cross-references

Evidence notes

Introduced + ENFORCED at MEM-OPT-UTXO-DISK S1 (2026-06-16) -- INTERFACE-PREP, explicitly NOT a memory victory and NOT a DC-MEM-07 flip and NOT an OP-MEM-02 movement (the BTreeMap is still fully in memory; no bounded storage, no owned-RSS win). utxo_lookup changed from -> Option<&TxOut> to -> Option<TxOut> behind a minimal UtxoStore seam (UTxOState/BTreeMap is the SOLE impl); the two production borrow sites -- phase.rs apply_phase_2_failure + tx_validity/phase1.rs required-signers resolution -- now route through the owned interface. The change is a single-TxOut clone per lookup (BOUNDED, intrinsic to the swappable-backend model where S2 materializes each output owned from disk -- NOT a full-map clone; criterion 'no extra clone-heavy path' guards against accidental MAP clones, which are not introduced). Proven behavior-invariant: ade_ledger validity + fingerprint tests, ade_runtime DC-WAL-03 replay (wal_replay_from_anchor), ade_node admission_replay_equivalence + adversarial corpus + cross-epoch guard ALL green; owned_lookup_returns_stored_value_and_does_not_mutate asserts the resolved value byte-equals the stored entry + the lookup never mutates; ci_check_utxo_lookup_owned.sh asserts the owned signature + the UtxoStore seam + the routed sites + no redb in ade_ledger. OPEN S2 ENTRY GATE carried (OQ-UD-3): block admission computes post_fp by FULL-UTxO iteration per block (runner.rs:437 -> fingerprint(&next_ledger).combined -> fingerprint_utxo), so S2 (the on-disk backend) needs an incremental-fingerprint plan first, else it replaces heap pressure with catastrophic per-block disk iteration. Plus the S2 key-order guardrail: prove redb key order == canonical TxIn order by a test vector, else use a fixed-width 32-byte txid ++ BE-u32 index key.