diff --git a/CHANGELOG.md b/CHANGELOG.md index eb91a353d..02442ac52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,11 @@ constrained yet. - PrettyCooked option `pcOptPrintLog`, which is a boolean, to turn on or off the log display in the pretty printer. The default value is `True`. +- Reference inputs with the right reference scripts are now automatically + attached to redeemers when such input exists. This can be turned on using + `txOptAutoReferenceScripts`. If disabled, the helper `withReferenceInput` can + be used on a redeemer to manually attach a reference input (which does not + necessarily have to contain the right reference script). - Capability to test the result of a mockchain run based on the log entries. ### Removed @@ -34,10 +39,8 @@ - GHC bumped to 9.6.6 - Internal representation of redeemers have changed, and are similar for any supported script purpose (minting, spending or proposing). -- Redeemers should now be built using one of the four following smart - constructors: `txSkelSomeRedeemer`, `txSkelEmptyRedeemer`, - `txSkelSomeRedeemerAndReferenceScript`, - `txSkelEmptyRedeemerAndReferenceScript`. +- Redeemers should now be built using one of the two following smart + constructors: `someTxSkelRedeemer`, `emptyTxSkelRedeemer` - `mkProposingScript` changed to `mkScript` - `withDatumHashed` changed to `withUnresolvedDatumHash` - `paysScriptDatumHashed` changed to `paysScriptUnresolvedDatumHash` diff --git a/cooked-validators.cabal b/cooked-validators.cabal index db5ce1f23..093b51d04 100644 --- a/cooked-validators.cabal +++ b/cooked-validators.cabal @@ -24,13 +24,14 @@ library Cooked.Conversion.ToHash Cooked.Conversion.ToOutputDatum Cooked.Conversion.ToPubKeyHash - Cooked.Conversion.ToScript Cooked.Conversion.ToScriptHash Cooked.Conversion.ToValue + Cooked.Conversion.ToVersionedScript Cooked.Currencies Cooked.InitialDistribution Cooked.Ltl Cooked.MockChain + Cooked.MockChain.AutoReferenceScripts Cooked.MockChain.Balancing Cooked.MockChain.BlockChain Cooked.MockChain.Direct diff --git a/src/Cooked/Conversion.hs b/src/Cooked/Conversion.hs index 17f8df084..371239c61 100644 --- a/src/Cooked/Conversion.hs +++ b/src/Cooked/Conversion.hs @@ -6,6 +6,6 @@ import Cooked.Conversion.ToCredential as X import Cooked.Conversion.ToHash as X import Cooked.Conversion.ToOutputDatum as X import Cooked.Conversion.ToPubKeyHash as X -import Cooked.Conversion.ToScript as X import Cooked.Conversion.ToScriptHash as X import Cooked.Conversion.ToValue as X +import Cooked.Conversion.ToVersionedScript as X diff --git a/src/Cooked/Conversion/ToScript.hs b/src/Cooked/Conversion/ToScript.hs deleted file mode 100644 index 8ce9ee943..000000000 --- a/src/Cooked/Conversion/ToScript.hs +++ /dev/null @@ -1,20 +0,0 @@ --- | Objects from which a versioned script can be extracted -module Cooked.Conversion.ToScript where - -import Plutus.Script.Utils.Scripts qualified as Script -import Plutus.Script.Utils.Typed qualified as Script - -class ToScript a where - toScript :: a -> Script.Versioned Script.Script - -instance ToScript (Script.Versioned Script.Script) where - toScript = id - -instance ToScript (Script.Versioned Script.Validator) where - toScript (Script.Versioned (Script.Validator script) version) = Script.Versioned script version - -instance ToScript (Script.TypedValidator a) where - toScript = toScript . Script.vValidatorScript - -instance ToScript (Script.Versioned Script.MintingPolicy) where - toScript (Script.Versioned (Script.MintingPolicy script) version) = Script.Versioned script version diff --git a/src/Cooked/Conversion/ToScriptHash.hs b/src/Cooked/Conversion/ToScriptHash.hs index bc8165f61..3247297ec 100644 --- a/src/Cooked/Conversion/ToScriptHash.hs +++ b/src/Cooked/Conversion/ToScriptHash.hs @@ -1,7 +1,7 @@ -- | Objects from which a script hash can be extracted module Cooked.Conversion.ToScriptHash where -import Cooked.Conversion.ToScript +import Cooked.Conversion.ToVersionedScript import Plutus.Script.Utils.Scripts qualified as Script import Plutus.Script.Utils.Typed qualified as Script import PlutusLedgerApi.V3 qualified as Api @@ -22,10 +22,10 @@ instance ToScriptHash (Script.Versioned Script.Script) where toScriptHash = Script.scriptHash instance ToScriptHash (Script.Versioned Script.Validator) where - toScriptHash = toScriptHash . toScript + toScriptHash = toScriptHash . toVersionedScript instance ToScriptHash (Script.TypedValidator a) where - toScriptHash = toScriptHash . toScript + toScriptHash = toScriptHash . toVersionedScript instance ToScriptHash (Script.Versioned Script.MintingPolicy) where - toScriptHash = toScriptHash . Script.mintingPolicyHash + toScriptHash = toScriptHash . toVersionedScript diff --git a/src/Cooked/Conversion/ToVersionedScript.hs b/src/Cooked/Conversion/ToVersionedScript.hs new file mode 100644 index 000000000..557a3348b --- /dev/null +++ b/src/Cooked/Conversion/ToVersionedScript.hs @@ -0,0 +1,20 @@ +-- | Objects from which a versioned script can be extracted +module Cooked.Conversion.ToVersionedScript where + +import Plutus.Script.Utils.Scripts qualified as Script +import Plutus.Script.Utils.Typed qualified as Script + +class ToVersionedScript a where + toVersionedScript :: a -> Script.Versioned Script.Script + +instance ToVersionedScript (Script.Versioned Script.Script) where + toVersionedScript = id + +instance ToVersionedScript (Script.Versioned Script.Validator) where + toVersionedScript (Script.Versioned (Script.Validator script) version) = Script.Versioned script version + +instance ToVersionedScript (Script.TypedValidator a) where + toVersionedScript = toVersionedScript . Script.vValidatorScript + +instance ToVersionedScript (Script.Versioned Script.MintingPolicy) where + toVersionedScript (Script.Versioned (Script.MintingPolicy script) version) = Script.Versioned script version diff --git a/src/Cooked/MockChain/AutoReferenceScripts.hs b/src/Cooked/MockChain/AutoReferenceScripts.hs new file mode 100644 index 000000000..af5d815d0 --- /dev/null +++ b/src/Cooked/MockChain/AutoReferenceScripts.hs @@ -0,0 +1,65 @@ +-- | This module provides a function to ensure that each redeemer used in a +-- skeleton is attached a reference input with the right reference script when +-- it exists in the index. +module Cooked.MockChain.AutoReferenceScripts (toTxSkelWithReferenceScripts) where + +import Control.Monad +import Cooked.Conversion +import Cooked.MockChain.BlockChain +import Cooked.MockChain.UtxoSearch +import Cooked.Output +import Cooked.Skeleton +import Data.Map qualified as Map +import Data.Maybe +import Optics.Core +import PlutusLedgerApi.V3 qualified as Api + +-- | Searches through the known utxos for a utxo containing a reference script +-- with a given script hash, and returns the first such utxo found, if any. +retrieveReferenceScript :: (MonadBlockChain m, ToScriptHash s) => s -> m (Maybe Api.TxOutRef) +retrieveReferenceScript = (listToMaybe . (fst <$>) <$>) . runUtxoSearch . referenceScriptOutputsSearch + +-- | Attempts to find in the index a utxo containing a reference script with the +-- given script hash, and attaches it to a redeemer when it does not yet have a +-- reference input, in which case an event is logged. +updateRedeemer :: (MonadBlockChain m, ToScriptHash s) => s -> TxSkelRedeemer -> m TxSkelRedeemer +updateRedeemer script txSkelRed@(TxSkelRedeemer red Nothing) = do + oRefM <- retrieveReferenceScript script + case oRefM of + Nothing -> return txSkelRed + Just oRef -> do + logEvent $ MCLogAddedReferenceScript red oRef (toScriptHash script) + return $ TxSkelRedeemer red $ Just oRef +updateRedeemer _ redeemer = return redeemer + +-- | Goes through the various parts of the skeleton where a redeemer can appear, +-- and attempt to attach a reference input to each of them, following the rules +-- from `updateRedeemer` +toTxSkelWithReferenceScripts :: (MonadBlockChain m) => TxSkel -> m TxSkel +toTxSkelWithReferenceScripts txSkel = do + newMints <- forM (txSkelMintsToList $ txSkel ^. txSkelMintsL) $ \(mPol, red, tk, nb) -> + (mPol,,tk,nb) <$> updateRedeemer mPol red + newInputs <- forM (Map.toList $ txSkel ^. txSkelInsL) $ \(oRef, red) -> do + outputM <- txOutByRef oRef + -- We retrieve the possible script hash of the current oRef + case (^. outputOwnerL) <$> (outputM >>= isScriptOutput) of + -- Either the txOutRef is unknown, or it belongs to a private key + Nothing -> return (oRef, red) + Just scriptHash -> (oRef,) <$> updateRedeemer scriptHash red + newProposals <- forM (txSkel ^. txSkelProposalsL) $ \prop -> + case prop ^. txSkelProposalWitnessL of + Nothing -> return prop + Just (script, red) -> flip (set txSkelProposalWitnessL) prop . Just . (script,) <$> updateRedeemer script red + newWithdrawals <- forM (Map.toList $ txSkel ^. txSkelWithdrawalsL) $ \(wit, (red, quantity)) -> case wit of + Right _ -> return (wit, (red, quantity)) + Left script -> (Left script,) . (,quantity) <$> updateRedeemer script red + return $ + txSkel + & txSkelMintsL + .~ txSkelMintsFromList newMints + & txSkelInsL + .~ Map.fromList newInputs + & txSkelProposalsL + .~ newProposals + & txSkelWithdrawalsL + .~ Map.fromList newWithdrawals diff --git a/src/Cooked/MockChain/Balancing.hs b/src/Cooked/MockChain/Balancing.hs index 417cf73b2..6c4612eee 100644 --- a/src/Cooked/MockChain/Balancing.hs +++ b/src/Cooked/MockChain/Balancing.hs @@ -398,5 +398,5 @@ computeBalancedTxSkel balancingWallet balancingUtxos txSkel@TxSkel {..} (Script. -- a new output at the end of the list, to keep the order intact. (txOutRefs, val) <- getOptimalCandidate candidatesRaw balancingWallet balancingError return (txOutRefs, txSkelOuts ++ [paysPK balancingWallet val]) - let newTxSkelIns = txSkelIns <> Map.fromList ((,txSkelEmptyRedeemer) <$> additionalInsTxOutRefs) + let newTxSkelIns = txSkelIns <> Map.fromList ((,emptyTxSkelRedeemer) <$> additionalInsTxOutRefs) return $ (txSkel & txSkelOutsL .~ newTxSkelOuts) & txSkelInsL .~ newTxSkelIns diff --git a/src/Cooked/MockChain/BlockChain.hs b/src/Cooked/MockChain/BlockChain.hs index 5c0b4324e..869811d6e 100644 --- a/src/Cooked/MockChain/BlockChain.hs +++ b/src/Cooked/MockChain/BlockChain.hs @@ -129,6 +129,8 @@ data MockChainLogEntry -- depending on whether the user has provided an explicit wallet or a set of -- utxos to be used as collaterals. MCLogUnusedCollaterals (Either Wallet (Set Api.TxOutRef)) + | -- | Logging the automatic addition of a reference script + MCLogAddedReferenceScript Redeemer Api.TxOutRef Script.ScriptHash -- | Contains methods needed for balancing. class (MonadFail m, MonadError MockChainError m) => MonadBlockChainBalancing m where diff --git a/src/Cooked/MockChain/Direct.hs b/src/Cooked/MockChain/Direct.hs index 43dcdf2b5..b1261bc78 100644 --- a/src/Cooked/MockChain/Direct.hs +++ b/src/Cooked/MockChain/Direct.hs @@ -14,6 +14,7 @@ import Control.Monad.Reader import Control.Monad.State.Strict import Control.Monad.Writer import Cooked.InitialDistribution +import Cooked.MockChain.AutoReferenceScripts import Cooked.MockChain.Balancing import Cooked.MockChain.BlockChain import Cooked.MockChain.GenerateTx @@ -137,21 +138,24 @@ instance (Monad m) => MonadBlockChainWithoutValidation (MockChainT m) where awaitSlot s = modify' (\st -> st {mcstCurrentSlot = max s (mcstCurrentSlot st)}) >> currentSlot instance (Monad m) => MonadBlockChain (MockChainT m) where - validateTxSkel skelUnbal = do + validateTxSkel skelUnbal@TxSkel {..} | TxOpts {..} <- txSkelOpts = do -- We log the submitted skeleton gets mcstToSkelContext >>= logEvent . (`MCLogSubmittedTxSkel` skelUnbal) -- We retrieve the current parameters oldParams <- getParams -- We compute the optionally modified parameters - let newParams = applyEmulatorParamsModification (txOptEmulatorParamsModification . txSkelOpts $ skelUnbal) oldParams + let newParams = applyEmulatorParamsModification txOptEmulatorParamsModification oldParams -- We change the parameters for the duration of the validation process setParams newParams -- We ensure that the outputs have the required minimal amount of ada, when -- requested in the skeleton options - minAdaSkelUnbal <- if txOptEnsureMinAda . txSkelOpts $ skelUnbal then toTxSkelWithMinAda skelUnbal else return skelUnbal + minAdaSkelUnbal <- (if txOptEnsureMinAda then toTxSkelWithMinAda else return) skelUnbal + -- We add reference scripts in the various redeemers of the skeleton, when + -- they can be found in the index and are requested in the skeleton options + minAdaRefScriptsSkelUnbal <- (if txOptAutoReferenceScripts then toTxSkelWithReferenceScripts else return) minAdaSkelUnbal -- We balance the skeleton when requested in the skeleton option, and get -- the associated fee, collateral inputs and return collateral wallet - (skel, fee, mCollaterals) <- balanceTxSkel minAdaSkelUnbal + (skel, fee, mCollaterals) <- balanceTxSkel minAdaRefScriptsSkelUnbal -- We log the adjusted skeleton gets mcstToSkelContext >>= \ctx -> logEvent $ MCLogAdjustedTxSkel ctx skel fee mCollaterals -- We retrieve data that will be used in the transaction generation process: @@ -169,7 +173,7 @@ instance (Monad m) => MonadBlockChain (MockChainT m) where cardanoTx <- case generateTx fee newParams hashedData (insMap <> refInsMap <> collateralInsMap) insValidators mCollaterals skel of Left err -> throwError . MCEGenerationError $ err -- We apply post-generation modification when applicable - Right tx -> return $ Ledger.CardanoEmulatorEraTx $ applyRawModOnBalancedTx (txOptUnsafeModTx . txSkelOpts $ skelUnbal) tx + Right tx -> return $ Ledger.CardanoEmulatorEraTx $ applyRawModOnBalancedTx txOptUnsafeModTx tx -- To run transaction validation we need a minimal ledger state eLedgerState <- gets mcstToEmulatedLedgerState -- We finally run the emulated validation, and we only care about the @@ -203,8 +207,7 @@ instance (Monad m) => MonadBlockChain (MockChainT m) where . addValidators (txSkelValidatorsInOutputs skel <> txSkelReferenceScripts skel) ) -- We apply a change of slot when requested in the options - when (txOptAutoSlotIncrease $ txSkelOpts skel) $ - modify' (\st -> st {mcstCurrentSlot = mcstCurrentSlot st + 1}) + when txOptAutoSlotIncrease $ modify' (\st -> st {mcstCurrentSlot = mcstCurrentSlot st + 1}) -- We return the parameters to their original state setParams oldParams -- We log the validated transaction diff --git a/src/Cooked/MockChain/GenerateTx/Output.hs b/src/Cooked/MockChain/GenerateTx/Output.hs index 3e86b1aed..654923c1b 100644 --- a/src/Cooked/MockChain/GenerateTx/Output.hs +++ b/src/Cooked/MockChain/GenerateTx/Output.hs @@ -45,4 +45,4 @@ toCardanoTxOut (Pays output) = do <$> Ledger.toCardanoScriptDataHash (Script.datumHash $ Api.Datum $ Api.toBuiltinData datum) TxSkelOutDatum datum -> return $ Cardano.TxOutDatumInTx Cardano.AlonzoEraOnwardsConway $ toHashableScriptData datum TxSkelOutInlineDatum datum -> return $ Cardano.TxOutDatumInline Cardano.BabbageEraOnwardsConway $ toHashableScriptData datum - return $ Cardano.TxOut address value datum $ Ledger.toCardanoReferenceScript (toScript <$> oRefScript) + return $ Cardano.TxOut address value datum $ Ledger.toCardanoReferenceScript (toVersionedScript <$> oRefScript) diff --git a/src/Cooked/MockChain/GenerateTx/Proposal.hs b/src/Cooked/MockChain/GenerateTx/Proposal.hs index d1a927558..98ea4b2b4 100644 --- a/src/Cooked/MockChain/GenerateTx/Proposal.hs +++ b/src/Cooked/MockChain/GenerateTx/Proposal.hs @@ -133,7 +133,7 @@ toProposalProcedureAndWitness txSkelProposal@TxSkelProposal {..} anchorResolutio let conwayProposalProcedure = Conway.ProposalProcedure (Emulator.Coin minDeposit) cred govAction anchor (conwayProposalProcedure,) <$> case txSkelProposalWitness of Nothing -> return Nothing - Just (script, redeemer) -> Just <$> liftTxGen (toScriptWitness (toScript script) redeemer Cardano.NoScriptDatumForStake) + Just (script, redeemer) -> Just <$> liftTxGen (toScriptWitness (toVersionedScript script) redeemer Cardano.NoScriptDatumForStake) -- | Translates a list of skeleton proposals into a proposal procedures toProposalProcedures :: [TxSkelProposal] -> AnchorResolution -> ProposalGen (Cardano.TxProposalProcedures Cardano.BuildTx Cardano.ConwayEra) diff --git a/src/Cooked/MockChain/GenerateTx/Witness.hs b/src/Cooked/MockChain/GenerateTx/Witness.hs index eeac4a4cd..5b0549fd8 100644 --- a/src/Cooked/MockChain/GenerateTx/Witness.hs +++ b/src/Cooked/MockChain/GenerateTx/Witness.hs @@ -41,8 +41,8 @@ toRewardAccount cred = (Ledger.toCardanoStakeKeyHash pubkeyHash) return $ Cardano.KeyHashObj pkHash --- | Translate a script and a reference script utxo into into either a plutus --- script or a reference input containing the right script +-- | Translates a script and a reference script utxo into either a plutus script +-- or a reference input containing the right script toPlutusScriptOrReferenceInput :: Script.Versioned Script.Script -> Maybe Api.TxOutRef -> WitnessGen (Cardano.PlutusScriptOrReferenceInput lang) toPlutusScriptOrReferenceInput (Script.Versioned (Script.Script script) _) Nothing = return $ Cardano.PScript $ Cardano.PlutusScriptSerialised script toPlutusScriptOrReferenceInput script (Just scriptOutRef) = do @@ -66,18 +66,18 @@ toPlutusScriptOrReferenceInput script (Just scriptOutRef) = do -- | Translates a script with its associated redeemer and datum to a script -- witness. -toScriptWitness :: (ToScript a) => a -> TxSkelRedeemer -> Cardano.ScriptDatum b -> WitnessGen (Cardano.ScriptWitness b Cardano.ConwayEra) -toScriptWitness (toScript -> script@(Script.Versioned _ version)) (TxSkelRedeemer {..}) datum = +toScriptWitness :: (ToVersionedScript a) => a -> TxSkelRedeemer -> Cardano.ScriptDatum b -> WitnessGen (Cardano.ScriptWitness b Cardano.ConwayEra) +toScriptWitness (toVersionedScript -> script@(Script.Versioned _ version)) (TxSkelRedeemer {..}) datum = let scriptData = case txSkelRedeemer of EmptyRedeemer -> Ledger.toCardanoScriptData $ Api.toBuiltinData () SomeRedeemer s -> Ledger.toCardanoScriptData $ Api.toBuiltinData s in case version of Script.PlutusV1 -> (\x -> Cardano.PlutusScriptWitness Cardano.PlutusScriptV1InConway Cardano.PlutusScriptV1 x datum scriptData Ledger.zeroExecutionUnits) - <$> toPlutusScriptOrReferenceInput script txSkelReferenceScript + <$> toPlutusScriptOrReferenceInput script txSkelReferenceInput Script.PlutusV2 -> (\x -> Cardano.PlutusScriptWitness Cardano.PlutusScriptV2InConway Cardano.PlutusScriptV2 x datum scriptData Ledger.zeroExecutionUnits) - <$> toPlutusScriptOrReferenceInput script txSkelReferenceScript + <$> toPlutusScriptOrReferenceInput script txSkelReferenceInput Script.PlutusV3 -> (\x -> Cardano.PlutusScriptWitness Cardano.PlutusScriptV3InConway Cardano.PlutusScriptV3 x datum scriptData Ledger.zeroExecutionUnits) - <$> toPlutusScriptOrReferenceInput script txSkelReferenceScript + <$> toPlutusScriptOrReferenceInput script txSkelReferenceInput diff --git a/src/Cooked/MockChain/MockChainSt.hs b/src/Cooked/MockChain/MockChainSt.hs index 2dafcc03f..80aa56aa0 100644 --- a/src/Cooked/MockChain/MockChainSt.hs +++ b/src/Cooked/MockChain/MockChainSt.hs @@ -6,8 +6,8 @@ import Cardano.Ledger.Shelley.API qualified as Shelley import Cardano.Ledger.Shelley.LedgerState qualified as Shelley import Cardano.Node.Emulator.Internal.Node qualified as Emulator import Control.Arrow -import Cooked.Conversion.ToScript import Cooked.Conversion.ToScriptHash +import Cooked.Conversion.ToVersionedScript import Cooked.InitialDistribution import Cooked.MockChain.GenerateTx (GenerateTxError (..), generateTxOut) import Cooked.MockChain.UtxoState @@ -178,7 +178,7 @@ referenceScriptMap0From (InitialDistribution initDist) = unitMaybeFrom :: TxSkelOut -> Maybe (Script.ValidatorHash, Script.Versioned Script.Validator) unitMaybeFrom (Pays output) = do refScript <- view outputReferenceScriptL output - let vScript@(Script.Versioned script version) = toScript refScript + let vScript@(Script.Versioned script version) = toVersionedScript refScript Api.ScriptHash scriptHash = toScriptHash vScript return (Script.ValidatorHash scriptHash, Script.Versioned (Script.Validator script) version) diff --git a/src/Cooked/Pretty/Cooked.hs b/src/Cooked/Pretty/Cooked.hs index c239d82cc..eb29654a3 100644 --- a/src/Cooked/Pretty/Cooked.hs +++ b/src/Cooked/Pretty/Cooked.hs @@ -155,13 +155,23 @@ instance PrettyCooked MockChainLogEntry where prettyCookedOpt opts (MCLogNewTx txId) = "New transaction:" <+> prettyCookedOpt opts txId prettyCookedOpt opts (MCLogDiscardedUtxos n s) = prettyCookedOpt opts n <+> "balancing utxos were discarded:" <+> PP.pretty s prettyCookedOpt opts (MCLogUnusedCollaterals (Left cWallet)) = - "Specific request to fetch collateral utxos from" - <+> prettyCookedOpt opts (walletPKHash cWallet) - <+> "has been disregarded because the transaction does not require collaterals" + "Specific request to fetch collateral utxos from " + <> prettyCookedOpt opts (walletPKHash cWallet) + <> " has been disregarded because the transaction does not require collaterals" prettyCookedOpt opts (MCLogUnusedCollaterals (Right (length -> n))) = - "Specific request to fetch collateral utxos from the given set of" - <+> prettyCookedOpt opts n - <+> "elements has been disregarded because the transaction does not require collaterals" + "Specific request to fetch collateral utxos from the given set of " + <> prettyCookedOpt opts n + <> " elements has been disregarded because the transaction does not require collaterals" + prettyCookedOpt opts (MCLogAddedReferenceScript red oRef sHash) = + "A reference script located in " + <> prettyCookedOpt opts oRef + <> " has been automatically associated to redeemer " + <> ( case red of + EmptyRedeemer -> "Empty" + SomeRedeemer s -> prettyCookedOpt opts s + ) + <> " for script " + <> prettyCookedOpt opts sHash prettyTxSkel :: PrettyCookedOpts -> SkelContext -> TxSkel -> DocCooked prettyTxSkel opts skelContext (TxSkel lbl txopts mints signers validityRange ins insReference outs proposals withdrawals) = diff --git a/src/Cooked/Skeleton.hs b/src/Cooked/Skeleton.hs index bfa80c91a..4d119a45f 100644 --- a/src/Cooked/Skeleton.hs +++ b/src/Cooked/Skeleton.hs @@ -31,6 +31,7 @@ module Cooked.Skeleton txOptEmulatorParamsModificationL, txOptCollateralUtxosL, txOptAnchorResolutionL, + txOptAutoReferenceScriptsL, TxSkelMints, addToTxSkelMints, txSkelMintsToList, @@ -58,7 +59,7 @@ module Cooked.Skeleton withStakingCredential, TxSkelRedeemer (..), Redeemer (..), - txSkelTypedRedeemer, + withReferenceInput, TxParameterChange (..), TxGovAction (..), TxSkelProposal (..), @@ -95,10 +96,8 @@ module Cooked.Skeleton txSkelValueInOutputs, txSkelReferenceScripts, txSkelReferenceTxOutRefs, - txSkelSomeRedeemer, - txSkelEmptyRedeemer, - txSkelSomeRedeemerAndReferenceScript, - txSkelEmptyRedeemerAndReferenceScript, + someTxSkelRedeemer, + emptyTxSkelRedeemer, ) where @@ -358,7 +357,14 @@ data TxOpts = TxOpts -- | How to resolve anchor in proposal procedures -- -- Default is 'AnchorResolutionLocal Map.Empty' - txOptAnchorResolution :: AnchorResolution + txOptAnchorResolution :: AnchorResolution, + -- | Whether to automatically fill up reference inputs in redeemers when + -- they contain the right reference script. This will imply going through + -- all the known utxos with reference scripts and compare their hashes, thus + -- will slightly reduce performance. + -- + -- Defaut is 'False'. + txOptAutoReferenceScripts :: Bool } deriving (Eq, Show) @@ -372,7 +378,8 @@ makeLensesFor ("txOptBalancingUtxos", "txOptBalancingUtxosL"), ("txOptEmulatorParamsModification", "txOptEmulatorParamsModificationL"), ("txOptCollateralUtxos", "txOptCollateralUtxosL"), - ("txOptAnchorResolution", "txOptAnchorResolutionL") + ("txOptAnchorResolution", "txOptAnchorResolutionL"), + ("txOptAutoReferenceScripts", "txOptAutoReferenceScriptsL") ] ''TxOpts @@ -388,7 +395,8 @@ instance Default TxOpts where txOptBalancingUtxos = def, txOptEmulatorParamsModification = Nothing, txOptCollateralUtxos = def, - txOptAnchorResolution = def + txOptAnchorResolution = def, + txOptAutoReferenceScripts = False } -- * Redeemers for transaction inputs @@ -417,25 +425,28 @@ instance Eq Redeemer where data TxSkelRedeemer = TxSkelRedeemer { txSkelRedeemer :: Redeemer, - txSkelReferenceScript :: Maybe Api.TxOutRef + -- An optional input containing a reference script + txSkelReferenceInput :: Maybe Api.TxOutRef } deriving (Show, Eq) -txSkelSomeRedeemer :: (RedeemerConstrs redeemer) => redeemer -> TxSkelRedeemer -txSkelSomeRedeemer a = TxSkelRedeemer (SomeRedeemer a) Nothing - -txSkelEmptyRedeemer :: TxSkelRedeemer -txSkelEmptyRedeemer = TxSkelRedeemer EmptyRedeemer Nothing +-- Two helpers to create skeleton redeemers +someTxSkelRedeemer :: (RedeemerConstrs redeemer) => redeemer -> TxSkelRedeemer +someTxSkelRedeemer a = TxSkelRedeemer (SomeRedeemer a) Nothing -txSkelSomeRedeemerAndReferenceScript :: (RedeemerConstrs redeemer) => Api.TxOutRef -> redeemer -> TxSkelRedeemer -txSkelSomeRedeemerAndReferenceScript outRef a = TxSkelRedeemer (SomeRedeemer a) (Just outRef) +emptyTxSkelRedeemer :: TxSkelRedeemer +emptyTxSkelRedeemer = TxSkelRedeemer EmptyRedeemer Nothing -txSkelEmptyRedeemerAndReferenceScript :: Api.TxOutRef -> TxSkelRedeemer -txSkelEmptyRedeemerAndReferenceScript outRef = TxSkelRedeemer EmptyRedeemer (Just outRef) +-- Additional helper to specify a given reference input. As reference inputs are +-- automatically attached during transaction generation when they contain the +-- right scripts by default, there are only 3 cases where this can be useful: +-- - The reliance on a reference script needs to be made explicit +-- - A wrong reference script somehow needs to be attached +-- - The automated attachement of reference inputs has been disabled using the +-- `txOptAutoReferenceScripts` option -txSkelTypedRedeemer :: (Api.FromData (Script.RedeemerType a)) => TxSkelRedeemer -> Maybe (Script.RedeemerType a) -txSkelTypedRedeemer (TxSkelRedeemer (SomeRedeemer red) _) = Api.fromData . Api.toData $ red -txSkelTypedRedeemer _ = Nothing +withReferenceInput :: TxSkelRedeemer -> Api.TxOutRef -> TxSkelRedeemer +withReferenceInput red ref = red {txSkelReferenceInput = Just ref} -- * Description of the Governance actions (or proposal procedures) @@ -584,8 +595,8 @@ makeLensesFor simpleTxSkelProposal :: (ToAddress a) => a -> TxGovAction -> TxSkelProposal simpleTxSkelProposal a govAction = TxSkelProposal (toAddress a) govAction Nothing Nothing -withWitness :: (ToScript a) => TxSkelProposal -> (a, TxSkelRedeemer) -> TxSkelProposal -withWitness prop (s, red) = prop {txSkelProposalWitness = Just (toScript s, red)} +withWitness :: (ToVersionedScript a) => TxSkelProposal -> (a, TxSkelRedeemer) -> TxSkelProposal +withWitness prop (s, red) = prop {txSkelProposalWitness = Just (toVersionedScript s, red)} withAnchor :: TxSkelProposal -> String -> TxSkelProposal withAnchor prop url = prop {txSkelProposalAnchor = Just url} @@ -607,10 +618,10 @@ txSkelWithdrawalsScripts :: TxSkel -> [Script.Versioned Script.Script] txSkelWithdrawalsScripts = fst . partitionEithers . (fst <$>) . Map.toList . txSkelWithdrawals pkWithdrawal :: (ToPubKeyHash pkh) => pkh -> Script.Ada -> TxSkelWithdrawals -pkWithdrawal pkh amount = Map.singleton (Right $ toPubKeyHash pkh) (txSkelEmptyRedeemer, amount) +pkWithdrawal pkh amount = Map.singleton (Right $ toPubKeyHash pkh) (emptyTxSkelRedeemer, amount) -scriptWithdrawal :: (ToScript script) => script -> TxSkelRedeemer -> Script.Ada -> TxSkelWithdrawals -scriptWithdrawal script red amount = Map.singleton (Left $ toScript script) (red, amount) +scriptWithdrawal :: (ToVersionedScript script) => script -> TxSkelRedeemer -> Script.Ada -> TxSkelWithdrawals +scriptWithdrawal script red amount = Map.singleton (Left $ toVersionedScript script) (red, amount) -- * Description of the Minting @@ -765,7 +776,7 @@ data TxSkelOut where ToCredential (OwnerType o), DatumType o ~ TxSkelOutDatum, ValueType o ~ Api.Value, -- needed for the 'txSkelOutValueL' - ToScript (ReferenceScriptType o), + ToVersionedScript (ReferenceScriptType o), Show (OwnerType o), Show (ReferenceScriptType o), Typeable (ReferenceScriptType o) @@ -1005,7 +1016,7 @@ withUnresolvedDatumHash (Pays output) datum = Pays $ (fromAbstractOutput output) -- | Add a reference script to a transaction output (or replace it if there is -- already one) -withReferenceScript :: (Show script, ToScript script, Typeable script, ToScriptHash script) => TxSkelOut -> script -> TxSkelOut +withReferenceScript :: (Show script, ToVersionedScript script, Typeable script, ToScriptHash script) => TxSkelOut -> script -> TxSkelOut withReferenceScript (Pays output) script = Pays $ (fromAbstractOutput output) {concreteOutputReferenceScript = Just script} -- | Add a staking credential to a transaction output (or replace it if there is @@ -1035,7 +1046,7 @@ data TxSkel where -- specifying how to spend it. You must make sure that -- -- - On 'TxOutRef's referencing UTxOs belonging to public keys, you use - -- the 'txSkelEmptyRedeemer' smart constructor. + -- the 'emptyTxSkelRedeemer' smart constructor. -- -- - On 'TxOutRef's referencing UTxOs belonging to scripts, you must make -- sure that the type of the redeemer is appropriate for the script. @@ -1127,7 +1138,7 @@ txSkelReferenceScripts = case output ^. outputReferenceScriptL of Nothing -> Map.empty Just x -> - let vScript@(Script.Versioned script version) = toScript x + let vScript@(Script.Versioned script version) = toVersionedScript x Script.ScriptHash hash = toScriptHash vScript in Map.singleton (Script.ValidatorHash hash) $ Script.Versioned (Script.Validator script) version ) @@ -1139,11 +1150,11 @@ txSkelReferenceTxOutRefs TxSkel {..} = -- direct reference inputs Set.toList txSkelInsReference -- reference inputs in inputs redeemers - <> mapMaybe txSkelReferenceScript (Map.elems txSkelIns) + <> mapMaybe txSkelReferenceInput (Map.elems txSkelIns) -- reference inputs in proposals redeemers - <> mapMaybe (txSkelReferenceScript . snd) (mapMaybe txSkelProposalWitness txSkelProposals) + <> mapMaybe (txSkelReferenceInput . snd) (mapMaybe txSkelProposalWitness txSkelProposals) -- reference inputs in mints redeemers - <> mapMaybe (txSkelReferenceScript . fst . snd) (Map.toList txSkelMints) + <> mapMaybe (txSkelReferenceInput . fst . snd) (Map.toList txSkelMints) -- | All `TxOutRefs` known by a given transaction skeleton. This includes -- TxOutRef`s used as inputs of the skeleton and `TxOutRef`s used as reference @@ -1171,7 +1182,7 @@ txSkelOutOwnerTypeP = case typeOf (output ^. outputOwnerL) `eqTypeRep` typeRep @ownerType of Just HRefl -> let cOut = fromAbstractOutput output - in Just $ cOut {concreteOutputReferenceScript = toScript <$> concreteOutputReferenceScript cOut} + in Just $ cOut {concreteOutputReferenceScript = toVersionedScript <$> concreteOutputReferenceScript cOut} Nothing -> Nothing ) diff --git a/tests/Cooked/Attack/DatumHijackingSpec.hs b/tests/Cooked/Attack/DatumHijackingSpec.hs index 0f471c6d0..a3a340730 100644 --- a/tests/Cooked/Attack/DatumHijackingSpec.hs +++ b/tests/Cooked/Attack/DatumHijackingSpec.hs @@ -56,7 +56,7 @@ lockTxSkel :: Api.TxOutRef -> Script.TypedValidator DHContract -> TxSkel lockTxSkel o v = txSkelTemplate { txSkelOpts = def {txOptEnsureMinAda = True}, - txSkelIns = Map.singleton o txSkelEmptyRedeemer, + txSkelIns = Map.singleton o emptyTxSkelRedeemer, txSkelOuts = [paysScriptInlineDatum v FirstLock lockValue], txSkelSigners = [wallet 1] } @@ -73,7 +73,7 @@ relockTxSkel :: Script.TypedValidator DHContract -> Api.TxOutRef -> TxSkel relockTxSkel v o = txSkelTemplate { txSkelOpts = def {txOptEnsureMinAda = True}, - txSkelIns = Map.singleton o $ txSkelSomeRedeemer (), + txSkelIns = Map.singleton o $ someTxSkelRedeemer (), txSkelOuts = [paysScriptInlineDatum v SecondLock lockValue], txSkelSigners = [wallet 1] } diff --git a/tests/Cooked/Attack/DoubleSatSpec.hs b/tests/Cooked/Attack/DoubleSatSpec.hs index 658662e61..623bbbdae 100644 --- a/tests/Cooked/Attack/DoubleSatSpec.hs +++ b/tests/Cooked/Attack/DoubleSatSpec.hs @@ -138,9 +138,9 @@ tests = toAddress aValidator /= toAddress bValidator, testGroup "unit tests on a 'TxSkel'" $ -- The following tests make sure that, depending on some - -- 'txSkelSomeRedeemer' constraints for UTxOs + -- 'someRedeemer' constraints for UTxOs -- belonging to the 'aValidator' on the input 'TxSkel', - -- the correct additional 'txSkelSomeRedeemer' + -- the correct additional 'someRedeemer' -- constraints for UTxOs of the 'bValidator' are on the -- output 'TxSkel's. Both 'DoubleSatSplitMode's are -- tested. @@ -149,7 +149,7 @@ tests = skelIn :: [(ARedeemer, Api.TxOutRef)] -> TxSkel skelIn aInputs = txSkelTemplate - { txSkelIns = Map.fromList $ map (second txSkelSomeRedeemer . swap) aInputs, + { txSkelIns = Map.fromList $ map (second someTxSkelRedeemer . swap) aInputs, txSkelOuts = [paysPK (wallet 2) (Script.lovelaceValueOf 2_500_000)], txSkelSigners = [wallet 1] } @@ -173,13 +173,13 @@ tests = if | aOref == fst aUtxo1 -> return - [ (txSkelSomeRedeemer ARedeemer2, toDelta bOref $ txSkelSomeRedeemer BRedeemer1) + [ (someTxSkelRedeemer ARedeemer2, toDelta bOref $ someTxSkelRedeemer BRedeemer1) | (bOref, bOut) <- bUtxos, outputValue bOut == Script.lovelaceValueOf 123 -- not satisfied by any UTxO in 'dsTestMockChain' ] | aOref == fst aUtxo2 -> return - [ (txSkelSomeRedeemer ARedeemer2, toDelta bOref $ txSkelSomeRedeemer BRedeemer1) + [ (someTxSkelRedeemer ARedeemer2, toDelta bOref $ someTxSkelRedeemer BRedeemer1) | (bOref, _) <- bUtxos, bOref == fst bUtxo1 ] @@ -189,10 +189,10 @@ tests = ( \(bOref, _) -> if | bOref == fst bUtxo1 -> - [(txSkelSomeRedeemer ARedeemer2, toDelta bOref $ txSkelSomeRedeemer BRedeemer1)] + [(someTxSkelRedeemer ARedeemer2, toDelta bOref $ someTxSkelRedeemer BRedeemer1)] | bOref == fst bUtxo2 -> - [ (txSkelSomeRedeemer ARedeemer2, toDelta bOref $ txSkelSomeRedeemer BRedeemer1), - (txSkelSomeRedeemer ARedeemer3, toDelta bOref $ txSkelSomeRedeemer BRedeemer2) + [ (someTxSkelRedeemer ARedeemer2, toDelta bOref $ someTxSkelRedeemer BRedeemer1), + (someTxSkelRedeemer ARedeemer3, toDelta bOref $ someTxSkelRedeemer BRedeemer2) ] | otherwise -> [] ) @@ -219,13 +219,13 @@ tests = txSkelIns = Map.fromList ( ( \(bRedeemer, (bOref, _)) -> - (bOref, txSkelSomeRedeemer bRedeemer) + (bOref, someTxSkelRedeemer bRedeemer) ) <$> bInputs ) <> Map.fromList ( ( \(aRedeemer, aOref) -> - (aOref, txSkelSomeRedeemer aRedeemer) + (aOref, someTxSkelRedeemer aRedeemer) ) <$> aInputs ), diff --git a/tests/Cooked/Attack/DupTokenSpec.hs b/tests/Cooked/Attack/DupTokenSpec.hs index 82acdddb8..7981eed15 100644 --- a/tests/Cooked/Attack/DupTokenSpec.hs +++ b/tests/Cooked/Attack/DupTokenSpec.hs @@ -49,7 +49,7 @@ dupTokenTrace :: (MonadBlockChain m) => Script.Versioned Script.MintingPolicy -> dupTokenTrace pol tName amount recipient = void $ validateTxSkel skel where skel = - let mints = txSkelMintsFromList [(pol, txSkelEmptyRedeemer, tName, amount)] + let mints = txSkelMintsFromList [(pol, emptyTxSkelRedeemer, tName, amount)] mintedValue = txSkelMintsValue mints in txSkelTemplate { txSkelOpts = def {txOptEnsureMinAda = True}, @@ -74,8 +74,8 @@ tests = txSkelTemplate { txSkelMints = txSkelMintsFromList - [ (pol1, txSkelEmptyRedeemer, tName1, 5), - (pol2, txSkelEmptyRedeemer, tName2, 7) + [ (pol1, emptyTxSkelRedeemer, tName1, 5), + (pol2, emptyTxSkelRedeemer, tName2, 7) ], txSkelOuts = [ paysPK (wallet 1) (Script.assetClassValue ac1 1 <> Script.lovelaceValueOf 1234), @@ -92,8 +92,8 @@ tests = { txSkelLabel = Set.singleton $ TxLabel DupTokenLbl, txSkelMints = txSkelMintsFromList - [ (pol1, txSkelEmptyRedeemer, tName1, v1), - (pol2, txSkelEmptyRedeemer, tName2, v2) + [ (pol1, emptyTxSkelRedeemer, tName1, v1), + (pol2, emptyTxSkelRedeemer, tName2, v2) ], txSkelOuts = [ paysPK (wallet 1) (Script.assetClassValue ac1 1 <> Script.lovelaceValueOf 1234), @@ -133,7 +133,7 @@ tests = ac2 = quickAssetClass "preExistingToken" skelIn = txSkelTemplate - { txSkelMints = txSkelMintsFromList [(pol, txSkelEmptyRedeemer, tName1, 1)], + { txSkelMints = txSkelMintsFromList [(pol, emptyTxSkelRedeemer, tName1, 1)], txSkelOuts = [paysPK (wallet 1) (Script.assetClassValue ac1 1 <> Script.assetClassValue ac2 2)], txSkelSigners = [wallet 2] } @@ -142,7 +142,7 @@ tests = ( Script.assetClassValue ac1 1, txSkelTemplate { txSkelLabel = Set.singleton $ TxLabel DupTokenLbl, - txSkelMints = txSkelMintsFromList [(pol, txSkelEmptyRedeemer, tName1, 2)], + txSkelMints = txSkelMintsFromList [(pol, emptyTxSkelRedeemer, tName1, 2)], txSkelOuts = [ paysPK (wallet 1) (Script.assetClassValue ac1 1 <> Script.assetClassValue ac2 2), paysPK attacker (Script.assetClassValue ac1 1) diff --git a/tests/Cooked/BalancingSpec.hs b/tests/Cooked/BalancingSpec.hs index 496e55f44..0ac9daca7 100644 --- a/tests/Cooked/BalancingSpec.hs +++ b/tests/Cooked/BalancingSpec.hs @@ -51,7 +51,7 @@ spendsScriptUtxo :: (MonadBlockChain m) => Bool -> m (Map Api.TxOutRef TxSkelRed spendsScriptUtxo False = return Map.empty spendsScriptUtxo True = do (scriptOutRef, _) : _ <- runUtxoSearch $ utxosAtSearch $ alwaysTrueValidator @MockContract - return $ Map.singleton scriptOutRef txSkelEmptyRedeemer + return $ Map.singleton scriptOutRef emptyTxSkelRedeemer testingBalancingTemplate :: (MonadBlockChain m) => @@ -78,7 +78,7 @@ testingBalancingTemplate toBobValue toAliceValue spendSearch balanceSearch colla let skel = txSkelTemplate { txSkelOuts = List.filter ((/= mempty) . (^. txSkelOutValueL)) [paysPK bob toBobValue, paysPK alice toAliceValue], - txSkelIns = additionalSpend <> Map.fromList ((,txSkelEmptyRedeemer) <$> toSpendUtxos), + txSkelIns = additionalSpend <> Map.fromList ((,emptyTxSkelRedeemer) <$> toSpendUtxos), txSkelOpts = optionsMod def @@ -136,7 +136,7 @@ noBalanceMaxFee = do validateTxSkel $ txSkelTemplate { txSkelOuts = [paysPK bob (Script.lovelace (30_000_000 - maxFee))], - txSkelIns = Map.singleton txOutRef txSkelEmptyRedeemer, + txSkelIns = Map.singleton txOutRef emptyTxSkelRedeemer, txSkelOpts = def { txOptBalancingPolicy = DoNotBalance, diff --git a/tests/Cooked/BasicUsageSpec.hs b/tests/Cooked/BasicUsageSpec.hs index f9c1cfcc6..8c086fe9e 100644 --- a/tests/Cooked/BasicUsageSpec.hs +++ b/tests/Cooked/BasicUsageSpec.hs @@ -36,7 +36,7 @@ mintingQuickValue = void $ validateTxSkel $ txSkelTemplate - { txSkelMints = txSkelMintsFromList [(Script.Versioned quickCurrencyPolicy Script.PlutusV3, txSkelEmptyRedeemer, "banana", 10)], + { txSkelMints = txSkelMintsFromList [(Script.Versioned quickCurrencyPolicy Script.PlutusV3, emptyTxSkelRedeemer, "banana", 10)], txSkelOuts = [paysPK alice (quickValue "banana" 10)], txSkelSigners = [alice], txSkelOpts = def {txOptEnsureMinAda = True} @@ -58,7 +58,7 @@ consumeAlwaysTrueValidator = do void $ validateTxSkel $ txSkelTemplate - { txSkelIns = Map.fromList [(outref, txSkelSomeRedeemer ())], + { txSkelIns = Map.fromList [(outref, someTxSkelRedeemer ())], txSkelOuts = [paysPK alice (Script.ada 10)], txSkelSigners = [alice] } diff --git a/tests/Cooked/InitialDistributionSpec.hs b/tests/Cooked/InitialDistributionSpec.hs index 81fa08457..e63d90edf 100644 --- a/tests/Cooked/InitialDistributionSpec.hs +++ b/tests/Cooked/InitialDistributionSpec.hs @@ -42,7 +42,7 @@ spendReferenceAlwaysTrueValidator = do validateTxSkel $ txSkelTemplate { txSkelOuts = [paysPK alice (Script.ada 2)], - txSkelIns = Map.singleton scriptTxOutRef (txSkelSomeRedeemerAndReferenceScript referenceScriptTxOutRef ()), + txSkelIns = Map.singleton scriptTxOutRef $ someTxSkelRedeemer () `withReferenceInput` referenceScriptTxOutRef, txSkelSigners = [bob] } diff --git a/tests/Cooked/InlineDatumsSpec.hs b/tests/Cooked/InlineDatumsSpec.hs index 85b4da1d1..fc41342f1 100644 --- a/tests/Cooked/InlineDatumsSpec.hs +++ b/tests/Cooked/InlineDatumsSpec.hs @@ -127,7 +127,7 @@ spendOutputTestTrace useInlineDatum validator = do validateTxSkel txSkelTemplate { txSkelOpts = def {txOptEnsureMinAda = True}, - txSkelIns = Map.singleton theTxOutRef $ txSkelSomeRedeemer (), + txSkelIns = Map.singleton theTxOutRef $ someTxSkelRedeemer (), txSkelSigners = [wallet 1] } @@ -152,7 +152,7 @@ continuingOutputTestTrace datumKindOnSecondPayment validator = do validateTxSkel txSkelTemplate { txSkelOpts = def {txOptEnsureMinAda = True}, - txSkelIns = Map.singleton theTxOutRef $ txSkelSomeRedeemer (), + txSkelIns = Map.singleton theTxOutRef $ someTxSkelRedeemer (), txSkelOuts = [ ( case datumKindOnSecondPayment of OnlyHash -> paysScriptUnresolvedDatumHash validator SecondPaymentDatum diff --git a/tests/Cooked/ProposingScriptSpec.hs b/tests/Cooked/ProposingScriptSpec.hs index f2b53b398..3977d004f 100644 --- a/tests/Cooked/ProposingScriptSpec.hs +++ b/tests/Cooked/ProposingScriptSpec.hs @@ -35,7 +35,7 @@ testProposingScript script govAction = validateTxSkel txSkelTemplate { txSkelSigners = [wallet 1], - txSkelProposals = [simpleTxSkelProposal (wallet 1) govAction `withWitness` (script, txSkelEmptyRedeemer)] + txSkelProposals = [simpleTxSkelProposal (wallet 1) govAction `withWitness` (script, emptyTxSkelRedeemer)] } testProposingRefScript :: (MonadBlockChain m) => Script.Versioned Script.Script -> TxGovAction -> m () @@ -50,7 +50,7 @@ testProposingRefScript script govAction = do validateTxSkel $ txSkelTemplate { txSkelSigners = [wallet 1], - txSkelProposals = [simpleTxSkelProposal (wallet 1) govAction `withWitness` (script, txSkelEmptyRedeemerAndReferenceScript pOutRef)] + txSkelProposals = [simpleTxSkelProposal (wallet 1) govAction `withWitness` (script, emptyTxSkelRedeemer `withReferenceInput` pOutRef)] } tests :: TestTree diff --git a/tests/Cooked/ReferenceInputsSpec.hs b/tests/Cooked/ReferenceInputsSpec.hs index f4a8c0a6f..e3668578b 100644 --- a/tests/Cooked/ReferenceInputsSpec.hs +++ b/tests/Cooked/ReferenceInputsSpec.hs @@ -116,7 +116,7 @@ trace1 = do void $ validateTxSkel txSkelTemplate - { txSkelIns = Map.singleton txOutRefBar $ txSkelSomeRedeemer (), + { txSkelIns = Map.singleton txOutRefBar $ someTxSkelRedeemer (), txSkelInsReference = Set.singleton txOutRefFoo, txSkelOuts = [paysPK (wallet 4) (Script.ada 5)], txSkelSigners = [wallet 3] @@ -138,7 +138,7 @@ trace2 = do validateTxSkel $ txSkelTemplate { txSkelSigners = [wallet 1], - txSkelIns = Map.singleton scriptORef (txSkelSomeRedeemer ()), + txSkelIns = Map.singleton scriptORef (someTxSkelRedeemer ()), txSkelInsReference = Set.singleton refORef } diff --git a/tests/Cooked/ReferenceScriptsSpec.hs b/tests/Cooked/ReferenceScriptsSpec.hs index 45d47f0b8..29f868ef3 100644 --- a/tests/Cooked/ReferenceScriptsSpec.hs +++ b/tests/Cooked/ReferenceScriptsSpec.hs @@ -99,7 +99,7 @@ checkReferenceScriptOnOref expectedScriptHash refScriptOref = do void $ validateTxSkel txSkelTemplate - { txSkelIns = Map.singleton oref $ txSkelSomeRedeemer (), + { txSkelIns = Map.singleton oref $ someTxSkelRedeemer (), txSkelInsReference = Set.singleton refScriptOref, txSkelSigners = [wallet 1] } @@ -116,12 +116,12 @@ useReferenceScript spendingSubmitter theScript = do void $ validateTxSkel txSkelTemplate - { txSkelIns = Map.singleton oref $ txSkelSomeRedeemerAndReferenceScript scriptOref (), + { txSkelIns = Map.singleton oref $ someTxSkelRedeemer () `withReferenceInput` scriptOref, txSkelSigners = [spendingSubmitter] } -referenceMint :: (MonadBlockChain m) => Script.Versioned Script.MintingPolicy -> Script.Versioned Script.MintingPolicy -> Int -> m () -referenceMint mp1 mp2 n = do +referenceMint :: (MonadBlockChain m) => Script.Versioned Script.MintingPolicy -> Script.Versioned Script.MintingPolicy -> Int -> Bool -> m () +referenceMint mp1 mp2 n autoRefScript = do ((!! n) -> mpOutRef) <- validateTxSkel' $ txSkelTemplate @@ -131,9 +131,10 @@ referenceMint mp1 mp2 n = do void $ validateTxSkel $ txSkelTemplate - { txSkelMints = txSkelMintsFromList [(mp2, txSkelEmptyRedeemerAndReferenceScript mpOutRef, "banana", 3)], + { txSkelMints = txSkelMintsFromList [(mp2, if autoRefScript then emptyTxSkelRedeemer else emptyTxSkelRedeemer `withReferenceInput` mpOutRef, "banana", 3)], txSkelOuts = [paysPK (wallet 1) (Script.ada 2 <> Script.assetClassValue (Script.AssetClass (Script.scriptCurrencySymbol mp2, "banana")) 3)], - txSkelSigners = [wallet 1] + txSkelSigners = [wallet 1], + txSkelOpts = def {txOptAutoReferenceScripts = autoRefScript} } tests :: TestTree @@ -196,13 +197,13 @@ tests = validateTxSkel' txSkelTemplate { txSkelOuts = [paysScript (alwaysTrueValidator @MockContract) () (Script.ada 42)], - txSkelIns = Map.singleton consumedOref txSkelEmptyRedeemer, + txSkelIns = Map.singleton consumedOref emptyTxSkelRedeemer, txSkelSigners = [wallet 1] } void $ validateTxSkel txSkelTemplate - { txSkelIns = Map.singleton oref (txSkelSomeRedeemerAndReferenceScript consumedOref ()), + { txSkelIns = Map.singleton oref (someTxSkelRedeemer () `withReferenceInput` consumedOref), txSkelSigners = [wallet 1] } ) @@ -223,14 +224,14 @@ tests = void $ validateTxSkel txSkelTemplate - { txSkelIns = Map.singleton oref (txSkelSomeRedeemerAndReferenceScript scriptOref ()), + { txSkelIns = Map.singleton oref (someTxSkelRedeemer () `withReferenceInput` scriptOref), txSkelSigners = [wallet 1] } ) `withErrorPred` \case MCEGenerationError err -> err .==. GenerateTxErrorGeneral "toPlutusScriptOrReferenceInput: Wrong reference script hash." _ -> testFailure, - testCase "phase 1 - fail if using a reference script with 'txSkelSomeRedeemer'" $ + testCase "phase 1 - fail if using a reference script with 'someRedeemer'" $ testFailsInPhase1 $ do scriptOref <- putRefScriptOnWalletOutput (wallet 3) alwaysTrueValidator oref : _ <- @@ -242,9 +243,10 @@ tests = void $ validateTxSkel txSkelTemplate - { txSkelIns = Map.singleton oref (txSkelSomeRedeemer ()), + { txSkelIns = Map.singleton oref (someTxSkelRedeemer ()), txSkelInsReference = Set.singleton scriptOref, - txSkelSigners = [wallet 1] + txSkelSigners = [wallet 1], + txSkelOpts = def {txOptAutoReferenceScripts = False} }, testCase "fail if reference script's requirement is violated" @@ -258,16 +260,20 @@ tests = "referencing minting policies" [ testCase "succeed if given a reference minting policy" $ testSucceeds $ - referenceMint quickCurrencyPolicyV3 quickCurrencyPolicyV3 0, + referenceMint quickCurrencyPolicyV3 quickCurrencyPolicyV3 0 False, + testCase "succeed if relying on automated finding of reference minting policy" $ + testToProp $ + mustSucceedTest (referenceMint quickCurrencyPolicyV3 quickCurrencyPolicyV3 0 True) + `withJournalPred` (testBool . any (\case MCLogAddedReferenceScript {} -> True; _ -> False)), testCase "fail if given the wrong reference minting policy" $ testToProp $ - mustFailTest (referenceMint permanentCurrencyPolicyV3 quickCurrencyPolicyV3 0) + mustFailTest (referenceMint permanentCurrencyPolicyV3 quickCurrencyPolicyV3 0 False) `withErrorPred` \case MCEGenerationError (GenerateTxErrorGeneral err) -> err .==. "toPlutusScriptOrReferenceInput: Wrong reference script hash." _ -> testFailure, testCase "fail if referencing the wrong utxo" $ testToProp $ - mustFailTest (referenceMint quickCurrencyPolicyV3 quickCurrencyPolicyV3 1) + mustFailTest (referenceMint quickCurrencyPolicyV3 quickCurrencyPolicyV3 1 False) `withErrorPred` \case MCEGenerationError (GenerateTxErrorGeneral err) -> err .==. "toPlutusScriptOrReferenceInput: Can't resolve reference script utxo." _ -> testFailure diff --git a/tests/Cooked/WithdrawalsSpec.hs b/tests/Cooked/WithdrawalsSpec.hs index 8d5ed9345..95eec8622 100644 --- a/tests/Cooked/WithdrawalsSpec.hs +++ b/tests/Cooked/WithdrawalsSpec.hs @@ -38,7 +38,7 @@ testWithdrawingScript n1 n2 = validateTxSkel $ txSkelTemplate { txSkelSigners = [wallet 1], - txSkelWithdrawals = scriptWithdrawal checkWithdrawalVersionedScript (txSkelSomeRedeemer (n1 * 1_000 :: Integer)) $ Script.Lovelace $ n2 * 1_000 + txSkelWithdrawals = scriptWithdrawal checkWithdrawalVersionedScript (someTxSkelRedeemer (n1 * 1_000 :: Integer)) $ Script.Lovelace $ n2 * 1_000 } tests :: TestTree