Skip to content

Commit 164f116

Browse files
committed
[Dijkstra] Restate CERTS PoV contract at full accounting; derive the batch bridge
Per review: the Certs-level parameters now state the complete value accounting of a CERTS run, and the ENTITIES PoV module surfaces it per transaction: - CERTS-rewards-pov (rewards preserved), CERTS-deposits-pov (closed-form deposit accounting D + new ≡ D' + refunds), CERTS-deposits-registered (invariant preservation), CERTS-new-thread (newCertDeposits split at a run boundary), refundCertDeposits-++ (fold algebra). - Entities.Properties.PoV adds SUBENTITIES/ENTITIES-deposits-pov, -deposits-registered, SUBENTITIES-new-thread (all definitional transports of the CERTS facts), and the combined full-CertState-coin identities SUBENTITIES/ENTITIES-pov-total: coin in + direct deposits + new deposits ≡ coin out + withdrawals + refunds. - Ledger.Properties.PoV now *derives* the batch-wide deposit accounting (SUBLEDGERS-deposits, telescoping per-step closed forms across the batch, with SUBLEDGERS-registered threading the invariant and refund-concatMap recombining refunds); the batch-cert-deposits-bridge parameter is gone. Its premises mentioned SUBLEDGERS, so it was not statable at the Certs level anyway. Restating the per-run accounting exposed a genuine soundness condition: POOL-reg adds its deposit with a left-biased union, so at a state with a stale pot entry for an unregistered pool, registering that pool destroys the deposit the batch balance charges, and value preservation is false. New PoolDepositsRegistered invariant in Certs (every pool-deposit entry belongs to a registered pool; preserved by CERTS, holds on-chain by construction); LEDGER-pov now takes it as a hypothesis on the initial state. The old bridge parameter silently baked in the same assumption and would have been undischargeable as stated. Also apply the review's prose policy: status/roadmap/issue-number prose moved from module documentation to the PR description; explanations deduplicated across modules (stated once, referenced elsewhere). Final touches: + general improvements + remove unnecessary CHANGELOG entry + add mkdocs nav entries AI-assisted: Claude Fable 5 (Anthropic)
1 parent 16c1142 commit 164f116

8 files changed

Lines changed: 474 additions & 217 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,9 @@
44

55
### WIP
66

7-
- Prove preservation of value for the `LEDGER` rule (`LEDGER-pov`, #1187), in new module
8-
`Ledger.Properties.PoV`. Supporting modules: `Entities.Properties.PoV`
9-
(`ENTITIES-pov`, `SUBENTITIES-pov`) and `Entities.Properties.ApplyToRewardsPoV`
10-
(`applyWithdrawals-pov`, `applyDirectDeposits-pov`). The supporting UTxO, Certs, and
11-
Gov facts are module parameters, to be discharged by #1186, #1210, and a future
12-
`Gov.Properties.PoV`.
7+
- Add `PoolDepositsRegistered` (every pool-deposit entry belongs to a registered
8+
pool) to `Certs`; the deposit accounting genuinely fails without it, since
9+
`POOL-reg` adds its deposit with a left-biased union.
1310
- Count governance-action deposits in `getCoin LedgerState` via a new
1411
`coinFromGovDeposit : GovState → Coin` (sum of `GovActionState.deposit`). These
1512
deposits live in `GovActionState.deposit`, not `GState.deposits`, so the three

build-tools/static/mkdocs/mkdocs.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,9 @@ nav:
241241
- Entities/:
242242
- Properties: Ledger.Dijkstra.Specification.Entities.Properties.md
243243
- Properties/:
244+
- ApplyToRewardsPoV: Ledger.Dijkstra.Specification.Entities.Properties.ApplyToRewardsPoV.md
244245
- Computational: Ledger.Dijkstra.Specification.Entities.Properties.Computational.md
246+
- PoV: Ledger.Dijkstra.Specification.Entities.Properties.PoV.md
245247
- Epoch: Ledger.Dijkstra.Specification.Epoch.md
246248
- Epoch/:
247249
- Properties: Ledger.Dijkstra.Specification.Epoch.Properties.md
@@ -260,6 +262,7 @@ nav:
260262
- Properties: Ledger.Dijkstra.Specification.Ledger.Properties.md
261263
- Properties/:
262264
- Computational: Ledger.Dijkstra.Specification.Ledger.Properties.Computational.md
265+
- PoV: Ledger.Dijkstra.Specification.Ledger.Properties.PoV.md
263266
- PoolReap: Ledger.Dijkstra.Specification.PoolReap.md
264267
- PoolReap/:
265268
- Properties: Ledger.Dijkstra.Specification.PoolReap.Properties.md

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,18 @@ coinFromDeposits cs =
380380
getCoin (DepositsOf (DStateOf cs)) + getCoin (DepositsOf (PStateOf cs)) + getCoin (DepositsOf (GStateOf cs))
381381
```
382382

383+
A `CertState`{.AgdaRecord} is *pool-deposit registered* when every entry of the pool
384+
deposit pot belongs to a registered pool. Deposit accounting relies on this:
385+
`POOL-reg`{.AgdaInductiveConstructor} adds the pool deposit with a left-biased union,
386+
so a stale pot entry for an unregistered pool would silently swallow the added
387+
deposit. The property is preserved by `CERTS`{.AgdaDatatype} (both maps gain exactly
388+
the new pool's key, and no rule removes a pool without its deposit).
389+
390+
```agda
391+
PoolDepositsRegistered : CertState → Type
392+
PoolDepositsRegistered cs = dom (DepositsOf (PStateOf cs)) ⊆ dom (PoolsOf cs)
393+
```
394+
383395
<!--
384396
```agda
385397
instance

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

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ open PParams
2222
```
2323
-->
2424

25-
# Auxiliary Types and Functions
25+
## Auxiliary Types and Functions
2626

2727
```agda
2828
record EntitiesEnv : Type where
@@ -89,7 +89,7 @@ applyWithdrawals : Withdrawals → Rewards → Rewards
8989
applyWithdrawals = applyToRewards _∸_
9090
```
9191

92-
# `ENTITIES`{.AgdaDatatype} Transition System
92+
## `ENTITIES`{.AgdaDatatype} Transition System
9393

9494
In Dijkstra, the new `ENTITIES`{.AgdaDatatype} rule subsumes the
9595
pre-Dijkstra `CERTS`{.AgdaDatatype} rule. This rule in addition to
@@ -101,7 +101,7 @@ and `balanceIntervals`. Direct deposits represent value that flows
101101
from the transaction into account addresses. Balance intervals enable
102102
transactions to assert predicates about account balances.
103103

104-
## Withdrawals
104+
### Withdrawals
105105

106106
The `ENTITIES`{.AgdaDatatype} rule applies withdrawals, via
107107
`applyWithdrawals`{.AgdaFunction} before certificate evaluation. In
@@ -111,7 +111,7 @@ rule (via `isLegacyMode`{.AgdaFunction}, defined in the
111111
`Utxow`{.AgdaModule} module) and provided here through the
112112
`legacyMode`{.AgdaField} field of `EntitiesEnv`{.AgdaRecord}.
113113

114-
## Direct Deposits
114+
### Direct Deposits
115115

116116
The `ENTITIES`{.AgdaDatatype} rule applies direct deposits to the
117117
`CertState`{.AgdaRecord} after `CERTS`{.AgdaDatatype}.
@@ -168,9 +168,7 @@ data _⊢_⇀⦇_,SUBENTITIES⦈_ : SubEntitiesEnv → CertState → SubLevelTx
168168
∙ directDepositsCredentials ⊆ dom rewards'
169169
────────────────────────────────
170170
⟦ e , pp , cc , rewards₀ ⟧ ⊢ ⟦ ⟦ voteDelegs , stakeDelegs , rewards , depositsᵈ ⟧ , pState , ⟦ dReps , ccHotKeys , depositsᵍ ⟧ ⟧ ⇀⦇ txSub ,SUBENTITIES⦈ ⟦ ⟦ voteDelegs' , stakeDelegs' , applyDirectDeposits directDeposits rewards' , depositsᵈ' ⟧ , pState' , gState' ⟧
171-
```
172171
173-
```agda
174172
data _⊢_⇀⦇_,ENTITIES⦈_ : EntitiesEnv → CertState → TopLevelTx → CertState → Type where
175173
176174
ENTITIES :

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

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,22 @@ source_branch: master
33
source_path: src/Ledger/Dijkstra/Specification/Entities/Properties/ApplyToRewardsPoV.lagda.md
44
---
55

6-
## `applyToRewards` Preservation of Value {#sec:apply-to-rewards-pov}
6+
# <span class="AgdaFunction">applyToRewards</span> Preservation of Value {#sec:apply-to-rewards-pov}
77

88
This module proves preservation of value for the two specializations of
99
`applyToRewards`{.AgdaFunction} used inside the `ENTITIES`{.AgdaDatatype} rule.
1010

1111
+ `applyWithdrawals-pov`{.AgdaFunction}.
1212

13-
`applyWithdrawals`{.AgdaFunction} *decreases* the total rewards balance by exactly
13+
`applyWithdrawals`{.AgdaFunction} decreases the total rewards balance by exactly
1414
the sum of withdrawal amounts. Truncating subtraction (`_∸_`) means the per-step
1515
lemma requires `amt ≤ bal`, and the fold induction requires a
1616
`Unique`{.AgdaDatatype} witness on the stake-projected withdrawal list so that no
1717
already-reduced balance is revisited.
1818

1919
+ `applyDirectDeposits-pov`{.AgdaFunction}.
2020

21-
`applyDirectDeposits`{.AgdaFunction} *increases* the total rewards balance by
21+
`applyDirectDeposits`{.AgdaFunction} increases the total rewards balance by
2222
exactly the sum of direct-deposit amounts. Because `_+_` is total and
2323
commutative, revisiting a credential is harmless, so neither the
2424
`NetworkId`{.AgdaFunction} witness nor the `Unique`{.AgdaDatatype} premise is
@@ -27,7 +27,7 @@ This module proves preservation of value for the two specializations of
2727
Both lemmas share a common backbone: a per-step result about
2828
`applyOne`{.AgdaFunction} (the lambda body of `applyToRewards`{.AgdaFunction})
2929
together with a `foldl`-induction lemma over `setToList (m ˢ)`. They are consumed
30-
directly by `ENTITIES-pov`{.AgdaFunction} in `Entities.Properties.PoV`.
30+
directly by `ENTITIES-pov`{.AgdaFunction} in `Entities.Properties.PoV`{.AgdaModule}.
3131

3232
<!--
3333
```agda
@@ -60,7 +60,7 @@ open ≡-Reasoning
6060
```
6161
-->
6262

63-
### Shared helpers
63+
## Shared helpers
6464

6565
```agda
6666
getCoin-∪ˡ-overwrite : (acc : Rewards) (c : Credential) (v : Coin)
@@ -139,11 +139,10 @@ split-by-lookup acc c bal lookup-eq =
139139
```
140140
-->
141141

142-
### The `ApplyToRewards-PoV` module
142+
## The <span class="AgdaModule">ApplyToRewards-PoV</span> module
143143

144144
The three assumed identities below are the same set/map identities used by the Conway
145-
PoV proofs; they are stated as module parameters here, to be discharged in a
146-
follow-up against the `agda-sets` library.
145+
PoV proofs; they are stated as module parameters here.
147146

148147
+ `∪ˡ-lookup-preserve`: lookup in a left-biased union with a singleton at `c` agrees
149148
with lookup in the right map for any key `c' ≠ c`.
@@ -223,8 +222,8 @@ The fold invariant tracks three things through the induction.
223222
3. No credential is revisited (the `Unique`{.AgdaDatatype} witness on the
224223
stake-projected list).
225224

226-
Uniqueness is essential here precisely because `applyOne _∸_` *modifies* the balance
227-
at the targeted credential without it, a re-visit could attempt to subtract from an
225+
Uniqueness is essential here precisely because `applyOne _∸_` modifies the balance
226+
at the targeted credential; without it, a re-visit could attempt to subtract from an
228227
already-reduced balance for which the caller's original `amt ≤ bal` bound no longer
229228
holds.
230229

@@ -291,7 +290,7 @@ holds.
291290
```
292291
-->
293292

294-
### `applyWithdrawals-pov`
293+
#### `applyWithdrawals-pov`
295294

296295
```agda
297296
applyWithdrawals-pov : (wdrls : Withdrawals) (rwds : Rewards)
@@ -328,9 +327,9 @@ holds.
328327
```
329328
-->
330329

331-
## Direct-deposit preservation of value
330+
### Direct-deposit preservation of value
332331

333-
### `applyOne-pov-add` (one direct-deposit step increases `getCoin` by `amt`)
332+
#### `applyOne-pov-add` (one direct-deposit step increases `getCoin` by `amt`)
334333

335334
For addition, no `amt ≤ bal` premise is needed (the operation is total),
336335
and the per-step equation is `getCoin (...) ≡ getCoin acc + amt`
@@ -361,10 +360,10 @@ balance.
361360
```
362361
-->
363362

364-
### `foldl-applyOne-pov-add` (fold induction, no `Unique` needed)
363+
#### `foldl-applyOne-pov-add` (fold induction, no `Unique` needed)
365364

366365
Unlike the withdrawal version, the additive fold induction needs only
367-
domain preservation the `Unique`{.AgdaDatatype} witness drops out.
366+
domain preservation; the `Unique`{.AgdaDatatype} witness drops out.
368367
The reason: `applyOne _+_` modifies the balance at the targeted
369368
credential, but since the per-step lemma `applyOne-pov-add` is
370369
unconditional on the prior balance and `_+_` is commutative, revisiting
@@ -406,7 +405,7 @@ the same credential simply accumulates additions correctly.
406405
```
407406
-->
408407

409-
### `applyDirectDeposits-pov`
408+
#### `applyDirectDeposits-pov`
410409

411410
Note the slimmed-down signature relative to `applyWithdrawals-pov`: no
412411
`NetworkId`{.AgdaFunction} premise (none is needed), no

0 commit comments

Comments
 (0)