feat: add Babbage phase-1 validations (#405)
This commit is contained in:
parent
ab1fd882d6
commit
181a13c3d6
32 changed files with 4584 additions and 143 deletions
|
|
@ -1,32 +1,33 @@
|
|||
# Alonzo phase-1 validation rules
|
||||
|
||||
This document covers the Alonzo era. This document covers the concepts, notation and validation rules realted to phase-1 validation in the Alonzo ledger. For further information, refer to the [Alonzo ledger white paper](https://github.com/input-output-hk/cardano-ledger/releases/latest/download/alonzo-ledger.pdf).
|
||||
This document covers the terminology and equations related to the Babbage ledger phase-1 validation rules. For further information, refer to the [Alonzo ledger white paper](https://github.com/input-output-hk/cardano-ledger/releases/latest/download/alonzo-ledger.pdf).
|
||||
|
||||
## Definitions and notation
|
||||
- **Blocks**:
|
||||
- ***Block*** is the set of all possible (not necessarily valid) Alonzo blocks. When clear, we will write ***block ∈ Blocks*** to refer to the current block being validated.
|
||||
- ***Block*** is the set of all possible (not necessarily valid) Alonzo blocks. We will write ***block*** to refer to the current block being validated.
|
||||
- ***txs(block)*** is the set of transactions of the block.
|
||||
- ***blockExUnits(block) ∈ ExUnits***, where ***ExUnits := (ℕ, ℕ)***, is the memory and execution step units resulting from the sum of memory and execution step units of all its transactions. That is, ***blockExUnits(block) := (∑ tx ∈ txs(block): txExUnits(txWits(tx)))***, where addition of execution units is defined pointwise.
|
||||
- ***blockExUnits(block) ∈ ExUnits***, where ***ExUnits := (ℕ, ℕ)***, is the memory and execution step units resulting from the sum of memory and execution step units of all its transactions. That is, ***blockExUnits(block) := ∑ tx ∈ txs(block): txExUnits(txWits(tx))***, where addition of execution units is defined pointwise.
|
||||
- **Transactions**:
|
||||
- ***Tx*** is the set of all possible (not necessarily valid) Alonzo transactions, composed of a transaction body and a witness set. When clear, we will write ***tx*** to refer to the current transaction.
|
||||
- ***txIsPhase1Valid(block, pps, tx) ∈ Bool*** indicates whether ***tx ∈ txs(block)*** is phase-1 valid under ***pps***.
|
||||
- ***TxBody*** is the type of Alonzo transaction bodies. Each transaction body is composed of a set of inputs, a list of outputs, and related data.
|
||||
- ***txBody(tx)*** is the transaction body of the transaction. When clear, we will write ***txBody*** to refer to the transaction body of the current transaction.
|
||||
- ***TxOut = Addr x Value x DatumHash*** is the set of transaction outputs, where
|
||||
- ***Tx*** is the type of Alonzo transactions, composed of a transaction body and a witness set. We will write ***tx*** to refer to the current transaction.
|
||||
- ***txIsPhase1Valid(pps, tx) ∈ Bool*** indicates whether ***tx ∈ Tx*** is phase-1 valid for the Alonzo leger under ***pps***.
|
||||
- ***TxBody*** is the type of Alonzo transaction bodies. Each transaction body is composed of a set of inputs, a list of outputs, and other related data.
|
||||
- ***txBody(tx)*** is the transaction body of the transaction. We will write ***txBody*** to refer to the transaction body of the current transaction.
|
||||
- ***TxOut = Addr x Value x DatumHash*** is the type of transaction outputs, where
|
||||
- ***Addr*** is the set of transaction output addresses.
|
||||
- ***Value*** is the type of multi-asset Alonzo values. We define addition, equality comparisons and ordering comparisons for them in a point-wise manner.
|
||||
- ***Value*** is the type of multi-asset Alonzo values. We define addition, equality comparison and ordering comparisons for values in a point-wise manner.
|
||||
- ***getValue(txOut) ∈ Value*** gives the value contained in the transaction output.
|
||||
- ***isADAOnly : Value -> Bool*** indicates whether a value contains only ADA assets.
|
||||
- ***balance : P(TxOut) → Value*** gives the sum of all assets in a set of transaction outputs.
|
||||
- ***adaValueOf : ℕ -> Value*** gives the ADA-only value representation of a natural number.
|
||||
- ***valSize : Value -> ℕ*** gives the size of a value in bytes, when serialized.
|
||||
- ***policies(v)*** gives the set of policies of the assets of the value.
|
||||
- ***DatumHash ⊆ Bytes*** is the type of hashes computed from datums. This field is optional.
|
||||
- ***txOuts(txBody) ∈ P(TxOut)*** gives the list of transaction outputs of the transaction body.
|
||||
- ***balance : P(TxOut) → Value*** gives the sum of all multi-asset values in a set of transaction outputs.
|
||||
- ***utxoEntrySize(txOut) ∈ ℕ*** gives the size of the transaction output when serialized, in bytes.
|
||||
- ***outputEntrySize(txOut) ∈ ℕ*** gives the size of the transaction output when serialized, in bytes.
|
||||
- ***TxIn = TxId x Ix*** is the set of transaction inputs, where
|
||||
- ***TxId*** is the type of transaction IDs.
|
||||
- ***Ix = ℕ*** is the set of indices (used to refer to a specific transaction output).
|
||||
- ***Ix = ℕ*** is the set of indices, which are used to refer to a specific transaction output.
|
||||
- ***txIns(txBody) ∈ P(TxIn)*** gives the set of *non-collateral* inputs of the transaction.
|
||||
- ***collateral(txBody) ∈ P(TxIn)*** gives the set of *collateral* inputs of the transaction.
|
||||
- ***txInsVKey(txBody) ∈ P(TxIn)*** gives the set of transaction inputs of the transaction which are verification-key locked.
|
||||
|
|
@ -40,12 +41,12 @@ This document covers the Alonzo era. This document covers the concepts, notation
|
|||
- ***PolicyID*** is the set of all possible policy IDs associated to multi-asset values. In particular, ***adaID ∈ Policy*** is the policy of lovelaces.
|
||||
- ***consumed(utxo, txBody) ∈ ℤ*** is the *consumed value* of the transaction, which equals the sum of all multi-asset values in the inputs of the transaction.
|
||||
- ***produced(txBody) ∈ ℤ*** is the *produced value* of the transaction, which equals the sum of all multi-asset values in the outputs of the transaction, plus the transaction fee, plus the minted value.
|
||||
- ***txNetId(txBody) ∈ NetworkID*** gives the network ID of a transaction (not to be confused with the network ID of addresses of unspent transaction outputs).
|
||||
- ***txNetId(txBody) ∈ NetworkID*** gives the network ID of a transaction (not to be confused with the network ID of addresses of unspent transaction outputs). This field is optional.
|
||||
- ***txWits(tx)*** is the transaction witness set. When clear, we will write ***txWits*** to refer to the transaction witness set of the current transaction.
|
||||
- ***txExUnits(txWits) ∈ ExUnits*** is the total execution units of the transaction.
|
||||
- ***txMD(tx)*** is the metadata of the transaction.
|
||||
- ***hashMD(md)*** is the result of hasing metadata ***md***.
|
||||
- ***txMDHash(txBody)*** is the metadata hash contained within the transaction body.
|
||||
- ***txAuxDat(tx)*** is the auxiliary data of the transaction.
|
||||
- ***hashMD(md)*** is the result of hasing auxiliary data ***md***.
|
||||
- ***txAuxDatHash(txBody)*** is the auxiliary data hash contained within the transaction body.
|
||||
- **Addresses**:
|
||||
- ***Addr*** is the set of all valid Alonzo addresses.
|
||||
- ***hashAddr : Addr -> Bytes*** is the hashing function for addresses.
|
||||
|
|
@ -67,9 +68,9 @@ This document covers the Alonzo era. This document covers the concepts, notation
|
|||
- ***keyHash: VKey -> KeyHash*** is the hashing function for verification keys, where ***KeyHash ⊆ Bytes***
|
||||
- **Scripts**:
|
||||
- ***Script*** is the set of all Alonzo scripts: minting policies, native scripts and Plutus scripts. We will use the term *script* to refer to any of these kinds of scripts.
|
||||
- ***isPlutusScript(script) ∈ Bool*** assesses whether a script is a Plutus one (that is, it is not a native script).
|
||||
- ***isPlutusScript(script) ∈ Bool*** assesses whether a script is a Plutus script (that is, it is not a native script).
|
||||
- ***scriptDataHash(txBody) ∈ Bytes*** is the hash of script-related data (transaction redeemers and relevant protocol parameters).
|
||||
- ***hashScriptIntegrity : PParams -> P((Tag, Ix, Redeemer, ExUnits)) -> Languages -> P(DaAtum) -> Bytes*** hashes the protocol parameters and data relevant to script execution.
|
||||
- ***hashScriptIntegrity : PParams -> P((Tag, Ix, Redeemer, ExUnits)) -> Languages -> P(Datum) -> Bytes*** hashes the protocol parameters and data relevant to script execution.
|
||||
- **Protocol Parameters**:
|
||||
- We will write ***pps ∈ PParams*** to represent the set of Alonzo protocol parameters, each of which contains at least the following associated functions:
|
||||
- ***maxBlockExUnits(pps) ∈ ExUnits*** gives the maximum memory and execution step units for a block.
|
||||
|
|
@ -81,10 +82,10 @@ This document covers the Alonzo era. This document covers the concepts, notation
|
|||
- ***collateralPercent(pps) ∈ {0,...,100}*** gives the fee percentage (multiplied by 100) that all lovelace in collateral inputs should add up to.
|
||||
- ***coinsPerUTxOWord(pps) ∈ ℕ*** is the number of lovelace a UTxO should contain per byte (when serialized). This is used to assess the minimum number of lovelace that an unspent transaction output should lock.
|
||||
- ***costModels : PParams -> (Languages -> CostModel)*** takes the protocol parameters and returns a map associating languages to their cost models.
|
||||
- ***Languages := {PlutusV1, PlutusV2}*** is the set of Alonzo languages.
|
||||
- ***Languages := {PlutusV1}*** is the set of Alonzo languages.
|
||||
- ***CostModel*** is the set of cost models.
|
||||
- ***Witnesses***:
|
||||
- ***TxWits*** is the set of all possible transaction witness set.
|
||||
- ***TxWits*** is the type of transaction witnesses.
|
||||
- ***VKey*** is the set of verification keys (a.k.a. public keys).
|
||||
- ***SKey*** is the set of signing keys (a.k.a. private keys).
|
||||
- ***Sig*** is the set of signatures (i.e., the result of signing a byte array using a signing key).
|
||||
|
|
@ -97,21 +98,21 @@ This document covers the Alonzo era. This document covers the concepts, notation
|
|||
- To all phase-1 validation purposes, we restrict ***Tag*** to ***Tag = {Mint, Spend}***. This is used to indicate whether a script is used on minting purposes (native scripts and minting policies), or should be executed (native scripts and Plutus scripts).
|
||||
- Recall that ***Ix := ℕ***, and represents an index on a list-like structure.
|
||||
- ***Redeemer*** is the low-level representation of a redeemer, required by executors to execute validation on Plutus scripts.
|
||||
- ***scriptsNeeded(utxo, txBody) ∈ P((ScriptPurpose x ScriptHash))*** assembles all the ***ScriptPurpose*** terms for validation of every transaction that may require script validation, each one paired with the hash of the corresponding witnessing script. This collects hashes of both native and Plutus scripts.
|
||||
- ***scriptsNeeded(utxo, txBody) ∈ P((ScriptPurpose x ScriptHash))*** assembles all the ***(ScriptPurpose, ScriptHash)*** values for validation of every aspect of the transaction that may require script validation. This collects hashes of both native and Plutus scripts.
|
||||
- ***ScriptPurpose := {PolicyID, TxIn}*** indicates whether the script is related to minting purposes (***PolicyID***) or should be executed to spend an input of the transaction (***TxIn***).
|
||||
- ***ScriptHash ⊆ Bytes*** is the type of validator hashes.
|
||||
- ***scriptHash : Script -> ScriptHash*** is the hashing function for scripts.
|
||||
- ***redeemerPointer: TxBody -> ScriptPurpose -> (Tag, Ix)*** builds a redeemer pointer (that is, a representation suitable for matching with ***txRedeemers(txWits)***), setting the tag according to the type of the script purpose, and the index according to the order of the item represented by the script purpose (either a policy ID or a transaction input) in its container. For example, applying ***redeemerPoint*** on script purpose ***txIn ∈ TxIn*** yields the index of ***txIn*** within ***txIns(txBody)***.
|
||||
- ***txScripts(txWits) ⊆ P(Script)*** is the set of scripts in the transaction witness set, both native and Plutus.
|
||||
- ***txScripts(txWits) ∈ P(Script)*** is the set of scripts in the transaction witness set, both native and Plutus.
|
||||
- ***txDats(txWits) ∈ P(Datum)*** is the set of all script-related datum objects of the transaction.
|
||||
- ***datumHash: Datum -> DatumHash*** is the application of the hashing function on a ***Datum*** value.
|
||||
- ***languages(txWits) ∈ Languages*** is the set of *languages* required by the scripts of the transaction.
|
||||
- ***languages(txWits) ∈ Languages*** is the set of *languages* required by the Plutus scripts of the transaction.
|
||||
|
||||
|
||||
## Validation rules for blocks
|
||||
Let ***block ∈ Block*** be an Alonzo block, and let ***tx ∈ Tx*** be one of its Alonzo transactions, with transaction body ***txBody ∈ TxBody*** and witness set ***txWits ∈ TxWits***. We say that ***block*** is a phase-1 valid block if and only if the total sum of execution units of all its transactions does not exceed the maximum allowed by the protocol, and all its transactions are phase-1 valid. That is, ***block*** is phase-1 valid if and only if:
|
||||
|
||||
<code>maxBlockExUnits(pps) ≥ blockExUnits(block) ∧ ∀ tx ∈ txs(block): txIsPhase1Valid(block, tx)</code>
|
||||
<code>maxBlockExUnits(pps) ≥ blockExUnits(block) ∧ ∀ tx ∈ txs(block): txIsPhase1Valid(pps, tx)</code>
|
||||
|
||||
## Validation rules for transactions
|
||||
|
||||
|
|
@ -120,13 +121,13 @@ Let ***tx ∈ Tx*** be one of its Alonzo transactions, with transaction body ***
|
|||
- **The set of transaction inputs is not empty**:
|
||||
|
||||
<code>txIns(txBody) ≠ ∅</code>
|
||||
- **All transaction inputs and collateral inputs are in the set of (yet) unspent transaction outputs**:
|
||||
- **All transaction inputs (regular inputs, collateral inputs and reference inputs) are in the UTxO**:
|
||||
|
||||
<code>txIns(txBody) ∪ collateral(txBody) ⊆ dom(utxo)</code>
|
||||
- **The block slot is contained in the transaction validity interval**:
|
||||
|
||||
<code>slot ∈ txValidityInterval(txBody)</code>
|
||||
- **The upper bound of the validity time interval is suitable for script execution**: if there are minting policies, native or Plutus scripts in the transaction, and the upper bound of its validity interval is defined, then the upper bound slot of the interval is translatable to system time. That is, if there are neeeded scripts in the transaction, then it is the case that ***txValidityInterval(txBody) := (\_, ub)*** where ***ub*** is defined.
|
||||
- **The upper bound of the validity time interval is suitable for script execution**: if there are minting policies, native scripts or Plutus scripts involved in the transaction, and if the upper bound of its validity interval is a finite number, then it can be translated to system time.
|
||||
|
||||
- **Fees**:
|
||||
- **The fee paid by the transaction should be greater than or equal to the minimum fee**:
|
||||
|
|
@ -151,10 +152,10 @@ Let ***tx ∈ Tx*** be one of its Alonzo transactions, with transaction body ***
|
|||
- **The preservation of value property holds**: Assuming no staking or delegation actions are involved, it should be that
|
||||
|
||||
<code>consumed(utxo, txBody) = produced(txBody) + fee(txBody) + minted(txBody)</code>
|
||||
- **All transaction outputs should contain at least the minimum lovelace**:
|
||||
- **All transaction outputs (regular outputs and collateral return outputs) should contain at least the minimum lovelace**:
|
||||
|
||||
<code>∀ txOut ∈ txOuts(txBody): adaValueOf(coinsPerUTxOWord(pps) * utxoEntrySize(txOut)) ≤ getValue(txOut)</code>
|
||||
- **The size of the value in each of the outputs should not be greater than the maximum allowed**:
|
||||
<code>∀ txOut ∈ txOuts(txBody): adaValueOf(coinsPerUTxOWord(pps) * outputEntrySize(txOut)) ≤ getValue(txOut)</code>
|
||||
- **The size of the value in each of the transaction outputs (regular outputs and collateral return outputs) should not be greater than the maximum allowed**:
|
||||
|
||||
<code>valSize(getValue(txOut)) ≤ maxValSize(pps)</code>
|
||||
- **The network ID of each output matches the global network ID**:
|
||||
|
|
@ -167,6 +168,9 @@ Let ***tx ∈ Tx*** be one of its Alonzo transactions, with transaction body ***
|
|||
- **The number of execution units of the transaction should not exceed the maximum allowed**:
|
||||
|
||||
<code>txExUnits(txBody) ≤ maxTxExUnits(pps)</code>
|
||||
- **No ADA is minted**:
|
||||
|
||||
<code>adaID ∉ policies(minted(txBody))</code>
|
||||
- **Witnesses**:
|
||||
- **Minting policy, native script and Plutus script witnesses**:
|
||||
|
||||
|
|
@ -187,19 +191,16 @@ Let ***tx ∈ Tx*** be one of its Alonzo transactions, with transaction body ***
|
|||
|
||||
- <code>verify(vk, σ, ⟦txBody⟧<sub>TxBody</sub>)</code>
|
||||
- <code>paymentCredential<sub>utxo</sub>(txIn) = keyHash(vk)</code>
|
||||
- **All required signers (needed by a Plutus script) have a corresponding match in the transaction witness set**: for each ***key_hash ∈ requiredSigners(txBody)***, there should exist ***(vk, σ) ∈ txVKWits(tx)*** such that:
|
||||
- **All required signers (needed by one of the Plutus scripts of the transaction) have a corresponding match in the transaction witness set**: for each ***key_hash ∈ requiredSigners(txBody)***, there should exist ***(vk, σ) ∈ txVKWits(tx)*** such that:
|
||||
|
||||
- <code>verify(vk, σ, ⟦txBody⟧<sub>TxBody</sub>)</code>
|
||||
- <code>keyHash(vk) = key_hash</code>
|
||||
- **The required script languages are included in the protocol parameters**:
|
||||
|
||||
<code>languages(txWits) ⊆ {l : (l -> _) ∈ costModels(pps, language)}</code>
|
||||
- **The metadata of the transaction is valid**:
|
||||
- **The auxiliary data of the transaction is valid**:
|
||||
|
||||
<code>txMDHash(tx) = hashMD(txMD(tx))</code>
|
||||
<code>txAuxDatHash(tx) = hashMD(txAuxDat(tx))</code>
|
||||
- **The script data integrity hash matches the hash of the redeemers, languages and datums of the transaction witness set**:
|
||||
|
||||
<code>scriptDataHash(txBody) = hashScriptIntegrity(pps, txRedeemers(txWits), languages(txWits), txDats(txWits))</code>
|
||||
- **No ADA is minted**:
|
||||
|
||||
<code>adaID ∉ policies(mint(txBody))</code>
|
||||
|
|
|
|||
239
pallas-applying/docs/babbage.md
Normal file
239
pallas-applying/docs/babbage.md
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
# Babbage phase-1 validation rules
|
||||
|
||||
This document covers the terminology and equations related to the Babbage ledger phase-1 validation rules. For further information, refer to the [Babbage ledger white paper](https://github.com/IntersectMBO/cardano-ledger/releases/download/cardano-ledger-spec-2023-04-03/babbage-ledger.pdf).
|
||||
|
||||
## Definitions and notation
|
||||
- **Blocks**:
|
||||
- ***Block*** is the type of Babbage blocks. We will write ***block*** to refer to the current block being validated.
|
||||
- ***txs(block)*** is the set of transactions of the block.
|
||||
- ***blockExUnits(block) ∈ ExUnits***, where ***ExUnits := (ℕ, ℕ)***, is the memory and execution step units resulting from the sum of memory and execution step units of all its transactions. That is, ***blockExUnits(block) := ∑ tx ∈ txs(block): txExUnits(txWits(tx))***, where addition of execution units is defined pointwise.
|
||||
- **Transactions**:
|
||||
- ***Tx*** is the type of Babbage transactions, composed of a transaction body and a witness set. We will write ***tx*** to refer to the current transaction.
|
||||
- ***txIsPhase1Valid(pps, tx) ∈ Bool*** indicates whether ***tx ∈ Tx*** is phase-1 valid for the Babbage leger under ***pps***.
|
||||
- ***TxBody*** is the type of Babbage transaction bodies. Each transaction body is composed of a set of inputs, a list of outputs, and other related data.
|
||||
- ***txBody(tx)*** is the transaction body of the transaction. We will write ***txBody*** to refer to the transaction body of the current transaction.
|
||||
- ***TxOut = Addr x Value x DatumOption x ScriptRef*** is the set of transaction outputs, where
|
||||
- ***Addr*** is the type of transaction output addresses.
|
||||
- ***Value*** is the type of multi-asset Babbage values. We define addition, equality comparison and ordering comparisons for values in a point-wise manner.
|
||||
- ***getValue(txOut) ∈ Value*** gives the value contained in the transaction output.
|
||||
- ***isADAOnly : Value -> Bool*** indicates whether a value contains only ADA assets.
|
||||
- ***balance : P(TxOut) → Value*** gives the sum of all assets in a set of transaction outputs.
|
||||
- ***adaValueOf : ℕ -> Value*** gives the ADA-only value representation of a natural number.
|
||||
- ***valSize : Value -> ℕ*** gives the size of a value in bytes, when serialized.
|
||||
- ***policies(v) ∈ P(PolicyID)*** gives the set of policies of the assets of the value.
|
||||
- ***DatumOption ⊆ DatumHash U Datum*** is the union type of datum hashes and datums. This field is optional, and combines the datum hash feature from Alonzo with the possibility to store datums *inline*.
|
||||
- ***isDatum : DatumOption -> Bool*** returns ***true*** if the datum option is in ***Datum***.
|
||||
- ***isWellFormedDatum(b) ∈ Bool*** assesses whether bytestring ***b*** corresponds to the CBOR of a well-formed datum.
|
||||
- ***isDatumHash : DatumOption -> Bool*** returns ***true*** if the datum option is in ***DatumHash***.
|
||||
- ***ScriptRef*** is the type of script references in transaction outputs. This novel Babbage feature allows transactions to use a script without having to spend an output.
|
||||
- ***txOuts(txBody) ∈ P(TxOut)*** gives the list of transaction outputs of the transaction body.
|
||||
- ***txCollateralReturn(txBody) ∈ TxOut*** is the collateral return output of the transaction.
|
||||
- ***allOuts(txBody) ∈ P(TxOut)*** is defined as ***txOuts(txBody) ∪ {txCollateralReturn(txBody)}***.
|
||||
- ***balance : P(TxOut) → Value*** gives the sum of all multi-asset values in a set of transaction outputs.
|
||||
- ***txCollateralBalance(txBody, utxo) ∈ Value*** gives the value paid as collateral by the transaction, defined by the following equation: ***txCollatralBalance(txBody, utxo) := balance(txCollateralIns(txBody) ◁ utxo) - balance(txCollateralReturn(txBody))***.
|
||||
- ***outputEntrySize(txOut) ∈ ℕ*** gives the size of the transaction output when serialized, in bytes (plus an offset required only in the Babbage era).
|
||||
- ***TxIn = TxId x Ix*** is the set of transaction inputs, where
|
||||
- ***TxId*** is the type of transaction IDs.
|
||||
- ***Ix = ℕ*** is the set of indices, which are used to refer to a specific transaction output.
|
||||
- ***txSpendIns(txBody) ∈ P(TxIn)*** gives the set of *regular* inputs—i.e., transaction inputs without taking into account collateral and reference inputs).
|
||||
- ***txSpendInsVKey(txBody) ∈ P(TxIn)*** gives the subset of regular inputs of the transaction which are verification-key locked—i.e., without taking into account script inputs from ***txSpendIns(txBody)***.
|
||||
- ***txCollateralIns(txBody) ∈ P(TxIn)*** gives the set of *collateral* inputs of the transaction.
|
||||
- ***txReferenceIns(txBody) ∈ P(TxIn)*** gives the set of *reference* inputs of the transaction.
|
||||
- ***utxo : TxIn → TxOut*** is a (partial) map that gives the unspent transaction output (UTxO) associated with a transaction input.
|
||||
- Given ***A ⊆ dom(utxo)***, we will write ***A ◁ utxo := {txOut ∈ TxOut / ∃ txIn ∈ dom utxo: utxo(txIn) = txOut}***. For example, we will write ***txSpendIns(txBody) ◁ utxo := {txOut ∈ TxOut / ∃ ti ∈ dom(utxo): utxo(txIn) = txOut}*** to express the set of unspent transaction outputs associated with the set of inputs of the transaction.
|
||||
- ***txTotalColl(txBody) ∈ ℕ*** is the collateral paid by the transaction. Note that this is merely an annotation, and that validations should check whether this number actually equals the balance between the lovelace in all collateral inputs and the lovelace in the collateral return output.
|
||||
- ***txValidityInterval(txBody) ∈ (Slot, Slot)*** is the transaction validity interval, made of a lower and upper bound, both of which are optional.
|
||||
- ***requiredSigners(txBody) ∈ P(KeyHash)*** is the set of hashes of verification keys required for the execution of Plutus scripts, where ***KeyHash ⊆ Bytes***.
|
||||
- ***txSize(txBody) ∈ ℕ*** is the size of the transaction in bytes, when serialized.
|
||||
- ***fee(txBody) ∈ ℕ*** is the fee paid by the transaction.
|
||||
- ***minted(txBody)*** is the multi-asset value minted (or burned) in the transaction.
|
||||
- ***PolicyID*** is the set of all possible policy IDs associated to multi-asset values. In particular, ***adaID ∈ Policy*** is the policy of lovelaces.
|
||||
- ***consumed(utxo, txBody) ∈ ℤ*** is the *consumed value* of the transaction, which equals the sum of all multi-asset values in the inputs of the transaction.
|
||||
- ***produced(txBody) ∈ ℤ*** is the *produced value* of the transaction, which equals the sum of all multi-asset values in the outputs of the transaction, plus the transaction fee, plus the minted value.
|
||||
- ***txNetId(txBody) ∈ NetworkID*** gives the network ID of a transaction (not to be confused with the network ID of addresses of unspent transaction outputs).
|
||||
- ***txWits(tx)*** is the transaction witness set. We will write ***txWits*** to refer to the transaction witness set of the current transaction.
|
||||
- ***txExUnits(txWits) ∈ ExUnits*** is the total execution units of the transaction.
|
||||
- ***txAuxDat(tx)*** is the auxiliary data of the transaction.
|
||||
- ***hashMD(md)*** is the result of hasing auxiliary data ***md***.
|
||||
- ***txAuxDatHash(txBody)*** is the auxiliary data hash contained within the transaction body.
|
||||
- **Addresses**:
|
||||
- ***Addr*** is the set of all valid Babbage addresses.
|
||||
- ***hashAddr : Addr -> Bytes*** is the hashing function for addresses.
|
||||
- ***NetworkId*** is the global network ID.
|
||||
- ***netId : Addr -> NetworkID*** gives the network ID of an address.
|
||||
- ***isVKeyAddress(addr) -> Bool*** assesses whether the address is that of a verification key.
|
||||
- ***isPlutusScriptAddress(addr, txWits)*** assesses whether the address is that of a Plutus script.
|
||||
- ***Time***:
|
||||
- ***Slot ∈ ℕ*** is the set of slots. When necessary, we write ***slot ∈ Slot*** to refer to the slot associated to the current block.
|
||||
- ***UTCTime*** is the system time (UTC time zone).
|
||||
- ***EpochInfo*** is the Babbage epoch info.
|
||||
- ***SystemStart*** is the start time of the system.
|
||||
- ***epochInfoSlotToUTCTime: EpochInfo -> SystemStart -> Slot -> UTCTime*** translates a slot number to system time. The result is not always computable, as the slot number may be too far in the future for the system to predict the exact time to which it refers.
|
||||
- **Serialization**:
|
||||
- ***Bytes*** is the set of byte arrays (a.k.a. data, upon which signatures are built).
|
||||
- ***⟦_⟧<sub>A</sub> : A -> Bytes*** takes an element of type ***A*** and returns a byte array resulting from serializing it.
|
||||
- **Hashing**:
|
||||
- ***hash: A -> Bytes*** is the abstract function (considering that ***A*** is a generic type) we use to refer to a hashing function.
|
||||
- ***keyHash: VKey -> KeyHash*** is the hashing function for verification keys, where ***KeyHash ⊆ Bytes***
|
||||
- **Scripts**:
|
||||
- ***Script*** is the set of all Babbage scripts: minting policies, native scripts and Plutus scripts. We will use the term *script* to refer to any of these kinds of scripts.
|
||||
- ***isWellFormedScript(script) ∈ Bool*** assesses whether a script is well formed.
|
||||
- ***isPlutusScript(script) ∈ Bool*** assesses whether a script is a Plutus script (that is, it is not a native script).
|
||||
- ***scriptDataHash(txBody) ∈ Bytes*** is the hash of script-related data (transaction redeemers and relevant protocol parameters).
|
||||
- ***hashScriptIntegrity : PParams -> P((Tag, Ix, Redeemer, ExUnits)) -> Languages -> P(Datum) -> Bytes*** hashes the protocol parameters and data relevant to script execution.
|
||||
- ***txWitScripts(txWits) ∈ P(Script)*** is the set of scripts contained in the witness set of the transaction.
|
||||
- ***refScripts(txBody, utxo) ∈ P(Script)*** is the set of scripts contained in reference inputs.
|
||||
- ***auxDataScripts(tx) ∈ P(Script)*** is the set of scripts contained in the auxiliary data of the transaction.
|
||||
- **Protocol Parameters**:
|
||||
- We will write ***pps ∈ PParams*** to represent the set of Babbage protocol parameters, each of which contains at least the following associated functions:
|
||||
- ***maxBlockExUnits(pps) ∈ ExUnits*** gives the maximum memory and execution step units for a block.
|
||||
- ***maxTxExUnits(pps) ∈ ExUnits*** gives the maximum memory and execution step units for a transaction.
|
||||
- ***minFees(pps, txBody) ∈ ℕ*** gives the minimum number of lovelace that must be paid by the transaction as fee.
|
||||
- ***maxCollateralInputs(pps) ∈ ℕ*** gives the maximum number of collateral inputs allowed per transaction.
|
||||
- ***maxTxSize(pps) ∈ ℕ*** gives the maximum size any transaction can have.
|
||||
- ***maxValSize(pps) ∈ ℕ*** gives the maximum size in bytes allowed for values, when serialized.
|
||||
- ***collateralPercent(pps) ∈ {0,...,100}*** gives the fee percentage (multiplied by 100) that all lovelace in collateral inputs should add up to.
|
||||
- ***coinsPerUTxOWord(pps) ∈ ℕ*** is the number of lovelace a UTxO should contain per byte (when serialized). This is used to assess the minimum number of lovelace that an unspent transaction output should lock.
|
||||
- ***costModels : PParams -> (Languages -> CostModel)*** takes the protocol parameters and returns a map associating languages to their cost models.
|
||||
- ***Languages := {PlutusV1, PlutusV2}*** is the set of Babbage languages.
|
||||
- ***CostModel*** is the set of cost models.
|
||||
- ***Witnesses***:
|
||||
- ***TxWits*** is the type of transaction witnesses.
|
||||
- ***VKey*** is the set of verification keys (a.k.a. public keys).
|
||||
- ***SKey*** is the set of signing keys (a.k.a. private keys).
|
||||
- ***Sig*** is the set of signatures (i.e., the result of signing a byte array using a signing key).
|
||||
- ***sig : SKey x Bytes -> Sig*** is the signing function.
|
||||
- ***verify : VKey x Sig x Bytes -> Bool*** assesses whether the result of applying the verification key to the signature equals the byte array parameter.
|
||||
- The assumption is that if ***sk*** and ***vk*** are, respectively, a pair of secret and verification keys associated with one another. Thus, if ***sig(sk, d) = σ***, then it must be that ***verify(vk, σ, d) = true***.
|
||||
- ***txVKWits(txWits) ⊆ P(VKey x Sig)*** gives the list of pairs of verification keys and signatures of the transaction.
|
||||
- ***paymentCredential<sub>utxo</sub>(txIn) ∈ KeyHash*** gets from ***txIn*** the associated transaction output in ***utxo***, extracts the address contained in it, and returns its hash. In other words, given ***utxo*** and transaction input ***txIn*** such that ***utxo(txIn) = (a, \_, \_, \_)***, we have that ***paymentCredential<sub>utxo</sub>(txIn) = hashAddr(a)***.
|
||||
- ***txRedeemers(txWits) ⊆ P((Tag, Ix, Redeemer, ExUnits))*** is the set of redeemers of the transaction. This (seemingly artificial) conjunction of values of different types will be useful to assess phase-1 validity of the transaction in a concise way.
|
||||
- To all phase-1 validation purposes, we restrict ***Tag*** to ***Tag = {Mint, Spend}***. This is used to indicate whether a script is used on minting purposes (native scripts and minting policies), or should be executed (native scripts and Plutus scripts).
|
||||
- Recall that ***Ix := ℕ***, and represents an index on a list-like structure.
|
||||
- ***Redeemer*** is the low-level representation of a redeemer, required by executors to execute validation on Plutus scripts.
|
||||
- ***scriptsNeeded(utxo, txBody) ∈ P((ScriptPurpose x ScriptHash))*** assembles all the ***(ScriptPurpose, ScriptHash)*** values for validation of every aspect of the transaction that may require script validation. This collects hashes of both native and Plutus scripts, and is comprised of the minting policies, the hash of all native and Plutus scripts in ***txSpendIns(txBody)***, and the hash of all elements in ***txReferenceIns(tx)***—that is, the hash of all reference scripts.
|
||||
- ***ScriptPurpose := {PolicyID, TxIn}*** indicates whether the script is related to minting purposes (***PolicyID***) or should be executed to spend an input of the transaction (***TxIn***).
|
||||
- ***ScriptHash ⊆ Bytes*** is the type of validator hashes.
|
||||
- ***scriptHash : Script -> ScriptHash*** is the hashing function for scripts.
|
||||
- ***redeemerPointer: TxBody -> ScriptPurpose -> (Tag, Ix)*** builds a redeemer pointer (that is, a representation suitable for matching with ***txRedeemers(txWits)***), setting the tag according to the type of the script purpose, and the index according to the order of the item represented by the script purpose (either a policy ID or a transaction input) in its container. For example, applying ***redeemerPoint*** on script purpose ***txIn ∈ TxIn*** yields the index of ***txIn*** within ***txSpendIns(txBody)***.
|
||||
- ***txScripts(tx, utxo) ∈ P(Script)*** is the set of scripts in the transaction witness set of ***tx***, both native and Plutus, as well as those in reference inputs—i.e., the scripts obtained applying ***utxo*** on the reference inputs of ***tx***.
|
||||
- ***txDats(txWits) ∈ P(Datum)*** is the set of all script-related datum objects of the transaction.
|
||||
- ***datumHash: Datum -> DatumHash*** is the application of the hashing function on a ***Datum*** value.
|
||||
- ***languages(tx, utxo) ∈ Languages*** is the set of *languages* required by the Plutus scripts in ***tx***.
|
||||
|
||||
|
||||
## Validation rules for blocks
|
||||
Let ***block ∈ Block*** be an Babbage block, and let ***tx ∈ Tx*** be one of its Babbage transactions, with transaction body ***txBody ∈ TxBody*** and witness set ***txWits ∈ TxWits***. We say that ***block*** is a phase-1 valid block if and only if the total sum of execution units of all its transactions does not exceed the maximum allowed by the protocol, and all its transactions are phase-1 valid. That is, ***block*** is phase-1 valid if and only if:
|
||||
|
||||
<code>maxBlockExUnits(pps) ≥ blockExUnits(block) ∧ ∀ tx ∈ txs(block): txIsPhase1Valid(pps, tx)</code>
|
||||
|
||||
## Validation rules for transactions
|
||||
|
||||
Let ***tx ∈ Tx*** be one of its Babbage transactions, with transaction body ***txBody ∈ TxBody*** and witness set ***txWits***. We say that ***tx*** is a phase-1 valid transaction if and only if
|
||||
|
||||
- **The set of transaction inputs is not empty**:
|
||||
|
||||
<code>txSpendIns(txBody) ≠ ∅</code>
|
||||
- **All transaction inputs, collateral inputs and reference inputs are in the UTxO**:
|
||||
|
||||
<code>txSpendIns(txBody) ∪ txCollateralIns(txBody) ∪ txReferenceIns(txBody) ⊆ dom(utxo)</code>
|
||||
- **The block slot is contained in the transaction validity interval**:
|
||||
|
||||
<code>slot ∈ txValidityInterval(txBody)</code>
|
||||
- **The upper bound of the validity time interval is suitable for script execution**: if there are minting policies, native scripts or Plutus scripts involved in the transaction, and if the upper bound of its validity interval is a finite number, then it can be translated to system time.
|
||||
|
||||
- **Fees**:
|
||||
- **The fee paid by the transaction is greater than or equal to the minimum fee**:
|
||||
|
||||
<code>fee(txBody) ≥ minFees(pps, txBody)</code>
|
||||
- **Collateral**: if there are Plutus scripts in the transaction, then
|
||||
- **The set of collateral inputs is not empty**:
|
||||
|
||||
<code>txCollateralIns(txBody) ≠ ∅</code>
|
||||
- **The number of collateral inputs is not above maximum**:
|
||||
|
||||
<code>∥txCollateralIns(txBody)∥ ≤ maxCollateralInputs(pps)</code>
|
||||
- **Each collateral input refers to a verification-key address**:
|
||||
|
||||
<code>∀(a,\_,\_,\_) ∈ txCollateralIns(txBody) ◁ utxo: isVKeyAddress(a)</code>
|
||||
- **The balance between collateral inputs and outputs contains only ADA**:
|
||||
|
||||
<code>isADAOnly(txCollateralBalance(txBody, utxo))</code>
|
||||
- **The paid collateral is greater than or equal to the minimum fee percentage**:
|
||||
|
||||
<code>txCollateralBalance(txBody, utxo) >= fee(txBody) * collateralPercent(pps)</code>
|
||||
- **If a number of collateral lovelace is specified in the transaction body, then it equals the actual collateral paid by the transaction**:
|
||||
|
||||
<code>balance(txCollateralIns(txBody) ◁ utxo) - balance(txCollateralReturn(txBody)) = txTotalColl(txBody)</code>
|
||||
- **The preservation of value property holds**: Assuming no staking or delegation actions are involved, it is the case that
|
||||
|
||||
<code>consumed(utxo, txBody) = produced(txBody) + fee(txBody) + minted(txBody)</code>
|
||||
- **All transaction outputs (regular outputs and collateral return outputs) contains at least the minimum lovelace**:
|
||||
|
||||
<code>∀ txOut ∈ txOuts(txBody): adaValueOf(coinsPerUTxOWord(pps) * (outputEntrySize(txOut) + 160)) ≤ getValue(txOut)</code>
|
||||
- **The size of the value in each of the outputs is not greater than the maximum allowed**:
|
||||
|
||||
<code>valSize(getValue(txOut)) ≤ maxValSize(pps)</code>
|
||||
- **The network ID of each regular output as well as that of the collateral return output match the global network ID**:
|
||||
|
||||
<code>∀(a,\_) ∈ txOuts(txBody): netId(a) = NetworkId</code>
|
||||
- **The network ID of the transaction body is either undefined or equal to the global network ID**
|
||||
- **The transaction size does not exceed the protocol limit**:
|
||||
|
||||
<code>txSize(txBody) ≤ maxTxSize(pps)</code>
|
||||
- **The number of execution units of the transaction does not exceed the maximum allowed**:
|
||||
|
||||
<code>txExUnits(txBody) ≤ maxTxExUnits(pps)</code>
|
||||
- **No ADA is minted**:
|
||||
|
||||
<code>adaID ∉ policies(minted(txBody))</code>
|
||||
- **Well-formedness of all datums and scripts**:
|
||||
- **All datums in the witness set are well-formed**:
|
||||
|
||||
<code>∀ d ∈ txDats(txWits): isWellFormedDatum(d)</code>
|
||||
- **All scripts in the witness set are well-formed**:
|
||||
|
||||
<code>∀ s ∈ txWitScripts(txWits): isWellFormedScript(s)</code>
|
||||
- **All scripts in the auxiliary data are well-formed**:
|
||||
|
||||
<code>∀ s ∈ auxDataScripts(txAuxDat(tx)): isWellFormedScript(s)</code>
|
||||
- **All output datums are well-formed**:
|
||||
|
||||
<code>∀ (\_,\_,d,\_) ∈ allOuts(txBody): isDatum(d) => isWellFormedDatum(d)</code>
|
||||
- **All output scripts are well-formed**:
|
||||
|
||||
<code>∀ (\_,\_,\_,d) ∈ allOuts(txBody): isWellFormedScript(d)</code>
|
||||
- **Witnesses**:
|
||||
- **Minting policies, native scripts and Plutus scripts, reference scripts**:
|
||||
|
||||
- **Each minting policy or script hash in a script input address can be matched to a script in the transaction witness set, except when it can be found in a reference input**:
|
||||
|
||||
<code>{h: (\_, h) ∈ scriptsNeeded(utxo, txBody)} - {scriptHash(s): s ∈ refScripts(txBody, utxo)} = {scriptHash(s) : s ∈ txScripts(tx, utxo)}</code>
|
||||
- **Each datum hash in a Plutus script input matches the hash of a datum in the transaction witness set**:
|
||||
|
||||
<code>{h : (a,\_,h,\_) ∈ txSpendIns(txBody) ◁ utxo, isPlutusScriptAddress(a, txWits)} ⊆ {datumHash(d) : d ∈ txDats(txWits)}</code>
|
||||
- **Each datum in the transaction witness set can be related to the datum hash in a Plutus script input, or in a reference input, or in a regular output, or in the collateral return output**:
|
||||
|
||||
<code>{datumHash(d): d ∈ txDats(txWits)} ⊆ {h: (a,\_,h,\_) ∈ txSpendIns(txBody) ◁ utxo, isPlutusScriptAddress(a, txWits), isDatumHash(h)} ∪ {h: (\_,\_,h,\_) ∈ txReferenceIns(tx) ◁ utxo, isDatumHash(h)} ∪ {h: (\_,\_,h,\_) ∈ allOuts(txBody), isDatumHash(h)}</code>
|
||||
- **The set of redeemers in the transaction witness set matches the set of Plutus scripts needed to validate the transaction**:
|
||||
|
||||
<code>{(tag, index): (tag, index, \_, \_) ∈ txRedeemers(txWits)} = {redeemerPointer(txBody, sp): (sp, h) ∈ scriptsNeeded(utxo, txBody), (∃s ∈ txScripts(tx, utxo): isPlutusScript(s), h = scriptHash(s)}</code>
|
||||
- **Verification-key witnesses**:
|
||||
- **The owner of each transaction input and each collateral input has signed the transaction**:
|
||||
|
||||
<code>∀ txIn ∈ txSpendInsVKey(txBody): (∃ (vk, σ) ∈ txVKWits(tx): verify(vk, σ, ⟦txBody⟧<sub>TxBody</sub>) ∧ paymentCredential<sub>utxo</sub>(txIn) = keyHash(vk))</code>
|
||||
- **All required signers (needed by one of the Plutus scripts of the transaction) have a corresponding match in the transaction witness set**: for each ***key_hash ∈ requiredSigners(txBody)***, there exists ***(vk, σ) ∈ txVKWits(tx)*** such that:
|
||||
|
||||
<code>∀ key_hash ∈ requiredSigners(txBody): (∃ (vk, σ) ∈ txVKWits(tx): verify(vk, σ, ⟦txBody⟧<sub>TxBody</sub>) ∧ keyHash(vk) = key_hash) </code>
|
||||
- **The required script languages are included in the protocol parameters**:
|
||||
|
||||
<code>languages(tx, utxo) ⊆ {l : (l -> _) ∈ costModels(pps, language)}</code>
|
||||
- **The auxiliary data of the transaction is valid**:
|
||||
|
||||
<code>txAuxDatHash(tx) = hashMD(txAuxDat(tx))</code>
|
||||
- **The script data integrity hash matches the hash of the redeemers, languages and datums of the transaction witness set**:
|
||||
|
||||
<code>scriptDataHash(txBody) = hashScriptIntegrity(pps, txRedeemers(txWits), languages(tx, utxo), txDats(txWits))</code>
|
||||
- **Each minted / burned asset can be related to the corresponding native or Plutus script in the transaction witness set**
|
||||
|
||||
<code>policies(minted(txBody)) ⊆ {scriptHash(s): s ∈ txScripts(tx, utxo)}</code>
|
||||
|
|
@ -1,9 +1,10 @@
|
|||
//! Utilities required for Shelley-era transaction validation.
|
||||
//! Utilities required for Alonzo-era transaction validation.
|
||||
|
||||
use crate::utils::{
|
||||
add_minted_value, add_values, empty_value, extract_auxiliary_data, get_alonzo_comp_tx_size,
|
||||
get_lovelace_from_alonzo_val, get_network_id_value, get_payment_part, get_shelley_address,
|
||||
get_val_size_in_words, mk_alonzo_vk_wits_check_list, values_are_equal, verify_signature,
|
||||
add_minted_value, add_values, aux_data_from_alonzo_minted_tx, compute_native_script_hash,
|
||||
compute_plutus_script_hash, empty_value, get_alonzo_comp_tx_size, get_lovelace_from_alonzo_val,
|
||||
get_network_id_value, get_payment_part, get_shelley_address, get_val_size_in_words,
|
||||
mk_alonzo_vk_wits_check_list, values_are_equal, verify_signature,
|
||||
AlonzoError::*,
|
||||
AlonzoProtParams, FeePolicy, UTxOs,
|
||||
ValidationError::{self, *},
|
||||
|
|
@ -18,9 +19,9 @@ use pallas_codec::{
|
|||
use pallas_crypto::hash::Hash;
|
||||
use pallas_primitives::{
|
||||
alonzo::{
|
||||
AddrKeyhash, Mint, MintedTx, MintedWitnessSet, NativeScript, PlutusData, PlutusScript,
|
||||
PolicyId, Redeemer, RedeemerPointer, RedeemerTag, RequiredSigners, TransactionBody,
|
||||
TransactionInput, TransactionOutput, VKeyWitness, Value,
|
||||
AddrKeyhash, Mint, MintedTx, MintedWitnessSet, Multiasset, NativeScript, PlutusData,
|
||||
PlutusScript, PolicyId, Redeemer, RedeemerPointer, RedeemerTag, RequiredSigners,
|
||||
TransactionBody, TransactionInput, TransactionOutput, VKeyWitness, Value,
|
||||
},
|
||||
byron::TxOut,
|
||||
};
|
||||
|
|
@ -48,7 +49,7 @@ pub fn validate_alonzo_tx(
|
|||
check_tx_ex_units(mtx, prot_pps)?;
|
||||
check_witness_set(mtx, utxos)?;
|
||||
check_languages(mtx, prot_pps)?;
|
||||
check_metadata(tx_body, mtx)?;
|
||||
check_auxiliary_data(tx_body, mtx)?;
|
||||
check_script_data_hash(tx_body, mtx)?;
|
||||
check_minting(tx_body, mtx)
|
||||
}
|
||||
|
|
@ -201,14 +202,15 @@ fn check_collaterals_address(collaterals: &[TransactionInput], utxos: &UTxOs) ->
|
|||
Some(multi_era_output) => {
|
||||
if let Some(alonzo_comp_output) = MultiEraOutput::as_alonzo(multi_era_output) {
|
||||
if let ShelleyPaymentPart::Script(_) =
|
||||
get_payment_part(alonzo_comp_output).ok_or(Alonzo(InputDecoding))?
|
||||
get_payment_part(&alonzo_comp_output.address)
|
||||
.ok_or(Alonzo(InputDecoding))?
|
||||
{
|
||||
return Err(Alonzo(CollateralNotVKeyLocked));
|
||||
}
|
||||
}
|
||||
}
|
||||
None => return Err(Alonzo(CollateralNotInUTxO)),
|
||||
};
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -258,12 +260,11 @@ fn check_collaterals_assets(
|
|||
|
||||
// The preservation of value property holds.
|
||||
fn check_preservation_of_value(tx_body: &TransactionBody, utxos: &UTxOs) -> ValidationResult {
|
||||
let neg_val_err: ValidationError = Alonzo(NegativeValue);
|
||||
let input: Value = get_consumed(tx_body, utxos)?;
|
||||
let mut input: Value = get_consumed(tx_body, utxos)?;
|
||||
let produced: Value = get_produced(tx_body)?;
|
||||
let output: Value = add_values(&produced, &Value::Coin(tx_body.fee), &neg_val_err)?;
|
||||
let output: Value = add_values(&produced, &Value::Coin(tx_body.fee), &Alonzo(NegativeValue))?;
|
||||
if let Some(m) = &tx_body.mint {
|
||||
add_minted_value(&output, m, &neg_val_err)?;
|
||||
input = add_minted_value(&input, m, &Alonzo(NegativeValue))?;
|
||||
}
|
||||
if !values_are_equal(&input, &output) {
|
||||
return Err(Alonzo(PreservationOfValue));
|
||||
|
|
@ -272,17 +273,18 @@ fn check_preservation_of_value(tx_body: &TransactionBody, utxos: &UTxOs) -> Vali
|
|||
}
|
||||
|
||||
fn get_consumed(tx_body: &TransactionBody, utxos: &UTxOs) -> Result<Value, ValidationError> {
|
||||
let neg_val_err: ValidationError = Alonzo(NegativeValue);
|
||||
let mut res: Value = empty_value();
|
||||
for input in tx_body.inputs.iter() {
|
||||
let utxo_value: &MultiEraOutput = utxos
|
||||
.get(&MultiEraInput::from_alonzo_compatible(input))
|
||||
.ok_or(Alonzo(InputNotInUTxO))?;
|
||||
match MultiEraOutput::as_alonzo(utxo_value) {
|
||||
Some(TransactionOutput { amount, .. }) => res = add_values(&res, amount, &neg_val_err)?,
|
||||
Some(TransactionOutput { amount, .. }) => {
|
||||
res = add_values(&res, amount, &Alonzo(NegativeValue))?
|
||||
}
|
||||
None => match MultiEraOutput::as_byron(utxo_value) {
|
||||
Some(TxOut { amount, .. }) => {
|
||||
res = add_values(&res, &Value::Coin(*amount), &neg_val_err)?
|
||||
res = add_values(&res, &Value::Coin(*amount), &Alonzo(NegativeValue))?
|
||||
}
|
||||
_ => return Err(Alonzo(InputNotInUTxO)),
|
||||
},
|
||||
|
|
@ -292,10 +294,9 @@ fn get_consumed(tx_body: &TransactionBody, utxos: &UTxOs) -> Result<Value, Valid
|
|||
}
|
||||
|
||||
fn get_produced(tx_body: &TransactionBody) -> Result<Value, ValidationError> {
|
||||
let neg_val_err: ValidationError = Alonzo(NegativeValue);
|
||||
let mut res: Value = empty_value();
|
||||
for TransactionOutput { amount, .. } in tx_body.outputs.iter() {
|
||||
res = add_values(&res, amount, &neg_val_err)?;
|
||||
res = add_values(&res, amount, &Alonzo(NegativeValue))?;
|
||||
}
|
||||
Ok(res)
|
||||
}
|
||||
|
|
@ -311,12 +312,12 @@ fn check_min_lovelace(tx_body: &TransactionBody, prot_pps: &AlonzoProtParams) ->
|
|||
}
|
||||
|
||||
fn compute_min_lovelace(output: &TransactionOutput, prot_pps: &AlonzoProtParams) -> u64 {
|
||||
let utxo_entry_size: u64 = get_val_size_in_words(&output.amount)
|
||||
let output_entry_size: u64 = get_val_size_in_words(&output.amount)
|
||||
+ match output.datum_hash {
|
||||
Some(_) => 37, // utxoEntrySizeWithoutVal (27) + dataHashSize (10)
|
||||
None => 27, // utxoEntrySizeWithoutVal
|
||||
};
|
||||
prot_pps.coins_per_utxo_word * utxo_entry_size
|
||||
prot_pps.coins_per_utxo_word * output_entry_size
|
||||
}
|
||||
|
||||
// The size of the value in each of the outputs should not be greater than the
|
||||
|
|
@ -433,7 +434,7 @@ fn check_needed_scripts_are_included(
|
|||
return Err(Alonzo(UnneededNativeScript));
|
||||
}
|
||||
}
|
||||
for (plutus_script_covered, _) in native_scripts.iter() {
|
||||
for (plutus_script_covered, _) in plutus_scripts.iter() {
|
||||
if !plutus_script_covered {
|
||||
return Err(Alonzo(UnneededPlutusScript));
|
||||
}
|
||||
|
|
@ -533,19 +534,23 @@ fn check_redeemers(
|
|||
.collect(),
|
||||
None => Vec::new(),
|
||||
};
|
||||
let plutus_scripts: Vec<RedeemerPointer> =
|
||||
mk_plutus_script_redeemer_pointers(tx_body, tx_wits, utxos);
|
||||
let plutus_scripts: Vec<RedeemerPointer> = mk_plutus_script_redeemer_pointers(
|
||||
&sort_inputs(&tx_body.inputs),
|
||||
&tx_body.mint,
|
||||
tx_wits,
|
||||
utxos,
|
||||
);
|
||||
redeemer_pointers_coincide(&redeemer_pointers, &plutus_scripts)
|
||||
}
|
||||
|
||||
fn mk_plutus_script_redeemer_pointers(
|
||||
tx_body: &TransactionBody,
|
||||
sorted_inputs: &[TransactionInput],
|
||||
mint: &Option<Multiasset<i64>>,
|
||||
tx_wits: &MintedWitnessSet,
|
||||
utxos: &UTxOs,
|
||||
) -> Vec<RedeemerPointer> {
|
||||
match &tx_wits.plutus_script {
|
||||
Some(plutus_scripts) => {
|
||||
let sorted_inputs: Vec<TransactionInput> = sort_inputs(&tx_body.inputs);
|
||||
let mut res: Vec<RedeemerPointer> = Vec::new();
|
||||
for (index, input) in sorted_inputs.iter().enumerate() {
|
||||
if let Some(script_hash) = get_script_hash_from_input(input, utxos) {
|
||||
|
|
@ -560,7 +565,7 @@ fn mk_plutus_script_redeemer_pointers(
|
|||
}
|
||||
}
|
||||
}
|
||||
match &tx_body.mint {
|
||||
match mint {
|
||||
Some(minted_value) => {
|
||||
let sorted_policies: Vec<PolicyId> = sort_policies(minted_value);
|
||||
for (index, policy) in sorted_policies.iter().enumerate() {
|
||||
|
|
@ -664,7 +669,7 @@ fn get_script_hash_from_input(input: &TransactionInput, utxos: &UTxOs) -> Option
|
|||
utxos
|
||||
.get(&MultiEraInput::from_alonzo_compatible(input))
|
||||
.and_then(MultiEraOutput::as_alonzo)
|
||||
.and_then(get_payment_part)
|
||||
.and_then(|tx_out| get_payment_part(&tx_out.address))
|
||||
.and_then(|payment_part| match payment_part {
|
||||
ShelleyPaymentPart::Script(script_hash) => Some(script_hash),
|
||||
_ => None,
|
||||
|
|
@ -707,19 +712,6 @@ fn check_minting_policies(
|
|||
}
|
||||
}
|
||||
|
||||
fn compute_native_script_hash(script: &NativeScript) -> PolicyId {
|
||||
let mut payload = Vec::new();
|
||||
let _ = encode(script, &mut payload);
|
||||
payload.insert(0, 0);
|
||||
pallas_crypto::hash::Hasher::<224>::hash(&payload)
|
||||
}
|
||||
|
||||
fn compute_plutus_script_hash(script: &PlutusScript) -> PolicyId {
|
||||
let mut payload: Vec<u8> = Vec::from(script.as_ref());
|
||||
payload.insert(0, 1);
|
||||
pallas_crypto::hash::Hasher::<224>::hash(&payload)
|
||||
}
|
||||
|
||||
// The owner of each transaction input and each collateral input should have
|
||||
// signed the transaction.
|
||||
fn check_vkey_input_wits(
|
||||
|
|
@ -741,7 +733,9 @@ fn check_vkey_input_wits(
|
|||
match utxos.get(&MultiEraInput::from_alonzo_compatible(input)) {
|
||||
Some(multi_era_output) => {
|
||||
if let Some(alonzo_comp_output) = MultiEraOutput::as_alonzo(multi_era_output) {
|
||||
match get_payment_part(alonzo_comp_output).ok_or(Alonzo(InputDecoding))? {
|
||||
match get_payment_part(&alonzo_comp_output.address)
|
||||
.ok_or(Alonzo(InputDecoding))?
|
||||
{
|
||||
ShelleyPaymentPart::Key(payment_key_hash) => {
|
||||
check_vk_wit(&payment_key_hash, vk_wits, tx_hash)?
|
||||
}
|
||||
|
|
@ -833,8 +827,11 @@ fn check_languages(_mtx: &MintedTx, _prot_pps: &AlonzoProtParams) -> ValidationR
|
|||
}
|
||||
|
||||
// The metadata of the transaction is valid.
|
||||
fn check_metadata(tx_body: &TransactionBody, mtx: &MintedTx) -> ValidationResult {
|
||||
match (&tx_body.auxiliary_data_hash, extract_auxiliary_data(mtx)) {
|
||||
fn check_auxiliary_data(tx_body: &TransactionBody, mtx: &MintedTx) -> ValidationResult {
|
||||
match (
|
||||
&tx_body.auxiliary_data_hash,
|
||||
aux_data_from_alonzo_minted_tx(mtx),
|
||||
) {
|
||||
(Some(metadata_hash), Some(metadata)) => {
|
||||
if metadata_hash.as_slice()
|
||||
== pallas_crypto::hash::Hasher::<256>::hash(metadata).as_ref()
|
||||
|
|
@ -925,7 +922,11 @@ fn check_minting(tx_body: &TransactionBody, mtx: &MintedTx) -> ValidationResult
|
|||
.map(|x| x.clone().unwrap())
|
||||
.collect(),
|
||||
};
|
||||
let plutus_script_wits: Vec<PlutusScript> = Vec::new();
|
||||
let plutus_script_wits: Vec<PlutusScript> =
|
||||
match &mtx.transaction_witness_set.plutus_script {
|
||||
None => Vec::new(),
|
||||
Some(plutus_script_wits) => plutus_script_wits.clone(),
|
||||
};
|
||||
for (policy, _) in minted_value.iter() {
|
||||
if native_script_wits
|
||||
.iter()
|
||||
|
|
|
|||
1458
pallas-applying/src/babbage.rs
Normal file
1458
pallas-applying/src/babbage.rs
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,11 +1,13 @@
|
|||
//! Logic for validating and applying new blocks and txs to the chain state
|
||||
|
||||
pub mod alonzo;
|
||||
pub mod babbage;
|
||||
pub mod byron;
|
||||
pub mod shelley_ma;
|
||||
pub mod utils;
|
||||
|
||||
use alonzo::validate_alonzo_tx;
|
||||
use babbage::validate_babbage_tx;
|
||||
use byron::validate_byron_tx;
|
||||
use pallas_traverse::{Era, MultiEraTx};
|
||||
use shelley_ma::validate_shelley_ma_tx;
|
||||
|
|
@ -40,5 +42,11 @@ pub fn validate(metx: &MultiEraTx, utxos: &UTxOs, env: &Environment) -> Validati
|
|||
}
|
||||
_ => Err(TxAndProtParamsDiffer),
|
||||
},
|
||||
MultiEraProtParams::Babbage(bpp) => match metx {
|
||||
MultiEraTx::Babbage(mtx) => {
|
||||
validate_babbage_tx(mtx, utxos, bpp, env.block_slot(), env.network_id())
|
||||
}
|
||||
_ => Err(TxAndProtParamsDiffer),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
//! Utilities required for ShelleyMA-era transaction validation.
|
||||
|
||||
use crate::utils::{
|
||||
add_minted_value, add_values, empty_value, extract_auxiliary_data, get_alonzo_comp_tx_size,
|
||||
get_lovelace_from_alonzo_val, get_payment_part, get_shelley_address, get_val_size_in_words,
|
||||
mk_alonzo_vk_wits_check_list, values_are_equal, verify_signature, FeePolicy,
|
||||
add_minted_value, add_values, aux_data_from_alonzo_minted_tx, empty_value,
|
||||
get_alonzo_comp_tx_size, get_lovelace_from_alonzo_val, get_payment_part, get_shelley_address,
|
||||
get_val_size_in_words, mk_alonzo_vk_wits_check_list, values_are_equal, verify_signature,
|
||||
FeePolicy,
|
||||
ShelleyMAError::*,
|
||||
ShelleyProtParams, UTxOs,
|
||||
ValidationError::{self, *},
|
||||
|
|
@ -195,7 +196,10 @@ fn check_network_id(tx_body: &TransactionBody, network_id: &u8) -> ValidationRes
|
|||
}
|
||||
|
||||
fn check_metadata(tx_body: &TransactionBody, mtx: &MintedTx) -> ValidationResult {
|
||||
match (&tx_body.auxiliary_data_hash, extract_auxiliary_data(mtx)) {
|
||||
match (
|
||||
&tx_body.auxiliary_data_hash,
|
||||
aux_data_from_alonzo_minted_tx(mtx),
|
||||
) {
|
||||
(Some(metadata_hash), Some(metadata)) => {
|
||||
if metadata_hash.as_slice()
|
||||
== pallas_crypto::hash::Hasher::<256>::hash(metadata).as_ref()
|
||||
|
|
@ -222,7 +226,9 @@ fn check_witnesses(
|
|||
match utxos.get(&MultiEraInput::from_alonzo_compatible(input)) {
|
||||
Some(multi_era_output) => {
|
||||
if let Some(alonzo_comp_output) = MultiEraOutput::as_alonzo(multi_era_output) {
|
||||
match get_payment_part(alonzo_comp_output).ok_or(ShelleyMA(AddressDecoding))? {
|
||||
match get_payment_part(&alonzo_comp_output.address)
|
||||
.ok_or(ShelleyMA(AddressDecoding))?
|
||||
{
|
||||
ShelleyPaymentPart::Key(payment_key_hash) => {
|
||||
check_vk_wit(&payment_key_hash, tx_hash, vk_wits)?
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,9 +10,12 @@ use pallas_codec::{
|
|||
utils::{Bytes, KeepRaw, KeyValuePairs},
|
||||
};
|
||||
use pallas_crypto::key::ed25519::{PublicKey, Signature};
|
||||
use pallas_primitives::alonzo::{
|
||||
AssetName, AuxiliaryData, Coin, MintedTx, Multiasset, NetworkId, PolicyId, TransactionBody,
|
||||
TransactionOutput, VKeyWitness, Value,
|
||||
use pallas_primitives::{
|
||||
alonzo::{
|
||||
AssetName, AuxiliaryData, Coin, MintedTx as AlonzoMintedTx, Multiasset, NativeScript,
|
||||
NetworkId, PlutusScript, PolicyId, TransactionBody, VKeyWitness, Value,
|
||||
},
|
||||
babbage::{MintedTransactionBody, MintedTx as BabbageMintedTx, PlutusV2Script},
|
||||
};
|
||||
use pallas_traverse::{MultiEraInput, MultiEraOutput};
|
||||
use std::collections::HashMap;
|
||||
|
|
@ -29,6 +32,14 @@ pub fn get_alonzo_comp_tx_size(tx_body: &TransactionBody) -> Option<u64> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_babbage_tx_size(tx_body: &MintedTransactionBody) -> Option<u64> {
|
||||
let mut buff: Vec<u8> = Vec::new();
|
||||
match encode(tx_body, &mut buff) {
|
||||
Ok(()) => Some(buff.len() as u64),
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn empty_value() -> Value {
|
||||
Value::Multiasset(0, Multiasset::<Coin>::from(Vec::new()))
|
||||
}
|
||||
|
|
@ -52,6 +63,61 @@ pub fn add_values(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn lovelace_diff_or_fail(
|
||||
first: &Value,
|
||||
second: &Value,
|
||||
err: &ValidationError,
|
||||
) -> Result<u64, ValidationError> {
|
||||
match (first, second) {
|
||||
(Value::Coin(f), Value::Coin(s)) => {
|
||||
if f >= s {
|
||||
Ok(f - s)
|
||||
} else {
|
||||
Err(err.clone())
|
||||
}
|
||||
}
|
||||
(Value::Coin(_), Value::Multiasset(_, _)) => Err(err.clone()),
|
||||
(Value::Multiasset(f, fma), Value::Coin(s)) => {
|
||||
if f >= s && fma.is_empty() {
|
||||
Ok(f - s)
|
||||
} else {
|
||||
Err(err.clone())
|
||||
}
|
||||
}
|
||||
(Value::Multiasset(f, fma), Value::Multiasset(s, sma)) => {
|
||||
if f >= s && multi_assets_are_equal(fma, sma) {
|
||||
Ok(f - s)
|
||||
} else {
|
||||
Err(err.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn multi_assets_are_equal(fma: &Multiasset<Coin>, sma: &Multiasset<Coin>) -> bool {
|
||||
for (fpolicy, fassets) in fma.iter() {
|
||||
match find_policy(sma, fpolicy) {
|
||||
Some(sassets) => {
|
||||
for (fasset_name, famount) in fassets.iter() {
|
||||
// Discard the case where there is 0 of an asset
|
||||
if *famount != 0 {
|
||||
match find_assets(&sassets, fasset_name) {
|
||||
Some(samount) => {
|
||||
if *famount != samount {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
None => return false,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
None => return false,
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub fn add_minted_value(
|
||||
base_value: &Value,
|
||||
minted_value: &Multiasset<i64>,
|
||||
|
|
@ -155,24 +221,7 @@ pub fn values_are_equal(first: &Value, second: &Value) -> bool {
|
|||
if f != s {
|
||||
false
|
||||
} else {
|
||||
for (fpolicy, fassets) in fma.iter() {
|
||||
match find_policy(sma, fpolicy) {
|
||||
Some(sassets) => {
|
||||
for (fasset_name, famount) in fassets.iter() {
|
||||
match find_assets(&sassets, fasset_name) {
|
||||
Some(samount) => {
|
||||
if *famount != samount {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
None => return false,
|
||||
};
|
||||
}
|
||||
}
|
||||
None => return false,
|
||||
}
|
||||
}
|
||||
true
|
||||
multi_assets_are_equal(fma, sma)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -235,8 +284,8 @@ pub fn verify_signature(vk_wit: &VKeyWitness, data_to_verify: &[u8]) -> bool {
|
|||
public_key.verify(data_to_verify, &sig)
|
||||
}
|
||||
|
||||
pub fn get_payment_part(tx_out: &TransactionOutput) -> Option<ShelleyPaymentPart> {
|
||||
let addr: ShelleyAddress = get_shelley_address(Bytes::deref(&tx_out.address))?;
|
||||
pub fn get_payment_part(address: &Bytes) -> Option<ShelleyPaymentPart> {
|
||||
let addr: ShelleyAddress = get_shelley_address(Bytes::deref(address))?;
|
||||
Some(addr.payment().clone())
|
||||
}
|
||||
|
||||
|
|
@ -247,7 +296,17 @@ pub fn get_shelley_address(address: &[u8]) -> Option<ShelleyAddress> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn extract_auxiliary_data<'a>(mtx: &'a MintedTx) -> Option<&'a [u8]> {
|
||||
pub fn is_byron_address(address: &[u8]) -> bool {
|
||||
matches!(Address::from_bytes(address), Ok(Address::Byron(_)))
|
||||
}
|
||||
|
||||
pub fn aux_data_from_alonzo_minted_tx<'a>(mtx: &'a AlonzoMintedTx) -> Option<&'a [u8]> {
|
||||
Option::<KeepRaw<AuxiliaryData>>::from((mtx.auxiliary_data).clone())
|
||||
.as_ref()
|
||||
.map(KeepRaw::raw_cbor)
|
||||
}
|
||||
|
||||
pub fn aux_data_from_babbage_minted_tx<'a>(mtx: &'a BabbageMintedTx) -> Option<&'a [u8]> {
|
||||
Option::<KeepRaw<AuxiliaryData>>::from((mtx.auxiliary_data).clone())
|
||||
.as_ref()
|
||||
.map(KeepRaw::raw_cbor)
|
||||
|
|
@ -258,3 +317,22 @@ pub fn get_val_size_in_words(val: &Value) -> u64 {
|
|||
let _ = encode(val, &mut tx_buf);
|
||||
(tx_buf.len() as u64 + 7) / 8 // ceiling of the result of dividing
|
||||
}
|
||||
|
||||
pub fn compute_native_script_hash(script: &NativeScript) -> PolicyId {
|
||||
let mut payload = Vec::new();
|
||||
let _ = encode(script, &mut payload);
|
||||
payload.insert(0, 0);
|
||||
pallas_crypto::hash::Hasher::<224>::hash(&payload)
|
||||
}
|
||||
|
||||
pub fn compute_plutus_script_hash(script: &PlutusScript) -> PolicyId {
|
||||
let mut payload: Vec<u8> = Vec::from(script.as_ref());
|
||||
payload.insert(0, 1);
|
||||
pallas_crypto::hash::Hasher::<224>::hash(&payload)
|
||||
}
|
||||
|
||||
pub fn compute_plutus_v2_script_hash(script: &PlutusV2Script) -> PolicyId {
|
||||
let mut payload: Vec<u8> = Vec::from(script.as_ref());
|
||||
payload.insert(0, 1);
|
||||
pallas_crypto::hash::Hasher::<224>::hash(&payload)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ pub enum MultiEraProtParams {
|
|||
Byron(ByronProtParams),
|
||||
Shelley(ShelleyProtParams),
|
||||
Alonzo(AlonzoProtParams),
|
||||
Babbage(BabbageProtParams),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
@ -51,6 +52,20 @@ pub struct AlonzoProtParams {
|
|||
pub coins_per_utxo_word: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BabbageProtParams {
|
||||
pub fee_policy: FeePolicy,
|
||||
pub max_tx_size: u64,
|
||||
pub max_block_ex_mem: u64,
|
||||
pub max_block_ex_steps: u64,
|
||||
pub max_tx_ex_mem: u32,
|
||||
pub max_tx_ex_steps: u64,
|
||||
pub max_val_size: u64,
|
||||
pub collateral_percent: u64,
|
||||
pub max_collateral_inputs: u64,
|
||||
pub coins_per_utxo_word: u64,
|
||||
}
|
||||
|
||||
impl Environment {
|
||||
pub fn prot_params(&self) -> &MultiEraProtParams {
|
||||
&self.prot_params
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ pub enum ValidationError {
|
|||
Byron(ByronError),
|
||||
ShelleyMA(ShelleyMAError),
|
||||
Alonzo(AlonzoError),
|
||||
Babbage(BabbageError),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
@ -91,4 +92,51 @@ pub enum AlonzoError {
|
|||
ScriptIntegrityHash,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[non_exhaustive]
|
||||
pub enum BabbageError {
|
||||
UnknownTxSize,
|
||||
TxInsEmpty,
|
||||
InputNotInUTxO,
|
||||
CollateralNotInUTxO,
|
||||
ReferenceInputNotInUTxO,
|
||||
RefInputNotInUTxO,
|
||||
BlockPrecedesValInt,
|
||||
BlockExceedsValInt,
|
||||
FeeBelowMin,
|
||||
CollateralMissing,
|
||||
TooManyCollaterals,
|
||||
InputDecoding,
|
||||
CollateralNotVKeyLocked,
|
||||
CollateralMinLovelace,
|
||||
NonLovelaceCollateral,
|
||||
CollateralWrongAssets,
|
||||
NegativeValue,
|
||||
CollateralAnnotation,
|
||||
PreservationOfValue,
|
||||
MinLovelaceUnreached,
|
||||
MaxValSizeExceeded,
|
||||
AddressDecoding,
|
||||
OutputWrongNetworkID,
|
||||
TxWrongNetworkID,
|
||||
TxExUnitsExceeded,
|
||||
RedeemerMissing,
|
||||
UnneededRedeemer,
|
||||
MaxTxSizeExceeded,
|
||||
MintingLacksPolicy,
|
||||
MetadataHash,
|
||||
DatumMissing,
|
||||
UnneededDatum,
|
||||
ScriptWitnessMissing,
|
||||
UnneededNativeScript,
|
||||
UnneededPlutusV1Script,
|
||||
UnneededPlutusV2Script,
|
||||
ReqSignerMissing,
|
||||
ReqSignerWrongSig,
|
||||
VKWitnessMissing,
|
||||
VKWrongSignature,
|
||||
UnsupportedPlutusLanguage,
|
||||
ScriptIntegrityHash,
|
||||
}
|
||||
|
||||
pub type ValidationResult = Result<(), ValidationError>;
|
||||
|
|
|
|||
|
|
@ -87,3 +87,42 @@ List of negative unit tests:
|
|||
- **min_lovelace_unreached** takes sucessful_mainnet_tx and submits validation on it with an environment requesting more lovelace on outputs than the amount actually paid by one of the outputs of the transaction.
|
||||
- **max_val_exceeded** takes sucessful_mainnet_tx and submits validation on it with an environment disallowing value sizes as high as the size ofg one of the values in one of the transaction outputs of sucessful_mainnet_tx.
|
||||
- **script_integrity_hash** takes sucessful_mainnet_tx_with_plutus_script and modifies the execution values of one of the redeemers in the witness set of the transaction, in such a way that all checks pass but the integrity hash of script-related data of the transaction is different from the script data hash contained in the body of the transaction.
|
||||
|
||||
### Babbage
|
||||
*pallas-applying/tests/babbage.rs* contains multiple unit tests for validation in the Alonzo era.
|
||||
|
||||
Babbage introduces novel ways to provide Plutus-script-related data, like the introduction of reference scripts and novel ways to provide for collateral.
|
||||
|
||||
List of positive unit tests:
|
||||
- **successful_mainnet_tx** ([here](https://cexplorer.io/tx/b17d685c42e714238c1fb3abcd40e5c6291ebbb420c9c69b641209607bd00c7d) to see on Cardano explorer) is a simple Babbage transaction, with no native, Plutus V1 or Plutus V2 scripts, nor metadata or minting.
|
||||
- **successful_mainnet_tx_with_plutus_v1_script** ([here](https://cexplorer.io/tx/f33d6f7eb877132af7307e385bb24a7d2c12298c8ac0b1460296748810925ccc) to see on Cardano explorer) is a Babbage transaction with a Plutus V1 script.
|
||||
- **successful_mainnet_tx_with_plutus_v2_script** ([here](https://cexplorer.io/tx/ac96a0a2dfdb876b237a8ae674eadab453fd146fb97b221cfd29a1812046fa36) to see on Cardano explorer) is a Babbage transaction with a Plutus V2 script.
|
||||
- **successful_mainnet_tx_with_minting** ([here](https://cexplorer.io/tx/8702b0a5835c16663101f68295e33e3b3868c487f736d3c8a0a4246242675a15) to see on Cardano explorer) is a simple Babbage transaction with minting.
|
||||
- **successful_mainnet_tx_with_metadata** ([here](https://cexplorer.io/tx/7ae8cbe887d5d4cdaa51bce93d296206d4fcc77963e65fad3a64d0e6df672260) to see on Cardano explorer) is a simple Babbage transaction with metadata.
|
||||
|
||||
List of negative unit tests:
|
||||
- **empty_ins** takes successful_mainnet_tx and removes its input.
|
||||
- **unfound_utxo_input** takes successful_mainnet_tx and calls validation on it with an empty UTxO (which causes the input to be unfound).
|
||||
- **validity_interval_lower_bound_unreached** takes sucessful_mainnet_tx and modifies its time interval in such a way that its validity time interval *lower* bound is located exactly one slot after the block slot.
|
||||
- **validity_interval_upper_bound_surpassed** takes sucessful_mainnt_tx and modifies its time interval in such a way that its validity time interval *upper* bound is located exactly one slot before the block slot.
|
||||
- **min_fees_unreached** submits validation on sucessful_mainnet_tx with an environment requesting the minimum fee to be higher than the one that the transaction actually paid.
|
||||
- **no_collateral_inputs** takes successful_mainnet_tx_with_plutus_v1_script and removes its collateral inputs before submitting the transaction for validation.
|
||||
- **too_many_collateral_inputs** takes successful_mainnet_tx_with_plutus_v1_script and submits its for validation with an environment allowing no collateral inputs.
|
||||
- **collateral_is_not_verification_key_locked** takes sucessful_mainnet_tx_with_plutus_v1_script and modifies the address of one of the collateral inputs to become a script-locked output instead of a verification-key-locked one.
|
||||
- **collateral_with_other_assets** takes sucessful_mainnet_tx_with_plutus_v1_script and adds non-lovelace assets to it.
|
||||
- **collateral_without_min_lovelace** takes sucessful_mainnet_tx_with_plutus_v1_script and submits it for validation with an environment requesting a higher lovelace percentage (when compared to the fee paid by the transaction) in collateral inputs than the actual amount paid by the transaction collateral.
|
||||
- **collateral_annotation** takes sucessful_mainnet_tx_with_plutus_v1_script and modifies the collateral annotation to make it wrong.
|
||||
- **preservation_of_value** modifies sucessful_mainnet_tx_with_plutus_v1_script in such a way that the preservation-of-value equality does not hold.
|
||||
- **min_lovelace_unreached** takes sucessful_mainnet_tx and submits validation on it with an environment requesting more lovelace on outputs than the amount actually paid by one of the outputs of the transaction.
|
||||
- **max_val_exceeded** takes sucessful_mainnet_tx and submits validation on it with an environment disallowing value sizes as high as the size ofg one of the values in one of the transaction outputs of sucessful_mainnet_tx.
|
||||
- **output_network_id** takes sucessful_mainnet_tx and modifies the network ID in the address of one of its outputs.
|
||||
- **tx_network_id** takes sucessful_mainnet_tx and modifies its network ID.
|
||||
- **tx_ex_units_exceeded** takes sucessful_mainnet_tx_with_plutus_v1_script and validates it with an environment whose Plutus script execution values are below the needs of the transaction.
|
||||
- **max_tx_size_exceeded** takes sucessful_mainnet_tx and validates it with an environment allowing only transactions whose size is lower than that of sucessful_mainnet_tx.
|
||||
- **minting_lacks_policy** takes sucessful_mainnet_tx_with_minting and removes the native script policy contained in it before submitting it for validation.
|
||||
- **auxiliary_data_removed** takes sucessful_mainnet_tx_with_metadata and removes its auxiliary data (a.k.a. metadata).
|
||||
- **script_input_lacks_script** takes sucessful_mainnet_tx_with_plutus_v1_script and clears the Plutus V1 scripts list in the witness set, making the script required by the transaction inexistent.
|
||||
- **missing_input_datum** takes sucessful_mainnet_tx_with_plutus_v1_script and removes the datum contained in its witness set.
|
||||
- **extra_input_datum** takes sucessful_mainnet_tx_with_plutus_v1_script and adds an unneded datum to its witness set.
|
||||
- **extra_redeemer** takes sucessful_mainnet_tx_with_plutus_v1_script and adds an unneeded redeemer to its witness set.
|
||||
- **script_integrity_hash** takes sucessful_mainnet_tx_with_plutus_v1_script and modifies the execution values of one of the redeemers in the witness set of the transaction, in such a way that all checks pass but the integrity hash of script-related data of the transaction is different from the script data hash contained in the body of the transaction.
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ mod alonzo_tests {
|
|||
),
|
||||
],
|
||||
);
|
||||
add_collateral(
|
||||
add_collateral_alonzo(
|
||||
&mtx.transaction_body,
|
||||
&mut utxos,
|
||||
&[(
|
||||
|
|
@ -315,7 +315,7 @@ mod alonzo_tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
// Same as successful_mainnet_tx, but the validation is called with an empty
|
||||
// Same as successful_mainnet_tx, but validation is called with an empty
|
||||
// UTxO set.
|
||||
fn unfound_utxo_input() {
|
||||
let cbor_bytes: Vec<u8> = cbor_to_bytes(include_str!("../../test_data/alonzo1.tx"));
|
||||
|
|
@ -454,7 +454,7 @@ mod alonzo_tests {
|
|||
#[test]
|
||||
// Same as succesful_mainnet_tx, except that validation is called with an
|
||||
// Environment requesting fees that exceed those paid by the transaction.
|
||||
fn min_fees_unreached() {
|
||||
fn min_fee_unreached() {
|
||||
let cbor_bytes: Vec<u8> = cbor_to_bytes(include_str!("../../test_data/alonzo1.tx"));
|
||||
let mtx: MintedTx = minted_tx_from_cbor(&cbor_bytes);
|
||||
let metx: MultiEraTx = MultiEraTx::from_alonzo_compatible(&mtx, Era::Alonzo);
|
||||
|
|
@ -573,7 +573,7 @@ mod alonzo_tests {
|
|||
),
|
||||
],
|
||||
);
|
||||
add_collateral(
|
||||
add_collateral_alonzo(
|
||||
&mtx.transaction_body,
|
||||
&mut utxos,
|
||||
&[(
|
||||
|
|
@ -698,7 +698,7 @@ mod alonzo_tests {
|
|||
),
|
||||
],
|
||||
);
|
||||
add_collateral(
|
||||
add_collateral_alonzo(
|
||||
&mtx.transaction_body,
|
||||
&mut utxos,
|
||||
&[(
|
||||
|
|
@ -954,7 +954,7 @@ mod alonzo_tests {
|
|||
),
|
||||
],
|
||||
);
|
||||
add_collateral(
|
||||
add_collateral_alonzo(
|
||||
&mtx.transaction_body,
|
||||
&mut utxos,
|
||||
&[(
|
||||
|
|
@ -1082,7 +1082,7 @@ mod alonzo_tests {
|
|||
),
|
||||
],
|
||||
);
|
||||
add_collateral(
|
||||
add_collateral_alonzo(
|
||||
&mtx.transaction_body,
|
||||
&mut utxos,
|
||||
&[(
|
||||
|
|
@ -1122,7 +1122,7 @@ mod alonzo_tests {
|
|||
|
||||
#[test]
|
||||
// Same as succesful_mainnet_tx, except that the fee is reduced by exactly 1,
|
||||
// and so the "preservation of value" property doesn't hold.
|
||||
// and so the "preservation of value" property does not hold.
|
||||
fn preservation_of_value() {
|
||||
let cbor_bytes: Vec<u8> = cbor_to_bytes(include_str!("../../test_data/alonzo1.tx"));
|
||||
let mut mtx: MintedTx = minted_tx_from_cbor(&cbor_bytes);
|
||||
|
|
@ -1162,7 +1162,7 @@ mod alonzo_tests {
|
|||
network_id: 1,
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
Ok(()) => panic!("Preservation of value doesn't hold"),
|
||||
Ok(()) => panic!("Preservation of value does not hold"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::PreservationOfValue) => (),
|
||||
_ => panic!("Unexpected error ({:?})", err),
|
||||
|
|
@ -1232,7 +1232,7 @@ mod alonzo_tests {
|
|||
network_id: 1,
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
Ok(()) => panic!("Transaction network ID should match environment network_id"),
|
||||
Ok(()) => panic!("Output network ID should match environment network ID"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::OutputWrongNetworkID) => (),
|
||||
_ => panic!("Unexpected error ({:?})", err),
|
||||
|
|
@ -1282,7 +1282,7 @@ mod alonzo_tests {
|
|||
network_id: 1,
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
Ok(()) => panic!("Transaction network ID should match environment network_id"),
|
||||
Ok(()) => panic!("Transaction network ID should match environment network ID"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::TxWrongNetworkID) => (),
|
||||
_ => panic!("Unexpected error ({:?})", err),
|
||||
|
|
@ -1292,7 +1292,7 @@ mod alonzo_tests {
|
|||
|
||||
#[test]
|
||||
// Same as successful_mainnet_tx_with_plutus_script, except that the Environment
|
||||
// execution values are below the ones assocaited with the transaction.
|
||||
// execution values are below the ones associated with the transaction.
|
||||
fn tx_ex_units_exceeded() {
|
||||
let cbor_bytes: Vec<u8> = cbor_to_bytes(include_str!("../../test_data/alonzo2.tx"));
|
||||
let mtx: MintedTx = minted_tx_from_cbor(&cbor_bytes);
|
||||
|
|
@ -1369,7 +1369,7 @@ mod alonzo_tests {
|
|||
),
|
||||
],
|
||||
);
|
||||
add_collateral(
|
||||
add_collateral_alonzo(
|
||||
&mtx.transaction_body,
|
||||
&mut utxos,
|
||||
&[(
|
||||
|
|
@ -1533,7 +1533,7 @@ mod alonzo_tests {
|
|||
),
|
||||
],
|
||||
);
|
||||
add_collateral(
|
||||
add_collateral_alonzo(
|
||||
&mtx.transaction_body,
|
||||
&mut utxos,
|
||||
&[(
|
||||
|
|
@ -1768,7 +1768,7 @@ mod alonzo_tests {
|
|||
),
|
||||
],
|
||||
);
|
||||
add_collateral(
|
||||
add_collateral_alonzo(
|
||||
&mtx.transaction_body,
|
||||
&mut utxos,
|
||||
&[(
|
||||
|
|
@ -1891,7 +1891,7 @@ mod alonzo_tests {
|
|||
),
|
||||
],
|
||||
);
|
||||
add_collateral(
|
||||
add_collateral_alonzo(
|
||||
&mtx.transaction_body,
|
||||
&mut utxos,
|
||||
&[(
|
||||
|
|
@ -1986,7 +1986,7 @@ mod alonzo_tests {
|
|||
network_id: 1,
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
Ok(()) => panic!("Minting policy is not supported by native script"),
|
||||
Ok(()) => panic!("Minting policy is not supported by the correponding native script"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::MintingLacksPolicy) => (),
|
||||
_ => panic!("Unexpected error ({:?})", err),
|
||||
|
|
@ -2072,7 +2072,7 @@ mod alonzo_tests {
|
|||
),
|
||||
],
|
||||
);
|
||||
add_collateral(
|
||||
add_collateral_alonzo(
|
||||
&mtx.transaction_body,
|
||||
&mut utxos,
|
||||
&[(
|
||||
|
|
@ -2195,7 +2195,7 @@ mod alonzo_tests {
|
|||
),
|
||||
],
|
||||
);
|
||||
add_collateral(
|
||||
add_collateral_alonzo(
|
||||
&mtx.transaction_body,
|
||||
&mut utxos,
|
||||
&[(
|
||||
|
|
@ -2324,7 +2324,7 @@ mod alonzo_tests {
|
|||
),
|
||||
],
|
||||
);
|
||||
add_collateral(
|
||||
add_collateral_alonzo(
|
||||
&mtx.transaction_body,
|
||||
&mut utxos,
|
||||
&[(
|
||||
|
|
@ -2454,7 +2454,7 @@ mod alonzo_tests {
|
|||
),
|
||||
],
|
||||
);
|
||||
add_collateral(
|
||||
add_collateral_alonzo(
|
||||
&mtx.transaction_body,
|
||||
&mut utxos,
|
||||
&[(
|
||||
|
|
@ -2536,7 +2536,7 @@ mod alonzo_tests {
|
|||
network_id: 1,
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
Ok(()) => panic!("Unneeded redeemer"),
|
||||
Ok(()) => panic!("Transaction auxiliary data removed"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::MetadataHash) => (),
|
||||
_ => panic!("Unexpected error ({:?})", err),
|
||||
|
|
@ -2545,7 +2545,7 @@ mod alonzo_tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
// Same as successful_mainnet_tx, except that the minimum lovelace in the UTxO
|
||||
// Same as successful_mainnet_tx, except that the minimum lovelace in an output
|
||||
// is unreached.
|
||||
fn min_lovelace_unreached() {
|
||||
let cbor_bytes: Vec<u8> = cbor_to_bytes(include_str!("../../test_data/alonzo1.tx"));
|
||||
|
|
@ -2573,14 +2573,14 @@ mod alonzo_tests {
|
|||
max_val_size: 5000,
|
||||
collateral_percent: 150,
|
||||
max_collateral_inputs: 3,
|
||||
coins_per_utxo_word: 10000000,
|
||||
coins_per_utxo_word: 10000000, // This was 34482 during Alonzo on mainnet.
|
||||
}),
|
||||
prot_magic: 764824073,
|
||||
block_slot: 44237276,
|
||||
network_id: 1,
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
Ok(()) => panic!("Unneeded redeemer"),
|
||||
Ok(()) => panic!("Output minimum lovelace is unreached"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::MinLovelaceUnreached) => (),
|
||||
_ => panic!("Unexpected error ({:?})", err),
|
||||
|
|
@ -2624,7 +2624,7 @@ mod alonzo_tests {
|
|||
network_id: 1,
|
||||
};
|
||||
match validate(&metx, &utxos, &env) {
|
||||
Ok(()) => panic!("Unneeded redeemer"),
|
||||
Ok(()) => panic!("Max value size exceeded"),
|
||||
Err(err) => match err {
|
||||
Alonzo(AlonzoError::MaxValSizeExceeded) => (),
|
||||
_ => panic!("Unexpected error ({:?})", err),
|
||||
|
|
@ -2712,7 +2712,7 @@ mod alonzo_tests {
|
|||
),
|
||||
],
|
||||
);
|
||||
add_collateral(
|
||||
add_collateral_alonzo(
|
||||
&mtx.transaction_body,
|
||||
&mut utxos,
|
||||
&[(
|
||||
|
|
|
|||
2400
pallas-applying/tests/babbage.rs
Normal file
2400
pallas-applying/tests/babbage.rs
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -2,12 +2,17 @@ use pallas_applying::UTxOs;
|
|||
use pallas_codec::{minicbor::bytes::ByteVec, utils::TagWrap};
|
||||
use pallas_primitives::{
|
||||
alonzo::{MintedTx, TransactionBody, TransactionOutput, Value},
|
||||
babbage::{
|
||||
MintedDatumOption, MintedPostAlonzoTransactionOutput, MintedScriptRef,
|
||||
MintedTransactionBody, MintedTransactionOutput, MintedTx as BabbageMintedTx,
|
||||
PseudoTransactionOutput,
|
||||
},
|
||||
byron::{Address, MintedTxPayload, Tx, TxOut},
|
||||
};
|
||||
use pallas_traverse::{MultiEraInput, MultiEraOutput};
|
||||
use std::{borrow::Cow, iter::zip, vec::Vec};
|
||||
|
||||
use pallas_codec::utils::Bytes;
|
||||
use pallas_codec::utils::{Bytes, CborWrap};
|
||||
use pallas_crypto::hash::Hash;
|
||||
|
||||
pub fn cbor_to_bytes(input: &str) -> Vec<u8> {
|
||||
|
|
@ -18,8 +23,12 @@ pub fn minted_tx_from_cbor(tx_cbor: &[u8]) -> MintedTx<'_> {
|
|||
pallas_codec::minicbor::decode::<MintedTx>(tx_cbor).unwrap()
|
||||
}
|
||||
|
||||
pub fn minted_tx_payload_from_cbor(tx_cbor: &[u8]) -> MintedTxPayload<'_> {
|
||||
pallas_codec::minicbor::decode::<MintedTxPayload>(tx_cbor).unwrap()
|
||||
pub fn babbage_minted_tx_from_cbor(tx_cbor: &[u8]) -> BabbageMintedTx<'_> {
|
||||
pallas_codec::minicbor::decode::<BabbageMintedTx>(&tx_cbor[..]).unwrap()
|
||||
}
|
||||
|
||||
pub fn minted_tx_payload_from_cbor<'a>(tx_cbor: &'a Vec<u8>) -> MintedTxPayload<'a> {
|
||||
pallas_codec::minicbor::decode::<MintedTxPayload>(&tx_cbor[..]).unwrap()
|
||||
}
|
||||
|
||||
pub fn mk_utxo_for_byron_tx<'a>(tx: &Tx, tx_outs_info: &[(String, u64)]) -> UTxOs<'a> {
|
||||
|
|
@ -45,10 +54,16 @@ pub fn mk_utxo_for_byron_tx<'a>(tx: &Tx, tx_outs_info: &[(String, u64)]) -> UTxO
|
|||
|
||||
pub fn mk_utxo_for_alonzo_compatible_tx<'a>(
|
||||
tx_body: &TransactionBody,
|
||||
tx_outs_info: &[(String, Value, Option<Hash<32>>)],
|
||||
tx_outs_info: &[(
|
||||
String, // address in string format
|
||||
Value,
|
||||
Option<Hash<32>>,
|
||||
)],
|
||||
) -> UTxOs<'a> {
|
||||
let mut utxos: UTxOs = UTxOs::new();
|
||||
for (tx_in, (address, amount, datum_hash)) in zip(tx_body.inputs.clone(), tx_outs_info) {
|
||||
let multi_era_in: MultiEraInput =
|
||||
MultiEraInput::AlonzoCompatible(Box::new(Cow::Owned(tx_in)));
|
||||
let address_bytes: Bytes = match hex::decode(address) {
|
||||
Ok(bytes_vec) => Bytes::from(bytes_vec),
|
||||
_ => panic!("Unable to decode input address"),
|
||||
|
|
@ -58,8 +73,6 @@ pub fn mk_utxo_for_alonzo_compatible_tx<'a>(
|
|||
amount: amount.clone(),
|
||||
datum_hash: *datum_hash,
|
||||
};
|
||||
let multi_era_in: MultiEraInput =
|
||||
MultiEraInput::AlonzoCompatible(Box::new(Cow::Owned(tx_in)));
|
||||
let multi_era_out: MultiEraOutput =
|
||||
MultiEraOutput::AlonzoCompatible(Box::new(Cow::Owned(tx_out)));
|
||||
utxos.insert(multi_era_in, multi_era_out);
|
||||
|
|
@ -67,10 +80,44 @@ pub fn mk_utxo_for_alonzo_compatible_tx<'a>(
|
|||
utxos
|
||||
}
|
||||
|
||||
pub fn add_collateral(
|
||||
pub fn mk_utxo_for_babbage_tx<'a>(
|
||||
tx_body: &MintedTransactionBody,
|
||||
tx_outs_info: &'a [(
|
||||
String, // address in string format
|
||||
Value,
|
||||
Option<MintedDatumOption>,
|
||||
Option<CborWrap<MintedScriptRef>>,
|
||||
)],
|
||||
) -> UTxOs<'a> {
|
||||
let mut utxos: UTxOs = UTxOs::new();
|
||||
for (tx_in, (addr, val, datum_opt, script_ref)) in zip(tx_body.inputs.clone(), tx_outs_info) {
|
||||
let multi_era_in: MultiEraInput =
|
||||
MultiEraInput::AlonzoCompatible(Box::new(Cow::Owned(tx_in)));
|
||||
let address_bytes: Bytes = match hex::decode(addr) {
|
||||
Ok(bytes_vec) => Bytes::from(bytes_vec),
|
||||
_ => panic!("Unable to decode input address"),
|
||||
};
|
||||
let tx_out: MintedTransactionOutput =
|
||||
PseudoTransactionOutput::PostAlonzo(MintedPostAlonzoTransactionOutput {
|
||||
address: address_bytes,
|
||||
value: val.clone(),
|
||||
datum_option: datum_opt.clone(),
|
||||
script_ref: script_ref.clone(),
|
||||
});
|
||||
let multi_era_out: MultiEraOutput = MultiEraOutput::Babbage(Box::new(Cow::Owned(tx_out)));
|
||||
utxos.insert(multi_era_in, multi_era_out);
|
||||
}
|
||||
utxos
|
||||
}
|
||||
|
||||
pub fn add_collateral_alonzo<'a>(
|
||||
tx_body: &TransactionBody,
|
||||
utxos: &mut UTxOs<'_>,
|
||||
collateral_info: &[(String, Value, Option<Hash<32>>)],
|
||||
collateral_info: &[(
|
||||
String, // address in string format
|
||||
Value,
|
||||
Option<Hash<32>>,
|
||||
)],
|
||||
) {
|
||||
match &tx_body.collateral {
|
||||
Some(collaterals) => {
|
||||
|
|
@ -94,3 +141,85 @@ pub fn add_collateral(
|
|||
None => panic!("Adding collateral to UTxO failed due to an empty list of collaterals"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_collateral_babbage<'a>(
|
||||
tx_body: &MintedTransactionBody,
|
||||
utxos: &mut UTxOs<'a>,
|
||||
collateral_info: &'a [(
|
||||
String, // address in string format
|
||||
Value,
|
||||
Option<MintedDatumOption>,
|
||||
Option<CborWrap<MintedScriptRef>>,
|
||||
)],
|
||||
) {
|
||||
match &tx_body.collateral {
|
||||
Some(collaterals) => {
|
||||
if collaterals.is_empty() {
|
||||
panic!("UTxO addition error - collateral input missing")
|
||||
} else {
|
||||
for (tx_in, (addr, val, datum_opt, script_ref)) in
|
||||
zip(collaterals.clone(), collateral_info)
|
||||
{
|
||||
let multi_era_in: MultiEraInput =
|
||||
MultiEraInput::AlonzoCompatible(Box::new(Cow::Owned(tx_in)));
|
||||
let address_bytes: Bytes = match hex::decode(addr) {
|
||||
Ok(bytes_vec) => Bytes::from(bytes_vec),
|
||||
_ => panic!("Unable to decode input address"),
|
||||
};
|
||||
let tx_out: MintedTransactionOutput =
|
||||
PseudoTransactionOutput::PostAlonzo(MintedPostAlonzoTransactionOutput {
|
||||
address: address_bytes,
|
||||
value: val.clone(),
|
||||
datum_option: datum_opt.clone(),
|
||||
script_ref: script_ref.clone(),
|
||||
});
|
||||
let multi_era_out: MultiEraOutput =
|
||||
MultiEraOutput::Babbage(Box::new(Cow::Owned(tx_out)));
|
||||
utxos.insert(multi_era_in, multi_era_out);
|
||||
}
|
||||
}
|
||||
}
|
||||
None => panic!("UTxO addition error - collateral input missing"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_ref_input_babbage<'a>(
|
||||
tx_body: &MintedTransactionBody,
|
||||
utxos: &mut UTxOs<'a>,
|
||||
ref_input_info: &'a [(
|
||||
String, // address in string format
|
||||
Value,
|
||||
Option<MintedDatumOption>,
|
||||
Option<CborWrap<MintedScriptRef>>,
|
||||
)],
|
||||
) {
|
||||
match &tx_body.reference_inputs {
|
||||
Some(ref_inputs) => {
|
||||
if ref_inputs.is_empty() {
|
||||
panic!("UTxO addition error - reference input missing")
|
||||
} else {
|
||||
for (tx_in, (addr, val, datum_opt, script_ref)) in
|
||||
zip(ref_inputs.clone(), ref_input_info)
|
||||
{
|
||||
let multi_era_in: MultiEraInput =
|
||||
MultiEraInput::AlonzoCompatible(Box::new(Cow::Owned(tx_in)));
|
||||
let address_bytes: Bytes = match hex::decode(addr) {
|
||||
Ok(bytes_vec) => Bytes::from(bytes_vec),
|
||||
_ => panic!("Unable to decode input address"),
|
||||
};
|
||||
let tx_out: MintedTransactionOutput =
|
||||
PseudoTransactionOutput::PostAlonzo(MintedPostAlonzoTransactionOutput {
|
||||
address: address_bytes,
|
||||
value: val.clone(),
|
||||
datum_option: datum_opt.clone(),
|
||||
script_ref: script_ref.clone(),
|
||||
});
|
||||
let multi_era_out: MultiEraOutput =
|
||||
MultiEraOutput::Babbage(Box::new(Cow::Owned(tx_out)));
|
||||
utxos.insert(multi_era_in, multi_era_out);
|
||||
}
|
||||
}
|
||||
}
|
||||
None => panic!("UTxO addition error - reference input missing"),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
1
test_data/babbage3.address
Normal file
1
test_data/babbage3.address
Normal file
|
|
@ -0,0 +1 @@
|
|||
011be1f490912af2fc39f8e3637a2bade2ecbebefe63e8bfef10989cd6f593309a155b0ebb45ff830747e61f98e5b77feaf7529ce9df351382
|
||||
1
test_data/babbage3.tx
Normal file
1
test_data/babbage3.tx
Normal file
|
|
@ -0,0 +1 @@
|
|||
84a40081825820f193aa92b0c401c4ab4694622501b4890330e7a4a7a20533d833a5639b7fc9e601018282581d61775a6cb8a363c28daacd0e535c8914df21533ad07458c23a99f9043a1a007a120082583901e241af5d59f4675250fcbf0f6f50e6c203a268955f92e036a5018243f593309a155b0ebb45ff830747e61f98e5b77feaf7529ce9df3513821a05abfc02021a00028cad031a044fa19ea10081825820f2fc4a141e5d2d2678434f851997a71610bf40ae2cd6b18cb67e8f188d8304ba5840f7b3cefab0d828972e6221e8896c336187ba55f8c79fe83d5a6de9c1a32e6ea788629d7294785c76ef49b9fdb7cd7a932fe32c2761d640c19aa7840a44fc060bf5f6
|
||||
1
test_data/babbage4.0.address
Normal file
1
test_data/babbage4.0.address
Normal file
|
|
@ -0,0 +1 @@
|
|||
11a55f409501bf65805bb0dc76f6f9ae90b61e19ed870bc0025681360881728e7ed4cf324e1323135e7e6d931f01e30792d9cdf17129cb806d
|
||||
1
test_data/babbage4.1.address
Normal file
1
test_data/babbage4.1.address
Normal file
|
|
@ -0,0 +1 @@
|
|||
01f1e126304308006938d2e8571842ff87302fff95a037b3fd838451b8b3c9396d0680d912487139cb7fc85aa279ea70e8cdacee4c6cae40fd
|
||||
1
test_data/babbage4.collateral.address
Normal file
1
test_data/babbage4.collateral.address
Normal file
|
|
@ -0,0 +1 @@
|
|||
01f1e126304308006938d2e8571842ff87302fff95a037b3fd838451b8b3c9396d0680d912487139cb7fc85aa279ea70e8cdacee4c6cae40fd
|
||||
1
test_data/babbage4.tx
Normal file
1
test_data/babbage4.tx
Normal file
File diff suppressed because one or more lines are too long
1
test_data/babbage5.0.address
Normal file
1
test_data/babbage5.0.address
Normal file
|
|
@ -0,0 +1 @@
|
|||
719b85d5e8611945505f078aeededcbed1d6ca11053f61e3f9d999fe44
|
||||
1
test_data/babbage5.1.address
Normal file
1
test_data/babbage5.1.address
Normal file
|
|
@ -0,0 +1 @@
|
|||
0121316dbc84420a5ee7461438483564c41fae876029319b3ee641fe4422339411d2df4c9c7c50b3d8f88db98d475e9d1bccd4244b412fbe5e
|
||||
1
test_data/babbage5.collateral.address
Normal file
1
test_data/babbage5.collateral.address
Normal file
|
|
@ -0,0 +1 @@
|
|||
0121316dbc84420a5ee7461438483564c41fae876029319b3ee641fe4422339411d2df4c9c7c50b3d8f88db98d475e9d1bccd4244b412fbe5e
|
||||
1
test_data/babbage5.tx
Normal file
1
test_data/babbage5.tx
Normal file
File diff suppressed because one or more lines are too long
1
test_data/babbage6.0.address
Normal file
1
test_data/babbage6.0.address
Normal file
|
|
@ -0,0 +1 @@
|
|||
11A55F409501BF65805BB0DC76F6F9AE90B61E19ED870BC0025681360881728E7ED4CF324E1323135E7E6D931F01E30792D9CDF17129CB806D
|
||||
1
test_data/babbage6.1.address
Normal file
1
test_data/babbage6.1.address
Normal file
|
|
@ -0,0 +1 @@
|
|||
01EDA33318624ADE03D53B7E954713D9E69440891F0D02E823267B610D6018DC6C7989A46EC26822425A3D2BAC60EEC2682A022740361ED957
|
||||
1
test_data/babbage6.collateral.address
Normal file
1
test_data/babbage6.collateral.address
Normal file
|
|
@ -0,0 +1 @@
|
|||
01eda33318624ade03d53b7e954713d9e69440891f0d02e823267b610d6018dc6c7989a46ec26822425a3d2bac60eec2682a022740361ed957
|
||||
1
test_data/babbage6.tx
Normal file
1
test_data/babbage6.tx
Normal file
File diff suppressed because one or more lines are too long
1
test_data/babbage7.0.address
Normal file
1
test_data/babbage7.0.address
Normal file
|
|
@ -0,0 +1 @@
|
|||
119068A7A3F008803EDAC87AF1619860F2CDCDE40C26987325ACE138AD81728E7ED4CF324E1323135E7E6D931F01E30792D9CDF17129CB806D
|
||||
1
test_data/babbage7.1.address
Normal file
1
test_data/babbage7.1.address
Normal file
|
|
@ -0,0 +1 @@
|
|||
01A7D37F1D43D1197A994D95B3CE15D9AF3B4697CC7CDF9BCD1F81688D3499AC08066B36BC6C2D86A21243B940E84DBE5CAC3FAB5F76AB9229
|
||||
1
test_data/babbage7.collateral.address
Normal file
1
test_data/babbage7.collateral.address
Normal file
|
|
@ -0,0 +1 @@
|
|||
01a7d37f1d43d1197a994d95b3ce15d9af3b4697cc7cdf9bcd1f81688d3499ac08066b36bc6c2d86a21243b940e84dbe5cac3fab5f76ab9229
|
||||
1
test_data/babbage7.reference.address
Normal file
1
test_data/babbage7.reference.address
Normal file
|
|
@ -0,0 +1 @@
|
|||
119068a7a3f008803edac87af1619860f2cdcde40c26987325ace138ad81728e7ed4cf324e1323135e7e6d931f01e30792d9cdf17129cb806d
|
||||
1
test_data/babbage7.tx
Normal file
1
test_data/babbage7.tx
Normal file
|
|
@ -0,0 +1 @@
|
|||
84a90082825820806560bebbd9ba3759d091efff97f007ce82fad9bc53d1d8a6d44f8760d6f76100825820a349f9146f6c638505e3dbd2625af1200dbaf4fd17bb8513bb966db70147e30d04018682583901f434b2c9818daa419e631a520e6bb98437add6c658fee52c1e07a20d6e4af7adcff67f1c1e7e5805b7c9155125092dd5dee927dd43ec64301a000f32a08258390170e60f3b5ea7153e0acc7a803e4401d44b8ed1bae1c7baaad1a62a721e78aae7c90cc36d624f7b3bb6d86b52696dc84e490f343eba89005f1a000f32a0825839011a5bd6e94501aa6b9a36a221b4dec2ef7ec007c99dcb7c54416428abbe45266367e628fb1ce04d4dee752dbf2e79ad91d22437b400cec0ae1a0098b5c082583901a7d37f1d43d1197a994d95b3ce15d9af3b4697cc7cdf9bcd1f81688d3499ac08066b36bc6c2d86a21243b940e84dbe5cac3fab5f76ab9229821a0011e360a1581c95ab9a125c900c14cf7d39093e3577b0c8e39c9f7548a8301a28ee2da14c4164614964696f74313132350182583901a7d37f1d43d1197a994d95b3ce15d9af3b4697cc7cdf9bcd1f81688d3499ac08066b36bc6c2d86a21243b940e84dbe5cac3fab5f76ab92291a068cc3d782583901a7d37f1d43d1197a994d95b3ce15d9af3b4697cc7cdf9bcd1f81688d3499ac08066b36bc6c2d86a21243b940e84dbe5cac3fab5f76ab92291a0686852e021a00063ea9031a04b263ec081a04b259600b58200c38855f28468901ccd7d2537b7b9438d84573f1d69fa43271a54b645fbbb4b00d81825820d53715d1b45852588d554b4fb14d78132e0c0022141fd30fe07a305c45f93827000e81581ca7d37f1d43d1197a994d95b3ce15d9af3b4697cc7cdf9bcd1f81688d12818258209a32459bd4ef6bbafdeb8cf3b909d0e3e2ec806e4cc6268529280b0fc1d06f5b00a300818258204bdb6862c2c613165eecf49a460d5abb885c258d95cd5bc3e867693a2f5a862b58405816ff0da3d3c152f5cc8f301b05ac54233f1a3ec9351e267150677523ce1bb55d69b1a17ee3e170fe2d2ea9b142c4190e192c9de3859e610d14359aa137d60c049fd8799f581c1a5bd6e94501aa6b9a36a221b4dec2ef7ec007c99dcb7c54416428ab9fd8799fd8799fd8799f581cf434b2c9818daa419e631a520e6bb98437add6c658fee52c1e07a20dffd8799fd8799fd8799f581c6e4af7adcff67f1c1e7e5805b7c9155125092dd5dee927dd43ec6430ffffffffa140d8799f00a1401a000f32a0ffffd8799fd8799fd8799f581c70e60f3b5ea7153e0acc7a803e4401d44b8ed1bae1c7baaad1a62a72ffd8799fd8799fd8799f581c1e78aae7c90cc36d624f7b3bb6d86b52696dc84e490f343eba89005fffffffffa140d8799f00a1401a000f32a0ffffd8799fd8799fd8799f581c1a5bd6e94501aa6b9a36a221b4dec2ef7ec007c99dcb7c54416428abffd8799fd8799fd8799f581cbe45266367e628fb1ce04d4dee752dbf2e79ad91d22437b400cec0aeffffffffa140d8799f00a1401a0098b5c0ffffffffff0581840000d87a80821a0027e6981a2bc017a9f5f6
|
||||
Loading…
Add table
Add a link
Reference in a new issue