Skip to content

Commit 1df397c

Browse files
authored
Tool to dump cost model parameters in order expected by ledger (#7171)
* Add executable to dump cost model parameters * Change some imports * Add a description of what the program does and is for * Add comment about default option * Update help text * Amend output format * Update comment
1 parent ee15d36 commit 1df397c

File tree

3 files changed

+217
-2
lines changed

3 files changed

+217
-2
lines changed
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
{-# LANGUAGE AllowAmbiguousTypes #-}
2+
{-# LANGUAGE LambdaCase #-}
3+
{-# LANGUAGE TypeApplications #-}
4+
5+
module Main (main)
6+
where
7+
8+
import Parsers (Format (..), WhichLL (..), parseDumpOptions)
9+
10+
import PlutusCore qualified as PLC
11+
import PlutusCore.Builtin qualified as PLC
12+
import PlutusCore.Default.Builtins qualified as PLC
13+
import PlutusCore.Evaluation.Machine.ExBudgetingDefaults qualified as PLC
14+
15+
import PlutusLedgerApi.Common (IsParamName, PlutusLedgerLanguage (..), showParamName)
16+
import PlutusLedgerApi.V1 qualified as V1
17+
import PlutusLedgerApi.V2 qualified as V2
18+
import PlutusLedgerApi.V3 qualified as V3
19+
20+
import Data.Aeson qualified as A (Object, ToJSON, Value (Array, Number))
21+
import Data.Aeson.Encode.Pretty (encodePretty)
22+
import Data.Aeson.Key qualified as K (fromString)
23+
import Data.Aeson.KeyMap qualified as KM (KeyMap, singleton)
24+
import Data.ByteString.Lazy (putStr)
25+
import Data.Int (Int64)
26+
import Data.List.Extra (enumerate)
27+
import Data.Map qualified as Map (lookup)
28+
import Data.Text (Text)
29+
import Data.Vector qualified as V (fromList)
30+
import Options.Applicative (execParser)
31+
import Text.Printf (printf)
32+
33+
{- | This executable prints out the cost model parameters according to the various
34+
`PlutusLedgerApi.V<n>.ParamName types`. These determine both the cost model
35+
parameters included in the protocol parameters (and hence which Plutus
36+
builtins are available to each Plutus ledger language version) and the order
37+
in which they occur. The protocol parameters and the ledger both treat the
38+
cost model parameters as ordered lists of integers and know nothing about
39+
the names of the parameters (see
40+
`cardano-ledger/libs/cardano-ledger-core/src/Cardano/Ledger/Plutus/CostModels.hs`
41+
for how the ledger (and also cardano-api and cardano-cli) deals with cost
42+
models), and the `ParamName` types provide the link between the lists of
43+
parameters and the complex structure used to represent a cost model in
44+
Plutus Core. New cost models (possibly enabling new builtins) are
45+
propagated to the chain by protocol updates which update the cost model
46+
parameters, and this executable produces lists of cost model parameters in a
47+
form suitable for inclusion in the protocol parameters, and so can be helpful
48+
when we need to propose new parameters for use on the chain, and to check
49+
that the on-chain parameters are as expected. Note that this code deals
50+
only with the cost model parameters in the current state of the `plutus`
51+
repository, which may differ from those on the chain: specifically, the cost
52+
model parameters dealt with by this code will often be those which are
53+
expected to come into effect at the next hard fork and hence will be ahead
54+
of those currently in use for new script executions on the chain. The exact
55+
structure of the cost model used by a particular ledger language is
56+
determined by a _semantic variant_ which depends on both the ledger language
57+
and the protocol version (see the `mkEvaluationContext` functions in the
58+
various `EvaluationContext` files), and this code will need to be updated
59+
if, for example, a new Plutus Ledger language is added or the structure of
60+
the cost model used by an existing ledger language changes.
61+
-}
62+
63+
-- Mapping of LL versions to semantic versions and parameter names for *the
64+
-- current state of the repository*. This MUST be updated if the mappings in
65+
-- the PlutusLedgerApi.V<n>.EvaluationContext modules are changed.
66+
infoFor :: PlutusLedgerLanguage -> (PLC.BuiltinSemanticsVariant PLC.DefaultFun, [Text])
67+
infoFor =
68+
let paramNames :: forall a . IsParamName a => [Text]
69+
paramNames = fmap showParamName $ enumerate @a
70+
in \case
71+
PlutusV1 -> (PLC.DefaultFunSemanticsVariantB, paramNames @V1.ParamName)
72+
PlutusV2 -> (PLC.DefaultFunSemanticsVariantB, paramNames @V2.ParamName)
73+
PlutusV3 -> (PLC.DefaultFunSemanticsVariantC, paramNames @V3.ParamName)
74+
75+
-- Return the current cost model parameters for a given LL version in the form
76+
-- of a list of (name, value) pairs ordered by name according to the relevant
77+
-- `ParamName` type.
78+
getParamsFor :: PlutusLedgerLanguage -> [(Text, Int64)]
79+
getParamsFor ll =
80+
let (semvar, paramNames) = infoFor ll
81+
params =
82+
case PLC.defaultCostModelParamsForVariant semvar of
83+
Nothing -> error $ "Can't find default cost model parameters for "
84+
++ show semvar
85+
Just p -> p
86+
lookupParam name =
87+
case Map.lookup name params of
88+
Nothing -> error $ "No entry for " ++ show name
89+
++ " in cost model for semantic variant "
90+
++ show semvar
91+
Just n -> (name, n)
92+
in fmap lookupParam paramNames
93+
94+
-- A couple of convenience functions for dealing with JSON.
95+
mkObject :: String -> v -> KM.KeyMap v
96+
mkObject k v = KM.singleton (K.fromString k) v
97+
98+
putJSON :: A.ToJSON a => a -> IO ()
99+
putJSON = Data.ByteString.Lazy.putStr . encodePretty
100+
101+
-- Return the cost model parameters for a given LL in the form of a JSON object
102+
-- containing the LL version and an array of parameter values. This is the same
103+
-- format that cardano-cli uses to render the protocol parameters. Cost model
104+
-- parameter names are not included in the protocol parameters: they used to be,
105+
-- but not any more.
106+
getParamsAsJSON :: PlutusLedgerLanguage -> A.Object
107+
getParamsAsJSON ll =
108+
let params = getParamsFor ll
109+
entries = A.Array $ V.fromList $ fmap (\(_,v) -> A.Number $ fromIntegral v) params
110+
in mkObject (show ll) entries
111+
112+
printParameters :: Format -> PlutusLedgerLanguage -> IO ()
113+
printParameters fmt ll =
114+
case fmt of
115+
Untagged -> do
116+
printf "%s:\n" $ show ll
117+
mapM_ (\(_,val) -> printf " %-d\n" val) $ getParamsFor ll
118+
printf "\n"
119+
Tagged -> do
120+
printf "%s:\n" $ show ll
121+
mapM_ (\(name,val) -> printf " %-12d -- %s\n" val name) $ getParamsFor ll
122+
printf "\n"
123+
JSON -> putJSON $ getParamsAsJSON ll
124+
125+
-- Print the cost model parameters for all ledger languages. For JSON we have
126+
-- to create a single object containing parameters for all ledger language
127+
-- versions and print that; for the other formats we just print them all out in
128+
-- sequence.
129+
printAll :: Format -> IO ()
130+
printAll fmt =
131+
case fmt of
132+
JSON -> putJSON $ mkObject "costModels" $ mconcat (fmap getParamsAsJSON enumerate)
133+
_ -> mapM_ (printParameters fmt) enumerate
134+
135+
main :: IO ()
136+
main = do
137+
(lls, fmt) <- execParser parseDumpOptions
138+
case lls of
139+
One ll -> printParameters fmt ll
140+
All -> printAll fmt
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
{-# LANGUAGE LambdaCase #-}
2+
3+
module Parsers (Format(..), WhichLL(..), parseDumpOptions)
4+
where
5+
6+
import Options.Applicative
7+
import PlutusLedgerApi.Common.Versions (PlutusLedgerLanguage (..))
8+
9+
data WhichLL =
10+
One PlutusLedgerLanguage -- Print parameters for a single LL.
11+
| All -- Print parameters for all LLs.
12+
deriving stock (Show)
13+
14+
parseVersion :: ReadM WhichLL
15+
parseVersion = eitherReader $ \case
16+
"1" -> Right $ One PlutusV1
17+
"2" -> Right $ One PlutusV2
18+
"3" -> Right $ One PlutusV3
19+
s -> Left $ "Unknown ledger language version: " ++ s
20+
21+
whichll :: Parser WhichLL
22+
whichll =
23+
option parseVersion
24+
(short 'V' <>
25+
metavar "N" <>
26+
help "Print parameters for PlutusV<N> only"
27+
)
28+
<|> flag All All
29+
-- This makes `All` the default: if the previous parser fails then we
30+
-- arrive here and it returns `All` whether or not the option is
31+
-- present on the command line.
32+
(short 'a' <>
33+
long "all" <>
34+
help "Print parameters for all Plutus ledger language versions (default)"
35+
)
36+
37+
data Format = Untagged | Tagged | JSON
38+
deriving stock (Show)
39+
40+
format :: Parser Format
41+
format =
42+
flag' Untagged (short 'u' <> long "untagged" <> help "Print parameter values only")
43+
<|> flag' Tagged (short 't' <> long "tagged" <> help "Print parameter values and names")
44+
<|> flag JSON JSON (short 'j' <> long "json" <> help "Print parameters in JSON format (default)")
45+
46+
dumpOptions :: Parser (WhichLL, Format)
47+
dumpOptions = (,) <$> whichll <*> format
48+
49+
parseDumpOptions :: ParserInfo (WhichLL, Format)
50+
parseDumpOptions =
51+
info (dumpOptions <**> helper)
52+
(fullDesc <>
53+
progDesc ("Print the current (and possibly undeployed) cost model parameters "
54+
++ " in the plutus repository in the order used in the protocol parameters.\n"
55+
++ "The purpose of this tool is to help with the deployment and verification "
56+
++ "of updated cost model parameters: it MUST be kept up to date with the "
57+
++ "`mkEvaluationContext` functions in plututus-ledger-api."))

plutus-ledger-api/plutus-ledger-api.cabal

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ executable test-onchain-evaluation
259259
main-is: Main.hs
260260
other-modules: LoadScriptEvents
261261
hs-source-dirs: exe/test-onchain-evaluation exe/common
262+
default-language: Haskell2010
262263
ghc-options: -threaded -rtsopts -with-rtsopts=-N
263264
build-depends:
264265
, async
@@ -273,13 +274,12 @@ executable test-onchain-evaluation
273274
, tasty
274275
, tasty-hunit
275276

276-
default-language: Haskell2010
277-
278277
executable analyse-script-events
279278
import: lang
280279
main-is: Main.hs
281280
other-modules: LoadScriptEvents
282281
hs-source-dirs: exe/analyse-script-events exe/common
282+
default-language: Haskell2010
283283
ghc-options: -threaded -rtsopts -with-rtsopts=-N
284284
build-depends:
285285
, base >=4.9 && <5
@@ -294,4 +294,22 @@ executable analyse-script-events
294294
, primitive
295295
, serialise
296296

297+
executable dump-cost-model-parameters
298+
import: lang
299+
main-is: Main.hs
300+
other-modules: Parsers
301+
hs-source-dirs: exe/dump-cost-model-parameters
297302
default-language: Haskell2010
303+
ghc-options: -threaded -rtsopts -with-rtsopts=-N
304+
build-depends:
305+
, aeson
306+
, aeson-pretty
307+
, base >=4.9 && <5
308+
, bytestring
309+
, containers
310+
, extra
311+
, optparse-applicative
312+
, plutus-core ^>=1.48
313+
, plutus-ledger-api ^>=1.48
314+
, text
315+
, vector

0 commit comments

Comments
 (0)