Skip to content

Commit 3ad7b77

Browse files
committed
[Dijkstra] CIP-159-10: Apply direct deposits in POST-CERT (#1122)
Per @carlostome's review of #1161, move CIP-159 direct-deposit application out of the LEDGER/SUBLEDGER orchestration rules and into the POST-CERT sub-rule of CERTS, alongside the existing voteDelegs filtering. CertEnv gains a sixth field, directDeposits, populated by LEDGER-V (DirectDepositsOf tx) and SUBLEDGER-V (DirectDepositsOf stx) when constructing each CERTS invocation's environment. POST-CERT (CERT-post) gains a premise dom directDeposits ⊆ dom rewards and updates its post-state's rewards to rewards ∪⁺ directDeposits. SUBLEDGER-V and LEDGER-V revert to threading-only: certStateWithDDeps, the certStateFinal let-binding, and the dom-check premises are removed. Computational instances are updated correspondingly. Per-transaction semantics are preserved (POST-CERT runs at the end of each transaction's CERTS invocation). Phantom-asset prevention via NoPhantomWithdrawals is unaffected (accountBalances is fixed at the pre-batch snapshot). depositsChange remains orthogonal (applyDirectDeposits touches rewards only; calculateDepositsChange reads deposits only). Direct-deposit documentation moves from Ledger.lagda.md to the POST-CERT section of Certs.lagda.md.
1 parent e8e951d commit 3ad7b77

5 files changed

Lines changed: 93 additions & 173 deletions

File tree

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

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,12 @@ instance
5959
6060
record CertEnv' : Type where
6161
field
62-
epoch : Epoch
63-
pp : PParams
64-
votes : List GovVote'
65-
wdrls : RewardAddress ⇀ Coin
66-
coldCreds : ℙ Credential
62+
epoch : Epoch
63+
pp : PParams
64+
votes : List GovVote'
65+
wdrls : RewardAddress ⇀ Coin
66+
coldCreds : ℙ Credential
67+
directDeposits : DirectDeposits
6768
6869
instance
6970
HsTy-CertEnv' = autoHsType CertEnv'
@@ -74,8 +75,8 @@ instance
7475
7576
mkCertEnv' : Convertible CertEnv CertEnv'
7677
mkCertEnv' = λ where
77-
.to ce → let module ce = CertEnv ce in record { epoch = ce.epoch ; pp = ce.pp ; votes = to ce.votes ; wdrls = ce.wdrls ; coldCreds = ce.coldCreds }
78-
.from ce → let module ce = CertEnv' ce in record { epoch = ce.epoch ; pp = ce.pp ; votes = from ce.votes ; wdrls = ce.wdrls ; coldCreds = ce.coldCreds }
78+
.to ce → let module ce = CertEnv ce in record { epoch = ce.epoch ; pp = ce.pp ; votes = to ce.votes ; wdrls = ce.wdrls ; coldCreds = ce.coldCreds ; directDeposits = ce.directDeposits }
79+
.from ce → let module ce = CertEnv' ce in record { epoch = ce.epoch ; pp = ce.pp ; votes = from ce.votes ; wdrls = ce.wdrls ; coldCreds = ce.coldCreds ; directDeposits = ce.directDeposits }
7980
8081
HsTy-CertEnv = MkHsType CertEnv (HsType CertEnv')
8182
Conv-CertEnv = mkCertEnv' ⨾ Conv-CertEnv'

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

Lines changed: 58 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,12 @@ cwitness (ccreghot c _) = just c
8585
-- Certification Types
8686
record CertEnv : Type where
8787
field
88-
epoch : Epoch
89-
pp : PParams
90-
votes : List GovVote
91-
wdrls : Withdrawals
92-
coldCreds : ℙ Credential
88+
epoch : Epoch
89+
pp : PParams
90+
votes : List GovVote
91+
wdrls : Withdrawals
92+
coldCreds : ℙ Credential
93+
directDeposits : DirectDeposits
9394
9495
record DState : Type where
9596
constructor ⟦_,_,_,_⟧ᵈ
@@ -255,6 +256,7 @@ private variable
255256
pools fPools : Pools
256257
retiring : Retiring
257258
wdrls : Withdrawals
259+
dd : DirectDeposits
258260
A : Type
259261
deposits deposits' : A ⇀ Coin
260262
@@ -290,8 +292,9 @@ applyDirectDeposits : DirectDeposits → DState → DState
290292
applyDirectDeposits dd ds = record ds { rewards = RewardsOf ds ∪⁺ dd }
291293
```
292294

293-
The `LEDGER`{.AgdaDatatype} rule will call `applyDirectDeposits`{.AgdaFunction} to
294-
credit direct deposits to account balances as part of processing a transaction batch.
295+
The `POST-CERT`{.AgdaDatatype} rule calls `applyDirectDeposits`{.AgdaFunction} to
296+
credit each transaction's direct deposits to its account balances after certificate
297+
processing. See *Direct Deposit Application (CIP-159)* below for details.
295298

296299
```agda
297300
applyWithdrawals : Withdrawals → Rewards → Rewards
@@ -407,32 +410,32 @@ data _⊢_⇀⦇_,GOVCERT⦈_ : CertEnv → GState → DCert → GState → Type
407410
GOVCERT-regdrep :
408411
∙ (d ≡ pp .drepDeposit × c ∉ dom dReps) ⊎ (d ≡ 0 × c ∈ dom dReps)
409412
────────────────────────────────
410-
⟦ e , pp , vs , wdrls , cc ⟧ ⊢ ⟦ dReps , ccKeys , deposits ⟧ ⇀⦇ regdrep c d an ,GOVCERT⦈ ⟦ ❴ c , e + pp .drepActivity ❵ ∪ˡ dReps , ccKeys , deposits ∪⁺ ❴ c , d ❵ ⟧
413+
⟦ e , pp , vs , wdrls , cc , dd ⟧ ⊢ ⟦ dReps , ccKeys , deposits ⟧ ⇀⦇ regdrep c d an ,GOVCERT⦈ ⟦ ❴ c , e + pp .drepActivity ❵ ∪ˡ dReps , ccKeys , deposits ∪⁺ ❴ c , d ❵ ⟧
411414
412415
GOVCERT-deregdrep :
413416
∙ c ∈ dom dReps
414417
∙ (c , d) ∈ deposits
415418
────────────────────────────────
416-
⟦ e , pp , vs , wdrls , cc ⟧ ⊢ ⟦ dReps , ccKeys , deposits ⟧ ⇀⦇ deregdrep c d ,GOVCERT⦈ ⟦ dReps ∣ ❴ c ❵ ᶜ , ccKeys , deposits ∣ ❴ c ❵ ᶜ ⟧
419+
⟦ e , pp , vs , wdrls , cc , dd ⟧ ⊢ ⟦ dReps , ccKeys , deposits ⟧ ⇀⦇ deregdrep c d ,GOVCERT⦈ ⟦ dReps ∣ ❴ c ❵ ᶜ , ccKeys , deposits ∣ ❴ c ❵ ᶜ ⟧
417420
418421
GOVCERT-ccreghot :
419422
∙ (c , nothing) ∉ ccKeys
420423
∙ c ∈ cc
421424
────────────────────────────────
422-
⟦ e , pp , vs , wdrls , cc ⟧ ⊢ ⟦ dReps , ccKeys , deposits ⟧ ⇀⦇ ccreghot c mc ,GOVCERT⦈ ⟦ dReps , ❴ c , mc ❵ ∪ˡ ccKeys , deposits ⟧
425+
⟦ e , pp , vs , wdrls , cc , dd ⟧ ⊢ ⟦ dReps , ccKeys , deposits ⟧ ⇀⦇ ccreghot c mc ,GOVCERT⦈ ⟦ dReps , ❴ c , mc ❵ ∪ˡ ccKeys , deposits ⟧
423426
424427
-- CERT Transition System --
425428
data _⊢_⇀⦇_,CERT⦈_ : CertEnv → CertState → DCert → CertState → Type where
426429
427430
CERT-deleg :
428431
∙ ⟦ pp , PState.pools stᵖ , dom (GState.dreps stᵍ) ⟧ ⊢ stᵈ ⇀⦇ dCert ,DELEG⦈ stᵈ'
429432
────────────────────────────────
430-
⟦ e , pp , vs , wdrls , cc ⟧ ⊢ ⟦ stᵈ , stᵖ , stᵍ ⟧ ⇀⦇ dCert ,CERT⦈ ⟦ stᵈ' , stᵖ , stᵍ ⟧
433+
⟦ e , pp , vs , wdrls , cc , dd ⟧ ⊢ ⟦ stᵈ , stᵖ , stᵍ ⟧ ⇀⦇ dCert ,CERT⦈ ⟦ stᵈ' , stᵖ , stᵍ ⟧
431434
432435
CERT-pool :
433436
∙ pp ⊢ stᵖ ⇀⦇ dCert ,POOL⦈ stᵖ'
434437
────────────────────────────────
435-
⟦ e , pp , vs , wdrls , cc ⟧ ⊢ ⟦ stᵈ , stᵖ , stᵍ ⟧ ⇀⦇ dCert ,CERT⦈ ⟦ stᵈ , stᵖ' , stᵍ ⟧
438+
⟦ e , pp , vs , wdrls , cc , dd ⟧ ⊢ ⟦ stᵈ , stᵖ , stᵍ ⟧ ⇀⦇ dCert ,CERT⦈ ⟦ stᵈ , stᵖ' , stᵍ ⟧
436439
437440
CERT-gov :
438441
∙ Γ ⊢ stᵍ ⇀⦇ dCert ,GOVCERT⦈ stᵍ'
@@ -473,7 +476,7 @@ data _⊢_⇀⦇_,PRE-CERT⦈_ : CertEnv → CertState → ⊤ → CertState →
473476
∙ wdrlCreds ⊆ dom rewards
474477
∙ ∀[ (addr , amt) ∈ wdrls ˢ ] amt ≤ maybe id 0 (lookupᵐ? rewards (stake addr))
475478
────────────────────────────────
476-
⟦ e , pp , vs , wdrls , cc ⟧ ⊢ ⟦ ⟦ voteDelegs , stakeDelegs , rewards , deposits ⟧ , stᵖ , ⟦ dReps , ccHotKeys , deposits' ⟧ ⟧ ⇀⦇ _ ,PRE-CERT⦈ ⟦ ⟦ voteDelegs , stakeDelegs , applyWithdrawals wdrls rewards , deposits ⟧ , stᵖ , ⟦ refreshedDReps , ccHotKeys , deposits' ⟧ ⟧
479+
⟦ e , pp , vs , wdrls , cc , dd ⟧ ⊢ ⟦ ⟦ voteDelegs , stakeDelegs , rewards , deposits ⟧ , stᵖ , ⟦ dReps , ccHotKeys , deposits' ⟧ ⟧ ⇀⦇ _ ,PRE-CERT⦈ ⟦ ⟦ voteDelegs , stakeDelegs , applyWithdrawals wdrls rewards , deposits ⟧ , stᵖ , ⟦ refreshedDReps , ccHotKeys , deposits' ⟧ ⟧
477480
```
478481

479482
**TODO**: Version restriction (deferred). CIP-159 specifies that partial withdrawals are
@@ -484,14 +487,55 @@ follow-up issue.
484487

485488
## POST-CERT Transition Rule
486489

490+
### Direct Deposit Application (CIP-159)
491+
492+
The `POST-CERT`{.AgdaDatatype} rule applies CIP-159 direct deposits to the
493+
threaded `CertState`{.AgdaRecord} after all individual `CERT`{.AgdaDatatype} steps
494+
for the transaction have run, alongside its existing `voteDelegs`{.AgdaField}
495+
filtering. Specifically:
496+
497+
+ `voteDelegs`{.AgdaField} is restricted to credentials that delegate to a
498+
currently-registered `DRep`{.AgdaInductiveConstructor} (or to the abstain /
499+
no-confidence pseudo-DReps).
500+
+ `rewards`{.AgdaField} is augmented by `directDeposits`{.AgdaField} via
501+
`∪⁺`{.AgdaFunction} (union with addition) — equivalently,
502+
`applyDirectDeposits directDeposits` is applied to the threaded
503+
`DState`{.AgdaRecord}.
504+
505+
The premise `dom directDeposits ⊆ dom rewards` ensures that
506+
`applyDirectDeposits`{.AgdaFunction} does not silently re-introduce a credential
507+
into `rewards`{.AgdaField} that was deregistered earlier in the same
508+
transaction's `CERT`{.AgdaDatatype} steps (and is therefore no longer present in
509+
`voteDelegs`{.AgdaField}, `stakeDelegs`{.AgdaField}, or `deposits`{.AgdaField}),
510+
which would produce an inconsistent `DState`{.AgdaRecord}. The check is
511+
performed against the post-`CERT`{.AgdaDatatype} `rewards`{.AgdaField} of the
512+
*same* transaction, so deregistrations performed by *prior* sub-transactions in
513+
the same batch are correctly accounted for: a sub-transaction whose deposit
514+
targets a credential deregistered earlier in the batch will fail this premise.
515+
516+
The phantom-asset prohibition of CIP-159 — that withdrawals in one
517+
sub-transaction may not draw from deposits made by an earlier sub-transaction in
518+
the same batch — is enforced separately in the `Utxo`{.AgdaModule} module by the
519+
`NoPhantomWithdrawals`{.AgdaFunction} predicate, which bounds *batch-wide*
520+
withdrawal totals (per reward address) by the `accountBalances`{.AgdaField} field
521+
of `UTxOEnv`{.AgdaRecord} / `SubUTxOEnv`{.AgdaRecord} — the *pre-batch* snapshot
522+
`RewardsOf certState₀`{.AgdaBound}. Because `accountBalances`{.AgdaField} is
523+
fixed at the pre-batch value and never updated by direct deposit application,
524+
the phantom-asset prohibition holds regardless of the per-transaction
525+
`rewards`{.AgdaField} updates done by `POST-CERT`{.AgdaDatatype}.
526+
527+
487528
```agda
488529
data _⊢_⇀⦇_,POST-CERT⦈_ : CertEnv → CertState → ⊤ → CertState → Type where
489530
490531
CERT-post :
491532
let activeVDelegs = mapˢ vDelegCredential (dom (DRepsOf stᵍ))
492533
∪ fromList (vDelegNoConfidence ∷ vDelegAbstain ∷ [])
493534
in
494-
⟦ e , pp , vs , wdrls , cc ⟧ ⊢ ⟦ ⟦ voteDelegs , stakeDelegs , rewards , deposits ⟧ , stᵖ , stᵍ ⟧ ⇀⦇ _ ,POST-CERT⦈ ⟦ ⟦ voteDelegs ∣^ activeVDelegs , stakeDelegs , rewards , deposits ⟧ , stᵖ , stᵍ ⟧
535+
∙ dom dd ⊆ dom rewards
536+
────────────────────────────────
537+
⟦ e , pp , vs , wdrls , cc , dd ⟧ ⊢ ⟦ ⟦ voteDelegs , stakeDelegs , rewards , deposits ⟧ , stᵖ , stᵍ ⟧ ⇀⦇ _ ,POST-CERT⦈ ⟦ ⟦ voteDelegs ∣^ activeVDelegs , stakeDelegs , rewards ∪⁺ dd , deposits ⟧ , stᵖ , stᵍ ⟧
538+
495539
496540
497541
-- CERTS Transition System --

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

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,10 @@ instance
9090
Computational-POOL .completeness _ stᵖ (regpool c _) _ (POOL-reg p)
9191
with ¿ Is-just (lookupᵐ? (PoolsOf stᵖ) c) ¿
9292
... | yes p' = ⊥-elim (¬Is-just↔Is-nothing _ .from p p')
93-
... | no ¬p = refl
93+
... | no _ = refl
9494
Computational-POOL .completeness _ stᵖ (regpool c _) _ (POOL-rereg p)
9595
with ¿ Is-just (lookupᵐ? (PoolsOf stᵖ) c) ¿
96-
... | yes p = refl
96+
... | yes _ = refl
9797
... | no ¬p = ⊥-elim (¬p p)
9898
Computational-POOL .completeness _ _ (retirepool _ _) _ POOL-retirepool = refl
9999
@@ -147,7 +147,7 @@ instance
147147
dCert@(regpool c poolParams) cs' (CERT-pool h)
148148
with computeProof (CertEnv.pp ce) (CertState.pState cs) dCert
149149
| completeness _ _ _ _ h
150-
... | success x | refl = refl
150+
... | success _ | refl = refl
151151
Computational-CERT .completeness ce cs
152152
dCert@(retirepool c e) cs' (CERT-pool h)
153153
with completeness _ _ _ _ h
@@ -182,14 +182,22 @@ instance
182182
p .proj₂ = refl
183183
184184
Computational-POST-CERT : Computational _⊢_⇀⦇_,POST-CERT⦈_ String
185-
Computational-POST-CERT .computeProof ce cs tt = success ( cs' , CERT-post)
185+
Computational-POST-CERT .computeProof ce cs tt with ¿ dom (CertEnv.directDeposits ce) ⊆ dom (RewardsOf cs) ¿
186+
... | (no ¬p) = failure (genErrors ¬p)
187+
... | (yes p) = success (cs' , CERT-post p)
186188
where
187189
validVoteDelegs : VoteDelegs
188190
validVoteDelegs = VoteDelegsOf cs ∣^ (mapˢ vDelegCredential (dom (DRepsOf cs)) ∪ fromList (vDelegNoConfidence ∷ vDelegAbstain ∷ []) )
191+
192+
newRewards : Rewards
193+
newRewards = RewardsOf cs ∪⁺ CertEnv.directDeposits ce
194+
189195
cs' : CertState
190-
cs' = ⟦ ⟦ validVoteDelegs , _ , _ ⟧ , PStateOf cs , GStateOf cs ⟧
196+
cs' = ⟦ ⟦ validVoteDelegs , StakeDelegsOf cs , newRewards , DepositsOf (DStateOf cs) ⟧ , PStateOf cs , GStateOf cs ⟧
191197
192-
Computational-POST-CERT .completeness ce cs _ cs' CERT-post = refl
198+
Computational-POST-CERT .completeness ce cs _ cs' (CERT-post p) with ¿ dom (CertEnv.directDeposits ce) ⊆ dom (RewardsOf cs) ¿
199+
... | yes _ = refl
200+
... | no ¬p = ⊥-elim (¬p p)
193201
194202
Computational-CERTS : Computational _⊢_⇀⦇_,CERTS⦈_ String
195203
Computational-CERTS = it

0 commit comments

Comments
 (0)