diff --git a/.changes/20261015_120100_cardano-cli_mateusz.galazyn_read-any-script-hash.yml b/.changes/20261015_120100_cardano-cli_mateusz.galazyn_read-any-script-hash.yml new file mode 100644 index 0000000000..a256facce8 --- /dev/null +++ b/.changes/20261015_120100_cardano-cli_mateusz.galazyn_read-any-script-hash.yml @@ -0,0 +1,6 @@ +project: cardano-cli +pr: 1452 +kind: + - refactoring +description: | + Add `readAnyScriptHash` to `Cardano.CLI.Read`, which returns the hash of a script file in any script language cardano-api supports, including Plutus V4. Add `MainnetEra` to `Cardano.CLI.EraBased.Option`, the era used by the `latest` command group and the top-level `node` and `query` commands. diff --git a/.changes/cardano_era_all_eras.yml b/.changes/cardano_era_all_eras.yml new file mode 100644 index 0000000000..eb625c8791 --- /dev/null +++ b/.changes/cardano_era_all_eras.yml @@ -0,0 +1,6 @@ +project: cardano-cli +pr: 1452 +kind: + - bugfix +description: | + `CARDANO_ERA` now accepts every era cardano-api supports, including `dijkstra`, in any letter case, and an unknown value stops the command with an error that lists the valid eras. diff --git a/.changes/plutus-v4-script-readers.yml b/.changes/plutus-v4-script-readers.yml new file mode 100644 index 0000000000..18baf3a0e4 --- /dev/null +++ b/.changes/plutus-v4-script-readers.yml @@ -0,0 +1,6 @@ +project: cardano-cli +pr: 1452 +kind: + - bugfix +description: | + `transaction policyid` and `address build` with `--payment-script-file` or `--stake-script-file` now accept Plutus V4 scripts, instead of failing with "Plutus language PlutusScriptV4 is not supported in the Conway era". They also accept simple scripts with a `guard`, which used to crash them. diff --git a/.changes/plutus-v4-script-witnesses.yml b/.changes/plutus-v4-script-witnesses.yml new file mode 100644 index 0000000000..b9235b7bd0 --- /dev/null +++ b/.changes/plutus-v4-script-witnesses.yml @@ -0,0 +1,6 @@ +project: cardano-cli +pr: 1452 +kind: + - test +description: | + Add golden tests for Plutus V4 scripts: script files as direct witnesses for every script purpose in `dijkstra transaction build-raw`, `hash script`, `transaction policyid`, `address build` with payment and stake scripts, and the error for a V4 reference script in a Conway transaction. diff --git a/.changes/reference-script-unsupported-language.yml b/.changes/reference-script-unsupported-language.yml new file mode 100644 index 0000000000..e0a5fe6ba0 --- /dev/null +++ b/.changes/reference-script-unsupported-language.yml @@ -0,0 +1,6 @@ +project: cardano-cli +pr: 1452 +kind: + - bugfix +description: | + A transaction output whose reference script is written in a Plutus language not supported by the transaction's era now makes the command fail with a clear error, instead of silently building the transaction with that reference script dropped from the output. diff --git a/cardano-cli/cardano-cli.cabal b/cardano-cli/cardano-cli.cabal index 9f47dcc52d..a8d709cb36 100644 --- a/cardano-cli/cardano-cli.cabal +++ b/cardano-cli/cardano-cli.cabal @@ -487,11 +487,13 @@ test-suite cardano-cli-golden Test.Golden.Conway.Transaction.Assemble Test.Golden.Conway.Transaction.BuildRaw Test.Golden.Conway.Transaction.CreateWitness + Test.Golden.Conway.Transaction.ReferenceScript Test.Golden.CreateStaked Test.Golden.CreateTestnetData Test.Golden.Debug.TransactionView Test.Golden.Dijkstra.StakePool.RegistrationCertificate Test.Golden.Dijkstra.Transaction.Assemble + Test.Golden.Dijkstra.Transaction.BuildRaw Test.Golden.Dijkstra.Transaction.SubTransaction Test.Golden.ErrorsSpec Test.Golden.Genesis.Common diff --git a/cardano-cli/src/Cardano/CLI/Compatible/Transaction/TxOut.hs b/cardano-cli/src/Cardano/CLI/Compatible/Transaction/TxOut.hs index 18eaacbe71..4b210aeb64 100644 --- a/cardano-cli/src/Cardano/CLI/Compatible/Transaction/TxOut.hs +++ b/cardano-cli/src/Cardano/CLI/Compatible/Transaction/TxOut.hs @@ -139,7 +139,11 @@ readRefScript sbe = \case ReferenceScriptAnyEraNone -> pure L.SNothing ReferenceScriptAnyEra fp -> do script <- readFileScriptInAnyLang fp - pure $ maybe L.SNothing (L.SJust . toShelleyScript) (toScriptInEra sbe script) + scriptInEra <- + fromMaybeCli + (TxOutputReferenceScriptLanguageNotSupportedInEra script (anyCardanoEra $ toCardanoEra sbe)) + $ toScriptInEra sbe script + pure . L.SJust $ toShelleyScript scriptInEra toTxOutValueInShelleyBasedEra :: ShelleyBasedEra era diff --git a/cardano-cli/src/Cardano/CLI/Environment.hs b/cardano-cli/src/Cardano/CLI/Environment.hs index c7c9503d93..58f90dde5a 100644 --- a/cardano-cli/src/Cardano/CLI/Environment.hs +++ b/cardano-cli/src/Cardano/CLI/Environment.hs @@ -14,15 +14,21 @@ where import Cardano.Api ( AnyCardanoEra (..) - , CardanoEra (..) , NetworkId (..) , NetworkMagic (..) , forEraMaybeEon + , pretty ) import Cardano.Api.Experimental qualified as Exp +import Control.Monad.IO.Class (MonadIO (..)) +import Data.Char (toLower) +import Data.Foldable (find) +import Data.List (intercalate) +import Data.Traversable (forM) import Data.Type.Equality import Data.Word (Word32) +import GHC.Stack (HasCallStack) import System.Environment qualified as IO import System.IO qualified as IO import Text.Read (readMaybe) @@ -84,21 +90,29 @@ getEnvNetworkId = do getEnvSocketPath :: IO (Maybe FilePath) getEnvSocketPath = IO.lookupEnv "CARDANO_NODE_SOCKET_PATH" --- | If the environment variable @CARDANO_ERA@ is set, then return the set value. +-- | If the environment variable @CARDANO_ERA@ is set to a known era, then return that era. +-- If it is set to an unknown era, fail with an error listing the valid eras. -- Otherwise, return 'Nothing'. -getCardanoEra :: IO (Maybe AnyCardanoEra) +getCardanoEra :: (HasCallStack, MonadIO m) => m (Maybe AnyCardanoEra) getCardanoEra = do - mEraString <- IO.lookupEnv "CARDANO_ERA" + mEraString <- liftIO $ IO.lookupEnv "CARDANO_ERA" + forM mEraString $ \eraString -> + maybe (error $ invalidEraMessage eraString) pure $ parseCardanoEra eraString + where + invalidEraMessage :: String -> String + invalidEraMessage eraString = + mconcat + [ "The era specified in CARDANO_ERA is invalid: " <> eraString <> "." + , " It should be one of: " <> intercalate ", " (cardanoEraName <$> allCardanoEras) <> "." + ] - case mEraString of - Just eraString -> - case eraString of - "byron" -> pure $ Just $ AnyCardanoEra ByronEra - "shelley" -> pure $ Just $ AnyCardanoEra ShelleyEra - "allegra" -> pure $ Just $ AnyCardanoEra AllegraEra - "mary" -> pure $ Just $ AnyCardanoEra MaryEra - "alonzo" -> pure $ Just $ AnyCardanoEra AlonzoEra - "babbage" -> pure $ Just $ AnyCardanoEra BabbageEra - "conway" -> pure $ Just $ AnyCardanoEra ConwayEra - unknown -> error $ "Unknown era: " <> unknown -- TODO improve error handling - Nothing -> pure Nothing + -- Parse an era name, ignoring case, using the names that cardano-api renders for its eras. + parseCardanoEra :: String -> Maybe AnyCardanoEra + parseCardanoEra eraString = + find ((== map toLower eraString) . cardanoEraName) allCardanoEras + + allCardanoEras :: [AnyCardanoEra] + allCardanoEras = enumFrom minBound + + cardanoEraName :: AnyCardanoEra -> String + cardanoEraName = map toLower . show . pretty diff --git a/cardano-cli/src/Cardano/CLI/EraBased/Option.hs b/cardano-cli/src/Cardano/CLI/EraBased/Option.hs index 5d9be2fce5..ea7f14667d 100644 --- a/cardano-cli/src/Cardano/CLI/EraBased/Option.hs +++ b/cardano-cli/src/Cardano/CLI/EraBased/Option.hs @@ -4,10 +4,12 @@ module Cardano.CLI.EraBased.Option ( pCmds , pAnyEraCommand + , MainnetEra ) where import Cardano.Api.Experimental +import Cardano.Api.Pretty (prettyShow) import Cardano.CLI.Environment import Cardano.CLI.EraBased.Command @@ -29,6 +31,9 @@ import Data.Maybe import Options.Applicative (Parser) import Options.Applicative qualified as Opt +-- | The era running on mainnet, used by the latest, top-level node and top-level query commands. +type MainnetEra = ConwayEra + pCmds :: forall era. IsEra era => EnvCli -> Parser (Cmds era) pCmds envCli = do asum $ @@ -59,6 +64,7 @@ pAnyEraCommand envCli = Opt.progDesc "Dijkstra era commands" , Opt.hsubparser $ commandWithMetavar "latest" $ - Opt.info (AnyEraCommandOf ConwayEra <$> pCmds @ConwayEra envCli) $ - Opt.progDesc "Latest era commands (Conway)" + Opt.info (AnyEraCommandOf (useEra @MainnetEra) <$> pCmds @MainnetEra envCli) $ + Opt.progDesc $ + "Latest era commands (" <> prettyShow (useEra @MainnetEra) <> ")" ] diff --git a/cardano-cli/src/Cardano/CLI/EraBased/Transaction/Run.hs b/cardano-cli/src/Cardano/CLI/EraBased/Transaction/Run.hs index 831320d89d..aef33e5c08 100644 --- a/cardano-cli/src/Cardano/CLI/EraBased/Transaction/Run.hs +++ b/cardano-cli/src/Cardano/CLI/EraBased/Transaction/Run.hs @@ -1530,12 +1530,9 @@ runTransactionPolicyIdCmd -> CIO e () runTransactionPolicyIdCmd Cmd.TransactionPolicyIdCmdArgs - { scriptFile = File sFile - } = do - script <- - readAnyScript @_ @ConwayEra sFile - let hash = fromShelleyScriptHash $ Exp.hashAnyScript script - liftIO . Text.putStrLn $ serialiseToRawBytesHexText hash + { scriptFile + } = + liftIO . Text.putStrLn . serialiseToRawBytesHexText =<< readAnyScriptHash scriptFile -- ---------------------------------------------------------------------------- -- Other misc small commands diff --git a/cardano-cli/src/Cardano/CLI/EraIndependent/Address/Run.hs b/cardano-cli/src/Cardano/CLI/EraIndependent/Address/Run.hs index 4012f01619..88f94be2b8 100644 --- a/cardano-cli/src/Cardano/CLI/EraIndependent/Address/Run.hs +++ b/cardano-cli/src/Cardano/CLI/EraIndependent/Address/Run.hs @@ -17,14 +17,12 @@ module Cardano.CLI.EraIndependent.Address.Run where import Cardano.Api -import Cardano.Api.Experimental.AnyScript qualified as Exp import Cardano.CLI.Compatible.Exception import Cardano.CLI.EraIndependent.Address.Command import Cardano.CLI.EraIndependent.Address.Info.Run import Cardano.CLI.EraIndependent.Key.Run qualified as Key import Cardano.CLI.Read -import Cardano.CLI.Read qualified as Exp import Cardano.CLI.Type.Common import Cardano.CLI.Type.Error.AddressCmdError import Cardano.CLI.Type.Key @@ -40,6 +38,7 @@ import Cardano.CLI.Type.Key import Control.Monad (void) import Data.ByteString.Char8 qualified as BS import Data.Function +import Data.Maybe (fromMaybe) import Data.Text.IO qualified as Text import Vary (Vary) import Vary qualified @@ -206,15 +205,11 @@ runAddressBuildCmd paymentVerifier mbStakeVerifier nw mOutFp = do nonPaymentKey -> throwCliError $ AddressCmdExpectedPaymentVerificationKey nonPaymentKey return $ serialiseAddress (addr :: AddressAny) - PaymentVerifierScriptFile (File fp) -> do - script <- - readAnyScript @_ @ConwayEra fp - - let hash = fromShelleyScriptHash $ Exp.hashAnyScript script - payCred = PaymentCredentialByScript hash + PaymentVerifierScriptFile scriptFile -> do + payCred <- PaymentCredentialByScript <$> readAnyScriptHash scriptFile stakeAddressReference <- - maybe (return NoStakeAddress) makeStakeAddressRef mbStakeVerifier + fromMaybe NoStakeAddress <$> traverse makeStakeAddressRef mbStakeVerifier return $ serialiseAddress . makeShelleyAddress nw payCred $ stakeAddressReference @@ -233,14 +228,8 @@ makeStakeAddressRef stakeIdentifier = stakeVKeyHash <- readVerificationKeyOrHashOrFile stkVkeyOrFile return . StakeAddressByValue $ StakeCredentialByKey stakeVKeyHash - StakeVerifierScriptFile (File fp) -> do - script <- - Exp.readAnyScript @_ @ConwayEra fp - - let hash = fromShelleyScriptHash $ Exp.hashAnyScript script - stakeCred = StakeCredentialByScript hash - - return (StakeAddressByValue stakeCred) + StakeVerifierScriptFile scriptFile -> + StakeAddressByValue . StakeCredentialByScript <$> readAnyScriptHash scriptFile StakeIdentifierAddress stakeAddr -> pure $ StakeAddressByValue $ stakeAddressCredential stakeAddr @@ -251,4 +240,5 @@ buildShelleyAddress -> CIO e (Address ShelleyAddr) buildShelleyAddress vkey mbStakeVerifier nw = makeShelleyAddress nw (PaymentCredentialByKey (verificationKeyHash vkey)) - <$> maybe (return NoStakeAddress) makeStakeAddressRef mbStakeVerifier + . fromMaybe NoStakeAddress + <$> traverse makeStakeAddressRef mbStakeVerifier diff --git a/cardano-cli/src/Cardano/CLI/EraIndependent/Hash/Run.hs b/cardano-cli/src/Cardano/CLI/EraIndependent/Hash/Run.hs index 2424002568..d56398571e 100644 --- a/cardano-cli/src/Cardano/CLI/EraIndependent/Hash/Run.hs +++ b/cardano-cli/src/Cardano/CLI/EraIndependent/Hash/Run.hs @@ -13,7 +13,6 @@ module Cardano.CLI.EraIndependent.Hash.Run where import Cardano.Api -import Cardano.Api.Experimental.AnyScript qualified as Exp import Cardano.Api.Ledger qualified as L import Cardano.CLI.Compatible.Exception @@ -88,15 +87,12 @@ runHashScriptCmd :: forall e . Cmd.HashScriptCmdArgs -> CIO e () -runHashScriptCmd Cmd.HashScriptCmdArgs{Cmd.toHash = File toHash, mOutFile} = +runHashScriptCmd Cmd.HashScriptCmdArgs{Cmd.toHash, mOutFile} = do - script <- - readAnyScript @_ @DijkstraEra toHash - let hash = Exp.hashAnyScript script + hash <- readAnyScriptHash toHash fromEitherIOCli @(FileError ()) $ writeTextOutput mOutFile $ - serialiseToRawBytesHexText $ - fromShelleyScriptHash hash + serialiseToRawBytesHexText hash runHashGenesisFile :: GenesisFile -> CIO e () runHashGenesisFile (GenesisFile fpath) = do diff --git a/cardano-cli/src/Cardano/CLI/Option.hs b/cardano-cli/src/Cardano/CLI/Option.hs index 328f78722f..743ccf2d75 100644 --- a/cardano-cli/src/Cardano/CLI/Option.hs +++ b/cardano-cli/src/Cardano/CLI/Option.hs @@ -8,8 +8,6 @@ module Cardano.CLI.Option ) where -import Cardano.Api.Experimental (ConwayEra) - import Cardano.CLI.Byron.Parser (backwardsCompatibilityCommands, parseByronCommands) import Cardano.CLI.Compatible.Option import Cardano.CLI.Environment (EnvCli) @@ -61,14 +59,14 @@ addressCmdsTopLevel envCli = AddressCommand <$> pAddressCmds envCli -- The node related commands are shelley era agnostic for the time being. -- There is no need to guard them by the era argument. nodeCmdsTopLevel :: Parser ClientCommand -nodeCmdsTopLevel = NodeCommands <$> pNodeCmds @ConwayEra +nodeCmdsTopLevel = NodeCommands <$> pNodeCmds @MainnetEra -- Queries actually depend on the node to client version which may coincide -- with a hardfork but not necessarily. We will expose commands at the top level -- regardless if they are compatible with the era or not. The help text should be -- updated to make this clear. Gating commands behind eras queryCmdsTopLevel :: EnvCli -> Parser ClientCommand -queryCmdsTopLevel envCli = QueryCommands @ConwayEra <$> pQueryCmdsTopLevel envCli +queryCmdsTopLevel envCli = QueryCommands @MainnetEra <$> pQueryCmdsTopLevel envCli keyCmdsTopLevel :: Parser ClientCommand keyCmdsTopLevel = KeyCommands <$> pKeyCmds diff --git a/cardano-cli/src/Cardano/CLI/Read.hs b/cardano-cli/src/Cardano/CLI/Read.hs index ece394ef91..4fe381577d 100644 --- a/cardano-cli/src/Cardano/CLI/Read.hs +++ b/cardano-cli/src/Cardano/CLI/Read.hs @@ -16,6 +16,7 @@ module Cardano.CLI.Read -- * Script , ScriptDecodeError (..) , readAnyScript + , readAnyScriptHash , deserialiseScriptInAnyLang , readFileScriptInAnyLang , PlutusScriptDecodeError (..) @@ -200,6 +201,15 @@ readVerificationKeySource extractHash = \case VksKeyHashFile vKeyOrHashOrFile -> L.KeyHashObj . extractHash <$> readVerificationKeyOrHashOrTextEnvFile vKeyOrHashOrFile +-- | Reads the script in cardano-api's newest era, so every script language decodes. +-- Returns only the era-independent script hash. +readAnyScriptHash :: MonadIO m => ScriptFile -> m ScriptHash +readAnyScriptHash scriptFile = + case maxBound of + Exp.Some (era :: Exp.Era era) -> + Exp.obtainCommonConstraints era $ + fromShelleyScriptHash . Exp.hashAnyScript <$> readAnyScript @_ @era (unFile scriptFile) + readAnyScript :: forall m era . (MonadIO m, Exp.IsEra era) diff --git a/cardano-cli/test/cardano-cli-golden/Test/Golden/Conway/Transaction/ReferenceScript.hs b/cardano-cli/test/cardano-cli-golden/Test/Golden/Conway/Transaction/ReferenceScript.hs new file mode 100644 index 0000000000..573abc64e9 --- /dev/null +++ b/cardano-cli/test/cardano-cli-golden/Test/Golden/Conway/Transaction/ReferenceScript.hs @@ -0,0 +1,43 @@ +{-# LANGUAGE OverloadedStrings #-} + +module Test.Golden.Conway.Transaction.ReferenceScript where + +import GHC.IO.Exception (ExitCode (ExitFailure)) + +import Test.Cardano.CLI.Util + +import Hedgehog (Property, (===)) +import Hedgehog.Extras.Test qualified as H + +-- A reference script in a Plutus language the era does not support must fail +-- the command instead of being silently dropped from the output. + +-- | Execute me with: +-- @cabal test cardano-cli-golden --test-options '-p "/golden conway build raw reference script unsupported language/"'@ +hprop_golden_conway_build_raw_reference_script_unsupported_language :: Property +hprop_golden_conway_build_raw_reference_script_unsupported_language = + watchdogProp . propertyOnce . H.moduleWorkspace "tmp" $ \tempDir -> do + outFile <- noteTempFile tempDir "out.json" + + (exitCode, _stdout, stderr) <- + execDetailCardanoCLI + [ "conway" + , "transaction" + , "build-raw" + , "--tx-in" + , "f62cd7bc15d8c6d2c8519fb8d13c57c0157ab6bab50af62bc63706feb966393d#0" + , "--tx-out" + , "addr_test1qpmxr8d8jcl25kyz2tz9a9sxv7jxglhddyf475045y8j3zxjcg9vquzkljyfn3rasfwwlkwu7hhm59gzxmsyxf3w9dps8832xh+5000000" + , "--tx-out-reference-script-file" + , "test/cardano-cli-golden/files/input/dijkstra/plutus/v4-always-succeeds.plutus" + , "--fee" + , "166777" + , "--out-file" + , outFile + ] + + exitCode === ExitFailure 1 + + H.diffVsGoldenFileExcludeTrace + stderr + "test/cardano-cli-golden/files/golden/conway/transaction/build-raw-reference-script-unsupported-language.out" diff --git a/cardano-cli/test/cardano-cli-golden/Test/Golden/Dijkstra/Transaction/BuildRaw.hs b/cardano-cli/test/cardano-cli-golden/Test/Golden/Dijkstra/Transaction/BuildRaw.hs new file mode 100644 index 0000000000..7a67a2fdd1 --- /dev/null +++ b/cardano-cli/test/cardano-cli-golden/Test/Golden/Dijkstra/Transaction/BuildRaw.hs @@ -0,0 +1,126 @@ +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TypeApplications #-} + +module Test.Golden.Dijkstra.Transaction.BuildRaw where + +import Cardano.Api.Experimental qualified as Exp +import Cardano.Api.Ledger qualified as L + +import Control.Monad (void) +import Data.Aeson qualified as Aeson + +import Test.Cardano.CLI.Util + +import Hedgehog (Property) +import Hedgehog qualified as H +import Hedgehog.Extras.Test qualified as H + +-- A Plutus V4 script file must work as a direct witness for every script purpose. +-- Regression test for https://github.com/IntersectMBO/cardano-cli/issues/1448 + +-- | Execute me with: +-- @cabal test cardano-cli-golden --test-options '-p "/golden dijkstra build raw plutus v4 script witnesses/"'@ +hprop_golden_dijkstra_build_raw_plutus_v4_script_witnesses :: Property +hprop_golden_dijkstra_build_raw_plutus_v4_script_witnesses = + watchdogProp . propertyOnce . H.moduleWorkspace "tmp" $ \tempDir -> do + pparamsFile <- noteTempFile tempDir "protocol-params.json" + proposalFile <- noteTempFile tempDir "info.action" + txBodyFile <- noteTempFile tempDir "tx-body" + + let v4Script = "test/cardano-cli-golden/files/input/dijkstra/plutus/v4-always-succeeds.plutus" + v4ScriptHash = "31a78786b5989dc6fd2d4ab15b297069e94106ecacceb8eb29e1b681" + + -- build-raw does not evaluate scripts, so empty protocol parameters suffice. + H.evalIO . Aeson.encodeFile pparamsFile . L.PParams $ + L.emptyPParamsIdentity @(Exp.LedgerEra Exp.DijkstraEra) + + void $ + execCardanoCLI + [ "dijkstra" + , "governance" + , "action" + , "create-info" + , "--testnet" + , "--governance-action-deposit" + , "12345" + , "--deposit-return-stake-verification-key-file" + , "test/cardano-cli-golden/files/input/governance/stake-address.vkey" + , "--anchor-url" + , "https://example.com" + , "--anchor-data-hash" + , "52e69500a92d80f2126c836a4903dc582006709f004cf7a28ed648f732dff8d2" + , "--out-file" + , proposalFile + ] + + void $ + execCardanoCLI + [ "dijkstra" + , "transaction" + , "build-raw" + , "--tx-in" + , "fe5dd07fb576bff960d6e066eade5b26cdb5afebe29f76ea58d0a098bce5d891#200" + , "--tx-in-script-file" + , v4Script + , "--tx-in-datum-value" + , "24" + , "--tx-in-redeemer-value" + , "42" + , "--tx-in-execution-units" + , "(100,110)" + , "--mint" + , "1000 " <> v4ScriptHash + , "--mint-script-file" + , v4Script + , "--mint-redeemer-value" + , "42" + , "--mint-execution-units" + , "(100,110)" + , "--withdrawal" + , "stake_test17qvxuvh64q9zdqgrjt76d42eclk5wgdxtnsun4808cwg0dqxv5r99+10000" + , "--withdrawal-script-file" + , v4Script + , "--withdrawal-redeemer-value" + , "83" + , "--withdrawal-execution-units" + , "(100,110)" + , "--certificate-file" + , "test/cardano-cli-golden/files/input/stake-address-registration.json" + , "--certificate-script-file" + , v4Script + , "--certificate-redeemer-value" + , "63" + , "--certificate-execution-units" + , "(100,110)" + , "--vote-file" + , "test/cardano-cli-golden/files/input/conway/vote1.drep.json" + , "--vote-script-file" + , v4Script + , "--vote-redeemer-value" + , "1" + , "--vote-execution-units" + , "(100,110)" + , "--proposal-file" + , proposalFile + , "--proposal-script-file" + , v4Script + , "--proposal-redeemer-value" + , "1" + , "--proposal-execution-units" + , "(100,110)" + , "--tx-out" + , "addr_test1vp0t4dfa9ktc2uvv7sg9leafuhtwyu0xcj4q4kf5pqkpjwqhklklg+15000000" + , "--fee" + , "200000" + , "--protocol-params-file" + , pparamsFile + , "--out-file" + , txBodyFile + ] + + result <- + execCardanoCLI + ["debug", "transaction", "view", "--tx-body-file", txBodyFile, "--output-yaml"] + H.diffVsGoldenFile + result + "test/cardano-cli-golden/files/golden/dijkstra/transaction/build-raw-plutus-v4-script-witnesses.out" diff --git a/cardano-cli/test/cardano-cli-golden/Test/Golden/Hash/Hash.hs b/cardano-cli/test/cardano-cli-golden/Test/Golden/Hash/Hash.hs index ec8e40f3db..96f682e400 100644 --- a/cardano-cli/test/cardano-cli-golden/Test/Golden/Hash/Hash.hs +++ b/cardano-cli/test/cardano-cli-golden/Test/Golden/Hash/Hash.hs @@ -25,3 +25,25 @@ hprop_golden_governance_hash_script = ] H.diffFileVsGoldenFile hashFile hashGold + +-- Check that `hash script` can hash a Plutus V4 script envelope. +-- Regression test for https://github.com/IntersectMBO/cardano-cli/issues/1448 +hprop_golden_hash_script_plutus_v4 :: Property +hprop_golden_hash_script_plutus_v4 = + watchdogProp . H.propertyOnce . H.moduleWorkspace "tmp" $ \tempDir -> do + scriptFile <- + noteInputFile "test/cardano-cli-golden/files/input/dijkstra/plutus/v4-always-succeeds.plutus" + hashFile <- H.noteTempFile tempDir "v4-always-succeeds.hash" + hashGold <- H.note "test/cardano-cli-golden/files/golden/dijkstra/plutus/v4-always-succeeds.hash" + + void $ + execCardanoCLI + [ "hash" + , "script" + , "--script-file" + , scriptFile + , "--out-file" + , hashFile + ] + + H.diffFileVsGoldenFile hashFile hashGold diff --git a/cardano-cli/test/cardano-cli-golden/Test/Golden/Shelley/Address/Build.hs b/cardano-cli/test/cardano-cli-golden/Test/Golden/Shelley/Address/Build.hs index a8787cd0ce..29357790f9 100644 --- a/cardano-cli/test/cardano-cli-golden/Test/Golden/Shelley/Address/Build.hs +++ b/cardano-cli/test/cardano-cli-golden/Test/Golden/Shelley/Address/Build.hs @@ -9,6 +9,7 @@ import Test.Cardano.CLI.Util as OP import Hedgehog (Property) import Hedgehog.Extras.Test.Base qualified as H import Hedgehog.Extras.Test.File qualified as H +import Hedgehog.Extras.Test.Golden qualified as H hprop_golden_shelleyAddressBuild :: Property hprop_golden_shelleyAddressBuild = @@ -65,3 +66,45 @@ hprop_golden_shelleyAddressBuild = H.writeFile enterpriseAddressHexFile enterpriseAddressText equivalence enterpriseAddressText goldenEnterpriseAddressHex + +-- Regression tests for https://github.com/IntersectMBO/cardano-cli/issues/1448 +hprop_golden_addressBuildPlutusV4PaymentScript :: Property +hprop_golden_addressBuildPlutusV4PaymentScript = + watchdogProp . propertyOnce $ do + address <- + execCardanoCLI + [ "latest" + , "address" + , "build" + , "--testnet-magic" + , "14" + , "--payment-script-file" + , plutusV4ScriptFile + ] + + H.diffVsGoldenFile + address + "test/cardano-cli-golden/files/golden/dijkstra/address/build-payment-script-v4.addr" + +hprop_golden_addressBuildPlutusV4StakeScript :: Property +hprop_golden_addressBuildPlutusV4StakeScript = + watchdogProp . propertyOnce $ do + address <- + execCardanoCLI + [ "latest" + , "address" + , "build" + , "--testnet-magic" + , "14" + , "--payment-verification-key-file" + , "test/cardano-cli-golden/files/input/shelley/keys/payment_keys/verification_key" + , "--stake-script-file" + , plutusV4ScriptFile + ] + + H.diffVsGoldenFile + address + "test/cardano-cli-golden/files/golden/dijkstra/address/build-stake-script-v4.addr" + +plutusV4ScriptFile :: FilePath +plutusV4ScriptFile = "test/cardano-cli-golden/files/input/dijkstra/plutus/v4-always-succeeds.plutus" diff --git a/cardano-cli/test/cardano-cli-golden/Test/Golden/Shelley/Transaction/Build.hs b/cardano-cli/test/cardano-cli-golden/Test/Golden/Shelley/Transaction/Build.hs index 43ddf1f5be..5aeb4a132e 100644 --- a/cardano-cli/test/cardano-cli-golden/Test/Golden/Shelley/Transaction/Build.hs +++ b/cardano-cli/test/cardano-cli-golden/Test/Golden/Shelley/Transaction/Build.hs @@ -83,6 +83,25 @@ hprop_golden_shelley_transaction_build_minting = goldenFile <- H.note "test/cardano-cli-golden/files/golden/shelley/build-raw-tx-body-out-3.json" H.diffFileVsGoldenFile txBodyOutFile goldenFile +-- The policy id of a Plutus V4 script is its script hash. +-- Regression test for https://github.com/IntersectMBO/cardano-cli/issues/1448 +hprop_golden_transaction_policyid_plutus_v4 :: Property +hprop_golden_transaction_policyid_plutus_v4 = + watchdogProp . propertyOnce $ do + policyId <- + execCardanoCLI + [ "latest" + , "transaction" + , "policyid" + , "--script-file" + , "test/cardano-cli-golden/files/input/dijkstra/plutus/v4-always-succeeds.plutus" + ] + + scriptHash <- + H.readFile "test/cardano-cli-golden/files/golden/dijkstra/plutus/v4-always-succeeds.hash" + + equivalence (filter (/= '\n') policyId) scriptHash + hprop_golden_shelley_transaction_build_withdrawal_script_witnessed :: Property hprop_golden_shelley_transaction_build_withdrawal_script_witnessed = watchdogProp . propertyOnce $ H.moduleWorkspace "tmp" $ \tempDir -> do diff --git a/cardano-cli/test/cardano-cli-golden/files/golden/conway/transaction/build-raw-reference-script-unsupported-language.out b/cardano-cli/test/cardano-cli-golden/files/golden/conway/transaction/build-raw-reference-script-unsupported-language.out new file mode 100644 index 0000000000..81a0e7d9f4 --- /dev/null +++ b/cardano-cli/test/cardano-cli-golden/files/golden/conway/transaction/build-raw-reference-script-unsupported-language.out @@ -0,0 +1,2 @@ +Command failed: transaction build-raw +Error: Reference script language PlutusV4 is not supported in the Conway era. diff --git a/cardano-cli/test/cardano-cli-golden/files/golden/dijkstra/address/build-payment-script-v4.addr b/cardano-cli/test/cardano-cli-golden/files/golden/dijkstra/address/build-payment-script-v4.addr new file mode 100644 index 0000000000..cfaf21fb02 --- /dev/null +++ b/cardano-cli/test/cardano-cli-golden/files/golden/dijkstra/address/build-payment-script-v4.addr @@ -0,0 +1 @@ +addr_test1wqc60puxkkvfm3ha949tzkefwp57jsgxajkvaw8t98smdqghg77g0 \ No newline at end of file diff --git a/cardano-cli/test/cardano-cli-golden/files/golden/dijkstra/address/build-stake-script-v4.addr b/cardano-cli/test/cardano-cli-golden/files/golden/dijkstra/address/build-stake-script-v4.addr new file mode 100644 index 0000000000..c02708bcda --- /dev/null +++ b/cardano-cli/test/cardano-cli-golden/files/golden/dijkstra/address/build-stake-script-v4.addr @@ -0,0 +1 @@ +addr_test1ypfqwx0t6v5d80f6gqaznkk676vph0wmt68lfera8am87f3357rcddvcnhr06t22k9djjurfa9qsdm9ve6uwk20pk6qsjutxhj \ No newline at end of file diff --git a/cardano-cli/test/cardano-cli-golden/files/golden/dijkstra/plutus/v4-always-succeeds.hash b/cardano-cli/test/cardano-cli-golden/files/golden/dijkstra/plutus/v4-always-succeeds.hash new file mode 100644 index 0000000000..8534ad9b2e --- /dev/null +++ b/cardano-cli/test/cardano-cli-golden/files/golden/dijkstra/plutus/v4-always-succeeds.hash @@ -0,0 +1 @@ +31a78786b5989dc6fd2d4ab15b297069e94106ecacceb8eb29e1b681 \ No newline at end of file diff --git a/cardano-cli/test/cardano-cli-golden/files/golden/dijkstra/transaction/build-raw-plutus-v4-script-witnesses.out b/cardano-cli/test/cardano-cli-golden/files/golden/dijkstra/transaction/build-raw-plutus-v4-script-witnesses.out new file mode 100644 index 0000000000..60db910a31 --- /dev/null +++ b/cardano-cli/test/cardano-cli-golden/files/golden/dijkstra/transaction/build-raw-plutus-v4-script-witnesses.out @@ -0,0 +1,127 @@ +auxiliary scripts: null +certificates: +- Stake address registration: + deposit: 2000000 + stake credential: + keyHash: 81b4245f84593f63c0ff2296930254f77a0690fa9de5f969cac27cb0 +collateral inputs: [] +currentTreasuryValue: null +datums: +- datum: I 24 + datum hash: df5078aee07dd171a343fb99d5fc1b5462fb3c94d82bf72dc1b77d9c0aceec29 +era: Dijkstra +fee: 200000 Lovelace +governance actions: +- anchor: + dataHash: 52e69500a92d80f2126c836a4903dc582006709f004cf7a28ed648f732dff8d2 + url: https://example.com + deposit: 12345 + governance action: + tag: InfoAction + return address: + credential: + keyHash: 8f4a3466a404c11eb410313015b88e447d81b60089e25f611600e605 + network: Testnet +inputs: +- fe5dd07fb576bff960d6e066eade5b26cdb5afebe29f76ea58d0a098bce5d891#200 +metadata: null +mint: + policy 31a78786b5989dc6fd2d4ab15b297069e94106ecacceb8eb29e1b681: + default asset: 1000 +outputs: +- address: addr_test1vp0t4dfa9ktc2uvv7sg9leafuhtwyu0xcj4q4kf5pqkpjwqhklklg + address era: Shelley + amount: + lovelace: 15000000 + datum: null + network: Testnet + payment credential key hash: 5ebab53d2d9785718cf4105fe7a9e5d6e271e6c4aa0ad934082c1938 + reference script: null + stake reference: null +redeemers: +- purpose: + spending script witnessed input: fe5dd07fb576bff960d6e066eade5b26cdb5afebe29f76ea58d0a098bce5d891#200 + redeemer: + data: I 42 + execution units: + memory: 110 + steps: 100 +- purpose: + minting currency with policy id: 31a78786b5989dc6fd2d4ab15b297069e94106ecacceb8eb29e1b681 + redeemer: + data: I 42 + execution units: + memory: 110 + steps: 100 +- purpose: + validating certificate with script credentials: + credential: + keyHash: 81b4245f84593f63c0ff2296930254f77a0690fa9de5f969cac27cb0 + deposit: 2000000 + kind: RegCert + redeemer: + data: I 63 + execution units: + memory: 110 + steps: 100 +- purpose: + withdrawing reward from script address: + credential: + scriptHash: 186e32faa80a26810392fda6d559c7ed4721a65ce1c9d4ef3e1c87b4 + network: Testnet + redeemer: + data: I 83 + execution units: + memory: 110 + steps: 100 +- purpose: + voting using script protected voter credentials: + contents: + keyHash: 8f4fefcf28017a57b41517a67d56ef4c0dc04181a11d35178dd53f4c + tag: DRepVoter + redeemer: + data: I 1 + execution units: + memory: 110 + steps: 100 +- purpose: + submitting a proposal following proposal policy: + anchor: + dataHash: 52e69500a92d80f2126c836a4903dc582006709f004cf7a28ed648f732dff8d2 + url: https://example.com + deposit: 12345 + govAction: + tag: InfoAction + returnAddr: + credential: + keyHash: 8f4a3466a404c11eb410313015b88e447d81b60089e25f611600e605 + network: Testnet + redeemer: + data: I 1 + execution units: + memory: 110 + steps: 100 +reference inputs: [] +required signers (payment key hashes needed for scripts): null +return collateral: null +scripts: +- script data: + plutus version: PlutusV4 + script: '46450101002499' + type: plutus + script hash: 31a78786b5989dc6fd2d4ab15b297069e94106ecacceb8eb29e1b681 +total collateral: null +treasuryDonation: 0 +validity range: + lower bound: null + upper bound: null +voters: + drep-keyHash-8f4fefcf28017a57b41517a67d56ef4c0dc04181a11d35178dd53f4c: + 704e5c60c51dd0f3732991980b273402fbad0581c3407d682f8ea5b808a530fc#0: + anchor: null + decision: VoteYes +withdrawals: +- address: stake_test17qvxuvh64q9zdqgrjt76d42eclk5wgdxtnsun4808cwg0dqxv5r99 + amount: 10000 Lovelace + network: Testnet + stake credential script hash: 186e32faa80a26810392fda6d559c7ed4721a65ce1c9d4ef3e1c87b4 diff --git a/cardano-cli/test/cardano-cli-golden/files/input/dijkstra/plutus/v4-always-succeeds.plutus b/cardano-cli/test/cardano-cli-golden/files/input/dijkstra/plutus/v4-always-succeeds.plutus new file mode 100644 index 0000000000..43cc31ebed --- /dev/null +++ b/cardano-cli/test/cardano-cli-golden/files/input/dijkstra/plutus/v4-always-succeeds.plutus @@ -0,0 +1,5 @@ +{ + "type": "PlutusScriptV4", + "description": "Always succeeds", + "cborHex": "46450101002499" +}