DC-LEDGER-PHASE2-02
DC derived enforcedThe accumulator consumes a RESOLVED SCALAR; it does not own a UTxO. The ADA a phase-2-invalid transaction consumes is collAdaBalance = sum(value(collateral inputs)) - collateral_return.coin, where the collateral-input values are supplied by the UTxO authority through a one-method resolver declared in BLUE (CollateralValueResolver) and the collateral return is read from the canonical block. An unresolved collateral input is a TYPED REFUSAL (UnresolvedCollateralInput) -- never zero, never a skipped contribution, never a fallback to total_collateral. total_collateral (body field 17) is NEVER the source of the value: per cardano-ledger it is a declared assertion the UTXO rule enforces when present (IncorrectTotalCollateralField) and which constrains nothing when absent. The accumulator never holds, indexes, queries or reconstructs a UTxO map.
- Source
docs/clusters/PREPROD-LIVE-2-FORGE-READINESS/SLICE-BND-2b-collateral-balance-handoff.md (INV-BND-2b)
- Cluster
- PREPROD-LIVE-2-FORGE-READINESS
- Introduced in
- PREPROD-LIVE-2-BND-2b
- Authority surface
- BLUE per-tx collateral valuation; the resolver is implemented by the RED/GREEN storage layer and answers only Option<Coin>
Enforcement trace
Code
Tests 6
- multiple_collateral_inputs_sum_deterministically
- the_collateral_return_is_subtracted_exactly_once
- an_unresolved_collateral_input_is_a_typed_refusal_not_zero
- one_unresolved_input_among_several_still_refuses
- a_return_exceeding_the_collateral_fails_closed
- the_refusal_is_replay_identical
Cross-references
Evidence notes
CAPABILITY-ONLY BY DESIGN: this slice introduces the resolver and the computation and changes NO existing behaviour. The accumulator's guards (InvalidTxCarriesAuthorityEffect, InvalidTxCollateralNeedsUtxo) still fire and its cursor stays pinned at 130,350,114; electing to trust the resolved result is BND-2c, which is also where the real-block value differential (CE-2b-7) belongs -- during the accumulator's walk the reduced checkpoint is positioned AT the block, so the collateral input resolves, whereas in isolation after the fact it has already been spent. NEGATIVE-TESTED both ways the rule is cheap to get wrong: treating an unresolved input as zero fails 3 tests AND is caught structurally by the gate (it greps the isolated function body for unwrap_or / unwrap_or_default and requires UnresolvedCollateralInput to remain raised); dropping one collateral input from the sum fails 5 of 6 tests. The gate also checks total_collateral against CODE ONLY, stripping comments first, because the module documents in prose that it does not consult field 17 and that sentence must not be mistaken for a use. CE-2b-5 is enforced by REUSING the pre-existing ci_check_epoch_accumulator_no_utxo.sh rather than restating it -- a second copy of an invariant is a second thing to drift. ID CORRECTION (BND-2d): this rule was first recorded as DC-LEDGER-02, an id already held by a long-standing rule, which broke registry uniqueness (ci_check_registry_unique_ids.sh was red from that commit until BND-2d). The older holder keeps the id; this entry -- three commits old and referenced only by its own slice doc -- takes the fresh DC-LEDGER-PHASE2-02.
Evidence
Reference rule quoted verbatim from Cardano.Ledger.Babbage.Collateral (collAdaBalance / collOuts) and the totalCollateral check (validateCollateralEqBalance / IncorrectTotalCollateralField) -- docs/evidence/run-stores/preprod-live2c/bnd2-oracle-extraction.md.
The gating fact was CHECKED, not assumed: ReducedUtxoCheckpoint::get already resolves an arbitrary TxIn, and the checkpoint retains EVERY entry (ReducedStakeRef is Base|NonContributing), keeping ADA Coin -- exactly and only what collAdaBalance needs.