Skip to content

Commit 0e251e7

Browse files
committed
clean up documentation and add more UTXO premises
1 parent 1f277fb commit 0e251e7

File tree

2 files changed

+102
-83
lines changed

2 files changed

+102
-83
lines changed

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

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -507,25 +507,21 @@ could be either of them.
507507

508508
### Auxiliary Functions for Transaction Structures
509509

510-
This section collects some unimportant but useful helper and accessor functions.
511-
In the Dijkstra era, we need to talk about *which UTxO* a helper is parameterised by.
512-
In particular:
510+
In the Dijkstra era, we need to talk about which UTxO a helper is parameterised by.
513511

514-
+ **Spend-side checks remain mempool-safe**. Spending inputs are always inspected
515-
against the pre-batch UTxO snapshot (`utxo₀`{.AgdaField}).
516-
+ **Script/data availability is batch-scoped**. In the ledger rules, the "global"
512+
+ Spending inputs are always inspected against the pre-batch UTxO snapshot (`utxo₀`{.AgdaField}).
513+
+ Script/data availability is batch-scoped. In the ledger rules, the global
517514
script universe and datum-by-hash pool are computed once per top-level batch
518-
(using `getAllScripts` / `getAllData`) and then threaded through the environment.
515+
(using `getAllScripts`{.AgdaFunction} and `getAllData`{.AgdaFunction}).
519516

520-
This module stays intentionally *policy-neutral* about batch wiring. The helpers
521-
below simply take a UTxO parameter, and callers choose whether that argument is
522-
the pre-batch snapshot (`utxo₀`), some batch view, or another derived map.
523-
524-
Informally, you can think of two common choices that appear elsewhere:
517+
The present module is abstract and "policy-neutral" about which UTxO view is assumed
518+
since the helper functions below simply take a UTxO parameter, and the caller will choose
519+
whether that argument ought to be the pre-batch snapshot (`utxo₀`{.AgdaBound}), some
520+
batch view, or another derived map. The two most common choices appearing elsewhere
521+
will be
525522

526523
+ `utxo₀`: the pre-batch UTxO snapshot used for spend-side lookups;
527-
+ `utxo₀ ∪ batchOuts`: a batch view that includes outputs created in the batch
528-
(when a rule needs those outputs explicitly).
524+
+ `utxo₀ ∪ batchOuts`: a batch view that includes outputs created in the batch.
529525

530526
```agda
531527
TxOutʰ : Type
@@ -583,7 +579,7 @@ Informally, you can think of two common choices that appear elsewhere:
583579
-- --------------------------------------------------------------------------
584580
-- Two-view script/data extraction
585581
--
586-
-- utxo₀ is the pre-batch snapshot for spend-side lookups (mempool-safety)
582+
-- utxo₀ is the pre-batch snapshot for spend-side lookups
587583
-- utxoₙ is the post-batch or evolving view for reference-input lookups
588584
-- --------------------------------------------------------------------------
589585
@@ -716,11 +712,11 @@ result, several checks that were "per-transaction" in Conway become *batch-aware
716712

717713
**Design Note** (spending inputs vs reference inputs).
718714
For Dijkstra batches, we distinguish *spending inputs* from *reference inputs*.
719-
All spending inputs across the whole batch must exist in the initial UTxO snapshot
720-
(mempool safety). Reference inputs are treated separately by the UTxO rules.
721-
For script/data availability, the ledger computes batch-wide `globalScripts` and
722-
`globalData` once per top-level batch and threads them through the environment, so
723-
Phase 2 execution can be done with a shared, batch-scoped witness pool.
715+
All spending inputs across the whole batch must exist in the initial UTxO snapshot.
716+
Reference inputs are treated separately by the UTxO rules. For script/data
717+
availability, the ledger computes batch-wide `globalScripts` and `globalData` once
718+
per top-level batch and threads them through the environment, so phase-2 execution
719+
can be done with a shared, batch-scoped witness pool.
724720

725721

726722

@@ -741,9 +737,8 @@ Phase 2 execution can be done with a shared, batch-scoped witness pool.
741737

742738
3. **Batch-wide phase-2 evaluation**
743739

744-
Phase-2 (Plutus) validation is performed *once* for the whole batch (mempool
745-
safety), even though script inputs/contexts are constructed from both sub- and
746-
top-level components.
740+
Phase-2 (Plutus) validation is performed *once* for the whole batch, even though
741+
script inputs/contexts are constructed from both sub- and top-level components.
747742

748743
4. **Guards are credentials**
749744

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

Lines changed: 84 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,25 @@ source_path: src/Ledger/Dijkstra/Specification/Utxo.lagda.md
66
# The UTxO Transition System
77

88
This is a **work-in-progress** of the Dijkstra-era UTxO transition system.
9-
Historically, this module captured the Phase 1 structural checks specific to
9+
Historically, this module captured the phase-1 structural checks specific to
1010
Dijkstra (nested transactions + guards). It now also contains a first pass at
11-
the *batch* semantics and the Phase 2 (Plutus) execution model for validating a
11+
the *batch* semantics and the phase-2 (Plutus) execution model for validating a
1212
top-level transaction together with all of its subtransactions.
1313

1414
The primary guiding design principles are
1515

16-
+ **Spend-side mempool safety**. All spending inputs across the whole batch must
17-
come from a pre-batch UTxO snapshot;
16+
+ **Spend-side safety**. All spending inputs across the whole batch must
17+
come from a pre-batch UTxO snapshot (see point 6 of the
18+
[Changes to Transaction Validity][1] section of CIP-0118);
1819
+ **Batch-scoped witnesses**. Scripts and datums are collected once per batch and
19-
then shared for Phase 2 evaluation;
20-
+ **Batch-consistency**. No two transactions in the batch may attempt to spend the
21-
same input. This is enforced explicitly below (rather than being accidentally
22-
masked by set unioning).
20+
then shared for phase-2 evaluation; CIP-0118 explicitly states that reference
21+
scripts, and by implication reference-input-resolved UTxO entries, could be
22+
outputs of preceding transactions in the batch (see point 5 of the
23+
[Changes to Transaction Validity][1] section of CIP-0118);
24+
+ **Batch-consistency**. Of course, no two transactions in the batch may spend the
25+
same input. This is enforced explicitly at the top level by a predicate
26+
(called `noOverlappingSpendInputs`{.AgdaFunction} below) that is checked in the
27+
`UTXO`{.AgdaDatatype} rule
2328

2429
<!--
2530
```agda
@@ -74,7 +79,7 @@ In Dijkstra, the `UTxOEnv`{.AgdaRecord} additionally carries
7479

7580
Following CIP-0118, scripts and datums are treated as *batch-wide witnesses*;
7681
attaching a script or datum to a transaction in the batch makes it available for
77-
Phase 2 validation of any transaction in the batch, independent of which
82+
phase-2 validation of any transaction in the batch, independent of which
7883
subtransaction originally supplied it. Consequently, `LEDGER` precomputes:
7984

8085
+ `globalScripts`: the set of all scripts available to the batch (witness scripts +
@@ -99,7 +104,7 @@ record UTxOEnv : Type where
99104

100105
The `utxo₀`{.AgdaField} field is introduced in the Dijkstra era; it denotes a
101106
*snapshot* of the UTxO before any subtransaction of a batch is applied. This is
102-
the canonical "mempool-safe" UTxO used for spend-side checks.
107+
the UTxO used for spend-side checks.
103108

104109
```agda
105110
record UTxOState : Type where
@@ -115,7 +120,7 @@ The rest of this module defines
115120

116121
+ common helper functions (balance, minfee, deposit accounting);
117122
+ batch-level accounting (consumed/produced across a collection of transactions);
118-
+ Phase 2 wiring for validating all Plutus scripts required by the batch.
123+
+ phase-2 wiring for validating all Plutus scripts required by the batch.
119124

120125
<!--
121126
```agda
@@ -131,8 +136,15 @@ record HasGlobalData {a} (A : Type a) : Type a where
131136
field GlobalDataOf : A → DataHash ⇀ Datum
132137
open HasGlobalData ⦃...⦄ public
133138
139+
record HasSlot {a} (A : Type a) : Type a where
140+
field SlotOf : A → Slot
141+
open HasSlot ⦃...⦄ public
142+
134143
135144
instance
145+
HasSlot-UTxOEnv : HasSlot UTxOEnv
146+
HasSlot-UTxOEnv .SlotOf = UTxOEnv.slot
147+
136148
HasPParams-UTxOEnv : HasPParams UTxOEnv
137149
HasPParams-UTxOEnv .PParamsOf = UTxOEnv.pparams
138150
@@ -160,14 +172,12 @@ instance
160172
unquoteDecl HasCast-UTxOEnv HasCast-UTxOState = derive-HasCast
161173
( (quote UTxOEnv , HasCast-UTxOEnv ) ∷
162174
[ (quote UTxOState , HasCast-UTxOState) ])
175+
176+
opaque
163177
```
164178
-->
165179

166-
167-
168180
```agda
169-
opaque
170-
171181
outs : Tx ℓ → UTxO
172182
outs tx = mapKeys (TxIdOf tx ,_) (IndexedOutputsOf tx)
173183
@@ -185,6 +195,7 @@ opaque
185195
+ txScriptFee (pp .prices) (totExUnits tx)
186196
+ scriptsCost pp (refScriptsSize utxo tx)
187197
```
198+
188199
<!--
189200
```agda
190201
instance
@@ -299,11 +310,9 @@ updateProposalDeposits (_ ∷ ps) txid gaDep deposits =
299310
∪⁺ ❴ GovActionDeposit (txid , length ps) , gaDep ❵
300311
301312
updateDeposits : PParams → Tx ℓ → Deposits → Deposits
302-
updateDeposits pp tx = updateCertDeposits pp (DCertsOf tx)
303-
∘ updateProposalDeposits (ListOfGovProposalsOf tx) (TxIdOf tx) (pp .govActionDeposit)
304-
305-
proposalDepositsΔ : List GovProposal → PParams → Tx ℓ → Deposits
306-
proposalDepositsΔ props pp tx = updateProposalDeposits props (TxIdOf tx) (pp .govActionDeposit) ∅
313+
updateDeposits pp tx =
314+
updateCertDeposits pp (DCertsOf tx)
315+
∘ updateProposalDeposits (ListOfGovProposalsOf tx) (TxIdOf tx) (pp .govActionDeposit)
307316
308317
data inInterval (slot : Slot) : (Maybe Slot × Maybe Slot) → Type where
309318
both : ∀ {l r} → l ≤ slot × slot ≤ r → inInterval slot (just l , just r)
@@ -354,16 +363,17 @@ collateralCheck pp txTop utxo =
354363
-- NOTE:
355364
-- Collateral is *top-level only* in Dijkstra. In this first-pass model,
356365
-- we keep Conway's collateral predicate, but interpret it as covering the entire
357-
-- batch's Phase 2 execution (top-level tx + all subtransactions).
366+
-- batch's phase-2 execution (top-level tx + all subtransactions).
358367
--
359368
-- The precise relationship between collateral, per-script execution units, and
360369
-- fee/minfee accounting may be refined as the CIPs and ledger design stabilize.
361370
362371
module Accounting (pp : PParams) (txTop : TopLevelTx) (deposits₀ : Deposits) where
363372
364373
updateDepositsBatch : Deposits
365-
updateDepositsBatch =
366-
foldl updateStep (updateDeposits pp txTop deposits₀) (SubTransactionsOf txTop)
374+
updateDepositsBatch = foldl updateStep
375+
(updateDeposits pp txTop deposits₀)
376+
(SubTransactionsOf txTop)
367377
where
368378
updateStep : Deposits → SubLevelTx → Deposits
369379
updateStep deps txSub = updateDeposits pp txSub deps
@@ -393,30 +403,27 @@ module Accounting (pp : PParams) (txTop : TopLevelTx) (deposits₀ : Deposits) w
393403
(SubTransactionsOf txTop)
394404
where
395405
producedTx : ∀ {ℓ} → Tx ℓ → Value
396-
producedTx {TxLevelTop} tx = balance (outs tx)
397-
+ inject (TxFeesOf tx)
398-
+ inject (DonationsOf tx)
399-
producedTx {TxLevelSub} tx = balance (outs tx)
400-
+ inject (DonationsOf tx)
401-
406+
producedTx {TxLevelSub} tx = balance (outs tx) + inject (DonationsOf tx)
407+
producedTx {TxLevelTop} tx =
408+
balance (outs tx) + inject (TxFeesOf tx) + inject (DonationsOf tx)
402409
```
403410

404-
## Phase 2 (Plutus) Execution for Nested Transactions
411+
## Phase-2 (Plutus) Execution for Nested Transactions
405412

406413
The `LEDGER`{.AgdaDatatype} rule computes a *batch-wide script universe* and a
407414
*datum-by-hash pool* once, which populate the `globalScripts`{.AgdaField} and
408415
`globalData`{.AgdaField} fields of `UTxOEnv`{.AgdaRecord}.
409416
In this module we access them via `GlobalScriptsOf Γ` and `GlobalDataOf Γ`.
410417

411-
Phase 2 execution in `UTXO`{.AgdaDatatype}/`UTXOS`{.AgdaDatatype} then evaluates all
418+
Phase-2 execution in `UTXO`{.AgdaDatatype}/`UTXOS`{.AgdaDatatype} then evaluates all
412419
Plutus scripts needed by the top-level transaction and all its subtransactions
413420
against this shared, batch-scoped context.
414421

415422
We distinguish two UTxO views:
416423

417424
+ **Pre-batch snapshot view**. `UTxOOf`{.AgdaField} `Γ`{.AgdaBound} (or
418425
`utxo₀`{.AgdaField}) is used for all *spend-side* lookups (inputs, collateral, and
419-
datum lookup for spent outputs), preserving the mempool-safety requirement that
426+
datum lookup for spent outputs), preserving the requirement that
420427
every spending input must exist before any part of the batch is applied.
421428

422429
+ **Batch output view**.
@@ -425,7 +432,7 @@ We distinguish two UTxO views:
425432
`∪ˡ`{.AgdaFunction} `batchOuts`{.AgdaFunction} `txTop`{.AgdaBound}
426433
is defined here mainly as a convenience for rules that need access to outputs
427434
created within the batch (top-level outputs plus all subtransaction outputs).
428-
Phase 2 script collection below stays spend-side with respect to UTxO lookups,
435+
Phase-2 script collection below stays spend-side with respect to UTxO lookups,
429436
and relies on `globalScripts`{.AgdaField}/`globalData`{.AgdaField} for
430437
batch-scoped availability.
431438

@@ -481,10 +488,12 @@ module Phase2 (Γ : UTxOEnv) (txTop : TopLevelTx) where
481488
(GlobalScriptsOf Γ) -- batch script universe
482489
483490
484-
-- union UTxO maps for outputs.
485491
batchScripts✓ : Bool
486492
batchScripts✓ = evalP2Scripts p2ScriptsWithContext
487493
494+
allDCerts : List DCert
495+
allDCerts = DCertsOf txTop ++ concatMap DCertsOf (SubTransactionsOf txTop)
496+
488497
-- union a list of sets
489498
concatMapˡ : {A B : Type} → (A → ℙ B) → List A → ℙ B
490499
concatMapˡ f as = proj₁ $ unions (fromList (map f as))
@@ -496,7 +505,6 @@ module Phase2 (Γ : UTxOEnv) (txTop : TopLevelTx) where
496505
497506
-- Reference inputs are validated against the "batch output view," so they may
498507
-- point to outputs produced in the same batch (including self-usable outputs).
499-
-- Spending inputs remain mempool-safe against `utxo₀`.
500508
batchReferenceInputs : ℙ TxIn
501509
batchReferenceInputs =
502510
ReferenceInputsOf txTop ∪ concatMapˡ ReferenceInputsOf (SubTransactionsOf txTop)
@@ -523,7 +531,6 @@ module Phase2 (Γ : UTxOEnv) (txTop : TopLevelTx) where
523531
-- `batchMintedCoin ≡ 0`; this is the generalization of Conway's
524532
-- `coin mint ≡ 0`.
525533
526-
527534
-- UTxO change in case Tx.isValid ≡ true. case
528535
utxo✓ : UTxO → UTxO
529536
utxo✓ utxo = (utxo ∣ batchSpendInputs ᶜ) ∪ˡ batchOuts txTop
@@ -568,10 +575,11 @@ module Phase2 (Γ : UTxOEnv) (txTop : TopLevelTx) where
568575
<!--
569576
```agda
570577
private variable
571-
Γ : UTxOEnv
572-
s s' : UTxOState
573-
txTop : TopLevelTx
574-
txSub : SubLevelTx
578+
Γ : UTxOEnv
579+
s s' : UTxOState
580+
txTop : TopLevelTx
581+
txSub : SubLevelTx
582+
deposits : Deposits
575583
```
576584
-->
577585

@@ -582,20 +590,27 @@ data _⊢_⇀⦇_,UTXOS⦈_ : UTxOEnv → UTxOState → TopLevelTx → UTxOState
582590
583591
let open Phase2 Γ txTop in
584592
585-
∙ Tx.isValid txTop ≡ batchScripts✓
586-
∙ batchScripts✓ ≡ true
593+
∙ ValidCertDeposits (PParamsOf Γ) deposits allDCerts
594+
∙ batchScripts✓ ≡ Tx.isValid txTop
595+
∙ Tx.isValid txTop ≡ true
587596
────────────────────────────────
588597
Γ ⊢ s ⇀⦇ txTop ,UTXOS⦈ scripts✓ s
589598
590599
UTXOS-scripts× :
591600
592601
let open Phase2 Γ txTop in
593602
594-
∙ Tx.isValid txTop ≡ batchScripts✓
595-
batchScripts✓ ≡ false
603+
batchScripts✓ ≡ Tx.isValid txTop
604+
Tx.isValid txTop ≡ false
596605
────────────────────────────────
597606
Γ ⊢ s ⇀⦇ txTop ,UTXOS⦈ scripts× s
598607
```
608+
<!--
609+
```agda
610+
unquoteDecl UTXOS-scripts✓-premises = genPremises UTXOS-scripts✓-premises (quote UTXOS-scripts✓)
611+
unquoteDecl UTXOS-scripts×-premises = genPremises UTXOS-scripts×-premises (quote UTXOS-scripts×)
612+
```
613+
-->
599614

600615
## The <span class="AgdaDatatype">UTXO</span> Rule
601616

@@ -632,10 +647,12 @@ data _⊢_⇀⦇_,SUBUTXO⦈_ : UTxOEnv → UTxOState → SubLevelTx → UTxOSta
632647
633648
SUBUTXO :
634649
635-
∙ SpendInputsOf txSub ≢ ∅
636-
∙ SpendInputsOf txSub ⊆ dom (UTxOOf Γ) -- (1) (redundant)
637-
────────────────────────────────
638-
Γ ⊢ s ⇀⦇ txSub ,SUBUTXO⦈ s
650+
∙ SpendInputsOf txSub ≢ ∅
651+
∙ SpendInputsOf txSub ∩ ReferenceInputsOf txSub ≡ ∅
652+
{-1-} ∙ SpendInputsOf txSub ⊆ dom (UTxOOf Γ)
653+
∙ inInterval (SlotOf Γ) (ValidIntervalOf txSub)
654+
────────────────────────────────
655+
Γ ⊢ s ⇀⦇ txSub ,SUBUTXO⦈ s
639656
640657
data _⊢_⇀⦇_,UTXO⦈_ : UTxOEnv → UTxOState → TopLevelTx → UTxOState → Type where
641658
@@ -646,19 +663,26 @@ data _⊢_⇀⦇_,UTXO⦈_ : UTxOEnv → UTxOState → TopLevelTx → UTxOState
646663
647664
utxo₀ : UTxO
648665
utxo₀ = UTxOOf Γ
666+
utxo : UTxO
667+
utxo = UTxOOf s
649668
in
650669
651-
∙ SpendInputsOf txTop ≢ ∅
652-
∙ SpendInputsOf txTop ⊆ dom utxo₀ -- (1) (redundant)
653-
∙ batchSpendInputs txTop ⊆ dom utxo₀ -- (1)
654-
∙ noOverlappingSpendInputs txTop -- (2)
655-
∙ batchReferenceInputs txTop ⊆ dom (utxoView utxo₀ txTop) -- (3)
656-
∙ requiredGuardsInTopLevel txTop (SubTransactionsOf txTop) -- (4)
657-
∙ consumed Γ ≡ produced
658-
∙ batchMintedCoin txTop ≡ 0
659-
∙ RedeemersOf txTop ˢ ≢ ∅ → collateralCheck (PParamsOf Γ) txTop utxo₀
660-
∙ Γ ⊢ s ⇀⦇ txTop ,UTXOS⦈ s
661-
────────────────────────────────
662-
Γ ⊢ s ⇀⦇ txTop ,UTXO⦈ s'
670+
∙ SpendInputsOf txTop ≢ ∅
671+
{-1-} ∙ SpendInputsOf txTop ⊆ dom utxo₀
672+
{-1-} ∙ batchSpendInputs txTop ⊆ dom utxo₀
673+
{-2-} ∙ noOverlappingSpendInputs txTop
674+
{-3-} ∙ batchReferenceInputs txTop ⊆ dom (utxoView utxo₀ txTop)
675+
{-4-} ∙ requiredGuardsInTopLevel txTop (SubTransactionsOf txTop)
676+
∙ inInterval (SlotOf Γ) (ValidIntervalOf txTop)
677+
∙ minfee (PParamsOf Γ) utxo txTop ≤ TxFeesOf txTop
678+
∙ RedeemersOf txTop ˢ ≢ ∅ → collateralCheck (PParamsOf Γ) txTop utxo₀
679+
∙ consumed Γ ≡ produced
680+
∙ SizeOf txTop ≤ maxTxSize (PParamsOf Γ)
681+
∙ batchMintedCoin txTop ≡ 0
682+
∙ Γ ⊢ s ⇀⦇ txTop ,UTXOS⦈ s'
683+
────────────────────────────────
684+
Γ ⊢ s ⇀⦇ txTop ,UTXO⦈ s'
663685
```
664686

687+
[1]: https://github.com/cardano-foundation/CIPs/tree/master/CIP-0118#changes-to-transaction-validity "CIP-0118 | Changes to Transaction Validity"
688+
[2]: https://cips.cardano.org/cip/CIP-0118 "CIP-0118 | Nested Transactions"

0 commit comments

Comments
 (0)