-
Notifications
You must be signed in to change notification settings - Fork 754
cardano-testnet | Fix flaky height check in rpc test #6550
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| ### Fixed | ||
|
|
||
| - Fixed flaky RPC transaction test that used a stale block height from a prior RPC connection to determine when to query UTxOs after submitting a transaction. Replaced the brittle block-counting wait with `retryUntilM`, which polls the RPC endpoint until the expected UTxOs appear at the destination address. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| {-# LANGUAGE DataKinds #-} | ||
| {-# LANGUAGE NamedFieldPuns #-} | ||
| {-# LANGUAGE NumericUnderscores #-} | ||
| {-# LANGUAGE OverloadedLists #-} | ||
| {-# LANGUAGE OverloadedStrings #-} | ||
|
|
@@ -26,12 +27,13 @@ import Cardano.Testnet | |
| import Prelude | ||
|
|
||
| import Control.Monad | ||
| import Control.Monad.Fix | ||
| import Control.Monad.Trans.Control (liftBaseOp) | ||
| import Data.Default.Class | ||
| import qualified Data.Text.Encoding as T | ||
| import GHC.Stack | ||
| import Lens.Micro | ||
|
|
||
| import Testnet.Components.Query (TestnetWaitPeriod (..), getEpochStateView, retryUntilM) | ||
| import Testnet.Property.Util (integrationRetryWorkspace) | ||
| import Testnet.Types | ||
|
|
||
|
|
@@ -40,7 +42,7 @@ import qualified Hedgehog as H | |
| import qualified Hedgehog.Extras.Test.Base as H | ||
| import qualified Hedgehog.Extras.Test.TestWatchdog as H | ||
|
|
||
| import RIO (ByteString, threadDelay) | ||
| import RIO (ByteString) | ||
|
|
||
| -- | Run with: | ||
| -- @TASTY_PATTERN='/RPC Transaction Submit/' cabal test cardano-testnet-test@ | ||
|
|
@@ -54,11 +56,13 @@ hprop_rpc_transaction = integrationRetryWorkspace 2 "rpc-tx" $ \tempAbsBasePath' | |
| addrInEra = AsAddressInEra eraProxy | ||
|
|
||
| TestnetRuntime | ||
| { testnetNodes = node0 : _ | ||
| { configurationFile | ||
| , testnetNodes = node0 : _ | ||
| , wallets = wallet0@(PaymentKeyInfo _ addrTxt0) : (PaymentKeyInfo _ addrTxt1) : _ | ||
| } <- | ||
| createAndRunTestnet options def conf | ||
|
|
||
| epochStateView <- getEpochStateView configurationFile $ nodeSocketPath node0 | ||
| rpcSocket <- H.note . unFile $ nodeRpcSocketPath node0 | ||
|
|
||
| -- prepare tx inputs and output address | ||
|
|
@@ -116,40 +120,30 @@ hprop_rpc_transaction = integrationRetryWorkspace 2 "rpc-tx" $ \tempAbsBasePath' | |
|
|
||
| H.noteShowPretty_ utxosResponse | ||
|
|
||
| (utxos, submitResponse) <- H.noteShowM . H.evalIO . Rpc.withConnection def rpcServer $ \conn -> do | ||
| submitResponse <- | ||
| liftBaseOp (Rpc.withConnection def rpcServer) $ \conn -> do | ||
| submitResponse <- H.noteShowM . H.evalIO $ | ||
| Rpc.nonStreaming conn (Rpc.rpc @(Rpc.Protobuf UtxoRpc.SubmitService "submitTx")) $ | ||
| def & U5c.tx .~ (def & U5c.raw .~ serialiseToCBOR signedTx) | ||
|
|
||
| fix $ \loop -> do | ||
| resp <- Rpc.nonStreaming conn (Rpc.rpc @(Rpc.Protobuf UtxoRpc.QueryService "readParams")) def | ||
| submittedTxId <- H.leftFail . deserialiseFromRawBytes AsTxId $ submitResponse ^. U5c.ref | ||
|
|
||
| let previousBlockNo = pparamsResponse ^. U5c.ledgerTip . U5c.height | ||
| currentBlockNo = resp ^. U5c.ledgerTip . U5c.height | ||
| -- wait for 2 blocks | ||
| when (previousBlockNo + 1 >= currentBlockNo) $ do | ||
| threadDelay 500_000 | ||
| loop | ||
| H.note_ "Ensure that submitted transaction ID is in the submitted transactions list" | ||
| txId' === submittedTxId | ||
|
|
||
| -- TODO use searchUtxos when available | ||
| utxos <- | ||
| Rpc.nonStreaming conn (Rpc.rpc @(Rpc.Protobuf UtxoRpc.QueryService "readUtxos")) def | ||
| pure (utxos, submitResponse) | ||
|
|
||
| submittedTxId <- H.leftFail . deserialiseFromRawBytes AsTxId $ submitResponse ^. U5c.ref | ||
|
|
||
| H.note_ "Ensure that submitted transaction ID is in the submitted transactions list" | ||
| txId' === submittedTxId | ||
|
|
||
| H.note_ $ "Ensure that there are 2 UTXOs in the address " <> show addrTxt1 | ||
| utxosForAddress <- H.noteShowM . flip filterM (utxos ^. U5c.items) $ \utxo -> do | ||
| utxoAddress <- deserialiseAddressBs addrInEra $ utxo ^. U5c.cardano . U5c.address | ||
| pure $ addr1 == utxoAddress | ||
| 2 === length utxosForAddress | ||
|
|
||
| let outputsAmounts = map (^. U5c.cardano . U5c.coin) utxosForAddress | ||
| H.note_ $ "Ensure that the output sent is one of the utxos for the address " <> show addrTxt1 | ||
| H.assertWith outputsAmounts $ elem (inject amount) | ||
| H.note_ $ "Ensure that there are 2 UTXOs in the address " <> show addrTxt1 | ||
| utxosForAddress <- retryUntilM epochStateView (WaitForBlocks 10) | ||
| (do utxos <- H.evalIO $ | ||
| Rpc.nonStreaming conn (Rpc.rpc @(Rpc.Protobuf UtxoRpc.QueryService "readUtxos")) def | ||
| flip filterM (utxos ^. U5c.items) $ \utxo -> do | ||
| utxoAddress <- deserialiseAddressBs addrInEra $ utxo ^. U5c.cardano . U5c.address | ||
| pure $ addr1 == utxoAddress | ||
| ) | ||
| (\xs -> length xs == 2) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This assumes the testnet generated address has a single UTxO, and it seems that is indeed the case. But I think it would be more robust to either use a freshly generated address or check the assumption. Also the last assertion ends up being Also, now I realise this is really not from this PR, it was in the code already |
||
|
|
||
| let outputsAmounts = map (^. U5c.cardano . U5c.coin) utxosForAddress | ||
| H.note_ $ "Ensure that the output sent is one of the utxos for the address " <> show addrTxt1 | ||
| H.assertWith outputsAmounts $ elem (inject amount) | ||
|
|
||
| txoRefToTxIn :: (HasCallStack, MonadTest m) => Proto UtxoRpc.TxoRef -> m TxIn | ||
| txoRefToTxIn r = withFrozenCallStack $ do | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The note text says this checks that the submitted tx id is "in the submitted transactions list", but the assertion only compares the locally computed tx id to the id returned by
submitTx. Consider updating the message to reflect what’s actually being verified (or add an RPC query to check presence in a list if that’s the intent).