@@ -3,7 +3,7 @@ module BotPlutusInterface.ExBudget (
33 estimateBudget ,
44) where
55
6- import BotPlutusInterface.QueryNode (NodeInfo (NodeInfo ))
6+ import BotPlutusInterface.QueryNode (NodeInfo (NodeInfo ), NodeQueryError )
77import BotPlutusInterface.QueryNode qualified as QueryNode
88import BotPlutusInterface.Types (
99 BudgetEstimationError (.. ),
@@ -14,11 +14,15 @@ import BotPlutusInterface.Types (
1414 TxFile (.. ),
1515 )
1616import Cardano.Api qualified as CAPI
17+ import Cardano.Api.Shelley (ProtocolParameters (protocolParamMaxTxExUnits ))
18+ import Cardano.Prelude (maybeToEither )
1719import Control.Arrow (left )
20+ import Data.Either (rights )
1821import Data.List (sort )
1922import Data.Map (Map )
2023import Data.Map qualified as Map
2124import Data.Text qualified as Text
25+ import GHC.Natural (Natural )
2226import Ledger (ExBudget (ExBudget ), ExCPU (ExCPU ), ExMemory (ExMemory ), MintingPolicyHash , TxOutRef )
2327import Ledger.Tx.CardanoAPI (fromCardanoPolicyId , fromCardanoTxIn )
2428import System.Directory.Internal.Prelude (getEnv )
@@ -37,26 +41,49 @@ estimateBudget pabConf txFile = do
3741 Raw rp -> deserialiseRaw rp
3842 Signed sp -> fmap CAPI. getTxBody <$> deserialiseSigned sp
3943
44+ pparamsRes <- QueryNode. queryProtocolParams debugNodeInf
45+
4046 budgetRes <-
4147 either
4248 (pure . Left )
43- (getExUnits debugNodeInf)
49+ (getExUnits pparamsRes debugNodeInf)
4450 txBody
4551
46- let txBudget = do
47- body <- txBody
48- budget <- budgetRes
49- let scaledBudget = fmap (fmap $ scaleBudget pabConf. pcBudgetMultiplier) budget
50- (spendingBudgets, policyBudgets) <- mkBudgetMaps scaledBudget body
51- Right $ TxBudget spendingBudgets policyBudgets
52+ return $
53+ do
54+ body <- txBody
55+ budget <- budgetRes
56+ pparams <- left toBudgetError pparamsRes
57+ maxUnits <- maybeToEither (BudgetEstimationError " Missing max units in parameters" ) $ protocolParamMaxTxExUnits pparams
58+
59+ let scaledBudget = getScaledBudget maxUnits pabConf. pcBudgetMultiplier budget
60+
61+ (spendingBudgets, policyBudgets) <- mkBudgetMaps scaledBudget body
5262
53- return txBudget
63+ Right $ TxBudget spendingBudgets policyBudgets
64+
65+ -- | Scale the budget clamping the total to the parameter limits
66+ getScaledBudget :: CAPI. ExecutionUnits -> Rational -> ExUnitsMap -> ExUnitsMap
67+ getScaledBudget maxUnits scaler budget = fmap (fmap $ scaleBudget scalers) budget
68+ where
69+ budgetSum = foldr addBudgets (CAPI. ExecutionUnits 0 0 ) $ rights $ Map. elems budget
70+ scalers =
71+ ( clampedScaler (CAPI. executionSteps budgetSum) (CAPI. executionSteps maxUnits) scaler
72+ , clampedScaler (CAPI. executionMemory budgetSum) (CAPI. executionMemory maxUnits) scaler
73+ )
74+
75+ clampedScaler :: Natural -> Natural -> Rational -> Rational
76+ clampedScaler 0 _ scaler = scaler
77+ clampedScaler val maxVal scaler = min scaler (toRational maxVal / toRational val)
5478
5579-- | Scale the budget by the multipliers in config
56- scaleBudget :: Rational -> CAPI. ExecutionUnits -> CAPI. ExecutionUnits
57- scaleBudget scaler (CAPI. ExecutionUnits steps mem) = CAPI. ExecutionUnits (scale steps) (scale mem)
80+ scaleBudget :: ( Rational , Rational ) -> CAPI. ExecutionUnits -> CAPI. ExecutionUnits
81+ scaleBudget (stepsScaler, memScaler) (CAPI. ExecutionUnits steps mem) = CAPI. ExecutionUnits (scale steps stepsScaler ) (scale mem memScaler )
5882 where
59- scale x = round $ toRational x * scaler
83+ scale x scaler = round $ toRational x * scaler
84+
85+ addBudgets :: CAPI. ExecutionUnits -> CAPI. ExecutionUnits -> CAPI. ExecutionUnits
86+ addBudgets (CAPI. ExecutionUnits steps mem) (CAPI. ExecutionUnits steps' mem') = CAPI. ExecutionUnits (steps + steps') (mem + mem')
6087
6188-- | Deserialize transaction body from ".signed" file
6289deserialiseSigned :: FilePath -> IO (Either BudgetEstimationError (CAPI. Tx CAPI. AlonzoEra ))
@@ -92,13 +119,13 @@ type ExUnitsMap =
92119
93120-- | Calculate execution units using `Cardano.Api``
94121getExUnits ::
122+ Either NodeQueryError ProtocolParameters ->
95123 NodeInfo ->
96124 CAPI. TxBody CAPI. AlonzoEra ->
97125 IO (Either BudgetEstimationError ExUnitsMap )
98- getExUnits nodeInf txBody = do
126+ getExUnits pparams nodeInf txBody = do
99127 sysStart <- QueryNode. querySystemStart nodeInf
100128 eraHist <- QueryNode. queryEraHistory nodeInf
101- pparams <- QueryNode. queryProtocolParams nodeInf
102129 utxo <- QueryNode. queryOutsByInputs nodeInf capiIns
103130 return $
104131 flattenEvalResult $
0 commit comments