Skip to content

Commit c73c057

Browse files
committed
Add test for ensuring calculating costs of transaction with simple script doesn't crash
1 parent 30f143e commit c73c057

File tree

3 files changed

+160
-5
lines changed

3 files changed

+160
-5
lines changed

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

Lines changed: 158 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
{-# LANGUAGE NamedFieldPuns #-}
22
{-# LANGUAGE NumericUnderscores #-}
3+
{-# LANGUAGE OverloadedStrings #-}
4+
{-# LANGUAGE ScopedTypeVariables #-}
35

46
module Cardano.Testnet.Test.Cli.Plutus.CostCalculation
57
( hprop_ref_plutus_cost_calculation
68
, hprop_included_plutus_cost_calculation
9+
, hprop_included_simple_script_cost_calculation
710
-- | Execute tests in this module with:
811
-- @DISABLE_RETRIES=1 cabal run cardano-testnet-test -- -p "/Spec.hs.Spec.Ledger Events.Plutus.Cost Calc/"@
912
)
1013
where
1114

1215
import Cardano.Api (AnyCardanoEra (AnyCardanoEra),
13-
AnyShelleyBasedEra (AnyShelleyBasedEra), File (File), MonadIO (liftIO),
14-
ShelleyBasedEra (ShelleyBasedEraConway), ToCardanoEra (toCardanoEra), renderTxIn,
15-
unFile)
16+
AnyShelleyBasedEra (AnyShelleyBasedEra), ExceptT, File (File), MonadIO (liftIO),
17+
ShelleyBasedEra (ShelleyBasedEraConway), ToCardanoEra (toCardanoEra),
18+
deserialiseAnyVerificationKey, liftEither, mapSomeAddressVerificationKey,
19+
renderTxIn, serialiseToRawBytesHex, unFile, verificationKeyHash)
1620
import Cardano.Api.Experimental (Some (Some))
1721
import Cardano.Api.Ledger (EpochInterval (EpochInterval), unCoin)
1822

@@ -21,8 +25,17 @@ import Cardano.Testnet
2125
import Prelude
2226

2327
import Control.Monad (void)
28+
import Control.Monad.Except (runExceptT)
29+
import Data.Aeson (Value, encodeFile)
30+
import qualified Data.Aeson.KeyMap as KeyMap
31+
import Data.Aeson.Types (Value (..), object)
32+
import Data.Bifunctor (first)
33+
import qualified Data.ByteString as BS
2434
import Data.Default.Class (Default (def))
35+
import Data.Text (Text)
2536
import qualified Data.Text as Text
37+
import Data.Text.Encoding (decodeLatin1)
38+
import qualified Data.Vector as Vector
2639
import System.Directory (makeAbsolute)
2740
import System.FilePath ((</>))
2841
import qualified System.Info as SYS
@@ -41,7 +54,8 @@ import Testnet.Process.Cli.Transaction (TxOutAddress (..), mkSpendOutp
4154
import Testnet.Process.Run (execCli', mkExecConfig)
4255
import Testnet.Property.Util (integrationRetryWorkspace)
4356
import Testnet.Start.Types (eraToString)
44-
import Testnet.Types (PaymentKeyInfo (paymentKeyInfoAddr), paymentKeyInfoPair)
57+
import Testnet.Types (PaymentKeyInfo (paymentKeyInfoAddr), paymentKeyInfoPair,
58+
verificationKey)
4559

4660
-- @DISABLE_RETRIES=1 cabal run cardano-testnet-test -- -p "/Spec.hs.Spec.Ledger Events.Plutus.Cost Calc.Ref Script/"@
4761
hprop_ref_plutus_cost_calculation :: Property
@@ -287,7 +301,7 @@ hprop_included_plutus_cost_calculation = integrationRetryWorkspace 2 "included p
287301
submitTx execConfig cEra signedIncludedScript
288302

289303
-- Calculate cost of the transaction
290-
let includedScriptCostOutput = File $ includedScriptUnlock </> "unsigned-tx.tx"
304+
let includedScriptCostOutput = File $ includedScriptUnlock </> "scriptCost.json"
291305
H.noteM_ $
292306
execCli'
293307
execConfig
@@ -300,3 +314,142 @@ hprop_included_plutus_cost_calculation = integrationRetryWorkspace 2 "included p
300314
H.diffFileVsGoldenFile
301315
(unFile includedScriptCostOutput)
302316
"test/cardano-testnet-test/files/calculatePlutusScriptCost.json"
317+
318+
-- @DISABLE_RETRIES=1 cabal run cardano-testnet-test -- -p "/Spec.hs.Spec.Ledger Events.Plutus.Cost Calc.Simple Script/"@
319+
hprop_included_simple_script_cost_calculation :: Property
320+
hprop_included_simple_script_cost_calculation = integrationRetryWorkspace 2 "included simple script" $ \tempAbsBasePath' -> H.runWithDefaultWatchdog_ $ do
321+
H.note_ SYS.os
322+
conf@Conf{tempAbsPath} <- mkConf tempAbsBasePath'
323+
let tempAbsPath' = unTmpAbsPath tempAbsPath
324+
work <- H.createDirectoryIfMissing $ tempAbsPath' </> "work"
325+
326+
let
327+
sbe = ShelleyBasedEraConway
328+
era = toCardanoEra sbe
329+
cEra = AnyCardanoEra era
330+
eraName = eraToString era
331+
tempBaseAbsPath = makeTmpBaseAbsPath $ TmpAbsolutePath tempAbsPath'
332+
options = def{cardanoNodeEra = AnyShelleyBasedEra sbe}
333+
334+
TestnetRuntime
335+
{ configurationFile
336+
, testnetMagic
337+
, testnetNodes
338+
, wallets = wallet0 : wallet1 : _
339+
} <-
340+
cardanoTestnetDefault options def conf
341+
342+
poolNode1 <- H.headM testnetNodes
343+
poolSprocket1 <- H.noteShow $ nodeSprocket poolNode1
344+
execConfig <- mkExecConfig tempBaseAbsPath poolSprocket1 testnetMagic
345+
epochStateView <- getEpochStateView configurationFile (nodeSocketPath poolNode1)
346+
347+
-- We write a simple script that allows any of the two payment keys to spend the money
348+
349+
addrHash1 <- H.evalEitherM $ liftIO $ runExceptT $ paymentKeyInfoHash wallet0
350+
addrHash2 <- H.evalEitherM $ liftIO $ runExceptT $ paymentKeyInfoHash wallet1
351+
352+
simpleScriptLockWork <- H.createDirectoryIfMissing $ work </> "simple-script-lock"
353+
let simpleScript = File $ simpleScriptLockWork </> "simple-script.json"
354+
liftIO $ encodeFile (unFile simpleScript) $ generateSimpleAnyKeyScript [addrHash1, addrHash2]
355+
356+
-- We now submit a transaction to the script address
357+
let lockedAmount = 10_000_000
358+
enoughAmountForFees = 2_000_000 -- Needs to be more than min ada
359+
360+
txBodySimpleScriptLock <-
361+
mkSpendOutputsOnlyTx
362+
execConfig
363+
epochStateView
364+
sbe
365+
simpleScriptLockWork
366+
"tx-body"
367+
wallet0
368+
[(ScriptAddress simpleScript, lockedAmount, Nothing)]
369+
370+
signedTxSimpleScriptLock <-
371+
signTx
372+
execConfig
373+
cEra
374+
simpleScriptLockWork
375+
"signed-tx"
376+
txBodySimpleScriptLock
377+
[Some $ paymentKeyInfoPair wallet0]
378+
submitTx execConfig cEra signedTxSimpleScriptLock
379+
380+
-- Wait until transaction is on chain and obtain transaction identifier
381+
txIdSimpleScriptLock <- retrieveTransactionId execConfig signedTxSimpleScriptLock
382+
txIxSimpleScriptLock <-
383+
H.evalMaybeM $
384+
watchEpochStateUpdate
385+
epochStateView
386+
(EpochInterval 2)
387+
(getTxIx sbe txIdSimpleScriptLock lockedAmount)
388+
389+
-- Create transaction that unlocks the simple script UTxO we just created
390+
simpleScriptUnlockWork <- H.createDirectoryIfMissing $ work </> "simple-script-unlock"
391+
let unsignedUnlockSimpleScript = File $ simpleScriptUnlockWork </> "unsigned-tx.tx"
392+
393+
void $
394+
execCli'
395+
execConfig
396+
[ eraName
397+
, "transaction", "build"
398+
, "--change-address", Text.unpack $ paymentKeyInfoAddr wallet1
399+
, "--tx-in", txIdSimpleScriptLock <> "#" <> show txIxSimpleScriptLock
400+
, "--tx-in-script-file", unFile simpleScript
401+
, "--tx-out", Text.unpack (paymentKeyInfoAddr wallet1) <> "+" <> show (unCoin (lockedAmount - enoughAmountForFees))
402+
, "--witness-override", "2"
403+
, "--out-file", unFile unsignedUnlockSimpleScript
404+
]
405+
406+
signedScriptUnlock <-
407+
signTx
408+
execConfig
409+
cEra
410+
simpleScriptUnlockWork
411+
"signed-tx"
412+
unsignedUnlockSimpleScript
413+
[Some $ paymentKeyInfoPair wallet1]
414+
415+
submitTx execConfig cEra signedScriptUnlock
416+
417+
-- Calculate cost of the transaction
418+
419+
output <-
420+
H.noteM $
421+
execCli'
422+
execConfig
423+
[ eraName
424+
, "transaction", "calculate-plutus-script-cost"
425+
, "--tx-file", unFile signedScriptUnlock
426+
]
427+
428+
H.diffVsGoldenFile output "test/cardano-testnet-test/files/calculateSimpleScriptCost.json"
429+
430+
where
431+
generateSimpleAnyKeyScript :: [Text] -> Value
432+
generateSimpleAnyKeyScript keyHashes =
433+
object
434+
[ ("type", "any")
435+
,
436+
( "scripts"
437+
, Array $
438+
Vector.fromList
439+
[ Object $
440+
KeyMap.fromList
441+
[ ("type", "sig")
442+
, ("keyHash", String keyHash)
443+
]
444+
| keyHash <- keyHashes
445+
]
446+
)
447+
]
448+
449+
paymentKeyInfoHash :: PaymentKeyInfo -> ExceptT String IO Text
450+
paymentKeyInfoHash wallet = do
451+
vkBs <- liftIO $ BS.readFile (unFile $ verificationKey $ paymentKeyInfoPair wallet)
452+
svk <- liftEither $ first show $ deserialiseAnyVerificationKey vkBs
453+
return $
454+
decodeLatin1 $
455+
mapSomeAddressVerificationKey (serialiseToRawBytesHex . verificationKeyHash) svk

cardano-testnet/test/cardano-testnet-test/cardano-testnet-test.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ tests = do
7878
, T.testGroup "Cost Calc"
7979
[ ignoreOnWindows "Ref Script" Cardano.Testnet.Test.Cli.Plutus.CostCalculation.hprop_ref_plutus_cost_calculation
8080
, ignoreOnWindows "Normal Script" Cardano.Testnet.Test.Cli.Plutus.CostCalculation.hprop_included_plutus_cost_calculation
81+
, ignoreOnWindows "Simple Script" Cardano.Testnet.Test.Cli.Plutus.CostCalculation.hprop_included_simple_script_cost_calculation
8182
]
8283
]
8384
]
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[]

0 commit comments

Comments
 (0)