1
1
{-# LANGUAGE NamedFieldPuns #-}
2
2
{-# LANGUAGE NumericUnderscores #-}
3
+ {-# LANGUAGE OverloadedStrings #-}
4
+ {-# LANGUAGE ScopedTypeVariables #-}
3
5
4
6
module Cardano.Testnet.Test.Cli.Plutus.CostCalculation
5
7
( hprop_ref_plutus_cost_calculation
6
8
, hprop_included_plutus_cost_calculation
9
+ , hprop_included_simple_script_cost_calculation
7
10
-- | Execute tests in this module with:
8
11
-- @DISABLE_RETRIES=1 cabal run cardano-testnet-test -- -p "/Spec.hs.Spec.Ledger Events.Plutus.Cost Calc/"@
9
12
)
10
13
where
11
14
12
15
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 )
16
20
import Cardano.Api.Experimental (Some (Some ))
17
21
import Cardano.Api.Ledger (EpochInterval (EpochInterval ), unCoin )
18
22
@@ -21,8 +25,17 @@ import Cardano.Testnet
21
25
import Prelude
22
26
23
27
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
24
34
import Data.Default.Class (Default (def ))
35
+ import Data.Text (Text )
25
36
import qualified Data.Text as Text
37
+ import Data.Text.Encoding (decodeLatin1 )
38
+ import qualified Data.Vector as Vector
26
39
import System.Directory (makeAbsolute )
27
40
import System.FilePath ((</>) )
28
41
import qualified System.Info as SYS
@@ -41,7 +54,8 @@ import Testnet.Process.Cli.Transaction (TxOutAddress (..), mkSpendOutp
41
54
import Testnet.Process.Run (execCli' , mkExecConfig )
42
55
import Testnet.Property.Util (integrationRetryWorkspace )
43
56
import Testnet.Start.Types (eraToString )
44
- import Testnet.Types (PaymentKeyInfo (paymentKeyInfoAddr ), paymentKeyInfoPair )
57
+ import Testnet.Types (PaymentKeyInfo (paymentKeyInfoAddr ), paymentKeyInfoPair ,
58
+ verificationKey )
45
59
46
60
-- @DISABLE_RETRIES=1 cabal run cardano-testnet-test -- -p "/Spec.hs.Spec.Ledger Events.Plutus.Cost Calc.Ref Script/"@
47
61
hprop_ref_plutus_cost_calculation :: Property
@@ -287,7 +301,7 @@ hprop_included_plutus_cost_calculation = integrationRetryWorkspace 2 "included p
287
301
submitTx execConfig cEra signedIncludedScript
288
302
289
303
-- Calculate cost of the transaction
290
- let includedScriptCostOutput = File $ includedScriptUnlock </> " unsigned-tx.tx "
304
+ let includedScriptCostOutput = File $ includedScriptUnlock </> " scriptCost.json "
291
305
H. noteM_ $
292
306
execCli'
293
307
execConfig
@@ -300,3 +314,142 @@ hprop_included_plutus_cost_calculation = integrationRetryWorkspace 2 "included p
300
314
H. diffFileVsGoldenFile
301
315
(unFile includedScriptCostOutput)
302
316
" 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
0 commit comments