@@ -6,20 +6,25 @@ source_path: src/Ledger/Dijkstra/Specification/Utxo.lagda.md
66# The UTxO Transition System
77
88This 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
1010Dijkstra (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
1212top-level transaction together with all of its subtransactions.
1313
1414The 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
7580Following CIP-0118, scripts and datums are treated as * batch-wide witnesses* ;
7681attaching 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
7883subtransaction 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
100105The ` 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
105110record 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
132137open HasGlobalData ⦃...⦄ public
133138
139+ record HasSlot {a} (A : Type a) : Type a where
140+ field SlotOf : A → Slot
141+ open HasSlot ⦃...⦄ public
142+
134143
135144instance
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
190201instance
@@ -299,11 +310,9 @@ updateProposalDeposits (_ ∷ ps) txid gaDep deposits =
299310 ∪⁺ ❴ GovActionDeposit (txid , length ps) , gaDep ❵
300311
301312updateDeposits : 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
308317data 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
362371module 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
406413The ` 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}.
409416In 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
412419Plutus scripts needed by the top-level transaction and all its subtransactions
413420against this shared, batch-scoped context.
414421
415422We 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
570577private 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
640657data _⊢_⇀⦇_,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