11{-# LANGUAGE DataKinds #-}
22{-# LANGUAGE NamedFieldPuns #-}
3+ {-# LANGUAGE NumericUnderscores #-}
34{-# LANGUAGE OverloadedLabels #-}
45{-# LANGUAGE OverloadedLists #-}
56{-# LANGUAGE OverloadedStrings #-}
67{-# LANGUAGE ScopedTypeVariables #-}
78{-# LANGUAGE TypeApplications #-}
9+ {-# LANGUAGE TypeOperators #-}
810
911module Cardano.Testnet.Test.Rpc.Transaction
1012 ( hprop_rpc_transaction
@@ -13,41 +15,54 @@ where
1315
1416import Cardano.Api
1517import qualified Cardano.Api.Ledger as L
18+ import qualified Cardano.Api.Parser.Text as P
1619
1720import Cardano.CLI.Type.Output (QueryTipLocalStateOutput (.. ))
1821import qualified Cardano.Ledger.Api as L
1922import qualified Cardano.Ledger.Binary.Version as L
2023import qualified Cardano.Ledger.Conway.Core as L
2124import qualified Cardano.Ledger.Conway.PParams as L
2225import qualified Cardano.Ledger.Plutus as L
26+ import Cardano.Rpc.Client (Proto )
2327import qualified Cardano.Rpc.Client as Rpc
2428import qualified Cardano.Rpc.Proto.Api.UtxoRpc.Query as UtxoRpc
29+ import qualified Cardano.Rpc.Proto.Api.UtxoRpc.Submit as UtxoRpc
2530import Cardano.Rpc.Server.Internal.UtxoRpc.Query ()
31+ import Cardano.Rpc.Server.Internal.UtxoRpc.Type
2632import Cardano.Testnet
2733
2834import Prelude
2935
36+ import Control.Monad
37+ import Control.Monad.Fix
3038import qualified Data.ByteString.Short as SBS
3139import Data.Default.Class
3240import qualified Data.Map.Strict as M
41+ import Data.Maybe
42+ import qualified Data.Text.Encoding as T
43+ import GHC.Stack
3344import Lens.Micro
3445
3546import Testnet.Components.Query
3647import Testnet.Process.Run
3748import Testnet.Property.Util (integrationRetryWorkspace )
3849import Testnet.Start.Types
50+ import Testnet.Types
3951
4052import Hedgehog
4153import qualified Hedgehog as H
4254import qualified Hedgehog.Extras.Test.Base as H
4355import qualified Hedgehog.Extras.Test.TestWatchdog as H
4456
57+ import RIO (threadDelay )
58+
4559hprop_rpc_transaction :: Property
4660hprop_rpc_transaction = integrationRetryWorkspace 2 " rpc-tx" $ \ tempAbsBasePath' -> H. runWithDefaultWatchdog_ $ do
4761 conf@ Conf {tempAbsPath} <- mkConf tempAbsBasePath'
4862 let tempAbsPath' = unTmpAbsPath tempAbsPath
4963
50- let ceo = ConwayEraOnwardsConway
64+ let (ceo, eraProxy) =
65+ (conwayBasedEra, asType) :: era ~ ConwayEra => (ConwayEraOnwards era , AsType era )
5166 sbe = convert ceo
5267 eraName = eraToString sbe
5368 options = def{cardanoNodeEra = AnyShelleyBasedEra sbe, cardanoEnableRpc = True }
@@ -56,29 +71,106 @@ hprop_rpc_transaction = integrationRetryWorkspace 2 "rpc-tx" $ \tempAbsBasePath'
5671 { testnetMagic
5772 , configurationFile
5873 , testnetNodes = node0@ TestnetNode {nodeSprocket} : _
74+ , wallets = wallet0@ (PaymentKeyInfo _ addrTxt0) : (PaymentKeyInfo _ addrTxt1) : _
5975 } <-
6076 createAndRunTestnet options def conf
6177
6278 execConfig <- mkExecConfig tempAbsPath' nodeSprocket testnetMagic
6379 epochStateView <- getEpochStateView configurationFile (nodeSocketPath node0)
64- pparams <- unLedgerProtocolParameters <$> getProtocolParams epochStateView ceo
65- -- H.noteShowPretty_ pparams
66- utxos <- findAllUtxos epochStateView sbe
67- H. noteShowPretty_ utxos
80+
6881 rpcSocket <- H. note . unFile $ nodeRpcSocketPath node0
6982
83+ -- prepare tx inputs and output address
84+ H. noteShow_ addrTxt0
85+ addr0 <- H. nothingFail $ deserialiseAddress (AsAddressInEra eraProxy) addrTxt0
86+
87+ H. noteShow_ addrTxt1
88+ addr1 <- H. nothingFail $ deserialiseAddress (AsAddressInEra eraProxy) addrTxt1
89+
90+ -- read key witnesses
91+ wit0 :: ShelleyWitnessSigningKey <-
92+ H. leftFailM . H. evalIO $
93+ readFileTextEnvelopeAnyOf
94+ [FromSomeType asType WitnessGenesisUTxOKey ]
95+ (signingKey $ paymentKeyInfoPair wallet0)
96+
7097 --------------
7198 -- RPC queries
7299 --------------
73100 let rpcServer = Rpc. ServerUnix rpcSocket
74101 (pparamsResponse, utxosResponse) <- H. noteShowM . H. evalIO . Rpc. withConnection def rpcServer $ \ conn -> do
75102 pparams' <- do
76- let req = Rpc. defMessage
103+ let req = def
77104 Rpc. nonStreaming conn (Rpc. rpc @ (Rpc. Protobuf UtxoRpc. QueryService " readParams" )) req
78105
79106 utxos' <- do
80- let req = Rpc. defMessage
107+ let req = def & # addresses . # items .~ [ T. encodeUtf8 addrTxt0]
81108 Rpc. nonStreaming conn (Rpc. rpc @ (Rpc. Protobuf UtxoRpc. QueryService " readUtxos" )) req
82109 pure (pparams', utxos')
83110
84- H. failure
111+ pparams <- H. leftFail $ utxoRpcPParamsToProtocolParams (convert ceo) $ pparamsResponse ^. # values . # cardano
112+
113+ txOut0 : _ <- H. noteShow $ utxosResponse ^. # items
114+ txIn0 <- txoRefToTxIn $ txOut0 ^. # txoRef
115+
116+ let outputCoin = txOut0 ^. # cardano . # coin . to fromIntegral
117+ amount = 200_000_000
118+ fee = 500
119+ change = outputCoin - amount - fee
120+ txOut = TxOut addr1 (lovelaceToTxOutValue sbe $ L. Coin amount) TxOutDatumNone ReferenceScriptNone
121+ changeTxOut = TxOut addr0 (lovelaceToTxOutValue sbe $ L. Coin change) TxOutDatumNone ReferenceScriptNone
122+ content =
123+ defaultTxBodyContent sbe
124+ & setTxIns [(txIn0, pure $ KeyWitness KeyWitnessForSpending )]
125+ & setTxFee (TxFeeExplicit sbe 500 )
126+ & setTxOuts [txOut, changeTxOut]
127+ & setTxProtocolParams (pure . pure $ LedgerProtocolParameters pparams)
128+
129+ txBody <- H. leftFail $ createTransactionBody sbe content
130+
131+ let signedTx = signShelleyTransaction sbe txBody [wit0]
132+ txId <- H. noteShow . getTxId $ getTxBody signedTx
133+
134+ H. noteShowPretty_ utxosResponse
135+
136+ (utxos, submitResponse) <- H. noteShowM . H. evalIO . Rpc. withConnection def rpcServer $ \ conn -> do
137+ submitResponse <-
138+ Rpc. nonStreaming conn (Rpc. rpc @ (Rpc. Protobuf UtxoRpc. SubmitService " submitTx" )) $
139+ def & # tx .~ [def & # raw .~ serialiseToCBOR signedTx]
140+
141+ fix $ \ loop -> do
142+ resp <- Rpc. nonStreaming conn (Rpc. rpc @ (Rpc. Protobuf UtxoRpc. QueryService " readParams" )) def
143+
144+ let previousBlockNo = pparamsResponse ^. # ledgerTip . # height
145+ currentBlockNo = resp ^. # ledgerTip . # height
146+ -- wait for 2 blocks
147+ when (previousBlockNo + 1 >= currentBlockNo) $ do
148+ threadDelay 500_000
149+ loop
150+
151+ utxos <-
152+ Rpc. nonStreaming conn (Rpc. rpc @ (Rpc. Protobuf UtxoRpc. QueryService " readUtxos" )) $
153+ def & # addresses . # items .~ [T. encodeUtf8 addrTxt1]
154+ pure (utxos, submitResponse)
155+
156+ submittedTxIds <- forM (submitResponse ^. # results) $ \ res -> do
157+ let mErr = res ^. # maybe'errorMessage
158+ mTxId = res ^. # maybe'ref
159+ case (mErr, mTxId) of
160+ (Just err, Nothing ) -> H. noteShow_ err >> H. failure
161+ (Nothing , Just txId) ->
162+ H. leftFail $ deserialiseFromRawBytes AsTxId txId
163+ _ -> do
164+ H. note_ $ " Protocol error: " <> show res
165+ H. failure
166+
167+ [txId] === submittedTxIds
168+
169+ 2 === length (utxos ^. # items)
170+ let utxo0: _ = utxos ^. # items
171+ fromIntegral amount === utxo0 ^. # cardano . # coin
172+
173+ txoRefToTxIn :: (HasCallStack , MonadTest m ) => Proto UtxoRpc. TxoRef -> m TxIn
174+ txoRefToTxIn r = withFrozenCallStack $ do
175+ txId' <- H. leftFail $ deserialiseFromRawBytes AsTxId $ r ^. # hash
176+ pure $ TxIn txId' (TxIx . fromIntegral $ r ^. # index)
0 commit comments