Skip to content

Commit 8e3b389

Browse files
committed
Implement hprop_collateral_with_tokens to test that return collateral
containing multiassets are valid
1 parent fd8549f commit 8e3b389

12 files changed

Lines changed: 761 additions & 6 deletions

File tree

cabal.project

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,4 @@ if impl (ghc >= 9.12)
7575
-- IMPORTANT
7676
-- Do NOT add more source-repository-package stanzas here unless they are strictly
7777
-- temporary! Please read the section in CONTRIBUTING about updating dependencies.
78+

cardano-testnet/cardano-testnet.cabal

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,8 +209,12 @@ test-suite cardano-testnet-test
209209
Cardano.Testnet.Test.Cli.QuerySlotNumber
210210
Cardano.Testnet.Test.Cli.Plutus.Scripts
211211
Cardano.Testnet.Test.Cli.Plutus.CostCalculation
212+
Cardano.Testnet.Test.Cli.Plutus.MultiAssetReturnCollateral
213+
Cardano.Testnet.Test.Cli.Scripts.Simple.CostCalculation
214+
Cardano.Testnet.Test.Cli.Scripts.Simple.Mint
212215
Cardano.Testnet.Test.Cli.StakeSnapshot
213216
Cardano.Testnet.Test.Cli.Transaction
217+
Cardano.Testnet.Test.Cli.Transaction.BuildEstimate
214218
Cardano.Testnet.Test.Cli.Transaction.RegisterDeregisterStakeAddress
215219
Cardano.Testnet.Test.DumpConfig
216220
Cardano.Testnet.Test.FoldEpochState

cardano-testnet/src/Testnet/Defaults.hs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ module Testnet.Defaults
3737
, defaultYamlHardforkViaConfig
3838
, defaultMainnetTopology
3939
, defaultUtxoKeys
40+
, plutusV2Script
4041
, plutusV3Script
4142
, plutusV3SupplementalDatumScript
4243
, plutusV2StakeScript
@@ -599,6 +600,11 @@ simpleScript signerRequired =
599600
"{ \"scripts\": [ { \"keyHash\": \"" <> signerRequired <> "\", \"type\": \"sig\" } ], \"type\": \"all\" }"
600601

601602

603+
plutusV2Script :: Text
604+
plutusV2Script =
605+
"{ \"type\": \"PlutusScriptV2\", \"description\": \"\", \"cborHex\": \"5822582001000022325333573466e1ccde5251333792945200000100111200116375a005\" }"
606+
607+
602608
-- | Default plutus script that always succeeds
603609
plutusV3Script :: Text
604610
plutusV3Script =
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
{-# LANGUAGE NamedFieldPuns #-}
2+
{-# LANGUAGE NumericUnderscores #-}
3+
{-# LANGUAGE OverloadedStrings #-}
4+
{-# LANGUAGE ScopedTypeVariables #-}
5+
{-# LANGUAGE TypeApplications #-}
6+
7+
module Cardano.Testnet.Test.Cli.Plutus.MultiAssetReturnCollateral
8+
( hprop_collateral_with_tokens
9+
) where
10+
11+
import Cardano.Api
12+
import Cardano.Testnet
13+
14+
import Prelude
15+
import qualified Data.Aeson as Aeson
16+
import Control.Monad (void)
17+
import Data.Default.Class
18+
import qualified Data.Text as T
19+
import System.FilePath ((</>))
20+
21+
import Testnet.Components.Configuration
22+
import Testnet.Components.Query
23+
import Testnet.Defaults
24+
import Testnet.Process.Run (execCli', mkExecConfig)
25+
import Testnet.Property.Util (integrationWorkspace, decodeEraUTxO)
26+
import Testnet.Types
27+
28+
import Hedgehog (Property)
29+
import qualified Hedgehog as H
30+
import qualified Hedgehog.Extras as H
31+
32+
-- @DISABLE_RETRIES=1 cabal test cardano-testnet-test --test-options '-p "/Collateral With Multiassets/"'@
33+
hprop_collateral_with_tokens :: Property
34+
hprop_collateral_with_tokens = integrationWorkspace "collateral-with-tokens" $ \tempAbsBasePath' -> H.runWithDefaultWatchdog_ $ do
35+
conf@Conf { tempAbsPath } <- mkConf tempAbsBasePath'
36+
let tempAbsPath' = unTmpAbsPath tempAbsPath
37+
work <- H.createDirectoryIfMissing $ tempAbsPath' </> "work"
38+
39+
let
40+
tempBaseAbsPath = makeTmpBaseAbsPath $ TmpAbsolutePath tempAbsPath'
41+
ceo = ConwayEraOnwardsConway
42+
sbe = convert ceo
43+
era = toCardanoEra sbe
44+
anyEra = AnyCardanoEra era
45+
options = def { cardanoNodeEra = AnyShelleyBasedEra sbe }
46+
47+
TestnetRuntime
48+
{ configurationFile
49+
, testnetMagic
50+
, testnetNodes
51+
, wallets=wallet0:wallet1:wallet2:_
52+
} <- createAndRunTestnet options def conf
53+
54+
node <- H.headM testnetNodes
55+
poolSprocket1 <- H.noteShow $ nodeSprocket node
56+
execConfig <- mkExecConfig tempBaseAbsPath poolSprocket1 testnetMagic
57+
H.noteShow_ wallet0
58+
let utxoAddr = T.unpack $ paymentKeyInfoAddr wallet0
59+
utxoSKeyFile = signingKeyFp $ paymentKeyInfoPair wallet0
60+
socketPath = nodeSocketPath node
61+
62+
epochStateView <- getEpochStateView configurationFile socketPath
63+
txin1 <- findLargestUtxoForPaymentKey epochStateView sbe wallet0
64+
txinCollateral <- findLargestUtxoForPaymentKey epochStateView sbe wallet1
65+
66+
void $ execCli' execConfig
67+
[ anyEraToString anyEra, "query", "utxo"
68+
, "--address", T.unpack $ paymentKeyInfoAddr wallet0
69+
, "--cardano-mode"
70+
, "--out-file", work </> "utxo-1.json"
71+
]
72+
73+
utxo1Json <- H.leftFailM . H.readJsonFile $ work </> "utxo-1.json"
74+
H.noteShowM_ $ decodeEraUTxO sbe utxo1Json
75+
-- Create a simple always-succeeds Plutus V3 script
76+
plutusScript <- H.note $ work </> "always-succeeds-script.plutusV3"
77+
H.writeFile plutusScript $ T.unpack plutusV3Script
78+
79+
80+
-- Get the policy ID
81+
mintingPolicyId <- filter (/= '\n') <$>
82+
execCli' execConfig
83+
[ anyEraToString anyEra, "transaction"
84+
, "policyid"
85+
, "--script-file", plutusScript
86+
]
87+
88+
let assetName = "7161636f696e" -- "qacoin" in hex
89+
90+
-- Create a Plutus script address
91+
plutusSpendingScriptAddr <-
92+
execCli' execConfig
93+
[ "latest", "address", "build"
94+
, "--payment-script-file", plutusScript
95+
]
96+
97+
98+
-- STEP 1: Mint tokens and send to an address we control
99+
-- This address will later be used as a collateral UTxO
100+
let maCollateralAddress = T.unpack $ paymentKeyInfoAddr wallet2
101+
mintTokensTxBody = work </> "mint-tokens-tx-body"
102+
mintTokensTx = work </> "mint-tokens-tx"
103+
adaOnlyCollateralAddress = T.unpack $ paymentKeyInfoAddr wallet1
104+
mintValue = mconcat ["100 ", mintingPolicyId, ".", assetName]
105+
adaOnlyCollateralValue = mconcat [adaOnlyCollateralAddress, "+", show @Int 3_000_000]
106+
collateralToBeValue = mconcat [maCollateralAddress, "+", show @Int 5_000_000, "+", mintValue]
107+
fundPlutusScriptAddrVal = mconcat [plutusSpendingScriptAddr, "+", show @Int 2_000_000]
108+
109+
void $ execCli' execConfig
110+
[ anyEraToString anyEra, "transaction", "build"
111+
, "--change-address", utxoAddr
112+
, "--tx-in", T.unpack $ renderTxIn txin1
113+
, "--tx-in-collateral", T.unpack $ renderTxIn txinCollateral
114+
, "--tx-out-return-collateral", adaOnlyCollateralValue
115+
, "--witness-override", show @Int 2
116+
, "--tx-out", collateralToBeValue
117+
, "--tx-out", fundPlutusScriptAddrVal
118+
, "--tx-out-datum-hash-value", "0"
119+
, "--mint", mintValue
120+
, "--mint-script-file", plutusScript
121+
, "--mint-redeemer-value", "0"
122+
, "--out-file", mintTokensTxBody
123+
]
124+
125+
void $ execCli' execConfig
126+
[ "latest", "transaction", "sign"
127+
, "--tx-body-file", mintTokensTxBody
128+
, "--signing-key-file", utxoSKeyFile
129+
, "--signing-key-file", signingKeyFp $ paymentKeyInfoPair wallet1
130+
, "--out-file", mintTokensTx
131+
]
132+
let mintTxDebugFile = work </> "mint-tokens-tx-view.json"
133+
void $ execCli' execConfig ["debug", "transaction", "view", "--tx-file", mintTokensTx, "--out-file", mintTxDebugFile]
134+
135+
H.note_ "Mint Tokens Tx"
136+
txMintJson :: Aeson.Value <- H.leftFailM . H.readJsonFile $ mintTxDebugFile
137+
H.noteShowPretty_ txMintJson
138+
139+
void $ execCli' execConfig
140+
[ "latest", "transaction", "submit"
141+
, "--tx-file", mintTokensTx
142+
]
143+
144+
145+
-- STEP 2: Attempt to spend from script with collateral containing tokens
146+
-- This will fail because collateral cannot contain non-ADA tokens
147+
148+
-- Wait for transactions to be processed and find UTxOs
149+
_ <- waitForBlocks epochStateView 1
150+
151+
-- Find the UTxO with tokens at wallet1 (for collateral)
152+
txinCollateralWithTokensM <-
153+
findLargestMultiAssetUtxoWithAddress epochStateView sbe $ T.pack maCollateralAddress
154+
(txinCollateralWithTokens, collateralTxOut) <- H.evalMaybe txinCollateralWithTokensM
155+
H.note_ "Collateral TxOut"
156+
H.noteShow_ collateralTxOut
157+
-- Find the UTxO at the script address
158+
plutusScriptTxIn <- fmap fst . retryUntilJustM epochStateView (WaitForBlocks 10) $
159+
findLargestUtxoWithAddress epochStateView sbe $ T.pack plutusSpendingScriptAddr
160+
161+
let spendScriptUTxOTxBody = work </> "spend-script-utxo-tx-body"
162+
spendScriptUTxOTx = work </> "spend-script-utxo-tx"
163+
164+
void $ execCli' execConfig
165+
[ anyEraToString anyEra, "transaction", "build"
166+
, "--change-address", T.unpack $ paymentKeyInfoAddr wallet0
167+
, "--tx-in", T.unpack $ renderTxIn plutusScriptTxIn
168+
, "--tx-in-script-file", plutusScript
169+
, "--tx-in-datum-value", "0"
170+
, "--tx-in-redeemer-value", "0"
171+
, "--witness-override", show @Int 2
172+
, "--tx-in-collateral", T.unpack $ renderTxIn txinCollateralWithTokens -- This is the key issue - using collateral with tokens
173+
, "--out-file", spendScriptUTxOTxBody
174+
]
175+
let prettyTxBodyFile = work </> "spend-script-utxo-tx-body-view.json"
176+
void $ execCli' execConfig ["debug", "transaction", "view", "--tx-body-file", spendScriptUTxOTxBody, "--out-file", prettyTxBodyFile]
177+
178+
txBodyPrettyJson :: Aeson.Value <- H.leftFailM . H.readJsonFile $ prettyTxBodyFile
179+
H.note_ "Tx body"
180+
H.noteShowPretty_ txBodyPrettyJson
181+
182+
void $ execCli' execConfig
183+
[ "latest", "transaction", "sign"
184+
, "--tx-body-file", spendScriptUTxOTxBody
185+
, "--signing-key-file", signingKeyFp $ paymentKeyInfoPair wallet1
186+
, "--signing-key-file", signingKeyFp $ paymentKeyInfoPair wallet2
187+
, "--out-file", spendScriptUTxOTx
188+
]
189+
190+
let prettyTxFile = work </> "spend-script-utxo-tx-view.json"
191+
void $ execCli' execConfig ["debug", "transaction", "view", "--tx-file", spendScriptUTxOTx, "--out-file", prettyTxFile]
192+
193+
txPrettyJson :: Aeson.Value <- H.leftFailM . H.readJsonFile $ prettyTxFile
194+
H.noteShowPretty_ txPrettyJson
195+
196+
void $ execCli' execConfig
197+
[ "latest", "transaction", "submit"
198+
, "--tx-file", spendScriptUTxOTx
199+
]
200+
201+
H.success

cardano-testnet/test/cardano-testnet-test/Cardano/Testnet/Test/Cli/Plutus/Scripts.hs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ import qualified Hedgehog.Extras as H
4444
-- Voting NO
4545
-- Proposing NO
4646
-- Execute me with:
47-
-- @DISABLE_RETRIES=1 cabal run cardano-testnet-test -- -p "/Spec.hs.Spec.Ledger Events.Plutus.Scripts/"@
47+
-- @DISABLE_RETRIES=1 cabal test cardano-testnet-test --test-options '-p "/PlutusV3 purposes/"'@
4848
hprop_plutus_purposes_v3 :: Property
4949
hprop_plutus_purposes_v3 = integrationWorkspace "all-plutus-script-purposes" $ \tempAbsBasePath' -> H.runWithDefaultWatchdog_ $ do
5050
conf@Conf { tempAbsPath } <- mkConf tempAbsBasePath'
@@ -194,7 +194,7 @@ hprop_plutus_purposes_v3 = integrationWorkspace "all-plutus-script-purposes" $ \
194194

195195
-- |
196196
-- Execute me with:
197-
-- @DISABLE_RETRIES=1 cabal test cardano-testnet-test --test-options '-p "/PlutusV2 Create transaction with two script certs/"'@
197+
-- @DISABLE_RETRIES=1 cabal test cardano-testnet-test --test-options '-p "/PlutusV2 transaction with two script certs/"'@
198198
hprop_tx_two_script_certs_v2 :: Property
199199
hprop_tx_two_script_certs_v2 = integrationWorkspace "tx-2-script-certs" $ \tempAbsBasePath' -> H.runWithDefaultWatchdog_ $ do
200200
conf@Conf { tempAbsPath } <- mkConf tempAbsBasePath'
@@ -229,7 +229,7 @@ hprop_tx_two_script_certs_v2 = integrationWorkspace "tx-2-script-certs" $ \tempA
229229
txin <- T.unpack . renderTxIn <$> findLargestUtxoForPaymentKey epochStateView sbe wallet0
230230

231231
plutusScript <- H.note $ work </> "always-succeeds-script.plutusV2"
232-
H.writeFile plutusScript $ T.unpack plutusV2StakeScript
232+
H.writeFile plutusScript $ T.unpack plutusV2StakeScript --plutusV3Script
233233

234234
scriptStakeRegistrationCertificate
235235
<- H.note $ work </> "script-stake-registration-certificate"
@@ -257,7 +257,9 @@ hprop_tx_two_script_certs_v2 = integrationWorkspace "tx-2-script-certs" $ \tempA
257257
let txbody = work </> "two-certs-tx-body"
258258
tx = work </> "two-certs-tx"
259259
txout = mconcat [ utxoAddr, "+", show @Int 2_000_000 ]
260-
260+
261+
s <- execCli' execConfig [anyEraToString anyEra, "transaction", "policyid", "--script-file", plutusScript]
262+
H.note_ $ "Script hash: " <> s
261263
let txBuildArgs =
262264
[ anyEraToString anyEra, "transaction", "build"
263265
, "--change-address", T.unpack $ paymentKeyInfoAddr wallet0

0 commit comments

Comments
 (0)