I have been trying to interact with a simple script I created using the CLI, and I am getting an error that I don't understand:
This is the error:
The Plutus script evaluation failed: An error has occurred: User error:
The provided Plutus code called 'error'.
Caused by: [ (builtin unConstrData) (con data #80) ]
This is the script:
{-|
Module : Horrocubes.Counter.
Description : Plutus script that keeps track of an internal counter.
License : Apache-2.0
Maintainer : [email protected]
Stability : experimental
This script keeps a counter and increases it everytime the eUTXO is spent.
-}
-- LANGUAGE EXTENSIONS --------------------------------------------------------
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE ViewPatterns #-}
-- MODULE DEFINITION ----------------------------------------------------------
module Horrocubes.Counter
(
counterScript,
counterScriptShortBs,
CounterParameter(..)
) where
-- IMPORTS --------------------------------------------------------------------
import Cardano.Api.Shelley (PlutusScript (..), PlutusScriptV1)
import Codec.Serialise
import qualified Data.ByteString.Lazy as LBS
import qualified Data.ByteString.Short as SBS
import Ledger hiding (singleton)
import qualified Ledger.Typed.Scripts as Scripts
import Ledger.Value as Value
import qualified PlutusTx
import PlutusTx.Prelude as P hiding (Semigroup (..), unless)
import Data.Aeson (FromJSON, ToJSON)
import GHC.Generics (Generic)
import qualified Ledger.Contexts as Validation
import Text.Show
import PlutusTx.Builtins
-- DATA TYPES -----------------------------------------------------------------
-- | The parameters for the counter contract.
data CounterParameter = CounterParameter {
ownerPkh :: !PubKeyHash, -- ^ The transaction that spends this output must be signed by the private key
identityNft :: !AssetClass -- ^ The NFT that identifies the correct eUTXO.
} deriving (Show, Generic, FromJSON, ToJSON)
PlutusTx.makeLift ''CounterParameter
-- PlutusTx.unstableMakeIsData ''CounterDatum
-- | The Counter script type. Sets the Redeemer and Datum types for this script.
data Counter
instance Scripts.ValidatorTypes Counter where
type instance DatumType Counter = BuiltinData
type instance RedeemerType Counter = ()
-- DEFINITIONS ----------------------------------------------------------------
-- | Maybe gets the datum from the transatcion output.
{-# INLINABLE counterDatum #-}
counterDatum :: TxOut -> (DatumHash -> Maybe Datum) -> Maybe Integer
counterDatum o f = do
dh <- txOutDatum o
Datum d <- f dh
PlutusTx.fromBuiltinData d
-- | Checks that the identity NFT is locked again in the contract.
{-# INLINABLE isIdentityNftRelocked #-}
isIdentityNftRelocked:: CounterParameter -> Value -> Bool
isIdentityNftRelocked params valueLockedByScript = assetClassValueOf valueLockedByScript (identityNft params) == 1
-- | Creates the validator script for the outputs on this contract.
{-# INLINABLE mkCounterValidator #-}
mkCounterValidator :: CounterParameter -> BuiltinData -> () -> ScriptContext -> Bool
mkCounterValidator parameters oldDatum _ ctx =
let oldCounterValue = oldDatumIntegerValue
isRightNexCounterValue = (newDatumValue == (oldCounterValue + 1))
in traceIfFalse "Wrong counter value" isRightNexCounterValue
where
info :: TxInfo
info = scriptContextTxInfo ctx
ownOutput :: TxOut
ownOutput = case getContinuingOutputs ctx of
[o] -> o
_ -> traceError "Expected exactly one output"
newDatumValue :: Integer
newDatumValue = case counterDatum ownOutput (`findDatum` info) of
Nothing -> traceError "Counter output datum not found"
Just datum -> datum
oldDatumIntegerValue :: Integer
oldDatumIntegerValue = case PlutusTx.fromBuiltinData oldDatum of
Nothing -> traceError "Counter output datum not found"
Just datum -> datum
valueLockedByScript :: Value
valueLockedByScript = Validation.valueLockedBy info (Validation.ownHash ctx)
isTransactionSignedByOwner :: Bool
isTransactionSignedByOwner = txSignedBy info (ownerPkh parameters)
-- | The script instance of the counter. It contains the mkCounterValidator function
-- compiled to a Plutus core validator script.
counterInstance :: CounterParameter -> Scripts.TypedValidator Counter
counterInstance counter = Scripts.mkTypedValidator @Counter
($$(PlutusTx.compile [|| mkCounterValidator ||]) `PlutusTx.applyCode` PlutusTx.liftCode counter) $$(PlutusTx.compile [|| wrap ||])
where
wrap = Scripts.wrapValidator @BuiltinData @()
-- | Gets the counter validator script that matches the given parameters.
counterValidator :: CounterParameter -> Validator
counterValidator params = Scripts.validatorScript . counterInstance $ params
-- | Generates the plutus script.
counterPlutusScript :: CounterParameter -> Script
counterPlutusScript params = unValidatorScript $ counterValidator params
-- | Serializes the contract in CBOR format.
counterScriptShortBs :: CounterParameter -> SBS.ShortByteString
counterScriptShortBs params = SBS.toShort . LBS.toStrict $ serialise $ counterPlutusScript params
-- | Gets a serizlized plutus script from the given parameters.
counterScript :: PubKeyHash -> AssetClass -> PlutusScript PlutusScriptV1
counterScript pkh ac = PlutusScriptSerialised $ counterScriptShortBs $ CounterParameter { ownerPkh = pkh, identityNft = ac }
This is how I am creating the transaction:
cardano-cli transaction build --alonzo-era --testnet-magic 1097911063 --change-address $(cat counter/payment.addr) --tx-in-collateral 7d65ca46aca44532d94da57ec6b7297efdda2e523626f90bbdc780f3767202f2#0 --tx-in 0be3e055fa3e51b34baa1cc5589397520ee79670dbf2428f7884713ba0066f4f#1 --tx-in-script-file ./counter/out2.plutus --tx-in-datum-file ./datum_0.json --tx-in-redeemer-value [] --tx-out "addr_test1vpfvmwfl8eucm8rnsej9pehzh7628k53raczagz4uvzzm2csx7sfl+1000000" --tx-out-datum-embed-file ./datum_1.json --protocol-params-file protocol.json --out-file tx-script2.build
I have been trying to find the root cause of the error to no avail. It seems it is related to one of the Datum inputs, but I don't the error on the script or the datum data.
This is what is on the datum.json files:
datum_0.json
{"constructor":0,"fields":[{"int":0}]}
datum_1.json
{"constructor":0,"fields":[{"int":1}]}