Skip to content

Commit

Permalink
Update ScriptErrorEvaluationFailed with DebugPlutusFailure
Browse files Browse the repository at this point in the history
  • Loading branch information
Jimbo4350 committed Nov 6, 2024
1 parent c8b3d83 commit 4dbd9fc
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 17 deletions.
3 changes: 2 additions & 1 deletion cardano-api/cardano-api.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ library internal
Cardano.Api.NetworkId
Cardano.Api.OperationalCertificate
Cardano.Api.Orphans
Cardano.Api.Plutus
Cardano.Api.Pretty
Cardano.Api.Protocol
Cardano.Api.ProtocolParameters
Expand Down Expand Up @@ -161,6 +162,7 @@ library internal
attoparsec,
base16-bytestring >=1.0,
base58-bytestring,
base64-bytestring,
bech32 >=1.1.0,
bytestring,
cardano-binary,
Expand Down Expand Up @@ -403,7 +405,6 @@ test-suite cardano-api-golden
microlens,
parsec,
plutus-core ^>=1.36,
plutus-ledger-api ^>=1.36,
tasty,
tasty-hedgehog,
text,
Expand Down
17 changes: 6 additions & 11 deletions cardano-api/internal/Cardano/Api/Fees.hs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import qualified Cardano.Api.Experimental.Eras as Exp
import Cardano.Api.Experimental.Tx
import Cardano.Api.Feature
import qualified Cardano.Api.Ledger.Lens as A
import Cardano.Api.Plutus
import Cardano.Api.Pretty
import Cardano.Api.ProtocolParameters
import Cardano.Api.Query
Expand All @@ -84,7 +85,6 @@ import qualified Cardano.Ledger.Keys as Ledger
import qualified Cardano.Ledger.Plutus.Language as Plutus
import qualified Cardano.Ledger.Val as L
import qualified Ouroboros.Consensus.HardFork.History as Consensus
import qualified PlutusLedgerApi.V1 as Plutus

import Control.Monad
import Data.Bifunctor (bimap, first, second)
Expand All @@ -99,7 +99,6 @@ import Data.Ratio
import Data.Set (Set)
import qualified Data.Set as Set
import Data.Text (Text)
import qualified Data.Text as Text
import GHC.Exts (IsList (..))
import Lens.Micro ((.~), (^.))

Expand Down Expand Up @@ -540,7 +539,7 @@ data ScriptExecutionError
-- (which is not possible for 'evaluateTransactionExecutionUnits' since
-- the whole point of it is to discover how many execution units are
-- needed).
ScriptErrorEvaluationFailed Plutus.EvaluationError [Text.Text]
ScriptErrorEvaluationFailed DebugPlutusFailure
| -- | The execution units overflowed a 64bit word. Congratulations if
-- you encounter this error. With the current style of cost model this
-- would need a script to run for over 7 months, which is somewhat more
Expand Down Expand Up @@ -581,11 +580,8 @@ instance Error ScriptExecutionError where
[ "The Plutus script witness has the wrong datum (according to the UTxO). "
, "The expected datum value has hash " <> pshow dh
]
ScriptErrorEvaluationFailed evalErr logs ->
mconcat
[ "The Plutus script evaluation failed: " <> pretty evalErr
, "\nScript debugging logs: " <> mconcat (map (\t -> pretty $ t `Text.append` "\n") logs)
]
ScriptErrorEvaluationFailed plutusDebugFailure ->
pretty $ renderDebugPlutusFailure plutusDebugFailure
ScriptErrorExecutionUnitsOverflow ->
mconcat
[ "The execution units required by this Plutus script overflows a 64bit "
Expand Down Expand Up @@ -740,9 +736,8 @@ evaluateTransactionExecutionUnitsShelley sbe systemstart epochInfo (LedgerProtoc
where
txin' = fromShelleyTxIn txin
L.MissingDatum dh -> ScriptErrorWrongDatum (ScriptDataHash dh)
L.ValidationFailure _ evalErr logs _ ->
-- TODO: Include additional information from ValidationFailure
ScriptErrorEvaluationFailed evalErr logs
L.ValidationFailure execUnits evalErr logs scriptWithContext ->
ScriptErrorEvaluationFailed $ DebugPlutusFailure evalErr scriptWithContext execUnits logs
L.IncompatibleBudget _ -> ScriptErrorExecutionUnitsOverflow
L.RedeemerPointsToUnknownScriptHash rdmrPtr ->
ScriptErrorRedeemerPointsToUnknownScriptHash $ toScriptIndex aOnwards rdmrPtr
Expand Down
88 changes: 88 additions & 0 deletions cardano-api/internal/Cardano/Api/Plutus.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE UndecidableInstances #-}

-- | This module provides an error to conveniently render plutus related failures.
module Cardano.Api.Plutus
( DebugPlutusFailure (..)
, renderDebugPlutusFailure
)
where

import Cardano.Api.Pretty

import qualified Cardano.Ledger.Api as L
import Cardano.Ledger.Binary.Encoding (serialize')
import Cardano.Ledger.Binary.Plain (serializeAsHexText)
import qualified Cardano.Ledger.Plutus.Evaluate as Plutus
import qualified Cardano.Ledger.Plutus.ExUnits as Plutus
import qualified Cardano.Ledger.Plutus.Language as Plutus
import qualified PlutusLedgerApi.V1 as Plutus

import qualified Data.ByteString.Base64 as B64
import Data.ByteString.Short as BSS
import Data.Text (Text)
import qualified Data.Text as Text
import qualified Data.Text.Encoding as Text
import Prettyprinter

-- | A structured representation of Plutus script validation failures,
-- providing detailed information about the failed execution for debugging purposes.
-- This type contains the same information as the data constructor
-- 'Cardano.Ledger.Alonzo.Plutus.Evaluate.TransactionScriptFailure.ValidationFailure'
-- but with named fields and fixed crypto parameters for easier debugging and
-- error reporting.
data DebugPlutusFailure
= DebugPlutusFailure
{ dpfEvaluationError :: Plutus.EvaluationError
, dpfScriptWithContext :: Plutus.PlutusWithContext L.StandardCrypto
, dpfExecutionUnits :: Plutus.ExUnits
, dpfExecutionLogs :: [Text]
}
deriving (Eq, Show)

renderDebugPlutusFailure :: DebugPlutusFailure -> Text
renderDebugPlutusFailure dpf =
let pwc = dpfScriptWithContext dpf
lang = case pwc of
Plutus.PlutusWithContext{Plutus.pwcScript = script} ->
either Plutus.plutusLanguage Plutus.plutusLanguage script

scriptArgs = case pwc of
Plutus.PlutusWithContext{Plutus.pwcArgs = args} ->
line <> indent 3 (pretty args)
protocolVersion = Plutus.pwcProtocolVersion pwc
scriptArgsBase64 = case pwc of
Plutus.PlutusWithContext{Plutus.pwcArgs = args} ->
Text.decodeUtf8 $ B64.encode $ serialize' protocolVersion args
evalError = dpfEvaluationError dpf
binaryScript = case pwc of
Plutus.PlutusWithContext{Plutus.pwcScript = scr} ->
let Plutus.Plutus bytes = either id Plutus.plutusFromRunnable scr
in Text.decodeUtf8 . B64.encode . BSS.fromShort $ Plutus.unPlutusBinary bytes
in Text.unlines
[ "Script hash: " <> serializeAsHexText (Plutus.pwcScriptHash pwc)
, "Script language: " <> Text.pack (show lang)
, "Protocol version: " <> Text.pack (show protocolVersion)
, "Script arguments: " <> docToText scriptArgs
, "Script evaluation error: " <> docToText (pretty evalError)
, "Script execution logs: " <> Text.unlines (dpfExecutionLogs dpf)
, "Script base64 encoded arguments: " <> scriptArgsBase64
, "Script base64 encoded bytes: " <> binaryScript
]

{-
-- Should be used on `dpfExecutionLogs dpf`. Disabled until next plutus release.
See: https://github.com/IntersectMBO/cardano-api/pull/672#issuecomment-2455909946
PlutusTx.ErrorCodes.plutusPreludeErrorCodes
lookupPlutusErrorCode :: Text -> Text
lookupPlutusErrorCode code =
let codeString = PlutusTx.stringToBuiltinString $ Text.unpack code
in case Map.lookup codeString plutusPreludeErrorCodes of
Just err -> Text.pack err
Nothing -> "Unknown error code: " <> code
-}
5 changes: 0 additions & 5 deletions cardano-api/test/cardano-api-golden/Test/Golden/ErrorsSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ import qualified Cardano.Ledger.Coin as L
import Cardano.Ledger.Crypto (StandardCrypto)
import qualified Cardano.Ledger.Plutus.Language as Plutus
import qualified PlutusCore.Evaluation.Machine.CostModelInterface as Plutus
import qualified PlutusLedgerApi.Common as Plutus hiding (PlutusV2)

import qualified Codec.Binary.Bech32 as Bech32
import Control.Error.Util (hush)
Expand Down Expand Up @@ -270,10 +269,6 @@ test_ScriptExecutionError =
[ ("ScriptErrorMissingTxIn", ScriptErrorMissingTxIn txin1)
, ("ScriptErrorTxInWithoutDatum", ScriptErrorTxInWithoutDatum txin1)
, ("ScriptErrorWrongDatum", ScriptErrorWrongDatum hashScriptData1)
,
( "ScriptErrorEvaluationFailed"
, ScriptErrorEvaluationFailed Plutus.CostModelParameterMismatch (replicate 5 text)
)
, ("ScriptErrorExecutionUnitsOverflow", ScriptErrorExecutionUnitsOverflow)
,
( "ScriptErrorNotPlutusWitnessedTxIn"
Expand Down

0 comments on commit 4dbd9fc

Please sign in to comment.