Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-evaluation of mainnet scripts to verify backward compatibility. #16

Merged
merged 14 commits into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 24 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
Plutus Scripts Evaluation
===
# Plutus Scripts Evaluation

Tools used to:

1. Accumulate Plutus script evaluation events by replaying blockchain folding over the Ledger state and extracting `PlutusScriptEvaluationEvent`s.
2. Record accumulated events:
1. On the file system as "dump" files.
2. In the PostgreSQL database.
1. On the file system as "dump" files.
2. In the PostgreSQL database.

## How to use

0. Initialise the PostgreSQL database and connection using files in the `database` folder:
* There is a [pgModeler](https://pgmodeler.io/) (Open-source tool) project for it,
* As well as the DDL statements.
- There is a [pgModeler](https://pgmodeler.io/) (Open-source tool) project for it,
- As well as the DDL statements.
1. Create `.envrc.local` with the following content (adjust the paths as needed):
```sh
export CARDANO_NODE_SOCKET_PATH="/home/projects/cardano/node/node-state/mainnet/node.sock"
Expand All @@ -21,3 +21,21 @@ Tools used to:
2. Enter the `nix` shell using either `nix develop` command or `direnv` hooked to your shell.
3. See available commands by entering `info` in the shell.
4. Run the script dump job using the `dump` command or script upload job with the `load` command.

## How to re-evaluate recorded Plutus Script evaluations locally

The database contains plutus script evaluation events from Mainnet which can be replayed locally to re-evaluate the scripts.

There is less value in re-evaluating scripts without any changes, as one would
simply re-obtain results that are already known. However, this can be useful
when the script evaluation logic has changed, and one wants to compare results
produced by the new logic with the old results.

The repository contains a program that can be used to re-evaluate the scripts
locally. You can use this program as a basis for your own re-evaluation, where
you can modify various parameters to suit your needs:

- The [Main module](plutus-script-evaluation/evaluate-scripts/Main.hs) of the `evaluate-scripts` executable.
- The main workhorse, function `evaluateScripts` in the [Evaluation module](plutus-script-evaluation/evaluate-scripts/Evaluation.hs) does the boring parts (aggregating relevant script evaluation inputs, streaming the data from DB to a local computer, decoding CBOR, forking worker threads) so that you can do the interesting part: traverse script evaluations from the Mainnet accessing all of the original evaluation inputs to re-interpret them accordingly to your task;

If a task requires maintaining local state (accumulator) during the evaluation, you can use the `accumulateScripts` function in the [Evaluation module](plutus-script-evaluation/evaluate-scripts/Evaluation.hs). This function is a more general version of `evaluateScripts` that allows you to maintain local state during the evaluation.
1 change: 0 additions & 1 deletion cabal.project
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,3 @@ packages:

package postgresql-libpq
flags: +use-pkg-config

5 changes: 3 additions & 2 deletions database/db.dbm
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
CAUTION: Do not modify this file unless you know what you are doing.
Unexpected results may occur if the code is changed deliberately.
-->
<dbmodel pgmodeler-ver="1.1.5" use-changelog="false" max-obj-count="18"
last-position="257,118" last-zoom="1" scene-rect="0,0,1570.8,1076.8"
<dbmodel pgmodeler-ver="1.1.6" use-changelog="false" max-obj-count="18"
last-position="0,0" last-zoom="1" scene-rect="0,0,1570.8,1076.8"
default-schema="public" default-owner="postgres"
layers="Default layer"
active-layers="0"
Expand Down Expand Up @@ -223,6 +223,7 @@ ORDER BY
SEE.EVALUATED_SUCCESSFULLY,
SEE.EXEC_BUDGET_CPU,
SEE.EXEC_BUDGET_MEM,
CMP.PK AS COST_MODEL_KEY,
CMP.PARAM_VALUES AS COST_MODEL_PARAM_VALUES,
SEE.DATUM,
SEE.REDEEMER,
Expand Down
2 changes: 1 addition & 1 deletion database/db.sql
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
-- Database generated with pgModeler (PostgreSQL Database Modeler).
-- pgModeler version: 1.1.5
-- pgModeler version: 1.1.6
-- PostgreSQL version: 16.0
-- Project Site: pgmodeler.io
-- Model Author: ---
Expand Down
2 changes: 1 addition & 1 deletion nix/shell.nix
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ cabalProject: {
description = "Evaluate Plutus Scripts from mainnet";
group = "general";
exec = ''
cabal run evaluate-scripts -- --database-conn-str "$DB_CONN_STRING"
cabal run evaluate-scripts -- --start-block=0 --database-conn-str "$DB_CONN_STRING"
'';
};
};
Expand Down
9 changes: 7 additions & 2 deletions plutus-script-evaluation/evaluate-scripts/Main.hs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
{- | This module contains the main entry point
into the program which CEK-evaluates scripts using
the information recorded in the database in a
streaming fashion.
-}
module Main where

import Control.Exception (bracket, catch)
Expand All @@ -15,10 +20,10 @@ main :: IO ()
main = withUtf8 do
hSetBuffering stdin LineBuffering
hSetBuffering stdout LineBuffering
Options{optsDatabaseConnStr} <- execParser parserInfo
Options{optsDatabaseConnStr, startBlock} <- execParser parserInfo
displaySqlError $
bracket (PG.connectPostgreSQL optsDatabaseConnStr) PG.close \conn -> do
_result <- evaluateScripts conn mempty onScriptEvaluationInput
evaluateScripts conn startBlock onScriptEvaluationInput
putStrLn "Done evaluating scripts"

displaySqlError :: IO () -> IO ()
Expand Down
15 changes: 14 additions & 1 deletion plutus-script-evaluation/evaluate-scripts/Options.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,14 @@ module Options (
)
where

import Cardano.Slotting.Block (BlockNo (BlockNo))
import Data.ByteString (ByteString)
import Options.Applicative qualified as O

newtype Options = Options {optsDatabaseConnStr :: ByteString}
data Options = Options
{ optsDatabaseConnStr :: ByteString
, startBlock :: BlockNo
}
deriving (Show)

options :: O.Parser Options
Expand All @@ -27,6 +31,15 @@ options = do
\/docs/current/libpq-connect.html#LIBPQ-CONNSTRING"
]
)
startBlock <-
O.option
(O.maybeReader (Just . BlockNo . read))
( mconcat
[ O.long "start-block"
, O.metavar "BLOCK_NO"
, O.help "Block number to start from"
]
)
pure Options{..}

parserInfo :: O.ParserInfo Options
Expand Down
25 changes: 19 additions & 6 deletions plutus-script-evaluation/lib/Database/Query.hs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
module Database.Query where

import Cardano.Slotting.Block (BlockNo (..))
import Cardano.Slotting.Slot (SlotNo)
import Control.Monad.IO.Unlift (MonadUnliftIO, withRunInIO)
import Data.Profunctor.Product.Default (Default)
import Database.Orphans ()
import Database.PostgreSQL.Simple (Connection)
Expand All @@ -10,10 +12,12 @@ import Opaleye (
Delete (..),
Insert (Insert, iOnConflict, iReturning, iRows, iTable),
ToFields,
asc,
doNothing,
limit,
maybeFields,
optional,
orderBy,
rCount,
runDelete,
runInsert,
Expand All @@ -25,6 +29,7 @@ import Opaleye (
(.==),
(.>=),
)
import Opaleye.Internal.Column (SqlNum (pgFromInteger))

insertCostModelValues
:: (Default ToFields CostModelValuesRecord CostModelValuesRecordFields)
Expand Down Expand Up @@ -92,13 +97,21 @@ selectSerialisedScriptsBatch conn count =
pure serialised

withScriptEvaluationEvents
:: Connection
:: (MonadUnliftIO m)
=> Connection
-> BlockNo
-> a
-> (a -> ScriptEvaluationRecord -> IO a)
-> IO a
withScriptEvaluationEvents conn a f = do
let select = selectTable scriptEvaluations
runSelectFold conn select a f
-> (a -> ScriptEvaluationRecord -> m a)
-> m a
withScriptEvaluationEvents conn blockNo a f = do
let startBlock = pgFromInteger (fromIntegral (unBlockNo blockNo))
select = orderBy (asc seBlockNo) do
res <- selectTable scriptEvaluations
where_ (seBlockNo res .>= startBlock)
pure res
withRunInIO \runInIO ->
runSelectFold conn select a \accum record ->
runInIO (f accum record)

insertScriptEvaluationEvents
:: (Default ToFields EvaluationEventRecord WriteEvaluationEventRecordFields)
Expand Down
9 changes: 7 additions & 2 deletions plutus-script-evaluation/lib/Database/Schema.hs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ data
datum
redeemer
scriptContext
costModelKey
costModel
= MkScriptEvaluationRecord'
{ sePk :: pk
Expand All @@ -207,6 +208,7 @@ data
, seDatum :: datum
, seRedeemer :: redeemer
, seScriptContext :: scriptContext
, seCostModelKey :: costModelKey
, seCostModelParams :: costModel
}
deriving (Show, Eq)
Expand All @@ -225,6 +227,7 @@ type ScriptEvaluationRecord =
(Maybe ByteString) -- datum
(Maybe ByteString) -- redeemer
ByteString -- script_context
Hash64 -- cost_model_key
[Int64] -- cost_model_params

type ScriptEvaluationRecordFields =
Expand All @@ -237,10 +240,11 @@ type ScriptEvaluationRecordFields =
(Field SqlBool) -- evaluated_successfully
(Field SqlInt4) -- exec_budget_cpu
(Field SqlInt4) -- exec_budget_mem
(Field SqlBytea) -- script_hash
(Field SqlBytea) -- script
(FieldNullable SqlBytea) -- datum
(FieldNullable SqlBytea) -- redeemer
(Field SqlBytea) -- script_context
(Field SqlInt8) -- cost_model_params
(Field (SqlArray SqlInt8)) -- cost_model_params

--------------------------------------------------------------------------------
Expand Down Expand Up @@ -292,10 +296,11 @@ scriptEvaluations =
, seEvaluatedSuccessfully = tableField "evaluated_successfully"
, seExecBudgetCpu = tableField "exec_budget_cpu"
, seExecBudgetMem = tableField "exec_budget_mem"
, seScript = tableField "serialised"
, seScript = tableField "script_serialised"
, seDatum = tableField "datum"
, seRedeemer = tableField "redeemer"
, seScriptContext = tableField "script_context"
, seCostModelKey = tableField "cost_model_key"
, seCostModelParams = tableField "cost_model_param_values"
}

Expand Down
Loading