@@ -58,6 +58,7 @@ open import Relation.Binary using (IsEquivalence)
5858open import Data.Nat.Properties using (n≤0⇒n≡0)
5959open RewardAddress
6060open Any
61+ open ≡-Reasoning
6162
6263private variable
6364 A : Type
@@ -98,7 +99,6 @@ getCoin-∪ˡ-overwrite acc c v =
9899 v + getCoin (acc ∣ ❴ c ❵ ᶜ)
99100 ∎
100101 where
101- open ≡-Reasoning
102102 open Equivalence
103103 module ≡ᵉ = IsEquivalence (≡ᵉ-isEquivalence {Credential × Coin})
104104 -- `res-decomp ❴ c , v ❵ᵐ acc` proves
@@ -115,7 +115,10 @@ getCoin-∪ˡ-overwrite acc c v =
115115 -- (`Map.agda`: `(x , _) ≡ᵐ (y , _) = x ≡ᵉ y`), so `res-comp-cong`
116116 -- (from `Axiom.Set.Rel`) lifts straight to the Map level.
117117 restrict-cong' : (❴ c , v ❵ᵐ ∪ˡ (acc ∣ dom (❴ c , v ❵ᵐ ˢ) ᶜ)) ˢ ≡ᵉ (❴ c , v ❵ᵐ ∪ˡ (acc ∣ ❴ c ❵ ᶜ)) ˢ
118- restrict-cong' = ∪ˡ-cong (≡ᵉ.refl {x = ❴ c , v ❵ᵐ ˢ}) (res-comp-cong dom-single≡single)
118+ restrict-cong' =
119+ ∪ˡ-cong {m = ❴ c , v ❵ᵐ} {m' = (acc ∣ dom (❴ c , v ❵ᵐ ˢ) ᶜ)}{m'' = ❴ c , v ❵ᵐ} {m''' = (acc ∣ ❴ c ❵ ᶜ)}
120+ (≡ᵉ.refl {x = ❴ c , v ❵ᵐ ˢ}) (res-comp-cong dom-single≡single)
121+ -- ∪ˡ-cong : ∀ {m m' m'' m''' : Map A B} → m ≡ᵐ m'' → m' ≡ᵐ m''' → (m ∪ˡ m') ≡ᵐ (m'' ∪ˡ m''')
119122
120123 bridge : (❴ c , v ❵ ∪ˡ acc) ˢ ≡ᵉ (❴ c , v ❵ ∪ˡ (acc ∣ ❴ c ❵ ᶜ)) ˢ
121124 bridge = ≡ᵉ.trans (res-decomp ❴ c , v ❵ᵐ acc) restrict-cong'
@@ -125,63 +128,80 @@ getCoin-∪ˡ-overwrite acc c v =
125128```
126129-->
127130
128- ### Single-step Lemma: ` applyOne ` decreases ` getCoin ` by ` amt `
131+ ### ` split-by-lookup ` : decompose ` getCoin acc ` along a known lookup result
129132
130- When ` stake addr ∈ dom acc ` and ` amt ≤ bal ` (where ` bal ` is the current balance),
131- applying a single withdrawal decreases the total by exactly ` amt ` .
133+ When ` lookupᵐ? acc c ≡ just bal ` , we can split ` getCoin acc ` into the
134+ contribution of ` c ` (which is ` bal ` ) plus the contribution of everything
135+ else (` acc ∣ ❴ c ❵ ᶜ ` ). This is the prefix shared by both ` applyOne-pov `
136+ and ` applyOne-pov-add ` ; factoring it out avoids duplicating the proof.
132137
133138``` agda
134- applyOne-pov :
135- (acc : Rewards) (addr : RewardAddress) (amt bal : Coin)
136- → lookupᵐ? acc (stake addr) ≡ just bal
137- → amt ≤ bal
138- → getCoin acc ≡ getCoin (❴ stake addr , bal ∸ amt ❵ ∪ˡ acc) + amt
139+ split-by-lookup : (acc : Rewards) (c : Credential) (bal : Coin)
140+ → lookupᵐ? acc c ≡ just bal
141+ → getCoin acc ≡ getCoin (acc ∣ ❴ c ❵ ᶜ) + bal
139142```
140143
141144<!--
142145```agda
143- applyOne-pov acc addr amt bal lookup-eq amt≤bal =
146+ split-by-lookup acc c bal lookup-eq =
144147 begin
145148 getCoin acc
146149 ≡˘⟨ ≡ᵉ-getCoin decomp acc
147- ( ≡ᵉ.trans (disjoint-∪ˡ-∪ (disjoint-sym res-ex-disjoint))
148- ( ≡ᵉ.trans ∪-sym (res-ex-∪ Dec-∈-singleton)) ) ⟩
150+ ( ≡ᵉ.trans (disjoint-∪ˡ-∪ (disjoint-sym res-ex-disjoint))
151+ ( ≡ᵉ.trans ∪-sym (res-ex-∪ Dec-∈-singleton)) ) ⟩
149152 getCoin decomp
150153 ≡⟨ indexedSumᵛ'-∪ (acc ∣ ❴ c ❵ ᶜ) (acc ∣ ❴ c ❵) (disjoint-sym res-ex-disjoint) ⟩
151154 getCoin (acc ∣ ❴ c ❵ ᶜ) + getCoin (acc ∣ ❴ c ❵)
152155 ≡⟨ cong (getCoin (acc ∣ ❴ c ❵ ᶜ) +_) acc∣c≡bal ⟩
153156 getCoin (acc ∣ ❴ c ❵ ᶜ) + bal
154- ≡⟨ cong (getCoin (acc ∣ ❴ c ❵ ᶜ) +_) (sym (m∸n+n≡m amt≤bal)) ⟩
155- getCoin (acc ∣ ❴ c ❵ ᶜ) + (bal ∸ amt + amt)
156- ≡⟨ trans (sym (+-assoc (getCoin (acc ∣ ❴ c ❵ ᶜ)) (bal ∸ amt) amt))
157- (cong (_+ amt) (+-comm (getCoin (acc ∣ ❴ c ❵ ᶜ)) (bal ∸ amt))) ⟩
158- (bal ∸ amt) + getCoin (acc ∣ ❴ c ❵ ᶜ) + amt
159- ≡˘⟨ cong (_+ amt) (getCoin-∪ˡ-overwrite acc c (bal ∸ amt)) ⟩
160- getCoin (❴ c , bal ∸ amt ❵ ∪ˡ acc) + amt
161157 ∎
162158 where
163159 module ≡ᵉ = IsEquivalence (≡ᵉ-isEquivalence {Credential × Coin})
164- open ≡-Reasoning
165160 open Equivalence
166-
167- c : Credential
168- c = stake addr
169-
170161 decomp : Credential ⇀ Coin
171162 decomp = (acc ∣ ❴ c ❵ ᶜ) ∪ˡ (acc ∣ ❴ c ❵)
172-
173163 c∈acc : (c , bal) ∈ acc ˢ
174164 c∈acc with c ∈? dom (acc ˢ)
175165 ... | yes c∈dom =
176166 subst (λ v → (c , v) ∈ acc ˢ) (just-injective lookup-eq) (lookupᵐ-∈ acc c c∈dom)
177167 ... | no c∉dom = case lookup-eq of λ ()
178-
179168 acc∣c≡bal : getCoin (acc ∣ ❴ c ❵) ≡ bal
180169 acc∣c≡bal =
181170 trans (getCoin-cong (acc ∣ ❴ c ❵) ❴ (c , bal) ❵ (res-singleton' {m = acc} c∈acc))
182171 getCoin-singleton
172+ ```
173+ -->
183174
184- -- `c∉dom-compl` and `disj-doms` removed: the bridge lemma encapsulates them.
175+
176+
177+ ### Single-step Lemma: ` applyOne ` decreases ` getCoin ` by ` amt `
178+
179+ When ` stake addr ∈ dom acc ` and ` amt ≤ bal ` (where ` bal ` is the current balance),
180+ applying a single withdrawal decreases the total by exactly ` amt ` .
181+
182+ ``` agda
183+ applyOne-pov :
184+ (acc : Rewards) (addr : RewardAddress) (amt bal : Coin)
185+ → lookupᵐ? acc (stake addr) ≡ just bal
186+ → amt ≤ bal
187+ → getCoin acc ≡ getCoin (❴ stake addr , bal ∸ amt ❵ ∪ˡ acc) + amt
188+ ```
189+
190+ <!--
191+ ```agda
192+ applyOne-pov acc addr amt bal lookup-eq amt≤bal = let c = stake addr in
193+ begin
194+ getCoin acc
195+ ≡⟨ split-by-lookup acc c bal lookup-eq ⟩
196+ getCoin (acc ∣ ❴ c ❵ ᶜ) + bal
197+ ≡⟨ cong (getCoin (acc ∣ ❴ c ❵ ᶜ) +_) (sym (m∸n+n≡m amt≤bal)) ⟩
198+ getCoin (acc ∣ ❴ c ❵ ᶜ) + (bal ∸ amt + amt)
199+ ≡⟨ trans (sym (+-assoc (getCoin (acc ∣ ❴ c ❵ ᶜ)) (bal ∸ amt) amt))
200+ (cong (_+ amt) (+-comm (getCoin (acc ∣ ❴ c ❵ ᶜ)) (bal ∸ amt))) ⟩
201+ (bal ∸ amt) + getCoin (acc ∣ ❴ c ❵ ᶜ) + amt
202+ ≡˘⟨ cong (_+ amt) (getCoin-∪ˡ-overwrite acc c (bal ∸ amt)) ⟩
203+ getCoin (❴ c , bal ∸ amt ❵ ∪ˡ acc) + amt
204+ ∎
185205```
186206-->
187207
@@ -218,9 +238,9 @@ module ApplyToRewards-PoV
218238
219239 -- TODO: ask that these be proved in the `agda-sets` library.
220240
221- -- 1. For any credential `c'` other than `c`, lookupᵐ? (❴ c , v ❵ ∪ˡ (m ∣ ❴ c ❵ ᶜ) ) c' ≡ lookupᵐ? m c'
222- ( ∪ˡ-res- lookup-preserve : (m : Rewards) (c : Credential) (v : Coin) (c' : Credential)
223- → c' ≢ c → lookupᵐ? (❴ c , v ❵ ∪ˡ (m ∣ ❴ c ❵ ᶜ) ) c' ≡ lookupᵐ? m c' )
241+ -- 1. For any credential `c'` other than `c`, lookupᵐ? (❴ c , v ❵ ∪ˡ m ) c' ≡ lookupᵐ? m c'
242+ ( ∪ˡ-lookup-preserve : (m : Rewards) (c : Credential) (v : Coin) (c' : Credential)
243+ → c' ≢ c → lookupᵐ? (❴ c , v ❵ ∪ˡ m ) c' ≡ lookupᵐ? m c' )
224244 -- It's hard because the `agda-sets` API requires instance resolution for
225245 -- `lookupᵐ?`, but the semantic content is clear (lookup in a left-biased union
226246 -- for a key not in the left map equals lookup in the right map, and complement
@@ -255,22 +275,22 @@ This is the form needed by `PRE-CERT-pov`.
255275``` agda
256276 applyWithdrawals-pov : (wdrls : Withdrawals) (rwds : Rewards)
257277 → mapˢ stake (dom wdrls) ⊆ dom rwds
278+ → ∀[ a ∈ dom wdrls ] NetworkIdOf a ≡ NetworkId
258279 → ∀[ (addr , amt) ∈ wdrls ˢ ] amt ≤ maybe id 0 (lookupᵐ? rwds (stake addr))
259280 → getCoin rwds ≡ getCoin (applyWithdrawals wdrls rwds) + getCoin wdrls
260281```
261282
262283<!--
263284```agda
264- applyWithdrawals-pov wdrls rwds creds∈ amts≤ =
285+ applyWithdrawals-pov wdrls rwds creds∈ netIds amts≤ =
265286 begin
266287 getCoin rwds
267- ≡⟨ foldl-applyOne-pov rwds (setToList (wdrls ˢ)) inv (setToList-Unique wdrls) ⟩
288+ ≡⟨ foldl-applyOne-pov rwds (setToList (wdrls ˢ)) inv (setToList-Unique wdrls netIds ) ⟩
268289 getCoin (foldl (applyOne _∸_) rwds (setToList (wdrls ˢ))) + sum (map proj₂ (setToList (wdrls ˢ)))
269290 ≡⟨ cong (getCoin (foldl (applyOne _∸_) rwds (setToList (wdrls ˢ))) +_) (sum-map-proj₂≡getCoin wdrls) ⟩
270291 getCoin (applyWithdrawals wdrls rwds) + getCoin wdrls
271292 ∎
272293 where
273- open ≡-Reasoning
274294 open Equivalence
275295
276296 inv : ∀ {addr amt} → (addr , amt) ∈ˡ setToList (wdrls ˢ)
@@ -357,9 +377,9 @@ This is the form needed by `PRE-CERT-pov`.
357377 c'≢c : stake addr' ≢ c
358378 c'≢c = ≢-sym (All.lookup c∉xs (∈-map⁺ (stake ∘ proj₁) mem))
359379 dom' : stake addr' ∈ dom acc'
360- dom' = ∪ˡ-res- dom-preserve acc c ( bal ∸ amt) (stake addr') c'∈dom c'≢c
380+ dom' = dom∪ˡʳ {m = ❴ c , bal ∸ amt ❵} {m' = acc} c'∈dom
361381 bal' : lookupᵐ? acc' (stake addr') ≡ lookupᵐ? acc (stake addr')
362- bal' = ∪ˡ-res- lookup-preserve acc c (bal ∸ amt) (stake addr') c'≢c
382+ bal' = ∪ˡ-lookup-preserve acc c (bal ∸ amt) (stake addr') c'≢c
363383 in dom' , subst (amt' ≤_) (cong (maybe id 0) (sym bal')) amt'≤
364384```
365385-->
@@ -396,15 +416,6 @@ directly from `getCoin-∪ˡ-overwrite`.
396416 ≡˘⟨ cong (_+ amt) (split-by-lookup acc c bal lookup-eq) ⟩
397417 getCoin acc + amt
398418 ∎
399- where
400- open ≡-Reasoning
401- -- Same decomposition `acc ≡ (acc ∣ ❴ c ❵ ᶜ) ∪ˡ (acc ∣ ❴ c ❵)` used in
402- -- `applyOne-pov`; factor it out if both proofs are kept in this module.
403- split-by-lookup : (acc : Rewards) (c : Credential) (bal : Coin)
404- → lookupᵐ? acc c ≡ just bal
405- → getCoin acc ≡ getCoin (acc ∣ ❴ c ❵ ᶜ) + bal
406- split-by-lookup acc c bal lookup-eq = {!!}
407- -- Same proof as the first three steps of `applyOne-pov`; factor it out.
408419```
409420-->
410421
@@ -421,13 +432,6 @@ directly from `getCoin-∪ˡ-overwrite`.
421432 sym (+-identityʳ (indexedSumᵛ' id acc))
422433 foldl-applyOne-pov-add acc ((addr , amt) ∷ xs) h (c∉xs :: uniq-xs)
423434 with lookupᵐ? acc (stake addr) in eq
424- -- Defensive `nothing` case ruled out by the membership precondition.
425- ... | nothing = ⊥-elim (case lookup-just (h (here refl)) of λ where
426- (_ , p) → case trans (sym eq) p of λ ())
427- where
428- -- A small helper: membership in domain implies `lookupᵐ?` is `just`.
429- lookup-just : ∀ {a} → a ∈ dom acc → Σ Coin λ v → lookupᵐ? acc a ≡ just v
430- lookup-just = {!!} -- standard agda-sets bridge; provable from `dom∈`.
431435 ... | just bal = begin
432436 getCoin (foldl (applyOne _+_) acc' xs)
433437 ≡⟨ foldl-applyOne-pov-add acc' xs h' uniq-xs ⟩
@@ -438,17 +442,20 @@ directly from `getCoin-∪ˡ-overwrite`.
438442 getCoin acc + (amt + sum (map proj₂ xs))
439443 ∎
440444 where
441- open ≡-Reasoning
442445 c = stake addr
443446 acc' = ❴ c , bal + amt ❵ ∪ˡ acc
444447 -- `h'` is the same invariant-transfer argument as in `foldl-applyOne-pov`,
445- -- but with no `amt ≤ maybe id 0 (lookupᵐ? _ _)` bound to thread —
446- -- only domain membership has to be preserved. Use the bridge lemma
447- -- to convert `acc' = ❴ c , bal + amt ❵ ∪ˡ acc` into the equivalent
448- -- `❴ c , bal + amt ❵ ∪ˡ (acc ∣ ❴ c ❵ ᶜ)` form, then reuse
449- -- `∪ˡ-res- dom-preserve` from `Certs/Properties/ApplyWithdrawalsPoV` .
448+ -- but with no `amt ≤ maybe id 0 (lookupᵐ? _ _)` bound to thread — only
449+ -- domain membership has to be preserved.
450+ -- Since `acc' = ❴ c , bal + amt ❵ ∪ˡ acc` (no complement restriction),
451+ -- we use `dom∪ˡʳ` directly; membership in `dom acc` lifts to membership
452+ -- in ` dom acc'` without needing the `c'≢c` witness .
450453 h' : ∀ {addr' amt'} → (addr' , amt') ∈ˡ xs → stake addr' ∈ dom acc'
451- h' = {!!} -- mechanical mirror of the original `h'`; see comment above.
454+ h' mem = dom∪ˡʳ {m = ❴ c , bal + amt ❵} {m' = acc} (h (there mem))
455+ -- Defensive `nothing` case ruled out by the membership precondition.
456+ ... | nothing with (stake addr ∈? dom (acc ˢ))
457+ ... | yes c∈ = case eq of λ ()
458+ ... | no a∉ = ⊥-elim (a∉ (h (here refl)))
452459```
453460-->
454461
@@ -468,14 +475,13 @@ directly from `getCoin-∪ˡ-overwrite`.
468475 getCoin (applyDirectDeposits dd rwds)
469476 ≡⟨ refl ⟩ -- by definition of `applyDirectDeposits = applyToRewards _+_`
470477 getCoin (foldl (applyOne _+_) rwds (setToList (dd ˢ)))
471- ≡⟨ sym ( foldl-applyOne-pov-add rwds (setToList (dd ˢ)) inv
472- (setToList-Unique dd netIds)) ⟩
478+ ≡⟨ foldl-applyOne-pov-add rwds (setToList (dd ˢ)) inv
479+ (setToList-Unique dd netIds) ⟩
473480 getCoin rwds + sum (map proj₂ (setToList (dd ˢ)))
474481 ≡⟨ cong (getCoin rwds +_) (sum-map-proj₂≡getCoin dd) ⟩
475482 getCoin rwds + getCoin dd
476483 ∎
477484 where
478- open ≡-Reasoning
479485 open Equivalence
480486 inv : ∀ {addr amt} → (addr , amt) ∈ˡ setToList (dd ˢ) → stake addr ∈ dom rwds
481487 inv {addr} {amt} mem =
0 commit comments