Skip to content

Commit 042fe31

Browse files
committed
Add Certs PoV: per-step ≡ᵐᵗ + coin bridges, RTC lift
New modules under src/Ledger/Dijkstra/Specification/Certs/Properties/: + PoVLemmas.lagda.md (CERT-level) + PoV.lagda.md (CERTS-level) PoVLemmas exports: + CERT-pov: preservation of value at one CERT step + CERT-pots-≡ᵐᵗ: per-step ≡ᵐ-componentwise triple bridge + CERT-coinFromDeposits-step: per-step coin bridge (derived) + Triple machinery: pots, coinFromDeposits-pots, updateCertDeposit-list, pots-updateCertDeposits + PoolDepositsAligned, Is-just-isPoolRegistered⇒∈-dom PoV exports a bundled Certs-PoV module parameterised by indexedSumᵛ'-∪ and PoolDepositsAligned-CERT, providing: + CERTS-pov: preservation across the closure + CERTS-Deposits-Bridge.CERTS-coinFromDeposits-updateCertDeposits: the closed-form coin bridge consumed by LEDGER-pov The triple-form per-step bridge from the previous Ledger-PoV branch required a deferred propositional equation m ∪ˡ ❴ k , v ❵ ≡ m (when k ∈ dom m). This PR drops that parameter, using instead the upstream ≡ᵐ-componentwise singleton-∈-∪ˡ plumbed through the closed form via ∪⁺-cong-r, ∪ˡ-cong, restrict-cong, and collapsed to a coin equality via ≡ᵉ-getCoin. Refs #1185
1 parent 88e39f3 commit 042fe31

3 files changed

Lines changed: 773 additions & 0 deletions

File tree

Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
---
2+
source_branch: master
3+
source_path: src/Ledger/Dijkstra/Specification/Certs/Properties/PoV.lagda.md
4+
---
5+
# The Preservation-of-Value Property for `CERTS`{.AgdaDatatype}
6+
7+
This module lifts the per-step results from `Certs.Properties.PoVLemmas`{.AgdaModule}
8+
across the reflexive-transitive closure `CERTS`{.AgdaDatatype} of `CERT`{.AgdaDatatype}.
9+
It exports two theorems consumed by `LEDGER-pov`{.AgdaFunction} in
10+
`Ledger.Properties.PoV`{.AgdaModule}:
11+
12+
+ **Preservation of value** (`CERTS-pov`{.AgdaFunction}): iterating
13+
`CERT`{.AgdaDatatype} over a list of certificates preserves `getCoin`{.AgdaField}
14+
of the `CertState`{.AgdaRecord}.
15+
+ **The closed-form deposit-coin bridge**
16+
(`CERTS-coinFromDeposits-updateCertDeposits`{.AgdaFunction}): after a
17+
`CERTS`{.AgdaDatatype} run, the post-state's deposit coin matches the coin of the
18+
**closed-form** `updateCertDeposits`{.AgdaFunction} applied to the pre-state and
19+
the certificate list; this is the bridge that lets `LEDGER-pov`{.AgdaFunction}
20+
relate the actual `CertState` deposit-evolution to the
21+
`newCertDeposits`{.AgdaFunction} / `refundCertDeposits`{.AgdaFunction} quantities
22+
appearing in the UTXO batch-balance equation (see the
23+
*Cert-State Threading and Deposit Accounting* design note in `Utxo`{.AgdaModule}).
24+
25+
## Module structure
26+
27+
Both theorems are bundled under a single named module `Certs-PoV`{.AgdaModule}
28+
parameterised by one deferred assumption:
29+
30+
+ `PoolDepositsAligned-CERT`{.AgdaBound}: preservation of the pool-deposit-alignment
31+
invariant under one `CERT`{.AgdaDatatype} step; consumed by the inductive step of
32+
`CERTS-pots-≡ᵐᵗ`{.AgdaFunction} to keep the alignment hypothesis
33+
available across the trace. Discharged at the `CHAIN`-invariant
34+
layer in a follow-up issue.
35+
36+
`CERT-pov`{.AgdaFunction} (the per-step preservation-of-value lemma) is now imported
37+
directly from `Certs.Properties.PoVLemmas`{.AgdaModule}; it no longer needs to be
38+
opened from a nested helper module.
39+
40+
## A note on explicit-everywhere call sites
41+
42+
Every cross-lemma call in this module passes its implicit arguments explicitly,
43+
including the implicit triples of `≡ᵐᵗ-refl`{.AgdaFunction},
44+
`≡ᵐᵗ-trans`{.AgdaFunction}, `coinFromDeposits-pots-cong`{.AgdaFunction},
45+
`CERT-pots-≡ᵐᵗ`{.AgdaFunction}, and the explicit `cs` argument of
46+
`updateCertDeposit-list-≡ᵐᵗ`{.AgdaFunction}. This is the same hygiene principle
47+
documented in `Certs.Properties.PoVLemmas`{.AgdaModule}: unification through
48+
`_≡ᵐ_`{.AgdaFunction} only constrains the relation projection of the `Map` Σ,
49+
so leaving any implicit `Map` or implicit `Triple` to be inferred via a
50+
`_≡ᵐ_`-typed hypothesis leaves its `left-unique`{.AgdaFunction} field as an
51+
unresolved meta. Passing the implicits explicitly pins both projections.
52+
53+
<!--
54+
```agda
55+
{-# OPTIONS --safe #-}
56+
57+
open import Ledger.Dijkstra.Specification.Gov.Base using (GovStructure)
58+
59+
module Ledger.Dijkstra.Specification.Certs.Properties.PoV
60+
(gs : GovStructure) (open GovStructure gs) where
61+
62+
open import Ledger.Prelude
63+
open import Ledger.Dijkstra.Specification.Certs gs
64+
open import Ledger.Dijkstra.Specification.Certs.Properties.PoVLemmas gs
65+
open import Ledger.Dijkstra.Specification.Gov.Actions gs hiding (yes; no)
66+
67+
open import Interface.STS using (BS-base; BS-ind; Id-nop)
68+
69+
open import Algebra using (CommutativeMonoid)
70+
open import Data.Nat.Properties using (+-0-monoid)
71+
72+
open CertState
73+
74+
private variable
75+
dCert : DCert
76+
cs : List DCert
77+
78+
instance
79+
_ = +-0-monoid
80+
```
81+
-->
82+
83+
## The bundled `Certs-PoV` module {#sec:certs-pov-module}
84+
85+
```agda
86+
module Certs-PoV
87+
( PoolDepositsAligned-CERT :
88+
∀ {Γ : CertEnv} {s s' : CertState} {c : DCert}
89+
→ Γ ⊢ s ⇀⦇ c ,CERT⦈ s'
90+
→ PoolDepositsAligned (PStateOf s)
91+
→ PoolDepositsAligned (PStateOf s') )
92+
where
93+
```
94+
95+
## `CERTS-pov` — preservation of value across the closure {#sec:CERTS-pov}
96+
97+
*Informally*. Let `s , s'` : `CertState`{.AgdaRecord} be related by a
98+
`CERTS`{.AgdaDatatype} step
99+
100+
Γ ⊢ s ⇀⦇cs,CERTS⦈ s'.
101+
102+
Then `getCoin s ≡ getCoin s'`.
103+
104+
*Proof*. By induction on the `BS-ind`{.AgdaInductiveConstructor} /
105+
`BS-base`{.AgdaInductiveConstructor} structure of the trace:
106+
107+
+ Base case `BS-base Id-nop`: the trace is empty, `s' = s`, and
108+
`refl`{.AgdaInductiveConstructor} suffices.
109+
+ Inductive case `BS-ind h h*`: chain `CERT-pov h` (preservation across
110+
one step) with the inductive hypothesis on `h*` (preservation across
111+
the remaining trace).
112+
113+
*Formally*.
114+
115+
```agda
116+
CERTS-pov : {Γ : CertEnv} {s s' : CertState}
117+
→ Γ ⊢ s ⇀⦇ cs ,CERTS⦈ s'
118+
→ getCoin s ≡ getCoin s'
119+
CERTS-pov (BS-base Id-nop) = refl
120+
CERTS-pov (BS-ind h h*) = trans (CERT-pov h) (CERTS-pov h*)
121+
```
122+
123+
## RTC-lifted `≡ᵐᵗ` bridge {#sec:CERTS-pots-eq}
124+
125+
We first lift the per-step `≡ᵐᵗ`{.AgdaFunction} bridge
126+
`CERT-pots-≡ᵐᵗ`{.AgdaFunction} across the trace. The result is an
127+
`≡ᵐᵗ`{.AgdaFunction}-statement comparing `pots s'`{.AgdaFunction}
128+
against `updateCertDeposit-list (PParamsOf Γ) (pots s) cs`{.AgdaFunction}
129+
— the iterated **triple-level** closed form.
130+
131+
*Informally*. Suppose the pool-deposit-alignment invariant holds at `s`,
132+
and `Γ ⊢ s ⇀⦇cs,CERTS⦈ s'`. Then
133+
134+
pots s' ≡ᵐᵗ updateCertDeposit-list (PParamsOf Γ) (pots s) cs.
135+
136+
*Proof*. Induction on `BS-ind`{.AgdaInductiveConstructor} /
137+
`BS-base`{.AgdaInductiveConstructor}:
138+
139+
+ `BS-base Id-nop`: trace empty; both sides reduce to `pots s`,
140+
discharged by `≡ᵐᵗ-refl (pots s)`{.AgdaFunction}. We pass the explicit
141+
triple `pots s` (rather than `_`) so the three `Map` Σ-fields are
142+
pinned at the call site.
143+
+ `BS-ind h h*` with intermediate state `smid`{.AgdaBound} and head/tail
144+
`c ∷ cs'` of the certificate list: chain three pieces via
145+
`≡ᵐᵗ-trans`{.AgdaFunction} with all three triples passed explicitly:
146+
147+
t₁ = pots s'
148+
t₂ = updateCertDeposit-list pp (pots smid) cs'
149+
t₃ = updateCertDeposit-list pp (updateCertDeposit pp c (pots s)) cs'
150+
151+
where `pp = PParamsOf Γ`. The first proof, IH on `h*`, gives
152+
`t₁ ≡ᵐᵗ t₂` (using `PoolDepositsAligned-CERT h plInv` to advance the
153+
invariant). The second proof,
154+
`updateCertDeposit-list-≡ᵐᵗ pp cs' (CERT-pots-≡ᵐᵗ … plInv h)`,
155+
gives `t₂ ≡ᵐᵗ t₃`. Note that `t₃` is definitionally equal to
156+
`updateCertDeposit-list pp (pots s) (c ∷ cs')` via `foldl`'s
157+
recurrence, so the chained equation matches the goal.
158+
**No deferred propositional map equation is required**, because
159+
everything happens at the `≡ᵐ`{.AgdaFunction} level.
160+
161+
*Formally*.
162+
163+
```agda
164+
module CERTS-Deposits-Bridge where
165+
CERTS-pots-≡ᵐᵗ : ∀ {Γ : CertEnv} {s s' : CertState} {cs : List DCert}
166+
→ PoolDepositsAligned (PStateOf s)
167+
→ Γ ⊢ s ⇀⦇ cs ,CERTS⦈ s'
168+
→ pots s' ≡ᵐᵗ updateCertDeposit-list (PParamsOf Γ) (pots s) cs
169+
CERTS-pots-≡ᵐᵗ {s = s} _ (BS-base Id-nop) = ≡ᵐᵗ-refl (pots s)
170+
CERTS-pots-≡ᵐᵗ {Γ = Γ} {s = s} {s'} plInv (BS-ind {sig = c} {s' = smid} {sigs = cs'} h h*) =
171+
-- All three triples passed explicitly to `≡ᵐᵗ-trans`; without this,
172+
-- Agda creates fresh `Triple` metas whose component `Map`s have
173+
-- unresolved `left-unique` Σ-fields. Similarly we pass `cs'`
174+
-- explicitly to `updateCertDeposit-list-≡ᵐᵗ` (whose `cs` argument
175+
-- is explicit) and the implicit `{Γ}` `{s}` `{s'}` `{cs}` `{dCert}`
176+
-- to every recursive / cross-lemma call.
177+
let pp = PParamsOf Γ
178+
t₁ = pots s'
179+
t₂ = updateCertDeposit-list pp (pots smid) cs'
180+
t₃ = updateCertDeposit-list pp (updateCertDeposit pp c (pots s)) cs'
181+
eq₁ : t₁ ≡ᵐᵗ t₂
182+
eq₁ = CERTS-pots-≡ᵐᵗ {Γ = Γ} {s = smid} {s' = s'} {cs = cs'}
183+
(PoolDepositsAligned-CERT h plInv) h*
184+
eq₂ : t₂ ≡ᵐᵗ t₃
185+
eq₂ = updateCertDeposit-list-≡ᵐᵗ pp cs'
186+
{t = pots smid} {t' = updateCertDeposit pp c (pots s)}
187+
(CERT-pots-≡ᵐᵗ {dCert = c} {Γ = Γ} {s = s} {s' = smid} plInv h)
188+
in ≡ᵐᵗ-trans t₁ t₂ t₃ eq₁ eq₂
189+
```
190+
191+
## `CERTS-coinFromDeposits-list` — coin form, triple shape {#sec:CERTS-coinFromDeposits-list}
192+
193+
Collapse `CERTS-pots-≡ᵐᵗ`{.AgdaFunction} to a coin equality via
194+
`coinFromDeposits-pots-cong`{.AgdaFunction}. This is the intermediate
195+
lemma; the final exported form (next subsection) bridges to the
196+
`CertState`{.AgdaRecord}-valued closed form
197+
`updateCertDeposits`{.AgdaFunction}.
198+
199+
The two implicit triples of `coinFromDeposits-pots-cong`{.AgdaFunction} are
200+
passed explicitly — mirroring the hygiene applied in
201+
`Certs.Properties.PoVLemmas.CERT-coinFromDeposits-step`{.AgdaFunction}.
202+
203+
```agda
204+
CERTS-coinFromDeposits-list : ∀ {Γ : CertEnv} {s s' : CertState} {cs : List DCert}
205+
→ PoolDepositsAligned (PStateOf s)
206+
→ Γ ⊢ s ⇀⦇ cs ,CERTS⦈ s'
207+
→ coinFromDeposits s'
208+
≡ coinFromDeposits-pots (updateCertDeposit-list (PParamsOf Γ) (pots s) cs)
209+
CERTS-coinFromDeposits-list {Γ = Γ} {s = s} {s' = s'} {cs = cs} plInv h =
210+
coinFromDeposits-pots-cong
211+
{t = pots s'}
212+
{t' = updateCertDeposit-list (PParamsOf Γ) (pots s) cs}
213+
(CERTS-pots-≡ᵐᵗ {Γ = Γ} {s = s} {s' = s'} {cs = cs} plInv h)
214+
```
215+
216+
## `CERTS-coinFromDeposits-updateCertDeposits` — the `LEDGER-pov` interface {#sec:CERTS-coinFromDeposits-updateCertDeposits}
217+
218+
The form `LEDGER-pov`{.AgdaFunction} actually consumes: a coin equality
219+
between the actual post-`CERTS`{.AgdaDatatype} state's
220+
`coinFromDeposits`{.AgdaFunction} and the **`CertState`-valued** closed
221+
form `updateCertDeposits`{.AgdaFunction}. Both quantities appear in
222+
`newCertDeposits`{.AgdaFunction} / `refundCertDeposits`{.AgdaFunction} in
223+
`Ledger.Dijkstra.Specification.Certs`{.AgdaModule}.
224+
225+
*Informally*. Under the same hypotheses,
226+
227+
coinFromDeposits s' ≡ coinFromDeposits (updateCertDeposits (PParamsOf Γ) s cs).
228+
229+
*Proof*. Chain `CERTS-coinFromDeposits-list`{.AgdaFunction} (giving the
230+
RHS in terms of `updateCertDeposit-list`{.AgdaFunction}, the
231+
triple-valued closed form) with the **propositional** bridge
232+
`pots-updateCertDeposits`{.AgdaFunction}, which says
233+
234+
pots (updateCertDeposits pp s cs) ≡ updateCertDeposit-list pp (pots s) cs.
235+
236+
Since
237+
238+
coinFromDeposits cs ≡ coinFromDeposits-pots (pots cs)
239+
240+
holds definitionally, applying `cong coinFromDeposits-pots`{.AgdaFunction}
241+
to `pots-updateCertDeposits`{.AgdaFunction} closes the chain.
242+
243+
*Formally*.
244+
245+
```agda
246+
CERTS-coinFromDeposits-updateCertDeposits :
247+
∀ {Γ : CertEnv} {s s' : CertState} {cs : List DCert}
248+
→ PoolDepositsAligned (PStateOf s)
249+
→ Γ ⊢ s ⇀⦇ cs ,CERTS⦈ s'
250+
→ coinFromDeposits s'
251+
≡ coinFromDeposits (updateCertDeposits (PParamsOf Γ) s cs)
252+
CERTS-coinFromDeposits-updateCertDeposits
253+
{Γ = Γ} {s = s} {s' = s'} {cs = cs} plInv h =
254+
trans
255+
(CERTS-coinFromDeposits-list {Γ = Γ} {s = s} {s' = s'} {cs = cs} plInv h)
256+
( sym (cong coinFromDeposits-pots
257+
(pots-updateCertDeposits (PParamsOf Γ) s cs)) )
258+
```
259+
260+
The right-hand side of the `sym (cong …)` step is
261+
`coinFromDeposits-pots (pots (updateCertDeposits (PParamsOf Γ) s cs))`,
262+
which is definitionally `coinFromDeposits (updateCertDeposits (PParamsOf Γ) s cs)`
263+
by the definitions of `coinFromDeposits`{.AgdaFunction} and
264+
`coinFromDeposits-pots`{.AgdaFunction}.

0 commit comments

Comments
 (0)