1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
//! ## Ordered Channel Test
//!
//! This walkthrough illustrates the behavior or an integration test that makes
//! use of the `BinaryChannelTest` trait. This trait is used for test cases that
//! require two running full nodes connected via IBC channels with completed
//! handshakes. The relayer is initialized with chain handles and foreign clients
//! for interfacing with the running full nodes.
//!
//! The test itself checks that transactions sent over an ordered channel are
//! successfully relayed and received by the intended recipient, even when the
//! transaction was queued up to be sent before the relayer was started.
//!
//! The test in most of its entirety (some parts omitted for brevity) looks like this:
//!
//! ```no_run
//! # use ibc_test_framework::ibc::denom::derive_ibc_denom;
//! # use ibc_test_framework::prelude::*;
//! # use ibc_test_framework::util::random::random_u128_range;
//!
//! #[test]
//! fn test_ordered_channel() -> Result<(), Error> {
//! run_binary_channel_test(&OrderedChannelTest)
//! }
//!
//! pub struct OrderedChannelTest;
//!
//! impl TestOverrides for OrderedChannelTest {
//! fn modify_relayer_config(&self, config: &mut Config) {
//! config.mode.packets.clear_on_start = false;
//! config.mode.packets.clear_interval = 0;
//! }
//!
//! fn should_spawn_supervisor(&self) -> bool {
//! false
//! }
//!
//! fn channel_order(&self) -> Ordering {
//! Ordering::Ordered
//! }
//! }
//!
//! impl BinaryChannelTest for OrderedChannelTest {
//! fn run<ChainA: ChainHandle, ChainB: ChainHandle>(
//! &self,
//! _config: &TestConfig,
//! relayer: RelayerDriver,
//! chains: ConnectedChains<ChainA, ChainB>,
//! channel: ConnectedChannel<ChainA, ChainB>,
//! ) -> Result<(), Error> {
//! let denom_a = chains.node_a.denom();
//!
//! let wallet_a = chains.node_a.wallets().user1().cloned();
//! let wallet_b = chains.node_b.wallets().user1().cloned();
//!
//! let balance_a = chains
//! .node_a
//! .chain_driver()
//! .query_balance(&wallet_a.address(), &denom_a)?;
//!
//! let amount1 = random_u128_range(1000, 5000);
//!
//! info!(
//! "Performing IBC transfer with amount {}, which should be relayed because it's an ordered channel",
//! amount1
//! );
//!
//! chains.node_a.chain_driver().ibc_transfer_token(
//! &channel.port_a.as_ref(),
//! &channel.channel_id_a.as_ref(),
//! &wallet_a.as_ref(),
//! &wallet_b.address(),
//! &denom_a.with_amount(amount1).as_ref(),
//! )?;
//!
//! sleep(Duration::from_secs(1));
//!
//! relayer.with_supervisor(|| {
//! sleep(Duration::from_secs(1));
//!
//! let amount2 = random_u128_range(1000, 5000);
//!
//! info!(
//! "Performing IBC transfer with amount {}, which should be relayed",
//! amount2
//! );
//!
//! chains.node_a.chain_driver().ibc_transfer_token(
//! &channel.port_a.as_ref(),
//! &channel.channel_id_a.as_ref(),
//! &wallet_a.as_ref(),
//! &wallet_b.address(),
//! &denom_a.with_amount(amount2).as_ref(),
//! )?;
//!
//! sleep(Duration::from_secs(1));
//!
//! let denom_b = derive_ibc_denom(
//! &channel.port_b.as_ref(),
//! &channel.channel_id_b.as_ref(),
//! &denom_a,
//! )?;
//!
//! chains.node_a.chain_driver().assert_eventual_wallet_amount(
//! &wallet_a.address(),
//! &(balance_a - amount1 - amount2).as_ref(),
//! )?;
//!
//! chains.node_b.chain_driver().assert_eventual_wallet_amount(
//! &wallet_b.address(),
//! &denom_b.with_amount(amount1 + amount2).as_ref(),
//! )?;
//!
//! Ok(())
//! })
//! }
//! }
//! ```
//!
//! The test is run by calling the `run_binary_channel_test` function, passing it
//! a struct, `OrderdChannelTest`, upon which we implement the `TestOverrides`
//! trait in order to configure the behavior of the test. We define the
//! `should_spawn_supervisor` function to have it return false in order to not
//! automatically spawn a supervisor when the relayer is initialized; this is
//! necessary in order to queue up an IBC transaction such that it is pending
//! until the relayer is initialized, not before that. We also define the
//! `channel_order` function in order to set the initialized channels to the
//! ordered variant; by default, the test will initialize unordered channels.
//! Lastly, we define the `modify_relayer_config` function in order to toggle off
//! the `clear_on_start` option, as well as set the `clear_interval` option to 0.
//! Setting these options means the relayer itself will not relay any packets
//! that were pending before the relayer started; we want to ensure that the
//! behavior of the ordered channel is what is causing the pending transaction
//! to be relayed.
//!
//! The logic of the test itself is defined in the `run` function of the
//! `BinaryChannelTest` trait. In this function, we first set up the two wallets,
//! the sending wallet, `wallet_a`, which is associated with chain A, and the
//! receiving wallet, `wallet_b`, which is associated iwth chain B. The balance
//! of `wallet_a` is also saved. An IBC transfer is then made from chain A to chain
//! B. At this point, because no relayer has been initialized yet, the transaction
//! is in a pending state.
//!
//! At this point, a relayer instance is initialized. The first thing it does is
//! perform another IBC transfer from chain A to chain B. The test then asserts
//! that `wallet_a` was indeed debited appropriately, that both transactions went
//! through due to the behavior of the ordered channel. It then checks `wallet_b`'s
//! balance to ensure that it was credited with the expected amount. If the assertions
//! pass, we can confident that the ordered channel is indeed exhibiting the expected
//! behavior of picking up pending transactions that were queued up before the relayer
//! was started.
//!
//! You can find the file containing this test at `tools/integration-test/src/tests/ordered_channel.rs`.