Skip to content

Commit fcf481c

Browse files
committed
wip
1 parent 9128662 commit fcf481c

File tree

6 files changed

+231
-7
lines changed

6 files changed

+231
-7
lines changed

cardano-testnet/cardano-testnet.cabal

+2-1
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,8 @@ test-suite cardano-testnet-test
185185

186186
main-is: cardano-testnet-test.hs
187187

188-
other-modules: Cardano.Testnet.Test.Cli.Conway.StakeSnapshot
188+
other-modules: Cardano.Testnet.Test.Api.TxSupplementalDatum
189+
Cardano.Testnet.Test.Cli.Conway.StakeSnapshot
189190
Cardano.Testnet.Test.Cli.KesPeriodInfo
190191
Cardano.Testnet.Test.Cli.LeadershipSchedule
191192
Cardano.Testnet.Test.Cli.Query

cardano-testnet/src/Testnet/Components/Query.hs

+12-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ module Testnet.Components.Query
3636
, checkDRepsNumber
3737
, checkDRepState
3838
, assertNewEpochState
39+
, getProtocolParams
3940
, getGovActionLifetime
4041
, getKeyDeposit
4142
, getDelegationState
@@ -44,7 +45,8 @@ module Testnet.Components.Query
4445

4546
import Cardano.Api as Api
4647
import Cardano.Api.Ledger (Credential, DRepState, EpochInterval (..), KeyRole (DRepRole))
47-
import Cardano.Api.Shelley (ShelleyLedgerEra)
48+
import Cardano.Api.Shelley (LedgerProtocolParameters (..), ShelleyLedgerEra,
49+
fromShelleyTxIn, fromShelleyTxOut)
4850
import qualified Cardano.Api.Ledger as L
4951

5052
import Cardano.Crypto.Hash (hashToStringAsHex)
@@ -558,6 +560,15 @@ assertNewEpochState epochStateView sbe maxWait lens expected = withFrozenCallSta
558560
Refl <- H.leftFail $ assertErasEqual sbe actualEra
559561
pure $ newEpochState ^. lens
560562

563+
-- | Return current protocol parameters from the governance state
564+
getProtocolParams :: (H.MonadAssertion m, MonadTest m, MonadIO m)
565+
=> EpochStateView
566+
-> ConwayEraOnwards era
567+
-> m (LedgerProtocolParameters era)
568+
getProtocolParams epochStateView ceo = conwayEraOnwardsConstraints ceo $ do
569+
govState :: ConwayGovState era <- getGovState epochStateView ceo
570+
pure . LedgerProtocolParameters $ govState ^. L.cgsCurPParamsL
571+
561572

562573
-- | Obtains the @govActionLifetime@ from the protocol parameters.
563574
-- The @govActionLifetime@ or governance action maximum lifetime in epochs is

cardano-testnet/src/Testnet/Types.hs

+18-4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ module Testnet.Types
2121
, testnetSprockets
2222
, TestnetNode(..)
2323
, nodeSocketPath
24+
, node0ConnectionInfo
2425
, isTestnetNodeSpo
2526
, SpoNodeKeys(..)
2627
, Delegator(..)
@@ -62,7 +63,6 @@ import Data.List (intercalate)
6263
import Data.Maybe
6364
import Data.MonoTraversable (Element, MonoFunctor (..))
6465
import Data.Text (Text)
65-
import Data.Time.Clock (UTCTime)
6666
import GHC.Exts (IsString (..))
6767
import GHC.Generics (Generic)
6868
import qualified GHC.IO.Handle as IO
@@ -73,7 +73,9 @@ import qualified System.Process as IO
7373

7474
import Testnet.Start.Types
7575

76+
import Hedgehog (MonadTest)
7677
import qualified Hedgehog as H
78+
import qualified Hedgehog.Extras as H
7779
import qualified Hedgehog.Extras.Stock as H
7880
import Hedgehog.Extras.Stock.IO.Network.Sprocket (Sprocket (..))
7981

@@ -115,7 +117,7 @@ data SKey k
115117
data TestnetRuntime = TestnetRuntime
116118
{ configurationFile :: !(NodeConfigFile In)
117119
, shelleyGenesisFile :: !FilePath
118-
, testnetMagic :: !Int
120+
, testnetMagic :: !Int -- TODO change to Word32
119121
, testnetNodes :: ![TestnetNode]
120122
, wallets :: ![PaymentKeyInfo]
121123
, delegators :: ![Delegator]
@@ -148,6 +150,18 @@ isTestnetNodeSpo = isJust . poolKeys
148150
nodeSocketPath :: TestnetNode -> SocketPath
149151
nodeSocketPath = File . H.sprocketSystemName . nodeSprocket
150152

153+
-- | Connection data for the first node in the testnet
154+
node0ConnectionInfo :: MonadTest m => TestnetRuntime -> m LocalNodeConnectInfo
155+
node0ConnectionInfo TestnetRuntime{testnetMagic, testnetNodes} = do
156+
case testnetNodes of
157+
[] -> H.note_ "There are no nodes in the testnet" >> H.failure
158+
node0:_ -> do
159+
pure LocalNodeConnectInfo
160+
{ localNodeSocketPath= nodeSocketPath node0
161+
, localNodeNetworkId=Testnet (NetworkMagic $ fromIntegral testnetMagic)
162+
, localConsensusModeParams=CardanoModeParams $ EpochSlots 21600}
163+
164+
151165
data SpoNodeKeys = SpoNodeKeys
152166
{ poolNodeKeysCold :: KeyPair StakePoolKey
153167
, poolNodeKeysVrf :: KeyPair VrfKey
@@ -187,14 +201,14 @@ getStartTime
187201
=> HasCallStack
188202
=> FilePath
189203
-> TestnetRuntime
190-
-> m UTCTime
204+
-> m SystemStart
191205
getStartTime tempRootPath TestnetRuntime{configurationFile} = withFrozenCallStack $ H.evalEither <=< H.evalIO . runExceptT $ do
192206
byronGenesisFile <-
193207
decodeNodeConfiguration configurationFile >>= \case
194208
NodeProtocolConfigurationCardano NodeByronProtocolConfiguration{npcByronGenesisFile} _ _ _ _ _ ->
195209
pure $ unGenesisFile npcByronGenesisFile
196210
let byronGenesisFilePath = tempRootPath </> byronGenesisFile
197-
G.gdStartTime . G.configGenesisData <$> decodeGenesisFile byronGenesisFilePath
211+
SystemStart . G.gdStartTime . G.configGenesisData <$> decodeGenesisFile byronGenesisFilePath
198212
where
199213
decodeNodeConfiguration :: File NodeConfig In -> ExceptT String IO NodeProtocolConfiguration
200214
decodeNodeConfiguration (File file) = do
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
{-# LANGUAGE LambdaCase #-}
2+
{-# LANGUAGE NamedFieldPuns #-}
3+
{-# LANGUAGE NumericUnderscores #-}
4+
{-# LANGUAGE OverloadedLists #-}
5+
{-# LANGUAGE OverloadedStrings #-}
6+
{-# LANGUAGE ScopedTypeVariables #-}
7+
8+
module Cardano.Testnet.Test.Api.TxSupplementalDatum
9+
( hprop_tx_supp_datum
10+
)
11+
where
12+
13+
import Cardano.Api
14+
import qualified Cardano.Api.Ledger as L
15+
import qualified Cardano.Api.Network as Net
16+
import qualified Cardano.Api.Network as Net.Tx
17+
import Cardano.Api.Shelley
18+
19+
import Cardano.Testnet
20+
21+
import Prelude
22+
23+
import Control.Monad
24+
import Data.Default.Class
25+
import qualified Data.Map.Strict as M
26+
import Data.Proxy
27+
import Data.Set (Set)
28+
import GHC.Exts (IsList (..))
29+
import Lens.Micro
30+
31+
import Testnet.Components.Query
32+
import Testnet.Property.Util (integrationRetryWorkspace)
33+
import Testnet.Types
34+
35+
import Hedgehog (Property, (===))
36+
import qualified Hedgehog as H
37+
import qualified Hedgehog.Extras.Test.Base as H
38+
import qualified Hedgehog.Extras.Test.TestWatchdog as H
39+
40+
hprop_tx_supp_datum :: Property
41+
hprop_tx_supp_datum = integrationRetryWorkspace 2 "api-tx-supp-dat" $ \tempAbsBasePath' -> H.runWithDefaultWatchdog_ $ do
42+
conf@Conf{tempAbsPath} <- mkConf tempAbsBasePath'
43+
let tempAbsPath' = unTmpAbsPath tempAbsPath
44+
45+
let ceo = ConwayEraOnwardsConway
46+
beo = convert ceo
47+
sbe = convert ceo
48+
eraProxy = proxyToAsType Proxy
49+
options = def{cardanoNodeEra = AnyShelleyBasedEra sbe}
50+
51+
tr@TestnetRuntime
52+
{ configurationFile
53+
, testnetNodes = node0 : _
54+
, wallets = wallet0@(PaymentKeyInfo _ addrTxt0) : wallet1 : _
55+
} <-
56+
cardanoTestnetDefault options def conf
57+
58+
systemStart <- H.noteShowM $ getStartTime tempAbsPath' tr
59+
epochStateView <- getEpochStateView configurationFile (nodeSocketPath node0)
60+
connectionInfo <- node0ConnectionInfo tr
61+
pparams <- getProtocolParams epochStateView ceo
62+
63+
-- prepare tx inputs and output address
64+
H.noteShow_ addrTxt0
65+
addr0 <- H.nothingFail $ deserialiseAddress (AsAddressInEra eraProxy) addrTxt0
66+
67+
let (PaymentKeyInfo _ addrTxt1) = wallet1
68+
H.noteShow_ addrTxt1
69+
addr1 <- H.nothingFail $ deserialiseAddress (AsAddressInEra eraProxy) addrTxt1
70+
71+
-- read key witnesses
72+
[wit0, wit1] :: [ShelleyWitnessSigningKey] <-
73+
forM [wallet0, wallet1] $ \wallet ->
74+
H.leftFailM . H.evalIO $
75+
readFileTextEnvelopeAnyOf
76+
[FromSomeType (proxyToAsType Proxy) WitnessGenesisUTxOKey]
77+
(signingKey $ paymentKeyInfoPair wallet)
78+
79+
-- query node for era history
80+
epochInfo <-
81+
(H.leftFail <=< H.leftFailM) . H.evalIO $
82+
executeLocalStateQueryExpr connectionInfo Net.VolatileTip $
83+
fmap toLedgerEpochInfo <$> queryEraHistory
84+
85+
let scriptData1 = unsafeHashableScriptData $ ScriptDataBytes "CAFEBABE"
86+
scriptData2 = unsafeHashableScriptData $ ScriptDataBytes "DEADBEEF"
87+
txDatum1 =
88+
TxOutDatumHash
89+
(convert beo)
90+
(hashScriptDataBytes scriptData1)
91+
txDatum2 = TxOutDatumInline (convert ceo) scriptData2
92+
93+
-- Build a first transaction with txout supplemental data
94+
tx1Utxo <- do
95+
txIn <- findLargestUtxoForPaymentKey epochStateView sbe wallet0
96+
97+
-- prepare txout
98+
let txOutValue = lovelaceToTxOutValue sbe 100_000_000
99+
txOuts =
100+
[ TxOut addr1 txOutValue txDatum1 ReferenceScriptNone
101+
, TxOut addr1 txOutValue txDatum2 ReferenceScriptNone
102+
]
103+
104+
-- build a transaction
105+
content =
106+
defaultTxBodyContent sbe
107+
& setTxIns [(txIn, pure $ KeyWitness KeyWitnessForSpending)]
108+
& setTxOuts txOuts
109+
& setTxProtocolParams (pure $ pure pparams)
110+
111+
utxo <- UTxO <$> findAllUtxos epochStateView sbe
112+
113+
BalancedTxBody _ txBody _ fee <-
114+
H.leftFail $
115+
makeTransactionBodyAutoBalance
116+
sbe
117+
systemStart
118+
epochInfo
119+
pparams
120+
mempty
121+
mempty
122+
mempty
123+
utxo
124+
content
125+
addr0
126+
Nothing -- keys override
127+
H.noteShow_ fee
128+
129+
let tx = signShelleyTransaction sbe txBody [wit0]
130+
txId <- H.noteShow . getTxId $ getTxBody tx
131+
132+
H.evalIO (submitTxToNodeLocal connectionInfo (TxInMode sbe tx)) >>= \case
133+
Net.Tx.SubmitFail reason -> H.noteShow_ reason >> H.failure
134+
Net.Tx.SubmitSuccess -> H.success
135+
136+
-- wait till transaction gets included in the block
137+
_ <- waitForBlocks epochStateView 1
138+
139+
-- test if it's in UTxO set
140+
utxo1 <- findAllUtxos epochStateView sbe
141+
let txUtxo = M.filterWithKey (\(TxIn txId' _) _ -> txId == txId') utxo1
142+
3 === length txUtxo
143+
144+
let chainTxOuts =
145+
reverse
146+
. drop 1
147+
. reverse
148+
. map (fromCtxUTxOTxOut . snd)
149+
. toList
150+
$ M.filterWithKey (\(TxIn txId' _) _ -> txId == txId') utxo1
151+
152+
txOuts === chainTxOuts
153+
154+
pure txUtxo
155+
156+
do
157+
[(txIn1, _)] <- pure $ filter (\(_, TxOut _ _ datum _) -> datum == txDatum1) $ toList tx1Utxo
158+
[(txIn2, _)] <- pure $ filter (\(_, TxOut _ _ datum _) -> datum == txDatum2) $ toList tx1Utxo
159+
160+
let scriptData3 = unsafeHashableScriptData $ ScriptDataBytes "C0FFEE"
161+
txDatum = TxOutDatumInline (convert ceo) scriptData3
162+
txOutValue = lovelaceToTxOutValue sbe 99_999_500
163+
txOut = TxOut addr0 txOutValue txDatum ReferenceScriptNone
164+
165+
let content =
166+
defaultTxBodyContent sbe
167+
& setTxIns [(txIn1, pure $ KeyWitness KeyWitnessForSpending)]
168+
& setTxInsReference (TxInsReference beo [txIn2])
169+
& setTxFee (TxFeeExplicit sbe 500)
170+
& setTxOuts [txOut]
171+
172+
txBody@(ShelleyTxBody _ _ _ (TxBodyScriptData _ (L.TxDats' datums) _) _ _) <-
173+
H.leftFail $ createTransactionBody sbe content
174+
let bodyScriptData = fromList . map fromAlonzoData $ M.elems datums :: Set HashableScriptData
175+
-- TODO why bodyScriptData is empty here?
176+
[scriptData1, scriptData2, scriptData3] === bodyScriptData
177+
178+
let tx = signShelleyTransaction sbe txBody [wit1]
179+
-- H.noteShowPretty_ tx
180+
txId <- H.noteShow . getTxId $ getTxBody tx
181+
182+
H.evalIO (submitTxToNodeLocal connectionInfo (TxInMode sbe tx)) >>= \case
183+
Net.Tx.SubmitFail reason -> H.noteShow_ reason >> H.failure
184+
Net.Tx.SubmitSuccess -> H.success
185+
186+
-- wait till transaction gets included in the block
187+
_ <- waitForBlocks epochStateView 1
188+
189+
-- test if it's in UTxO set
190+
utxo1 <- findAllUtxos epochStateView sbe
191+
let txUtxo = M.filterWithKey (\(TxIn txId' _) _ -> txId == txId') utxo1
192+
[txOut] === M.elems txUtxo
193+
194+
H.failure

cardano-testnet/test/cardano-testnet-test/Cardano/Testnet/Test/Cli/QuerySlotNumber.hs

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ module Cardano.Testnet.Test.Cli.QuerySlotNumber
1414

1515
import Cardano.Ledger.Shelley.Genesis (fromNominalDiffTimeMicro)
1616
import Cardano.Slotting.Slot
17+
import Cardano.Slotting.Time (SystemStart (..))
1718
import Cardano.Testnet
1819

1920
import Prelude
@@ -47,7 +48,7 @@ hprop_querySlotNumber = integrationRetryWorkspace 2 "query-slot-number" $ \tempA
4748
, testnetNodes
4849
} <- cardanoTestnetDefault def def conf
4950
ShelleyGenesis{sgSlotLength, sgEpochLength} <- H.noteShowM $ shelleyGenesis tr
50-
startTime <- H.noteShowM $ getStartTime tempAbsBasePath' tr
51+
SystemStart startTime <- H.noteShowM $ getStartTime tempAbsBasePath' tr
5152

5253
let slotLength = fromNominalDiffTimeMicro sgSlotLength
5354
-- how many slots can the checked value differ from

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

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ module Main
55
) where
66

77
import qualified Cardano.Crypto.Init as Crypto
8+
import qualified Cardano.Testnet.Test.Api.TxSupplementalDatum
89
import qualified Cardano.Testnet.Test.Cli.KesPeriodInfo
910
import qualified Cardano.Testnet.Test.Cli.Query
1011
import qualified Cardano.Testnet.Test.Cli.QuerySlotNumber
@@ -82,6 +83,8 @@ tests = do
8283
]
8384
]
8485
]
86+
, T.testGroup "API"
87+
[ignoreOnWindows "transaction with supplemental datum" Cardano.Testnet.Test.Api.TxSupplementalDatum.hprop_tx_supp_datum]
8588
, T.testGroup "CLI"
8689
[ ignoreOnWindows "Shutdown" Cardano.Testnet.Test.Node.Shutdown.hprop_shutdown
8790
-- ShutdownOnSigint fails on Mac with

0 commit comments

Comments
 (0)