11{-# LANGUAGE CPP #-}
2+ {-# LANGUAGE DataKinds #-}
23{-# LANGUAGE GADTs #-}
34{-# LANGUAGE LambdaCase #-}
45{-# LANGUAGE NamedFieldPuns #-}
56{-# LANGUAGE NumericUnderscores #-}
7+ {-# LANGUAGE RankNTypes #-}
68{-# LANGUAGE OverloadedStrings #-}
79{-# LANGUAGE RecordWildCards #-}
810{-# LANGUAGE ScopedTypeVariables #-}
911{-# LANGUAGE TypeApplications #-}
1012
1113{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
1214
13- import Cardano.Api
15+ import Cardano.Api hiding (eraProtVerHigh )
16+ import Cardano.Api.Experimental (AnyWitness (.. ), IsEra (useEra ),
17+ PlutusScriptDatum (.. ), PlutusScriptPurpose (.. ), SignedTx (.. ),
18+ eraProtVerHigh , makeKeyWitness , makeUnsignedTx ,
19+ obtainCommonConstraints , signTx , toPlutusSLanguage )
20+ import Cardano.Api.Experimental.AnyScriptWitness (AnyPlutusScriptWitness (.. ),
21+ createPlutusSpendingScriptWitness )
22+ import qualified Cardano.Api.Experimental as Exp (PlutusScriptInEra (.. ),
23+ PlutusScriptOrReferenceInput (.. ), PlutusScriptWitness (.. ),
24+ evaluateTransactionFee )
25+ import Cardano.Api.Experimental.Plutus (AnyPlutusScript (.. ),
26+ plutusScriptInEraSLanguage )
27+ import qualified Cardano.Api.Experimental.Tx as Exp
28+
29+ import qualified Cardano.Ledger.Plutus.Language as L (PlutusLanguage , Plutus (.. ), PlutusBinary (.. ),
30+ SLanguage (.. ), decodePlutusRunnable )
1431
1532import Cardano.Benchmarking.Compiler (keyBenchmarkInputs )
1633import Cardano.Benchmarking.GeneratorTx.SizedMetadata (mkMetadata )
@@ -19,21 +36,22 @@ import Cardano.Benchmarking.PlutusScripts (listPlutusScripts)
1936#endif
2037import Cardano.TxGenerator.Calibrate.Utils
2138import Cardano.TxGenerator.PlutusContext
22- import Cardano.TxGenerator.ProtocolParameters ( ProtocolParameters (.. ), convertToLedgerProtocolParameters ,
23- toLedgerPParams )
39+ import Cardano.TxGenerator.ProtocolParameters (ProtocolParameters (.. ),
40+ convertToLedgerProtocolParameters )
2441import Cardano.TxGenerator.Setup.Plutus
2542import Cardano.TxGenerator.Tx (txSizeInBytes )
2643import Cardano.TxGenerator.Types
2744import Cardano.TxGenerator.Utils (keyAddress , mkTxIn )
2845
2946import Control.Exception
47+ import Data.Typeable (Typeable )
3048import Data.Aeson (decodeFileStrict' )
3149import qualified Data.ByteString.Lazy.Char8 as BSL (writeFile )
50+
3251import Data.Char
3352import Data.Function (on , (&) )
3453import Data.List (nub , sort , transpose )
3554import Data.List.Extra (split )
36-
3755import Data.Map.Strict as Map (Map , empty , fromList , union )
3856import Data.Maybe
3957import qualified Data.Text as T
@@ -157,6 +175,17 @@ runPlutus strategy budgetType protoParamFile plutusDef@PlutusOn{..} scales
157175 = do
158176 protocolParameters <- readProtocolParametersOrDie protoParamFile
159177 (script, resolvedTo) <- either (error . show ) pure =<< readPlutusScript plutusScript
178+ let era = useEra @ ConwayEra
179+ anyPlutusScript <- obtainCommonConstraints era $
180+ case script of
181+ ScriptInAnyLang _lang (PlutusScript version (PlutusScriptSerialised sbs)) -> do
182+ let slang = toPlutusSLanguage version
183+ decode :: forall l . (L. PlutusLanguage l , Typeable l ) => L. SLanguage l -> IO (AnyPlutusScript (ShelleyLedgerEra ConwayEra ))
184+ decode _ = case L. decodePlutusRunnable @ l (eraProtVerHigh era) (L. Plutus (L. PlutusBinary sbs)) of
185+ Left err -> throwIO $ userError $ " script decode failed: " ++ show err
186+ Right runnable -> pure $ AnyPlutusScript (Exp. PlutusScriptInEra runnable)
187+ obtainLangConstraints slang $ decode slang
188+ _ -> throwIO $ userError " expected a Plutus script"
160189
161190 let
162191 redeemerDef = Right plutusDef
@@ -189,7 +218,10 @@ runPlutus strategy budgetType protoParamFile plutusDef@PlutusOn{..} scales
189218 jsonName = " summaries_" ++ scriptName <.> " json"
190219 csvName = " scaling_" ++ scriptName <.> " csv"
191220
192- summariesWithApprox <- mapM (approximateTxProperties script protocolParameters) summaries
221+ ledgerProtocolParameters <-
222+ either (error . docToString . prettyError) pure
223+ $ convertToLedgerProtocolParameters shelleyBasedEra protocolParameters
224+ summariesWithApprox <- mapM (approximateTxProperties anyPlutusScript ledgerProtocolParameters) summaries
193225 writeResultsJSON jsonName summariesWithApprox
194226 writeResultsCSV csvName summariesWithApprox
195227
@@ -481,75 +513,76 @@ writeResultsJSON jsonName summaries = do
481513-- | Builds a dummy transaction that resembles the ones submitted during some Plutus benchmark and
482514-- uses it to augment the budget summary with txn size and fee.
483515-- * If anything fails to evaluate, the summary is returned unchanged.
484- -- * This function is currently monorphic in the ledger era and will resolve era parameters to Conway.
485- approximateTxProperties :: ScriptInAnyLang -> ProtocolParameters -> (PlutusBudgetSummary , ScriptRedeemer ) -> IO PlutusBudgetSummary
486- approximateTxProperties script protocolParameters (summary, redeemer) = do
516+ -- * This function is currently monomorphic in the ledger era and will resolve era parameters to Conway.
517+ approximateTxProperties :: AnyPlutusScript ( ShelleyLedgerEra ConwayEra ) -> LedgerProtocolParameters ConwayEra -> (PlutusBudgetSummary , ScriptRedeemer ) -> IO PlutusBudgetSummary
518+ approximateTxProperties ( AnyPlutusScript ps) ledgerProtocolParameters (summary, redeemer) = do
487519 putStrLn $ " --> approximating txn size and fee for: " ++ messageId summary
488- evaluate $ summary
489- { projectedTxSize = Just $ txSizeInBytes dummyTx
490- , projectedTxFee = Just $ evaluateTransactionFee era ledgerPParams2 (getTxBody dummyTx) 2 0 0 -- 1 (script witness) + 1 (collateral) = 2
491- }
492-
493- `catch` \ (SomeException e) -> do
494- putStrLn $ " approximation failed: " ++ show e
495- ++ " \n --> using unmodified summary"
496- pure summary
497- where
498- era = ShelleyBasedEraConway
499-
500- ledgerPParams1 :: LedgerProtocolParameters ConwayEra
501- ledgerPParams1 =
502- either (error . docToString . prettyError) id
503- $ convertToLedgerProtocolParameters era protocolParameters
504-
505- ledgerPParams2 =
506- either (error . docToString . prettyError) id
507- $ toLedgerPParams era protocolParameters
508-
509- witness :: Witness WitCtxTxIn ConwayEra
510- witness =
511- fromMaybe (error " could not get PlutusScriptWitness" )
512- $ case script of
513- ScriptInAnyLang lang (PlutusScript version script') -> do
514- scriptLang <- scriptLanguageSupportedInEra era lang
515- pure
516- $ ScriptWitness ScriptWitnessForSpending
517- $ PlutusScriptWitness
518- scriptLang
519- version
520- (PScript script')
521- (ScriptDatumForTxIn $ Just $ unsafeHashableScriptData $ ScriptDataNumber 0 )
522- redeemer
523- (budgetUsedPerTxInput summary)
524- _ -> Nothing
525-
526- -- build a dummy tx akin to what we'd get in the tx-generator's benchmarking workload;
527- -- it just needs to be sufficient to get our approximations.
528- dummyTx :: Tx ConwayEra
529- dummyTx
530- = signShelleyTransaction era txbody [WitnessPaymentKey keyBenchmarkInputs]
531- where
532- txbody =
533- either (error . docToString . prettyError) id
534- $ createTransactionBody era content
535-
536- content =
537- defaultTxBodyContent era
538- & setTxIns [(dummyTxIn 0 , BuildTxWith witness)]
539- & setTxInsCollateral (TxInsCollateral AlonzoEraOnwardsConway [dummyTxIn 1 ])
540- & setTxOuts [dummyTxOut]
541- & setTxValidityLowerBound TxValidityNoLowerBound
542- & setTxValidityUpperBound (defaultTxValidityUpperBound era)
543- & setTxMetadata dummyMetadata
544- & setTxFee (TxFeeExplicit era 1_000_000 )
545- & setTxProtocolParams (BuildTxWith (Just ledgerPParams1))
546-
520+ let
521+ era = useEra @ ConwayEra
522+ pparams = unLedgerProtocolParameters ledgerProtocolParameters
523+ slang = plutusScriptInEraSLanguage ps
524+ dummyDatum = unsafeHashableScriptData $ ScriptDataNumber 0
525+ datum = mkSpendingScriptDatum slang dummyDatum
526+ anyWitness =
527+ let witness = Exp. PlutusScriptWitness slang (Exp. PScript ps) datum redeemer (budgetUsedPerTxInput summary)
528+ in AnyPlutusScriptWitness (AnyPlutusSpendingScriptWitness (createPlutusSpendingScriptWitness slang witness))
529+ obtainCommonConstraints era (do
547530 -- Corresponds to the metadata inserted in benchmarking workloads, which is why it's needed for the estimate.
548531 -- default value taken from: `add_tx_size` in nix/nixos/tx-generator-service.nix
549- dummyMetadata :: TxMetadataInEra ConwayEra
550- dummyMetadata = either error id $ mkMetadata 100
532+ dummyMetadata <- either (\ e -> throwIO $ userError $ " approximateTxProperties: mkMetadata: " ++ e) pure
533+ $ mkMetadata @ ConwayEra 100
534+ let
535+ expMetadata = case dummyMetadata of
536+ TxMetadataNone -> mempty
537+ TxMetadataInEra _ m -> m
538+
539+ -- just placeholders
540+ dummyTxIn ix = mkTxIn $ " 900fc5da77a0747da53f7675cbb7d149d46779346dea2f879ab811ccc72a2162#" <> textShow @ Int ix
541+ dummyTxOut = TxOut (keyAddress (Testnet (NetworkMagic 42 )) keyBenchmarkInputs) (lovelaceToTxOutValue shelleyBasedEra 1_000_000 ) TxOutDatumNone ReferenceScriptNone
542+
543+ -- build a dummy tx akin to what we'd get in the tx-generator's benchmarking workload;
544+ -- it just needs to be sufficient to get our approximations.
545+ txBodyContent =
546+ Exp. defaultTxBodyContent
547+ & Exp. setTxIns [(dummyTxIn 0 , anyWitness)]
548+ & Exp. setTxInsCollateral [dummyTxIn 1 ]
549+ & Exp. setTxOuts [Exp. TxOut $ toShelleyTxOutAny shelleyBasedEra dummyTxOut]
550+ & Exp. setTxFee (Coin 1_000_000 )
551+ & Exp. setTxMetadata expMetadata
552+ & Exp. setTxProtocolParams pparams
553+
554+ unsignedTx <- either (\ err -> throwIO $ userError $ " approximateTxProperties: " ++ show err) pure
555+ $ makeUnsignedTx era txBodyContent
556+
557+ let
558+ witVKey = makeKeyWitness era unsignedTx (WitnessPaymentKey keyBenchmarkInputs)
559+ dummyTx :: Tx ConwayEra
560+ dummyTx =
561+ case signTx era [] [witVKey] unsignedTx of
562+ SignedTx signedLedgerTx -> ShelleyTx shelleyBasedEra signedLedgerTx
551563
552- -- just placeholders
553- dummyTxIn ix = mkTxIn $ " 900fc5da77a0747da53f7675cbb7d149d46779346dea2f879ab811ccc72a2162#" <> textShow @ Int ix
554- dummyTxOut = TxOut (keyAddress (Testnet (NetworkMagic 42 )) keyBenchmarkInputs) (lovelaceToTxOutValue era 1_000_000 ) TxOutDatumNone ReferenceScriptNone
564+ pure summary
565+ { projectedTxSize = Just $ txSizeInBytes dummyTx
566+ , projectedTxFee = Just $ Exp. evaluateTransactionFee pparams unsignedTx 2 0 0 -- 1 (script witness) + 1 (collateral) = 2
567+ }
568+ ) `catch` \ (SomeException e) -> do
569+ putStrLn $ " approximation failed: " ++ show e
570+ ++ " \n --> using unmodified summary"
571+ pure summary
572+
573+ -- TODO: remove these vendored functions and import from
574+ -- Cardano.Api.Experimental when the published cardano-api version includes them.
575+
576+ obtainLangConstraints :: L. SLanguage lang -> ((L. PlutusLanguage lang , Typeable lang ) => a ) -> a
577+ obtainLangConstraints L. SPlutusV1 f = f
578+ obtainLangConstraints L. SPlutusV2 f = f
579+ obtainLangConstraints L. SPlutusV3 f = f
580+ obtainLangConstraints L. SPlutusV4 f = f
581+
582+ mkSpendingScriptDatum :: L. SLanguage lang -> HashableScriptData -> PlutusScriptDatum lang 'SpendingScript
583+ mkSpendingScriptDatum = \ case
584+ L. SPlutusV1 -> SpendingScriptDatum
585+ L. SPlutusV2 -> SpendingScriptDatum
586+ L. SPlutusV3 -> SpendingScriptDatum . Just
587+ L. SPlutusV4 -> SpendingScriptDatum . Just
555588
0 commit comments