Skip to content

Commit e304e52

Browse files
claudewilliamdemeo
authored andcommitted
Make getCoin on CertState total (rewards + deposits)
`HasCoin-CertState.getCoin` previously returned only the rewards balance (`rewardsBalance ∘ DStateOf`), a misleading partial notion that needed a paragraph of prose to explain why the deposit pots had to be re-added at the `LedgerState` level. Introduce `coinFromRewards = rewardsBalance ∘ DStateOf` and redefine `getCoin (CertState) = coinFromRewards cs + coinFromDeposits cs` — the honest total coin a cert state accounts for (rewards plus the three deposit pots). The cert-level PoV lemmas that genuinely track only the rewards flow now say `coinFromRewards` explicitly: - `CERTS-pov` / `ENTITIES-pov` — these preserve/move the rewards balance, not the deposits (`CERTS` changes the deposit pots), so the old getCoin- preservation statements are false under the new instance and must be restated; - `SUBLEDGERS-certs-pov`, `combined-certs`, and the `R₀`/`R₂` bindings. Their proof bodies are unchanged: `coinFromRewards` is definitionally the old instance, so these are mechanical renames. The `LedgerState` total keeps its explicit four-summand form (UTxO + `coinFromRewards` + `coinFromDeposits` + gov); the two middle summands are now exactly `getCoin (CertStateOf s)`. The obsolete N.B. prose is rewritten. Typechecks under --safe (Certs, Ledger, Entities/Ledger PoV). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01We2YdXX2ozJAdAbCrRwi6r
1 parent dcb9749 commit e304e52

4 files changed

Lines changed: 62 additions & 54 deletions

File tree

src/Ledger/Dijkstra/Specification/Certs.lagda.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,9 @@ doesn't balance.
356356
coinFromDeposits : CertState → Coin
357357
coinFromDeposits cs = coinFromDepositTriple (depositTripleOf cs)
358358
359+
coinFromRewards : CertState → Coin
360+
coinFromRewards = rewardsBalance ∘ DStateOf
361+
359362
module _ (pp : PParams) (certState : CertState) where
360363
361364
updateCertDeposits : List DCert → CertState
@@ -376,7 +379,8 @@ module _ (pp : PParams) (certState : CertState) where
376379
```agda
377380
instance
378381
HasCoin-CertState : HasCoin CertState
379-
HasCoin-CertState .getCoin = rewardsBalance ∘ DStateOf
382+
-- Total coin held in a CertState: the rewards balance plus the deposit pots.
383+
HasCoin-CertState .getCoin = λ cs → coinFromRewards cs + coinFromDeposits cs
380384
381385
unquoteDecl DecEq-StakePoolParams = derive-DecEq
382386
((quote StakePoolParams , DecEq-StakePoolParams) ∷ [])

src/Ledger/Dijkstra/Specification/Entities/Properties/PoV.lagda.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ introduced in [CIP-159-11d][PR-1201]. In the Dijkstra era, `ENTITIES`{.AgdaData
1010
wraps the inner `CERTS`{.AgdaDatatype} step with per-transaction withdrawal- and
1111
direct-deposit-handling: withdrawals are applied to the rewards balance *before*
1212
`CERTS`{.AgdaDatatype}, direct deposits *after*. The value-flow equation captures
13-
the net effect of all three components on `getCoin (CertState)`:
13+
the net effect of all three components on the cert-state rewards balance
14+
(`coinFromRewards`{.AgdaFunction}; the deposit pots are accounted separately):
1415

15-
getCoin s + getCoin (DirectDepositsOf Γ) ≡ getCoin s' + getCoin (WithdrawalsOf Γ)
16+
coinFromRewards s + getCoin (DirectDepositsOf Γ) ≡ coinFromRewards s' + getCoin (WithdrawalsOf Γ)
1617

1718
Intuitively, the deposits added on the right are matched by the withdrawals removed
1819
on the left — they "pass through" the rule.
@@ -96,7 +97,7 @@ module ENTITIES-PoV
9697
-- `Certs.Properties.PoV`; lifted to a module parameter so this PR proves only
9798
-- the `ENTITIES`/`LEDGER` layer (top-down strategy).
9899
( CERTS-pov : ∀ {Γ : CertEnv} {s s' : CertState} {dCerts : List DCert}
99-
→ Γ ⊢ s ⇀⦇ dCerts ,CERTS⦈ s' → getCoin s ≡ getCoin s' )
100+
→ Γ ⊢ s ⇀⦇ dCerts ,CERTS⦈ s' → coinFromRewards s ≡ coinFromRewards s' )
100101
where
101102
open ApplyToRewards-PoV ∪ˡ-lookup-preserve sum-map-proj₂≡getCoin setToList-Unique public
102103
```
@@ -110,7 +111,7 @@ per-batch `NetworkId`{.AgdaFunction} witnesses for `WithdrawalsOf Γ`{.AgdaBound
110111
`DirectDepositsOf Γ`{.AgdaBound} (produced at the call site by the
111112
`SUBUTXOW`{.AgdaDatatype} or `UTXOW`{.AgdaDatatype} step). Then,
112113

113-
getCoin s + getCoin (DirectDepositsOf Γ) ≡ getCoin s' + getCoin (WithdrawalsOf Γ)
114+
coinFromRewards s + getCoin (DirectDepositsOf Γ) ≡ coinFromRewards s' + getCoin (WithdrawalsOf Γ)
114115

115116
**Formally**.
116117

@@ -119,7 +120,7 @@ per-batch `NetworkId`{.AgdaFunction} witnesses for `WithdrawalsOf Γ`{.AgdaBound
119120
→ ∀[ a ∈ dom (WithdrawalsOf Γ) ] NetworkIdOf a ≡ NetworkId
120121
→ ∀[ a ∈ dom (DirectDepositsOf Γ) ] NetworkIdOf a ≡ NetworkId
121122
→ Γ ⊢ s ⇀⦇ dCerts ,ENTITIES⦈ s'
122-
getCoin s + getCoin (DirectDepositsOf Γ) ≡ getCoin s' + getCoin (WithdrawalsOf Γ)
123+
coinFromRewards s + getCoin (DirectDepositsOf Γ) ≡ coinFromRewards s' + getCoin (WithdrawalsOf Γ)
123124
```
124125

125126
**Proof**. Case-split on the single `ENTITIES`{.AgdaInductiveConstructor}
@@ -166,10 +167,9 @@ step then preserves `getCoin`{.AgdaFunction} through the inner closure;
166167
and the final rewrite folds `applyDirectDeposits`{.AgdaFunction} back
167168
into the LHS of the goal.
168169

169-
Equivalences used implicitly: under
170-
`HasCoin-CertState`{.AgdaFunction}, `getCoin (CertState) ≡ getCoin (rewards ∘ DStateOf)`,
171-
which is why `G r₀`, `G aw`, `G r₁`, and `G (applyDirectDeposits dd r₁)`
172-
are interchangeable with `getCoin s`, `getCoin <intermediate>`,
173-
`getCoin <post-CERTS>`, and `getCoin s'` respectively — both sides
174-
project to the `rewards`{.AgdaField} field, which is exactly what the
175-
chain manipulates.
170+
Equivalences used implicitly: `coinFromRewards`{.AgdaFunction} is
171+
`rewardsBalance ∘ DStateOf`{.AgdaFunction} by definition, which is why `G r₀`, `G aw`,
172+
`G r₁`, and `G (applyDirectDeposits dd r₁)` are interchangeable with
173+
`coinFromRewards s`, `coinFromRewards <intermediate>`, `coinFromRewards <post-CERTS>`,
174+
and `coinFromRewards s'` respectively — both sides project to the `rewards`{.AgdaField}
175+
field, which is exactly what the chain manipulates.

src/Ledger/Dijkstra/Specification/Ledger.lagda.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -185,9 +185,10 @@ allColdCreds govSt es =
185185
4. the governance-action deposits, summed by `coinFromGovDeposit`{.AgdaFunction} over
186186
`GovActionState.deposit`{.AgdaField} for each action in the current `GovState`{.AgdaRecord}.
187187

188-
N.B. `HasCoin-CertState` counts only the rewards balance (component 2) — its `getCoin` is
189-
`rewardsBalance ∘ DStateOf`{.AgdaFunction} — so components 3 and 4 must be added at the
190-
`LedgerState`{.AgdaRecord} level to make the `LEDGER-pov` equation balance against the
188+
`HasCoin-CertState` sums components 2 and 3 — its `getCoin` is `coinFromRewards cs +
189+
coinFromDeposits cs`{.AgdaFunction} (the rewards balance plus the three deposit pots) — so
190+
the `LedgerState`{.AgdaRecord} total adds only component 1 (UTxO coin) and component 4
191+
(governance-action deposits). This balances the `LEDGER-pov` equation against the
191192
`UTXO`{.AgdaDatatype} batch-balance equation, which charges `newCertDeposits`{.AgdaFunction}
192193
and `govProposalsDeposits`{.AgdaFunction} on the *produced* side. Cert deposits flow into
193194
the `DState`/`PState` pots tracked by `coinFromDeposits`{.AgdaFunction}; governance-action
@@ -205,7 +206,7 @@ coinFromGovDeposit = foldr (λ (_ , gaSt) acc → GovActionState.deposit gaSt +
205206
instance
206207
HasCoin-LedgerState : HasCoin LedgerState
207208
HasCoin-LedgerState .getCoin s = getCoin (UTxOStateOf s)
208-
+ rewardsBalance (DStateOf (CertStateOf s))
209+
+ coinFromRewards (CertStateOf s)
209210
+ coinFromDeposits (CertStateOf s)
210211
+ coinFromGovDeposit (GovStateOf s)
211212
```

src/Ledger/Dijkstra/Specification/Ledger/Properties/PoV.lagda.md

Lines changed: 40 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,16 @@ then `getCoin s ≡ getCoin s'`.
1818
Recall (from `Ledger.lagda.md`) that `getCoin (LedgerState)` is
1919

2020
getCoin (UTxOStateOf s)
21-
+ rewardsBalance (DStateOf (CertStateOf s))
21+
+ coinFromRewards (CertStateOf s)
2222
+ coinFromDeposits (CertStateOf s)
2323
+ coinFromGovDeposit (GovStateOf s)
2424

25-
This is the sum of UTxO coin, rewards balance, the deposits from `DState`, `PState`,
26-
and `GState` (`coinFromDeposits`{.AgdaFunction}), and the governance-action deposits
27-
(`coinFromGovDeposit`{.AgdaFunction}).
25+
This is the sum of UTxO coin, the cert-state rewards balance
26+
(`coinFromRewards`{.AgdaFunction}), the deposits from `DState`, `PState`, and `GState`
27+
(`coinFromDeposits`{.AgdaFunction}), and the governance-action deposits
28+
(`coinFromGovDeposit`{.AgdaFunction}). Note `getCoin (CertState)` itself now sums the
29+
rewards balance *and* the deposit pots (`coinFromRewards + coinFromDeposits`), so the
30+
two middle summands are exactly `getCoin (CertStateOf s)`.
2831

2932
> **Status — complete.** `LEDGER-pov` typechecks end-to-end under `--safe` (no
3033
> postulates or holes). Following the top-down plan, this module proves only the
@@ -206,7 +209,7 @@ module LEDGER-PoV
206209
-- Certs-PoV stubs (discharged later by #1210). These were the `Certs.Properties.PoV`
207210
-- provider lemmas; under the top-down plan they are module parameters here.
208211
( CERTS-pov : ∀ {Γ : CertEnv} {s s' : CertState} {dCerts : List DCert}
209-
→ Γ ⊢ s ⇀⦇ dCerts ,CERTS⦈ s' → getCoin s ≡ getCoin s' )
212+
→ Γ ⊢ s ⇀⦇ dCerts ,CERTS⦈ s' → coinFromRewards s ≡ coinFromRewards s' )
210213
-- Closed-form cert-deposit coin equation: the post-`CERTS` `CertState` has the same
211214
-- `coinFromDeposits` as the closed-form `updateCertDeposits` applied to the initial
212215
-- state and the cert list. (#1210 discharges this using the ledger-level
@@ -422,8 +425,8 @@ deposits.
422425
SUBLEDGERS-certs-pov : ∀ {Γ : SubLedgerEnv} {s₀ s₁ : LedgerState} {stxs : List SubLevelTx}
423426
→ SubLedgerEnv.isTopLevelValid Γ ≡ true
424427
→ Γ ⊢ s₀ ⇀⦇ stxs ,SUBLEDGERS⦈ s₁
425-
getCoin (CertStateOf s₀) + sum (map ddwl stxs)
426-
getCoin (CertStateOf s₁) + sum (map wdrwl stxs)
428+
coinFromRewards (CertStateOf s₀) + sum (map ddwl stxs)
429+
coinFromRewards (CertStateOf s₁) + sum (map wdrwl stxs)
427430
428431
SUBLEDGERS-certs-pov _ (BS-base Id-nop) = refl
429432
@@ -433,28 +436,28 @@ deposits.
433436
SUBLEDGERS-certs-pov {Γ} isV (BS-ind {s = s₀} {s' = s₁} {sigs} {s'' = sₙ}
434437
(SUBLEDGER-V {stx = stx} (isV' , subutxowStep , entitiesStep , _)) rest) =
435438
begin
436-
getCoin (CertStateOf s₀) + (getCoin (DirectDepositsOf stx) + sum (map ddwl sigs))
437-
≡⟨ sym (+-assoc (getCoin (CertStateOf s₀))
439+
coinFromRewards (CertStateOf s₀) + (getCoin (DirectDepositsOf stx) + sum (map ddwl sigs))
440+
≡⟨ sym (+-assoc (coinFromRewards (CertStateOf s₀))
438441
(getCoin (DirectDepositsOf stx))
439442
(sum (map ddwl sigs))) ⟩
440-
(getCoin (CertStateOf s₀) + getCoin (DirectDepositsOf stx)) + sum (map ddwl sigs)
443+
(coinFromRewards (CertStateOf s₀) + getCoin (DirectDepositsOf stx)) + sum (map ddwl sigs)
441444
≡⟨ cong (_+ sum (map ddwl sigs))
442445
(ENTITIES-pov wd-netId dd-netId entitiesStep) ⟩
443-
(getCoin (CertStateOf s₁) + getCoin (WithdrawalsOf stx)) + sum (map ddwl sigs)
444-
≡⟨ swap-right (getCoin (CertStateOf s₁))
446+
(coinFromRewards (CertStateOf s₁) + getCoin (WithdrawalsOf stx)) + sum (map ddwl sigs)
447+
≡⟨ swap-right (coinFromRewards (CertStateOf s₁))
445448
(getCoin (WithdrawalsOf stx))
446449
(sum (map ddwl sigs)) ⟩
447-
(getCoin (CertStateOf s₁) + sum (map ddwl sigs)) + getCoin (WithdrawalsOf stx)
450+
(coinFromRewards (CertStateOf s₁) + sum (map ddwl sigs)) + getCoin (WithdrawalsOf stx)
448451
≡⟨ cong (_+ getCoin (WithdrawalsOf stx)) ih ⟩
449-
(getCoin (CertStateOf sₙ) + sum (map wdrwl sigs)) + getCoin (WithdrawalsOf stx)
450-
≡⟨ swap-right (getCoin (CertStateOf sₙ))
452+
(coinFromRewards (CertStateOf sₙ) + sum (map wdrwl sigs)) + getCoin (WithdrawalsOf stx)
453+
≡⟨ swap-right (coinFromRewards (CertStateOf sₙ))
451454
(sum (map wdrwl sigs))
452455
(getCoin (WithdrawalsOf stx)) ⟩
453-
(getCoin (CertStateOf sₙ) + getCoin (WithdrawalsOf stx)) + sum (map wdrwl sigs)
454-
≡⟨ +-assoc (getCoin (CertStateOf sₙ))
456+
(coinFromRewards (CertStateOf sₙ) + getCoin (WithdrawalsOf stx)) + sum (map wdrwl sigs)
457+
≡⟨ +-assoc (coinFromRewards (CertStateOf sₙ))
455458
(getCoin (WithdrawalsOf stx))
456459
(sum (map wdrwl sigs)) ⟩
457-
getCoin (CertStateOf sₙ) + (getCoin (WithdrawalsOf stx) + sum (map wdrwl sigs))
460+
coinFromRewards (CertStateOf sₙ) + (getCoin (WithdrawalsOf stx) + sum (map wdrwl sigs))
458461
459462
where
460463
-- The two NetworkId witnesses, extracted from the SUBUTXOW step.
@@ -477,8 +480,8 @@ deposits.
477480
wd-netId = proj₁ netIds
478481
dd-netId = proj₂ netIds
479482
480-
ih : getCoin (CertStateOf s₁) + sum (map ddwl sigs)
481-
getCoin (CertStateOf sₙ) + sum (map wdrwl sigs)
483+
ih : coinFromRewards (CertStateOf s₁) + sum (map ddwl sigs)
484+
coinFromRewards (CertStateOf sₙ) + sum (map wdrwl sigs)
482485
ih = SUBLEDGERS-certs-pov isV rest
483486
```
484487

@@ -557,15 +560,15 @@ are unchanged. Only the `UTXOW` step affects `getCoin`, and it preserves it via
557560

558561
```agda
559562
LEDGER-pov {Γ} {s} (LEDGER-I (invalid , _ , utxoStep)) =
560-
cong (λ u → u + getCoin (CertStateOf s) + coinFromDeposits (CertStateOf s)
563+
cong (λ u → u + coinFromRewards (CertStateOf s) + coinFromDeposits (CertStateOf s)
561564
+ coinFromGovDeposit (GovStateOf s))
562565
(utxow-pov-invalid utxoStep invalid)
563566
```
564567

565568
### `LEDGER-V` case (valid transaction)
566569

567570
The proof is a single equational chain over `LedgerState` coin totals. Setting
568-
`U = getCoin (UTxOState)`, `R = rewardsBalance`, `D = coinFromDeposits`,
571+
`U = getCoin (UTxOState)`, `R = coinFromRewards`, `D = coinFromDeposits`,
569572
`G = coinFromGovDeposit`, and `allDirectDeps` / `allWdrls` for the top-level and
570573
sub-level totals of direct deposits and withdrawals respectively, the goal
571574
`getCoin s ≡ getCoin s'` is
@@ -626,8 +629,8 @@ are stated explicitly to keep the chain readable.
626629
D₂ = coinFromDeposits cs₂
627630
628631
R₀ R₂ : Coin
629-
R₀ = rewardsBalance (DStateOf (CertStateOf s))
630-
R₂ = rewardsBalance (DStateOf cs₂)
632+
R₀ = coinFromRewards (CertStateOf s)
633+
R₂ = coinFromRewards cs₂
631634
632635
-- Governance-deposit summands of the LedgerState totals. G₀ is the initial
633636
-- GovState's deposit; G' is the final state's (`rmOrphanDRepVotes cs₂ govSt₂`),
@@ -708,27 +711,27 @@ The "combined" `ENTITIES-pov` invocation: pre-batch `certState` + all direct dep
708711
key step where direct deposits cancel between the UTxO and CertState sides of the ledger.
709712

710713
```agda
711-
combined-certs : getCoin (CertStateOf s) + allDirectDeps
712-
getCoin cs₂ + allWdrls
714+
combined-certs : coinFromRewards (CertStateOf s) + allDirectDeps
715+
coinFromRewards cs₂ + allWdrls
713716
combined-certs =
714717
begin
715-
getCoin (CertStateOf s) + allDirectDeps
716-
≡⟨ cong (getCoin (CertStateOf s) +_)
718+
coinFromRewards (CertStateOf s) + allDirectDeps
719+
≡⟨ cong (coinFromRewards (CertStateOf s) +_)
717720
(+-comm (getCoin (DirectDepositsOf tx)) subDirectDepsCoin) ⟩
718-
getCoin (CertStateOf s) + (subDirectDepsCoin + getCoin (DirectDepositsOf tx))
719-
≡⟨ sym (+-assoc (getCoin (CertStateOf s))
721+
coinFromRewards (CertStateOf s) + (subDirectDepsCoin + getCoin (DirectDepositsOf tx))
722+
≡⟨ sym (+-assoc (coinFromRewards (CertStateOf s))
720723
subDirectDepsCoin
721724
(getCoin (DirectDepositsOf tx))) ⟩
722-
getCoin (CertStateOf s) + subDirectDepsCoin + getCoin (DirectDepositsOf tx)
725+
coinFromRewards (CertStateOf s) + subDirectDepsCoin + getCoin (DirectDepositsOf tx)
723726
≡⟨ cong (_+ getCoin (DirectDepositsOf tx))
724727
(SUBLEDGERS-certs-pov valid subStep) ⟩
725-
getCoin cs₁ + subWdrlsCoin + getCoin (DirectDepositsOf tx)
726-
≡⟨ swap-right (getCoin cs₁) subWdrlsCoin (getCoin (DirectDepositsOf tx)) ⟩
727-
getCoin cs₁ + getCoin (DirectDepositsOf tx) + subWdrlsCoin
728+
coinFromRewards cs₁ + subWdrlsCoin + getCoin (DirectDepositsOf tx)
729+
≡⟨ swap-right (coinFromRewards cs₁) subWdrlsCoin (getCoin (DirectDepositsOf tx)) ⟩
730+
coinFromRewards cs₁ + getCoin (DirectDepositsOf tx) + subWdrlsCoin
728731
≡⟨ cong (_+ subWdrlsCoin) (ENTITIES-pov top-wd-netId top-dd-netId entitiesStep) ⟩
729-
getCoin cs₂ + getCoin (WithdrawalsOf tx) + subWdrlsCoin
730-
≡⟨ +-assoc (getCoin cs₂) (getCoin (WithdrawalsOf tx)) subWdrlsCoin ⟩
731-
getCoin cs₂ + (getCoin (WithdrawalsOf tx) + subWdrlsCoin)
732+
coinFromRewards cs₂ + getCoin (WithdrawalsOf tx) + subWdrlsCoin
733+
≡⟨ +-assoc (coinFromRewards cs₂) (getCoin (WithdrawalsOf tx)) subWdrlsCoin ⟩
734+
coinFromRewards cs₂ + (getCoin (WithdrawalsOf tx) + subWdrlsCoin)
732735
733736
```
734737

0 commit comments

Comments
 (0)