@@ -20,6 +20,8 @@ module Cardano.Api.Experimental.Tx.Internal.Fee
2020 , calcMinFeeRecursive
2121 , collectTxBodyScriptWitnesses
2222 , estimateBalancedTxBody
23+ , evaluateTransaction
24+ , TxEvaluationResult (.. )
2325 , evaluateTransactionExecutionUnits
2426 , evaluateTransactionFee
2527 , indexWitnessedTxProposalProcedures
@@ -45,14 +47,15 @@ import Cardano.Api.Experimental.Tx.Internal.Type
4547import Cardano.Api.Key.Internal qualified as Api
4648import Cardano.Api.Ledger.Internal.Reexport qualified as L
4749import Cardano.Api.Plutus.Internal
48- import Cardano.Api.Plutus.Internal.Script (fromAlonzoExUnits )
50+ import Cardano.Api.Plutus.Internal.Script (fromAlonzoExUnits , toAlonzoExUnits )
4951import Cardano.Api.Plutus.Internal.Script qualified as Old
5052import Cardano.Api.Plutus.Internal.ScriptData
5153import Cardano.Api.Pretty
5254import Cardano.Api.ProtocolParameters
5355import Cardano.Api.Query.Internal.Type.QueryInMode
5456import Cardano.Api.Tx.Internal.Body
5557 ( ScriptWitnessIndex (.. )
58+ , fromScriptWitnessIndex
5659 , indexCertificatesWith
5760 , renderScriptWitnessIndex
5861 , toScriptIndex
@@ -93,7 +96,7 @@ import Data.Set (Set)
9396import Data.Set qualified as Set
9497import GHC.Exts (IsList (.. ))
9598import GHC.Stack
96- import Lens.Micro ((.~) , (^.) )
99+ import Lens.Micro ((%~) , ( .~) , (^.) )
97100import Prettyprinter (punctuate )
98101
99102data TxBodyErrorAutoBalance era
@@ -532,6 +535,86 @@ calculateMinimumUTxO pp (TxOut txout) =
532535 let txOutWithMinCoin = L. setMinCoinTxOut pp txout
533536 in txOutWithMinCoin ^. L. coinTxOutL
534537
538+ -- | Result of evaluating a signed transaction against the current ledger state.
539+ data TxEvaluationResult era = Show (L. Value era ) => TxEvaluationResult
540+ { txEvalFee :: L. Coin
541+ -- ^ Computed minimum fee for the transaction
542+ , txEvalExecutionUnits
543+ :: Map ScriptWitnessIndex (Either ScriptExecutionError (EvalTxExecutionUnitsLog , ExecutionUnits ))
544+ -- ^ Per-redeemer execution units or script errors
545+ , txEvalBalance :: L. Value era
546+ -- ^ Remaining balance (consumed - produced); mempty when balanced
547+ }
548+
549+ deriving instance Show (TxEvaluationResult era )
550+
551+ -- | Run all scripts, compute the minimum fee, and check the balance.
552+ evaluateTransaction
553+ :: forall era
554+ . IsEra era
555+ => SystemStart
556+ -- ^ Start time of the blockchain
557+ -> LedgerEpochInfo
558+ -- ^ Epoch info for slot/time conversions
559+ -> L. PParams (LedgerEra era )
560+ -- ^ Protocol parameters
561+ -> Set PoolId
562+ -- ^ Registered stake pools
563+ -> Map StakeCredential L. Coin
564+ -- ^ Stake delegation deposits
565+ -> Map (Ledger. Credential Ledger. DRepRole ) L. Coin
566+ -- ^ DRep delegation deposits
567+ -> L. UTxO (LedgerEra era )
568+ -- ^ UTxO set for the transaction inputs
569+ -> L. Tx L. TopTx (LedgerEra era )
570+ -- ^ Signed transaction to evaluate
571+ -> TxEvaluationResult (LedgerEra era )
572+ evaluateTransaction systemStart epochInfo protocolParams poolIds stakeDelegDeposits drepDelegDeposits utxo tx =
573+ obtainCommonConstraints (useEra @ era ) $ do
574+ let txEvalExecutionUnits =
575+ evaluateTransactionExecutionUnits systemStart epochInfo protocolParams utxo tx
576+ evaluatedExUnitsMap =
577+ Map. fromList
578+ [ (purpose, toAlonzoExUnits units)
579+ | (scriptWitnessIndex, Right (_, units)) <- Map. toList txEvalExecutionUnits
580+ , Just purpose <- [fromScriptWitnessIndex (convert $ useEra @ era ) scriptWitnessIndex]
581+ ]
582+ txWithEvaluatedExUnits =
583+ tx
584+ & L. witsTxL . L. rdmrsTxWitsL
585+ %~ \ redeemers ->
586+ L. Redeemers
587+ . Map. mapWithKey
588+ ( \ purpose (datum, oldExUnits) ->
589+ (datum, Map. findWithDefault oldExUnits purpose evaluatedExUnitsMap)
590+ )
591+ $ L. unRedeemers redeemers
592+ txEvalFee =
593+ L. setMinFeeTxUtxo protocolParams txWithEvaluatedExUnits utxo
594+ ^. L. bodyTxL . L. feeTxBodyL
595+ txEvalBalance =
596+ L. evalBalanceTxBody
597+ protocolParams
598+ lookupDelegDeposit
599+ lookupDRepDeposit
600+ isRegPool
601+ utxo
602+ $ txWithEvaluatedExUnits ^. L. bodyTxL
603+ TxEvaluationResult {txEvalFee, txEvalExecutionUnits, txEvalBalance}
604+ where
605+ isRegPool :: Ledger. KeyHash Ledger. StakePool -> Bool
606+ isRegPool keyHash = Api. StakePoolKeyHash keyHash `Set.member` poolIds
607+
608+ lookupDelegDeposit
609+ :: Ledger. Credential Ledger. Staking -> Maybe L. Coin
610+ lookupDelegDeposit stakeCred =
611+ Map. lookup (fromShelleyStakeCredential stakeCred) stakeDelegDeposits
612+
613+ lookupDRepDeposit
614+ :: Ledger. Credential Ledger. DRepRole -> Maybe L. Coin
615+ lookupDRepDeposit drepCred =
616+ Map. lookup drepCred drepDelegDeposits
617+
535618-- | Compute the total balance of the proposed transaction. Ultimately, a valid
536619-- transaction must be fully balanced, which means that it has a total value
537620-- of zero.
0 commit comments