From 1373792064f94660748c2bfdd5015c4ac5063b78 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Fri, 6 May 2022 13:14:57 +0200 Subject: [PATCH 1/9] Add simple_send_tx Introduce TxConfig Add test constructor for TxConfig Add send_tx method on ChainDriver Accept Wallet instead of WalletAddress for transferring tokens Implement ibc_token_transfer Simplify ibc_token_transfer Token transfer using ibc_token_transfer is now working --- Cargo.lock | 2 + relayer/src/chain/cosmos.rs | 20 ++- relayer/src/chain/cosmos/batch.rs | 60 ++++---- relayer/src/chain/cosmos/encode.rs | 24 +++- relayer/src/chain/cosmos/estimate.rs | 13 +- relayer/src/chain/cosmos/query/account.rs | 5 +- relayer/src/chain/cosmos/retry.rs | 30 ++-- relayer/src/chain/cosmos/tx.rs | 35 +++-- relayer/src/chain/cosmos/types/config.rs | 42 ++++++ relayer/src/chain/cosmos/types/gas.rs | 7 +- relayer/src/chain/cosmos/types/mod.rs | 1 + relayer/src/transfer.rs | 38 ++++- .../src/tests/clear_packet.rs | 4 +- .../src/tests/client_expiration.rs | 4 +- .../src/tests/connection_delay.rs | 2 +- tools/integration-test/src/tests/ica.rs | 2 +- tools/integration-test/src/tests/memo.rs | 2 +- .../src/tests/ordered_channel.rs | 4 +- .../src/tests/query_packet.rs | 4 +- .../integration-test/src/tests/supervisor.rs | 6 +- .../src/tests/ternary_transfer.rs | 8 +- tools/integration-test/src/tests/transfer.rs | 15 +- tools/test-framework/Cargo.toml | 2 + tools/test-framework/src/bootstrap/init.rs | 3 + tools/test-framework/src/chain/builder.rs | 21 ++- tools/test-framework/src/chain/driver.rs | 26 ++++ .../test-framework/src/chain/driver/tagged.rs | 38 ++++- .../src/chain/driver/transfer.rs | 19 ++- tools/test-framework/src/framework/base.rs | 7 +- tools/test-framework/src/relayer/mod.rs | 1 + tools/test-framework/src/relayer/transfer.rs | 73 +++++++++- tools/test-framework/src/relayer/tx.rs | 132 ++++++++++++++++++ tools/test-framework/src/types/config.rs | 2 + tools/test-framework/src/types/single/node.rs | 6 +- tools/test-framework/src/types/tagged/dual.rs | 3 + tools/test-framework/src/types/tagged/mono.rs | 3 + 36 files changed, 540 insertions(+), 124 deletions(-) create mode 100644 relayer/src/chain/cosmos/types/config.rs create mode 100644 tools/test-framework/src/relayer/tx.rs diff --git a/Cargo.lock b/Cargo.lock index d906e54f69..2b49c0b2eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1627,12 +1627,14 @@ dependencies = [ name = "ibc-test-framework" version = "0.14.1" dependencies = [ + "async-trait", "color-eyre", "crossbeam-channel 0.5.4", "env_logger", "eyre", "flex-error", "hex", + "http", "ibc", "ibc-proto", "ibc-relayer", diff --git a/relayer/src/chain/cosmos.rs b/relayer/src/chain/cosmos.rs index b59343a661..21f99edf08 100644 --- a/relayer/src/chain/cosmos.rs +++ b/relayer/src/chain/cosmos.rs @@ -72,6 +72,7 @@ use crate::chain::cosmos::query::status::query_status; use crate::chain::cosmos::query::tx::query_txs; use crate::chain::cosmos::query::{abci_query, fetch_version_specs, packet_query}; use crate::chain::cosmos::types::account::Account; +use crate::chain::cosmos::types::config::TxConfig; use crate::chain::cosmos::types::gas::{default_gas_from_config, max_gas_from_config}; use crate::chain::tx::TrackedMsgs; use crate::chain::{ChainEndpoint, HealthCheck}; @@ -103,6 +104,7 @@ pub const GENESIS_MAX_BYTES_MAX_FRACTION: f64 = 0.9; pub struct CosmosSdkChain { config: ChainConfig, + tx_config: TxConfig, rpc_client: HttpClient, grpc_addr: Uri, rt: Arc, @@ -402,12 +404,12 @@ impl CosmosSdkChain { get_or_fetch_account(&self.grpc_addr, &key_entry.account, &mut self.account).await?; send_batched_messages_and_wait_commit( - &self.config, - &self.rpc_client, - &self.config.rpc_addr, - &self.grpc_addr, + &self.tx_config, + self.config.max_msg_num, + self.config.max_tx_size, &key_entry, account, + &self.config.address_type, &self.config.memo_prefix, proto_msgs, ) @@ -431,11 +433,12 @@ impl CosmosSdkChain { get_or_fetch_account(&self.grpc_addr, &key_entry.account, &mut self.account).await?; send_batched_messages_and_wait_check_tx( - &self.config, - &self.rpc_client, - &self.grpc_addr, + &self.tx_config, + self.config.max_msg_num, + self.config.max_tx_size, &key_entry, account, + &self.config.address_type, &self.config.memo_prefix, proto_msgs, ) @@ -461,6 +464,8 @@ impl ChainEndpoint for CosmosSdkChain { let grpc_addr = Uri::from_str(&config.grpc_addr.to_string()) .map_err(|e| Error::invalid_uri(config.grpc_addr.to_string(), e))?; + let tx_config = TxConfig::try_from(&config)?; + // Retrieve the version specification of this chain let chain = Self { @@ -470,6 +475,7 @@ impl ChainEndpoint for CosmosSdkChain { rt, keybase, account: None, + tx_config, }; Ok(chain) diff --git a/relayer/src/chain/cosmos/batch.rs b/relayer/src/chain/cosmos/batch.rs index 6a36fb8639..075c574625 100644 --- a/relayer/src/chain/cosmos/batch.rs +++ b/relayer/src/chain/cosmos/batch.rs @@ -2,25 +2,24 @@ use ibc::events::IbcEvent; use ibc_proto::google::protobuf::Any; use prost::Message; use tendermint_rpc::endpoint::broadcast::tx_sync::Response; -use tendermint_rpc::{HttpClient, Url}; -use tonic::codegen::http::Uri; use crate::chain::cosmos::retry::send_tx_with_account_sequence_retry; use crate::chain::cosmos::types::account::Account; +use crate::chain::cosmos::types::config::TxConfig; use crate::chain::cosmos::types::tx::TxSyncResult; use crate::chain::cosmos::wait::wait_for_block_commits; -use crate::config::types::Memo; -use crate::config::ChainConfig; +use crate::config::types::{MaxMsgNum, MaxTxSize, Memo}; +use crate::config::AddressType; use crate::error::Error; use crate::keyring::KeyEntry; pub async fn send_batched_messages_and_wait_commit( - config: &ChainConfig, - rpc_client: &HttpClient, - rpc_address: &Url, - grpc_address: &Uri, + config: &TxConfig, + max_msg_num: MaxMsgNum, + max_tx_size: MaxTxSize, key_entry: &KeyEntry, account: &mut Account, + address_type: &AddressType, tx_memo: &Memo, messages: Vec, ) -> Result, Error> { @@ -30,19 +29,20 @@ pub async fn send_batched_messages_and_wait_commit( let mut tx_sync_results = send_messages_as_batches( config, - rpc_client, - grpc_address, + max_msg_num, + max_tx_size, key_entry, account, + address_type, tx_memo, messages, ) .await?; wait_for_block_commits( - &config.id, - rpc_client, - rpc_address, + &config.chain_id, + &config.rpc_client, + &config.rpc_address, &config.rpc_timeout, &mut tx_sync_results, ) @@ -57,11 +57,12 @@ pub async fn send_batched_messages_and_wait_commit( } pub async fn send_batched_messages_and_wait_check_tx( - config: &ChainConfig, - rpc_client: &HttpClient, - grpc_address: &Uri, + config: &TxConfig, + max_msg_num: MaxMsgNum, + max_tx_size: MaxTxSize, key_entry: &KeyEntry, account: &mut Account, + address_type: &AddressType, tx_memo: &Memo, messages: Vec, ) -> Result, Error> { @@ -69,17 +70,16 @@ pub async fn send_batched_messages_and_wait_check_tx( return Ok(Vec::new()); } - let batches = batch_messages(config, messages)?; + let batches = batch_messages(max_msg_num, max_tx_size, messages)?; let mut responses = Vec::new(); for batch in batches { let response = send_tx_with_account_sequence_retry( config, - rpc_client, - grpc_address, key_entry, account, + address_type, tx_memo, batch, 0, @@ -93,11 +93,12 @@ pub async fn send_batched_messages_and_wait_check_tx( } async fn send_messages_as_batches( - config: &ChainConfig, - rpc_client: &HttpClient, - grpc_address: &Uri, + config: &TxConfig, + max_msg_num: MaxMsgNum, + max_tx_size: MaxTxSize, key_entry: &KeyEntry, account: &mut Account, + address_type: &AddressType, tx_memo: &Memo, messages: Vec, ) -> Result, Error> { @@ -105,7 +106,7 @@ async fn send_messages_as_batches( return Ok(Vec::new()); } - let batches = batch_messages(config, messages)?; + let batches = batch_messages(max_msg_num, max_tx_size, messages)?; let mut tx_sync_results = Vec::new(); @@ -114,10 +115,9 @@ async fn send_messages_as_batches( let response = send_tx_with_account_sequence_retry( config, - rpc_client, - grpc_address, key_entry, account, + address_type, tx_memo, batch, 0, @@ -135,9 +135,13 @@ async fn send_messages_as_batches( Ok(tx_sync_results) } -fn batch_messages(config: &ChainConfig, messages: Vec) -> Result>, Error> { - let max_message_count = config.max_msg_num.0; - let max_tx_size = config.max_tx_size.into(); +fn batch_messages( + max_msg_num: MaxMsgNum, + max_tx_size: MaxTxSize, + messages: Vec, +) -> Result>, Error> { + let max_message_count = max_msg_num.0; + let max_tx_size = max_tx_size.into(); let mut batches = vec![]; diff --git a/relayer/src/chain/cosmos/encode.rs b/relayer/src/chain/cosmos/encode.rs index fcd20f28a0..1e7ee1fc97 100644 --- a/relayer/src/chain/cosmos/encode.rs +++ b/relayer/src/chain/cosmos/encode.rs @@ -7,22 +7,31 @@ use ibc_proto::google::protobuf::Any; use tendermint::account::Id as AccountId; use crate::chain::cosmos::types::account::{Account, AccountNumber, AccountSequence}; +use crate::chain::cosmos::types::config::TxConfig; use crate::chain::cosmos::types::tx::SignedTx; use crate::config::types::Memo; use crate::config::AddressType; -use crate::config::ChainConfig; use crate::error::Error; use crate::keyring::{sign_message, KeyEntry}; pub fn sign_and_encode_tx( - config: &ChainConfig, + config: &TxConfig, key_entry: &KeyEntry, account: &Account, + address_type: &AddressType, tx_memo: &Memo, messages: Vec, fee: &Fee, ) -> Result, Error> { - let signed_tx = sign_tx(config, key_entry, account, tx_memo, messages, fee)?; + let signed_tx = sign_tx( + config, + key_entry, + account, + address_type, + tx_memo, + messages, + fee, + )?; let tx_raw = TxRaw { body_bytes: signed_tx.body_bytes, @@ -34,25 +43,26 @@ pub fn sign_and_encode_tx( } pub fn sign_tx( - config: &ChainConfig, + config: &TxConfig, key_entry: &KeyEntry, account: &Account, + address_type: &AddressType, tx_memo: &Memo, messages: Vec, fee: &Fee, ) -> Result { let key_bytes = encode_key_bytes(key_entry)?; - let signer = encode_signer_info(&config.address_type, account.sequence, key_bytes)?; + let signer = encode_signer_info(address_type, account.sequence, key_bytes)?; let (body, body_bytes) = tx_body_and_bytes(messages, tx_memo)?; let (auth_info, auth_info_bytes) = auth_info_and_bytes(signer, fee.clone())?; let signed_doc = encode_sign_doc( - &config.id, + &config.chain_id, key_entry, - &config.address_type, + address_type, account.number, auth_info_bytes.clone(), body_bytes.clone(), diff --git a/relayer/src/chain/cosmos/estimate.rs b/relayer/src/chain/cosmos/estimate.rs index 22faf937ea..d09e205f46 100644 --- a/relayer/src/chain/cosmos/estimate.rs +++ b/relayer/src/chain/cosmos/estimate.rs @@ -8,21 +8,22 @@ use crate::chain::cosmos::encode::sign_tx; use crate::chain::cosmos::gas::{gas_amount_to_fees, PrettyFee}; use crate::chain::cosmos::simulate::send_tx_simulate; use crate::chain::cosmos::types::account::Account; +use crate::chain::cosmos::types::config::TxConfig; use crate::chain::cosmos::types::gas::GasConfig; use crate::config::types::Memo; -use crate::config::ChainConfig; +use crate::config::AddressType; use crate::error::Error; use crate::keyring::KeyEntry; pub async fn estimate_tx_fees( - config: &ChainConfig, - grpc_address: &Uri, + config: &TxConfig, key_entry: &KeyEntry, account: &Account, + address_type: &AddressType, tx_memo: &Memo, messages: Vec, ) -> Result { - let gas_config = GasConfig::from_chain_config(config); + let gas_config = &config.gas_config; debug!( "max fee, for use in tx simulation: {}", @@ -33,6 +34,7 @@ pub async fn estimate_tx_fees( config, key_entry, account, + address_type, tx_memo, messages, &gas_config.max_fee, @@ -44,7 +46,8 @@ pub async fn estimate_tx_fees( signatures: signed_tx.signatures, }; - let estimated_fee = estimate_fee_with_tx(&gas_config, grpc_address, &config.id, tx).await?; + let estimated_fee = + estimate_fee_with_tx(gas_config, &config.grpc_address, &config.chain_id, tx).await?; Ok(estimated_fee) } diff --git a/relayer/src/chain/cosmos/query/account.rs b/relayer/src/chain/cosmos/query/account.rs index b7d9f43b9d..15cdd8f467 100644 --- a/relayer/src/chain/cosmos/query/account.rs +++ b/relayer/src/chain/cosmos/query/account.rs @@ -49,7 +49,10 @@ pub async fn refresh_account<'a>( } /// Uses the GRPC client to retrieve the account sequence -async fn query_account(grpc_address: &Uri, account_address: &str) -> Result { +pub async fn query_account( + grpc_address: &Uri, + account_address: &str, +) -> Result { let mut client = QueryClient::connect(grpc_address.clone()) .await .map_err(Error::grpc_transport)?; diff --git a/relayer/src/chain/cosmos/retry.rs b/relayer/src/chain/cosmos/retry.rs index 9960455969..9a9c4f2988 100644 --- a/relayer/src/chain/cosmos/retry.rs +++ b/relayer/src/chain/cosmos/retry.rs @@ -5,15 +5,14 @@ use ibc_proto::google::protobuf::Any; use std::thread; use tendermint::abci::Code; use tendermint_rpc::endpoint::broadcast::tx_sync::Response; -use tendermint_rpc::HttpClient; -use tonic::codegen::http::Uri; use tracing::{debug, error, span, warn, Level}; use crate::chain::cosmos::query::account::refresh_account; use crate::chain::cosmos::tx::estimate_fee_and_send_tx; use crate::chain::cosmos::types::account::Account; +use crate::chain::cosmos::types::config::TxConfig; use crate::config::types::Memo; -use crate::config::ChainConfig; +use crate::config::AddressType; use crate::error::Error; use crate::keyring::KeyEntry; use crate::sdk_error::sdk_error_from_tx_sync_error_code; @@ -47,25 +46,23 @@ const INCORRECT_ACCOUNT_SEQUENCE_ERR: u32 = 32; /// nonetheless at the worker `step` level). Upon case #2, we retry /// submitting the same transaction. pub async fn send_tx_with_account_sequence_retry( - config: &ChainConfig, - rpc_client: &HttpClient, - grpc_address: &Uri, + config: &TxConfig, key_entry: &KeyEntry, account: &mut Account, + address_type: &AddressType, tx_memo: &Memo, messages: Vec, retry_counter: u64, ) -> Result { crate::time!("send_tx_with_account_sequence_retry"); let _span = - span!(Level::ERROR, "send_tx_with_account_sequence_retry", id = %config.id).entered(); + span!(Level::ERROR, "send_tx_with_account_sequence_retry", id = %config.chain_id).entered(); do_send_tx_with_account_sequence_retry( config, - rpc_client, - grpc_address, key_entry, account, + address_type, tx_memo, messages, retry_counter, @@ -77,11 +74,10 @@ pub async fn send_tx_with_account_sequence_retry( // do not currently support recursive async functions behind the // `async fn` syntactic sugar. fn do_send_tx_with_account_sequence_retry<'a>( - config: &'a ChainConfig, - rpc_client: &'a HttpClient, - grpc_address: &'a Uri, + config: &'a TxConfig, key_entry: &'a KeyEntry, account: &'a mut Account, + address_type: &'a AddressType, tx_memo: &'a Memo, messages: Vec, retry_counter: u64, @@ -95,10 +91,9 @@ fn do_send_tx_with_account_sequence_retry<'a>( let tx_result = estimate_fee_and_send_tx( config, - rpc_client, - grpc_address, key_entry, account, + address_type, tx_memo, messages.clone(), ) @@ -113,7 +108,7 @@ fn do_send_tx_with_account_sequence_retry<'a>( // retry at the worker-level will handle retrying. Err(e) if mismatching_account_sequence_number(&e) => { warn!("failed at estimate_gas step mismatching account sequence: dropping the tx & refreshing account sequence number"); - refresh_account(grpc_address, &key_entry.account, account).await?; + refresh_account(&config.grpc_address, &key_entry.account, account).await?; // Note: propagating error here can lead to bug & dropped packets: // https://github.com/informalsystems/ibc-rs/issues/1153 // But periodic packet clearing will catch any dropped packets. @@ -130,15 +125,14 @@ fn do_send_tx_with_account_sequence_retry<'a>( let backoff = retry_counter * BACKOFF_MULTIPLIER_ACCOUNT_SEQUENCE_RETRY; thread::sleep(Duration::from_millis(backoff)); - refresh_account(grpc_address, &key_entry.account, account).await?; + refresh_account(&config.grpc_address, &key_entry.account, account).await?; // Now retry. do_send_tx_with_account_sequence_retry( config, - rpc_client, - grpc_address, key_entry, account, + address_type, tx_memo, messages, retry_counter + 1, diff --git a/relayer/src/chain/cosmos/tx.rs b/relayer/src/chain/cosmos/tx.rs index 0ac651d270..b534a0f2a9 100644 --- a/relayer/src/chain/cosmos/tx.rs +++ b/relayer/src/chain/cosmos/tx.rs @@ -2,53 +2,66 @@ use ibc_proto::cosmos::tx::v1beta1::Fee; use ibc_proto::google::protobuf::Any; use tendermint_rpc::endpoint::broadcast::tx_sync::Response; use tendermint_rpc::{Client, HttpClient, Url}; -use tonic::codegen::http::Uri; use crate::chain::cosmos::encode::sign_and_encode_tx; use crate::chain::cosmos::estimate::estimate_tx_fees; use crate::chain::cosmos::types::account::Account; +use crate::chain::cosmos::types::config::TxConfig; use crate::config::types::Memo; -use crate::config::ChainConfig; +use crate::config::AddressType; use crate::error::Error; use crate::keyring::KeyEntry; pub async fn estimate_fee_and_send_tx( - config: &ChainConfig, - rpc_client: &HttpClient, - grpc_address: &Uri, + config: &TxConfig, key_entry: &KeyEntry, account: &Account, + address_type: &AddressType, tx_memo: &Memo, messages: Vec, ) -> Result { let fee = estimate_tx_fees( config, - grpc_address, key_entry, account, + address_type, tx_memo, messages.clone(), ) .await?; send_tx_with_fee( - config, rpc_client, key_entry, account, tx_memo, messages, &fee, + config, + key_entry, + account, + address_type, + tx_memo, + messages, + &fee, ) .await } async fn send_tx_with_fee( - config: &ChainConfig, - rpc_client: &HttpClient, + config: &TxConfig, key_entry: &KeyEntry, account: &Account, + address_type: &AddressType, tx_memo: &Memo, messages: Vec, fee: &Fee, ) -> Result { - let tx_bytes = sign_and_encode_tx(config, key_entry, account, tx_memo, messages, fee)?; + let tx_bytes = sign_and_encode_tx( + config, + key_entry, + account, + address_type, + tx_memo, + messages, + fee, + )?; - let response = broadcast_tx_sync(rpc_client, &config.rpc_addr, tx_bytes).await?; + let response = broadcast_tx_sync(&config.rpc_client, &config.rpc_address, tx_bytes).await?; Ok(response) } diff --git a/relayer/src/chain/cosmos/types/config.rs b/relayer/src/chain/cosmos/types/config.rs new file mode 100644 index 0000000000..34bdd7fc06 --- /dev/null +++ b/relayer/src/chain/cosmos/types/config.rs @@ -0,0 +1,42 @@ +use core::str::FromStr; +use core::time::Duration; +use http::Uri; +use ibc::core::ics24_host::identifier::ChainId; +use tendermint_rpc::{HttpClient, Url}; + +use crate::chain::cosmos::types::gas::GasConfig; +use crate::config::ChainConfig; +use crate::error::Error; + +#[derive(Debug, Clone)] +pub struct TxConfig { + pub chain_id: ChainId, + pub gas_config: GasConfig, + pub rpc_client: HttpClient, + pub rpc_address: Url, + pub grpc_address: Uri, + pub rpc_timeout: Duration, +} + +impl<'a> TryFrom<&'a ChainConfig> for TxConfig { + type Error = Error; + + fn try_from(config: &'a ChainConfig) -> Result { + let rpc_client = HttpClient::new(config.rpc_addr.clone()) + .map_err(|e| Error::rpc(config.rpc_addr.clone(), e))?; + + let grpc_address = Uri::from_str(&config.grpc_addr.to_string()) + .map_err(|e| Error::invalid_uri(config.grpc_addr.to_string(), e))?; + + let gas_config = GasConfig::from(config); + + Ok(Self { + chain_id: config.id.clone(), + gas_config, + rpc_client, + rpc_address: config.rpc_addr.clone(), + grpc_address, + rpc_timeout: config.rpc_timeout, + }) + } +} diff --git a/relayer/src/chain/cosmos/types/gas.rs b/relayer/src/chain/cosmos/types/gas.rs index 55625dab3c..79e1001772 100644 --- a/relayer/src/chain/cosmos/types/gas.rs +++ b/relayer/src/chain/cosmos/types/gas.rs @@ -11,6 +11,7 @@ const DEFAULT_GAS_PRICE_ADJUSTMENT: f64 = 0.1; const DEFAULT_FEE_GRANTER: &str = ""; +#[derive(Debug, Clone)] pub struct GasConfig { pub default_gas: u64, pub max_gas: u64, @@ -20,9 +21,9 @@ pub struct GasConfig { pub fee_granter: String, } -impl GasConfig { - pub fn from_chain_config(config: &ChainConfig) -> GasConfig { - GasConfig { +impl<'a> From<&'a ChainConfig> for GasConfig { + fn from(config: &'a ChainConfig) -> Self { + Self { default_gas: default_gas_from_config(config), max_gas: max_gas_from_config(config), gas_adjustment: gas_adjustment_from_config(config), diff --git a/relayer/src/chain/cosmos/types/mod.rs b/relayer/src/chain/cosmos/types/mod.rs index 4d91a59966..b8fc7adc9d 100644 --- a/relayer/src/chain/cosmos/types/mod.rs +++ b/relayer/src/chain/cosmos/types/mod.rs @@ -1,3 +1,4 @@ pub mod account; +pub mod config; pub mod gas; pub mod tx; diff --git a/relayer/src/transfer.rs b/relayer/src/transfer.rs index 111f862ac9..e44b04cda9 100644 --- a/relayer/src/transfer.rs +++ b/relayer/src/transfer.rs @@ -6,9 +6,11 @@ use flex_error::{define_error, DetailOnly}; use ibc::applications::ics20_fungible_token_transfer::msgs::transfer::MsgTransfer; use ibc::core::ics24_host::identifier::{ChainId, ChannelId, PortId}; use ibc::events::IbcEvent; +use ibc::signer::Signer; use ibc::timestamp::{Timestamp, TimestampOverflowError}; use ibc::tx_msg::Msg; use ibc::Height; +use ibc_proto::google::protobuf::Any; use uint::FromStrRadixErr; use crate::chain::handle::ChainHandle; @@ -75,6 +77,12 @@ impl FromStr for Amount { } } +impl From for Amount { + fn from(amount: u64) -> Self { + Self(amount.into()) + } +} + #[derive(Copy, Clone)] pub struct TransferTimeout { pub timeout_height: Height, @@ -129,6 +137,32 @@ pub struct TransferOptions { pub number_msgs: usize, } +pub fn build_transfer_message( + packet_src_port_id: PortId, + packet_src_channel_id: ChannelId, + amount: Amount, + denom: String, + sender: Signer, + receiver: Signer, + timeout_height: Height, + timeout_timestamp: Timestamp, +) -> Any { + let msg = MsgTransfer { + source_port: packet_src_port_id, + source_channel: packet_src_channel_id, + token: Some(ibc_proto::cosmos::base::v1beta1::Coin { + denom, + amount: amount.to_string(), + }), + sender, + receiver, + timeout_height, + timeout_timestamp, + }; + + msg.to_any() +} + pub fn build_and_send_transfer_messages( packet_src_chain: &SrcChain, // the chain whose account is debited packet_dst_chain: &DstChain, // the chain whose account eventually gets credited @@ -141,14 +175,14 @@ pub fn build_and_send_transfer_messages for TernaryIbcTransferTest { node_a.chain_driver().transfer_token( &channel_a_to_b.port_a.as_ref(), &channel_a_to_b.channel_id_a.as_ref(), - &wallet_a1.address(), + &wallet_a1.as_ref(), &wallet_b1.address(), a_to_b_amount, &denom_a, @@ -110,7 +110,7 @@ impl NaryChannelTest<3> for TernaryIbcTransferTest { node_b.chain_driver().transfer_token( &channel_b_to_c.port_a.as_ref(), &channel_b_to_c.channel_id_a.as_ref(), - &wallet_b1.address(), + &wallet_b1.as_ref(), &wallet_c1.address(), b_to_c_amount, &denom_a_to_b.as_ref(), @@ -148,7 +148,7 @@ impl NaryChannelTest<3> for TernaryIbcTransferTest { node_c.chain_driver().transfer_token( &channel_c_to_a.port_a.as_ref(), &channel_c_to_a.channel_id_a.as_ref(), - &wallet_c1.address(), + &wallet_c1.as_ref(), &wallet_a1.address(), c_to_a_amount, &denom_a_to_c.as_ref(), @@ -178,7 +178,7 @@ impl NaryChannelTest<3> for TernaryIbcTransferTest { node_c.chain_driver().transfer_token( &channel_b_to_c.port_b.as_ref(), &channel_b_to_c.channel_id_b.as_ref(), - &wallet_c1.address(), + &wallet_c1.as_ref(), &wallet_b2.address(), c_to_b_amount, &denom_a_to_c.as_ref(), diff --git a/tools/integration-test/src/tests/transfer.rs b/tools/integration-test/src/tests/transfer.rs index 53e5d0c844..4bcd86a2d8 100644 --- a/tools/integration-test/src/tests/transfer.rs +++ b/tools/integration-test/src/tests/transfer.rs @@ -1,5 +1,6 @@ use ibc_test_framework::ibc::denom::derive_ibc_denom; use ibc_test_framework::prelude::*; +use ibc_test_framework::relayer::transfer::ibc_token_transfer; use ibc_test_framework::util::random::random_u64_range; #[test] @@ -70,13 +71,14 @@ impl BinaryChannelTest for IbcTransferTest { denom_a ); - chains.node_a.chain_driver().transfer_token( + ibc_token_transfer( + &chains.node_a.chain_driver(), &channel.port_a.as_ref(), &channel.channel_id_a.as_ref(), - &wallet_a.address(), + &wallet_a.as_ref(), &wallet_b.address(), - a_to_b_amount, &denom_a, + a_to_b_amount, )?; let denom_b = derive_ibc_denom( @@ -123,13 +125,14 @@ impl BinaryChannelTest for IbcTransferTest { denom_b ); - chains.node_b.chain_driver().transfer_token( + ibc_token_transfer( + &chains.node_b.chain_driver(), &channel.port_b.as_ref(), &channel.channel_id_b.as_ref(), - &wallet_b.address(), + &wallet_b.as_ref(), &wallet_c.address(), - b_to_a_amount, &denom_b.as_ref(), + b_to_a_amount, )?; chains.node_b.chain_driver().assert_eventual_wallet_amount( diff --git a/tools/test-framework/Cargo.toml b/tools/test-framework/Cargo.toml index 1baec236bc..a1729b95f3 100644 --- a/tools/test-framework/Cargo.toml +++ b/tools/test-framework/Cargo.toml @@ -21,6 +21,8 @@ ibc-proto = { path = "../../proto" } tendermint = { version = "=0.23.7" } tendermint-rpc = { version = "=0.23.7", features = ["http-client", "websocket-client"] } +async-trait = "0.1.53" +http = "0.2.6" tokio = { version = "1.0", features = ["full"] } tracing = "0.1.34" tracing-subscriber = "0.3.11" diff --git a/tools/test-framework/src/bootstrap/init.rs b/tools/test-framework/src/bootstrap/init.rs index 0dfc120c62..ca5719b324 100644 --- a/tools/test-framework/src/bootstrap/init.rs +++ b/tools/test-framework/src/bootstrap/init.rs @@ -41,6 +41,8 @@ pub fn init_test() -> Result { let base_chain_store_dir = env::var("CHAIN_STORE_DIR").unwrap_or_else(|_| "data".to_string()); + let account_prefix = env::var("ACCOUNT_PREFIX").unwrap_or_else(|_| "cosmos".to_string()); + let chain_store_dir = format!("{}/test-{}", base_chain_store_dir, random_u32()); fs::create_dir_all(&chain_store_dir)?; @@ -55,6 +57,7 @@ pub fn init_test() -> Result { Ok(TestConfig { chain_command_path, chain_store_dir, + account_prefix, hang_on_fail, bootstrap_with_random_ids: true, }) diff --git a/tools/test-framework/src/chain/builder.rs b/tools/test-framework/src/chain/builder.rs index 91af6dcafc..ebbeacc42a 100644 --- a/tools/test-framework/src/chain/builder.rs +++ b/tools/test-framework/src/chain/builder.rs @@ -2,7 +2,9 @@ Builder construct that spawn new chains with some common parameters. */ +use alloc::sync::Arc; use ibc::core::ics24_host::identifier::ChainId; +use tokio::runtime::Runtime; use crate::chain::driver::ChainDriver; use crate::error::Error; @@ -31,26 +33,39 @@ pub struct ChainBuilder { The filesystem path to store the data files used by the chain. */ pub base_store_dir: String, + + pub account_prefix: String, + + pub runtime: Arc, } impl ChainBuilder { /** Create a new `ChainBuilder`. */ - pub fn new(command_path: &str, base_store_dir: &str) -> Self { + pub fn new( + command_path: &str, + base_store_dir: &str, + account_prefix: &str, + runtime: Arc, + ) -> Self { Self { command_path: command_path.to_string(), base_store_dir: base_store_dir.to_string(), + account_prefix: account_prefix.to_string(), + runtime, } } /** Create a `ChainBuilder` based on the provided [`TestConfig`]. */ - pub fn new_with_config(config: &TestConfig) -> Self { + pub fn new_with_config(config: &TestConfig, runtime: Arc) -> Self { Self::new( &config.chain_command_path, &format!("{}", config.chain_store_dir.display()), + &config.account_prefix, + runtime, ) } @@ -86,10 +101,12 @@ impl ChainBuilder { self.command_path.clone(), chain_id, home_path, + self.account_prefix.clone(), rpc_port, grpc_port, grpc_web_port, p2p_port, + self.runtime.clone(), )?; Ok(driver) diff --git a/tools/test-framework/src/chain/driver.rs b/tools/test-framework/src/chain/driver.rs index c1b925984e..18f0f3593b 100644 --- a/tools/test-framework/src/chain/driver.rs +++ b/tools/test-framework/src/chain/driver.rs @@ -5,6 +5,7 @@ use core::str::FromStr; use core::time::Duration; +use alloc::sync::Arc; use eyre::eyre; use semver::Version; use serde_json as json; @@ -12,16 +13,20 @@ use std::fs; use std::path::PathBuf; use std::process::{Command, Stdio}; use std::str; +use tokio::runtime::Runtime; use toml; use tracing::debug; use ibc::core::ics24_host::identifier::ChainId; +use ibc_proto::google::protobuf::Any; +use ibc_relayer::chain::cosmos::types::config::TxConfig; use ibc_relayer::keyring::{HDPath, KeyEntry, KeyFile}; use crate::chain::exec::{simple_exec, ExecOutput}; use crate::chain::version::get_chain_command_version; use crate::error::{handle_generic_error, Error}; use crate::ibc::denom::Denom; +use crate::relayer::tx::{new_tx_config_for_test, simple_send_tx}; use crate::types::env::{EnvWriter, ExportEnv}; use crate::types::process::ChildProcess; use crate::types::wallet::{Wallet, WalletAddress, WalletId}; @@ -82,6 +87,8 @@ pub struct ChainDriver { */ pub home_path: String, + pub account_prefix: String, + /** The port used for RPC. */ @@ -98,6 +105,10 @@ pub struct ChainDriver { The port used for P2P. (Currently unused other than for setup) */ pub p2p_port: u16, + + pub tx_config: TxConfig, + + pub runtime: Arc, } impl ExportEnv for ChainDriver { @@ -115,24 +126,35 @@ impl ChainDriver { command_path: String, chain_id: ChainId, home_path: String, + account_prefix: String, rpc_port: u16, grpc_port: u16, grpc_web_port: u16, p2p_port: u16, + runtime: Arc, ) -> Result { // Assume we're on Gaia 6 if we can't get a version // (eg. with `icad`, which returns an empty string). let command_version = get_chain_command_version(&command_path)?; + let tx_config = new_tx_config_for_test( + chain_id.clone(), + format!("http://localhost:{}", rpc_port), + format!("http://localhost:{}", grpc_port), + )?; + Ok(Self { command_path, command_version, chain_id, home_path, + account_prefix, rpc_port, grpc_port, grpc_web_port, p2p_port, + tx_config, + runtime, }) } @@ -480,6 +502,10 @@ impl ChainDriver { Ok(amount) } + pub async fn send_tx(&self, wallet: &Wallet, messages: Vec) -> Result<(), Error> { + simple_send_tx(&self.tx_config, &wallet.key, messages).await + } + /** Assert that a wallet should eventually have the expected amount in the given denomination. diff --git a/tools/test-framework/src/chain/driver/tagged.rs b/tools/test-framework/src/chain/driver/tagged.rs index 04ce2b9676..fdb7ff19c5 100644 --- a/tools/test-framework/src/chain/driver/tagged.rs +++ b/tools/test-framework/src/chain/driver/tagged.rs @@ -2,15 +2,17 @@ Methods for tagged version of the chain driver. */ +use async_trait::async_trait; +use ibc_proto::google::protobuf::Any; use serde::Serialize; use serde_json as json; use crate::error::Error; use crate::ibc::denom::Denom; use crate::prelude::TaggedConnectionIdRef; -use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef}; +use crate::types::id::{TaggedChainIdRef, TaggedChannelIdRef, TaggedPortIdRef}; use crate::types::tagged::*; -use crate::types::wallet::WalletAddress; +use crate::types::wallet::{Wallet, WalletAddress}; use super::interchain::{interchain_submit, query_interchain_account, register_interchain_account}; use super::query_txs::query_recipient_transactions; @@ -27,7 +29,16 @@ use super::ChainDriver; The tagged chain driver methods help ensure that the `ChainDriver` methods are used with the values associated to the correct chain. */ +#[async_trait] pub trait TaggedChainDriverExt { + fn chain_id(&self) -> TaggedChainIdRef; + + async fn send_tx( + &self, + wallet: &MonoTagged, + messages: Vec, + ) -> Result<(), Error>; + /** Tagged version of [`ChainDriver::query_balance`]. @@ -77,7 +88,7 @@ pub trait TaggedChainDriverExt { &self, port_id: &TaggedPortIdRef, channel_id: &TaggedChannelIdRef, - sender: &MonoTagged, + sender: &MonoTagged, recipient: &MonoTagged, amount: u64, denom: &MonoTagged, @@ -85,7 +96,7 @@ pub trait TaggedChainDriverExt { fn local_transfer_token( &self, - sender: &MonoTagged, + sender: &MonoTagged, recipient: &MonoTagged, amount: u64, denom: &MonoTagged, @@ -122,7 +133,20 @@ pub trait TaggedChainDriverExt { ) -> Result<(), Error>; } -impl<'a, Chain> TaggedChainDriverExt for MonoTagged { +#[async_trait] +impl<'a, Chain: Send> TaggedChainDriverExt for MonoTagged { + fn chain_id(&self) -> TaggedChainIdRef { + MonoTagged::new(&self.value().chain_id) + } + + async fn send_tx( + &self, + wallet: &MonoTagged, + messages: Vec, + ) -> Result<(), Error> { + self.value().send_tx(wallet.value(), messages).await + } + fn query_balance( &self, wallet_id: &MonoTagged, @@ -145,7 +169,7 @@ impl<'a, Chain> TaggedChainDriverExt for MonoTagged, channel_id: &TaggedChannelIdRef, - sender: &MonoTagged, + sender: &MonoTagged, recipient: &MonoTagged, amount: u64, denom: &MonoTagged, @@ -163,7 +187,7 @@ impl<'a, Chain> TaggedChainDriverExt for MonoTagged, + sender: &MonoTagged, recipient: &MonoTagged, amount: u64, denom: &MonoTagged, diff --git a/tools/test-framework/src/chain/driver/transfer.rs b/tools/test-framework/src/chain/driver/transfer.rs index 063213daa0..1d746fc5c1 100644 --- a/tools/test-framework/src/chain/driver/transfer.rs +++ b/tools/test-framework/src/chain/driver/transfer.rs @@ -6,7 +6,7 @@ use ibc::core::ics24_host::identifier::{ChannelId, PortId}; use crate::error::Error; use crate::ibc::denom::Denom; -use crate::types::wallet::WalletAddress; +use crate::types::wallet::{Wallet, WalletAddress}; use super::ChainDriver; @@ -21,11 +21,20 @@ pub fn transfer_token( driver: &ChainDriver, port_id: &PortId, channel_id: &ChannelId, - sender: &WalletAddress, + sender: &Wallet, recipient: &WalletAddress, amount: u64, denom: &Denom, ) -> Result<(), Error> { + // let message = build_transfer_message( + // port_id, + // channel_id, + // amount.into(), + // denom.as_str().to_string(), + // Signer::new(sender.address.0), + // Signer::new(recipient.0), + // ) + driver.exec(&[ "--node", &driver.rpc_listen_address(), @@ -37,7 +46,7 @@ pub fn transfer_token( &recipient.0, &format!("{}{}", amount, denom), "--from", - &sender.0, + &sender.address.0, "--chain-id", driver.chain_id.as_str(), "--home", @@ -52,7 +61,7 @@ pub fn transfer_token( pub fn local_transfer_token( driver: &ChainDriver, - sender: &WalletAddress, + sender: &Wallet, recipient: &WalletAddress, amount: u64, denom: &Denom, @@ -63,7 +72,7 @@ pub fn local_transfer_token( "tx", "bank", "send", - &sender.0, + &sender.address.0, &recipient.0, &format!("{}{}", amount, denom), "--chain-id", diff --git a/tools/test-framework/src/framework/base.rs b/tools/test-framework/src/framework/base.rs index 28eb30db87..0ba59ea9fb 100644 --- a/tools/test-framework/src/framework/base.rs +++ b/tools/test-framework/src/framework/base.rs @@ -3,6 +3,8 @@ initializing the logger and loading the test configuration. */ +use alloc::sync::Arc; +use tokio::runtime::Runtime; use tracing::info; use crate::bootstrap::init::init_test; @@ -90,11 +92,14 @@ where { fn run(&self) -> Result<(), Error> { let mut config = init_test()?; + + let runtime = Arc::new(Runtime::new()?); + self.test.get_overrides().modify_test_config(&mut config); info!("starting test with test config: {:?}", config); - let builder = ChainBuilder::new_with_config(&config); + let builder = ChainBuilder::new_with_config(&config, runtime); self.test.run(&config, &builder)?; diff --git a/tools/test-framework/src/relayer/mod.rs b/tools/test-framework/src/relayer/mod.rs index 312150afdd..44a848d41e 100644 --- a/tools/test-framework/src/relayer/mod.rs +++ b/tools/test-framework/src/relayer/mod.rs @@ -25,3 +25,4 @@ pub mod driver; pub mod foreign_client; pub mod refresh; pub mod transfer; +pub mod tx; diff --git a/tools/test-framework/src/relayer/transfer.rs b/tools/test-framework/src/relayer/transfer.rs index 81643bd4da..ee08e3611f 100644 --- a/tools/test-framework/src/relayer/transfer.rs +++ b/tools/test-framework/src/relayer/transfer.rs @@ -5,14 +5,22 @@ use core::time::Duration; use ibc::events::IbcEvent; +use ibc::signer::Signer; +use ibc_relayer::chain::cosmos::query::status::query_status; use ibc_relayer::chain::handle::ChainHandle; -use ibc_relayer::transfer::{build_and_send_transfer_messages, Amount, TransferOptions}; +use ibc_relayer::transfer::{ + build_and_send_transfer_messages, build_transfer_message, Amount, TransferOptions, + TransferTimeout, +}; +use crate::chain::driver::tagged::TaggedChainDriverExt; +use crate::chain::driver::ChainDriver; use crate::error::Error; use crate::ibc::denom::Denom; use crate::types::binary::channel::ConnectedChannel; +use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef}; use crate::types::tagged::*; -use crate::types::wallet::WalletAddress; +use crate::types::wallet::{Wallet, WalletAddress}; /** Perform the same operation as `hermes tx raw ft-transfer`. @@ -64,3 +72,64 @@ pub fn tx_raw_ft_transfer( Ok(events) } + +pub fn ibc_token_transfer( + chain_driver: &MonoTagged, + port_id: &TaggedPortIdRef<'_, SrcChain, DstChain>, + channel_id: &TaggedChannelIdRef<'_, SrcChain, DstChain>, + sender: &MonoTagged, + recipient: &MonoTagged, + denom: &MonoTagged, + amount: u64, +) -> Result<(), Error> { + chain_driver + .value() + .runtime + .block_on(async_ibc_token_transfer( + chain_driver, + port_id, + channel_id, + sender, + recipient, + denom, + amount, + )) +} + +pub async fn async_ibc_token_transfer( + chain_driver: &MonoTagged, + port_id: &TaggedPortIdRef<'_, SrcChain, DstChain>, + channel_id: &TaggedChannelIdRef<'_, SrcChain, DstChain>, + sender: &MonoTagged, + recipient: &MonoTagged, + denom: &MonoTagged, + amount: u64, +) -> Result<(), Error> { + let chain_id = chain_driver.chain_id(); + + let tx_config = &chain_driver.value().tx_config; + + let status = query_status( + chain_id.value(), + &tx_config.rpc_client, + &tx_config.rpc_address, + ) + .await?; + + let timeout = TransferTimeout::new(500, Duration::from_secs(60), &status)?; + + let message = build_transfer_message( + (*port_id.value()).clone(), + **channel_id.value(), + amount.into(), + denom.value().to_string(), + Signer::new(sender.value().address.0.clone()), + Signer::new(recipient.value().0.clone()), + timeout.timeout_height, + timeout.timeout_timestamp, + ); + + chain_driver.send_tx(sender, vec![message]).await?; + + Ok(()) +} diff --git a/tools/test-framework/src/relayer/tx.rs b/tools/test-framework/src/relayer/tx.rs new file mode 100644 index 0000000000..0cf9ea9245 --- /dev/null +++ b/tools/test-framework/src/relayer/tx.rs @@ -0,0 +1,132 @@ +use core::str::FromStr; +use core::time::Duration; +use eyre::eyre; +use http::uri::Uri; +use ibc::core::ics24_host::identifier::ChainId; +use ibc::events::IbcEvent; +use ibc_proto::cosmos::tx::v1beta1::Fee; +use ibc_proto::google::protobuf::Any; +use ibc_relayer::chain::cosmos::gas::calculate_fee; +use ibc_relayer::chain::cosmos::query::account::query_account; +use ibc_relayer::chain::cosmos::tx::estimate_fee_and_send_tx; +use ibc_relayer::chain::cosmos::types::config::TxConfig; +use ibc_relayer::chain::cosmos::types::gas::GasConfig; +use ibc_relayer::chain::cosmos::types::tx::TxSyncResult; +use ibc_relayer::chain::cosmos::wait::wait_for_block_commits; +use ibc_relayer::config::GasPrice; +use ibc_relayer::keyring::KeyEntry; +use tendermint_rpc::{HttpClient, Url}; + +use crate::error::{handle_generic_error, Error}; + +pub fn gas_config_for_test() -> GasConfig { + let max_gas = 3000000; + let gas_adjustment = 0.1; + let gas_price = GasPrice::new(0.001, "stake".to_string()); + + let default_gas = max_gas; + let fee_granter = "".to_string(); + + let max_fee = Fee { + amount: vec![calculate_fee(max_gas, &gas_price)], + gas_limit: max_gas, + payer: "".to_string(), + granter: fee_granter.clone(), + }; + + GasConfig { + default_gas, + max_gas, + gas_adjustment, + gas_price, + max_fee, + fee_granter, + } +} + +pub fn new_tx_config_for_test( + chain_id: ChainId, + raw_rpc_address: String, + raw_grpc_address: String, +) -> Result { + let rpc_address = Url::from_str(&raw_rpc_address).map_err(handle_generic_error)?; + + let rpc_client = HttpClient::new(rpc_address.clone()).map_err(handle_generic_error)?; + + let grpc_address = Uri::from_str(&raw_grpc_address).map_err(handle_generic_error)?; + + let gas_config = gas_config_for_test(); + + let rpc_timeout = Duration::from_secs(10); + + Ok(TxConfig { + chain_id, + gas_config, + rpc_client, + rpc_address, + grpc_address, + rpc_timeout, + }) +} + +/** + A simplified version of send_tx that does not depend on `ChainHandle`. + + This allows different wallet ([`KeyEntry`]) to be used for submitting + transactions. The simple behavior as follows: + + - Query the account information on the fly. This may introduce more + overhead in production, but does not matter in testing. + - Do not split the provided messages into smaller batches. + - Wait for TX sync result, and error if any result contains + error event. +*/ +pub async fn simple_send_tx( + config: &TxConfig, + key_entry: &KeyEntry, + messages: Vec, +) -> Result<(), Error> { + let account = query_account(&config.grpc_address, &key_entry.account) + .await? + .into(); + + let message_count = messages.len(); + + let response = estimate_fee_and_send_tx( + config, + key_entry, + &account, + &Default::default(), + &Default::default(), + messages, + ) + .await?; + + let events_per_tx = vec![IbcEvent::default(); message_count]; + + let tx_sync_result = TxSyncResult { + response, + events: events_per_tx, + }; + + let mut tx_sync_results = vec![tx_sync_result]; + + wait_for_block_commits( + &config.chain_id, + &config.rpc_client, + &config.rpc_address, + &config.rpc_timeout, + &mut tx_sync_results, + ) + .await?; + + for result in tx_sync_results.iter() { + for event in result.events.iter() { + if let IbcEvent::ChainError(e) = event { + return Err(Error::generic(eyre!("send_tx result in error: {}", e))); + } + } + } + + Ok(()) +} diff --git a/tools/test-framework/src/types/config.rs b/tools/test-framework/src/types/config.rs index 7a555d81ce..bc971f999c 100644 --- a/tools/test-framework/src/types/config.rs +++ b/tools/test-framework/src/types/config.rs @@ -28,6 +28,8 @@ pub struct TestConfig { */ pub chain_command_path: String, + pub account_prefix: String, + /** The directory path for storing the chain and relayer files. Defaults to `"data"`. This can be overridden with the `$CHAIN_STORE_DIR` diff --git a/tools/test-framework/src/types/single/node.rs b/tools/test-framework/src/types/single/node.rs index 9d86c2728f..55817d0415 100644 --- a/tools/test-framework/src/types/single/node.rs +++ b/tools/test-framework/src/types/single/node.rs @@ -19,6 +19,10 @@ use crate::types::process::ChildProcess; use crate::types::tagged::*; use crate::types::wallet::TestWallets; +pub type TaggedFullNode = MonoTagged; + +pub type TaggedFullNodeRef<'a, Chain> = MonoTagged; + /** Represents a full node running as a child process managed by the test. */ @@ -120,7 +124,7 @@ impl FullNode { websocket_addr: Url::from_str(&self.chain_driver.websocket_address())?, grpc_addr: Url::from_str(&self.chain_driver.grpc_address())?, rpc_timeout: Duration::from_secs(10), - account_prefix: "cosmos".to_string(), + account_prefix: self.chain_driver.account_prefix.clone(), key_name: self.wallets.relayer.id.0.clone(), // By default we use in-memory key store to avoid polluting diff --git a/tools/test-framework/src/types/tagged/dual.rs b/tools/test-framework/src/types/tagged/dual.rs index f1ab3f583f..851e2a9428 100644 --- a/tools/test-framework/src/types/tagged/dual.rs +++ b/tools/test-framework/src/types/tagged/dual.rs @@ -391,6 +391,9 @@ impl AsRef for Tagged { impl Copy for Tagged {} +unsafe impl Send for Tagged {} +unsafe impl Sync for Tagged {} + impl Clone for Tagged { fn clone(&self) -> Self { Self::new(self.0.clone()) diff --git a/tools/test-framework/src/types/tagged/mono.rs b/tools/test-framework/src/types/tagged/mono.rs index c3631604d2..ef4a228b93 100644 --- a/tools/test-framework/src/types/tagged/mono.rs +++ b/tools/test-framework/src/types/tagged/mono.rs @@ -362,6 +362,9 @@ impl IntoIterator for Tagged { impl Copy for Tagged {} +unsafe impl Send for Tagged {} +unsafe impl Sync for Tagged {} + impl Clone for Tagged { fn clone(&self) -> Self { Self::new(self.0.clone()) From c69f4b23ff357851a7d3bd8917b83cbc684c948c Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Tue, 10 May 2022 11:44:07 +0200 Subject: [PATCH 2/9] Move AddressType into TxConfig, as it is configured per chain --- relayer/src/chain/cosmos.rs | 2 -- relayer/src/chain/cosmos/batch.rs | 31 +++++---------------- relayer/src/chain/cosmos/encode.rs | 16 +++-------- relayer/src/chain/cosmos/estimate.rs | 3 --- relayer/src/chain/cosmos/retry.rs | 16 ++--------- relayer/src/chain/cosmos/tx.rs | 34 +++--------------------- relayer/src/chain/cosmos/types/config.rs | 4 ++- tools/test-framework/src/relayer/tx.rs | 15 +++++------ 8 files changed, 23 insertions(+), 98 deletions(-) diff --git a/relayer/src/chain/cosmos.rs b/relayer/src/chain/cosmos.rs index 21f99edf08..bafa3085a6 100644 --- a/relayer/src/chain/cosmos.rs +++ b/relayer/src/chain/cosmos.rs @@ -409,7 +409,6 @@ impl CosmosSdkChain { self.config.max_tx_size, &key_entry, account, - &self.config.address_type, &self.config.memo_prefix, proto_msgs, ) @@ -438,7 +437,6 @@ impl CosmosSdkChain { self.config.max_tx_size, &key_entry, account, - &self.config.address_type, &self.config.memo_prefix, proto_msgs, ) diff --git a/relayer/src/chain/cosmos/batch.rs b/relayer/src/chain/cosmos/batch.rs index 075c574625..9c0b84a87a 100644 --- a/relayer/src/chain/cosmos/batch.rs +++ b/relayer/src/chain/cosmos/batch.rs @@ -9,7 +9,6 @@ use crate::chain::cosmos::types::config::TxConfig; use crate::chain::cosmos::types::tx::TxSyncResult; use crate::chain::cosmos::wait::wait_for_block_commits; use crate::config::types::{MaxMsgNum, MaxTxSize, Memo}; -use crate::config::AddressType; use crate::error::Error; use crate::keyring::KeyEntry; @@ -19,7 +18,6 @@ pub async fn send_batched_messages_and_wait_commit( max_tx_size: MaxTxSize, key_entry: &KeyEntry, account: &mut Account, - address_type: &AddressType, tx_memo: &Memo, messages: Vec, ) -> Result, Error> { @@ -33,7 +31,6 @@ pub async fn send_batched_messages_and_wait_commit( max_tx_size, key_entry, account, - address_type, tx_memo, messages, ) @@ -62,7 +59,6 @@ pub async fn send_batched_messages_and_wait_check_tx( max_tx_size: MaxTxSize, key_entry: &KeyEntry, account: &mut Account, - address_type: &AddressType, tx_memo: &Memo, messages: Vec, ) -> Result, Error> { @@ -75,16 +71,9 @@ pub async fn send_batched_messages_and_wait_check_tx( let mut responses = Vec::new(); for batch in batches { - let response = send_tx_with_account_sequence_retry( - config, - key_entry, - account, - address_type, - tx_memo, - batch, - 0, - ) - .await?; + let response = + send_tx_with_account_sequence_retry(config, key_entry, account, tx_memo, batch, 0) + .await?; responses.push(response); } @@ -98,7 +87,6 @@ async fn send_messages_as_batches( max_tx_size: MaxTxSize, key_entry: &KeyEntry, account: &mut Account, - address_type: &AddressType, tx_memo: &Memo, messages: Vec, ) -> Result, Error> { @@ -113,16 +101,9 @@ async fn send_messages_as_batches( for batch in batches { let events_per_tx = vec![IbcEvent::default(); batch.len()]; - let response = send_tx_with_account_sequence_retry( - config, - key_entry, - account, - address_type, - tx_memo, - batch, - 0, - ) - .await?; + let response = + send_tx_with_account_sequence_retry(config, key_entry, account, tx_memo, batch, 0) + .await?; let tx_sync_result = TxSyncResult { response, diff --git a/relayer/src/chain/cosmos/encode.rs b/relayer/src/chain/cosmos/encode.rs index 1e7ee1fc97..416bc049d0 100644 --- a/relayer/src/chain/cosmos/encode.rs +++ b/relayer/src/chain/cosmos/encode.rs @@ -18,20 +18,11 @@ pub fn sign_and_encode_tx( config: &TxConfig, key_entry: &KeyEntry, account: &Account, - address_type: &AddressType, tx_memo: &Memo, messages: Vec, fee: &Fee, ) -> Result, Error> { - let signed_tx = sign_tx( - config, - key_entry, - account, - address_type, - tx_memo, - messages, - fee, - )?; + let signed_tx = sign_tx(config, key_entry, account, tx_memo, messages, fee)?; let tx_raw = TxRaw { body_bytes: signed_tx.body_bytes, @@ -46,14 +37,13 @@ pub fn sign_tx( config: &TxConfig, key_entry: &KeyEntry, account: &Account, - address_type: &AddressType, tx_memo: &Memo, messages: Vec, fee: &Fee, ) -> Result { let key_bytes = encode_key_bytes(key_entry)?; - let signer = encode_signer_info(address_type, account.sequence, key_bytes)?; + let signer = encode_signer_info(&config.address_type, account.sequence, key_bytes)?; let (body, body_bytes) = tx_body_and_bytes(messages, tx_memo)?; @@ -62,7 +52,7 @@ pub fn sign_tx( let signed_doc = encode_sign_doc( &config.chain_id, key_entry, - address_type, + &config.address_type, account.number, auth_info_bytes.clone(), body_bytes.clone(), diff --git a/relayer/src/chain/cosmos/estimate.rs b/relayer/src/chain/cosmos/estimate.rs index d09e205f46..15fba52d22 100644 --- a/relayer/src/chain/cosmos/estimate.rs +++ b/relayer/src/chain/cosmos/estimate.rs @@ -11,7 +11,6 @@ use crate::chain::cosmos::types::account::Account; use crate::chain::cosmos::types::config::TxConfig; use crate::chain::cosmos::types::gas::GasConfig; use crate::config::types::Memo; -use crate::config::AddressType; use crate::error::Error; use crate::keyring::KeyEntry; @@ -19,7 +18,6 @@ pub async fn estimate_tx_fees( config: &TxConfig, key_entry: &KeyEntry, account: &Account, - address_type: &AddressType, tx_memo: &Memo, messages: Vec, ) -> Result { @@ -34,7 +32,6 @@ pub async fn estimate_tx_fees( config, key_entry, account, - address_type, tx_memo, messages, &gas_config.max_fee, diff --git a/relayer/src/chain/cosmos/retry.rs b/relayer/src/chain/cosmos/retry.rs index 9a9c4f2988..2b901243b9 100644 --- a/relayer/src/chain/cosmos/retry.rs +++ b/relayer/src/chain/cosmos/retry.rs @@ -12,7 +12,6 @@ use crate::chain::cosmos::tx::estimate_fee_and_send_tx; use crate::chain::cosmos::types::account::Account; use crate::chain::cosmos::types::config::TxConfig; use crate::config::types::Memo; -use crate::config::AddressType; use crate::error::Error; use crate::keyring::KeyEntry; use crate::sdk_error::sdk_error_from_tx_sync_error_code; @@ -49,7 +48,6 @@ pub async fn send_tx_with_account_sequence_retry( config: &TxConfig, key_entry: &KeyEntry, account: &mut Account, - address_type: &AddressType, tx_memo: &Memo, messages: Vec, retry_counter: u64, @@ -62,7 +60,6 @@ pub async fn send_tx_with_account_sequence_retry( config, key_entry, account, - address_type, tx_memo, messages, retry_counter, @@ -77,7 +74,6 @@ fn do_send_tx_with_account_sequence_retry<'a>( config: &'a TxConfig, key_entry: &'a KeyEntry, account: &'a mut Account, - address_type: &'a AddressType, tx_memo: &'a Memo, messages: Vec, retry_counter: u64, @@ -89,15 +85,8 @@ fn do_send_tx_with_account_sequence_retry<'a>( account.sequence, ); - let tx_result = estimate_fee_and_send_tx( - config, - key_entry, - account, - address_type, - tx_memo, - messages.clone(), - ) - .await; + let tx_result = + estimate_fee_and_send_tx(config, key_entry, account, tx_memo, messages.clone()).await; match tx_result { // Gas estimation failed with acct. s.n. mismatch at estimate gas step. @@ -132,7 +121,6 @@ fn do_send_tx_with_account_sequence_retry<'a>( config, key_entry, account, - address_type, tx_memo, messages, retry_counter + 1, diff --git a/relayer/src/chain/cosmos/tx.rs b/relayer/src/chain/cosmos/tx.rs index b534a0f2a9..e6a0519e1f 100644 --- a/relayer/src/chain/cosmos/tx.rs +++ b/relayer/src/chain/cosmos/tx.rs @@ -8,7 +8,6 @@ use crate::chain::cosmos::estimate::estimate_tx_fees; use crate::chain::cosmos::types::account::Account; use crate::chain::cosmos::types::config::TxConfig; use crate::config::types::Memo; -use crate::config::AddressType; use crate::error::Error; use crate::keyring::KeyEntry; @@ -16,50 +15,23 @@ pub async fn estimate_fee_and_send_tx( config: &TxConfig, key_entry: &KeyEntry, account: &Account, - address_type: &AddressType, tx_memo: &Memo, messages: Vec, ) -> Result { - let fee = estimate_tx_fees( - config, - key_entry, - account, - address_type, - tx_memo, - messages.clone(), - ) - .await?; + let fee = estimate_tx_fees(config, key_entry, account, tx_memo, messages.clone()).await?; - send_tx_with_fee( - config, - key_entry, - account, - address_type, - tx_memo, - messages, - &fee, - ) - .await + send_tx_with_fee(config, key_entry, account, tx_memo, messages, &fee).await } async fn send_tx_with_fee( config: &TxConfig, key_entry: &KeyEntry, account: &Account, - address_type: &AddressType, tx_memo: &Memo, messages: Vec, fee: &Fee, ) -> Result { - let tx_bytes = sign_and_encode_tx( - config, - key_entry, - account, - address_type, - tx_memo, - messages, - fee, - )?; + let tx_bytes = sign_and_encode_tx(config, key_entry, account, tx_memo, messages, fee)?; let response = broadcast_tx_sync(&config.rpc_client, &config.rpc_address, tx_bytes).await?; diff --git a/relayer/src/chain/cosmos/types/config.rs b/relayer/src/chain/cosmos/types/config.rs index 34bdd7fc06..fa2f924d2d 100644 --- a/relayer/src/chain/cosmos/types/config.rs +++ b/relayer/src/chain/cosmos/types/config.rs @@ -5,7 +5,7 @@ use ibc::core::ics24_host::identifier::ChainId; use tendermint_rpc::{HttpClient, Url}; use crate::chain::cosmos::types::gas::GasConfig; -use crate::config::ChainConfig; +use crate::config::{AddressType, ChainConfig}; use crate::error::Error; #[derive(Debug, Clone)] @@ -16,6 +16,7 @@ pub struct TxConfig { pub rpc_address: Url, pub grpc_address: Uri, pub rpc_timeout: Duration, + pub address_type: AddressType, } impl<'a> TryFrom<&'a ChainConfig> for TxConfig { @@ -37,6 +38,7 @@ impl<'a> TryFrom<&'a ChainConfig> for TxConfig { rpc_address: config.rpc_addr.clone(), grpc_address, rpc_timeout: config.rpc_timeout, + address_type: config.address_type.clone(), }) } } diff --git a/tools/test-framework/src/relayer/tx.rs b/tools/test-framework/src/relayer/tx.rs index 0cf9ea9245..e0e85ed1cf 100644 --- a/tools/test-framework/src/relayer/tx.rs +++ b/tools/test-framework/src/relayer/tx.rs @@ -59,6 +59,8 @@ pub fn new_tx_config_for_test( let rpc_timeout = Duration::from_secs(10); + let address_type = Default::default(); + Ok(TxConfig { chain_id, gas_config, @@ -66,6 +68,7 @@ pub fn new_tx_config_for_test( rpc_address, grpc_address, rpc_timeout, + address_type, }) } @@ -92,15 +95,9 @@ pub async fn simple_send_tx( let message_count = messages.len(); - let response = estimate_fee_and_send_tx( - config, - key_entry, - &account, - &Default::default(), - &Default::default(), - messages, - ) - .await?; + let response = + estimate_fee_and_send_tx(config, key_entry, &account, &Default::default(), messages) + .await?; let events_per_tx = vec![IbcEvent::default(); message_count]; From 558551b15133864587cf301d4b8999321ab09650 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Tue, 10 May 2022 12:24:56 +0200 Subject: [PATCH 3/9] Disable GRPC Web and not rely on chain version --- tools/test-framework/src/bootstrap/single.rs | 7 ++++ tools/test-framework/src/chain/config.rs | 15 ++++++-- tools/test-framework/src/chain/driver.rs | 37 +++----------------- tools/test-framework/src/chain/version.rs | 2 +- tools/test-framework/src/relayer/tx.rs | 2 +- 5 files changed, 27 insertions(+), 36 deletions(-) diff --git a/tools/test-framework/src/bootstrap/single.rs b/tools/test-framework/src/bootstrap/single.rs index e85595b9df..f64e1a0f9d 100644 --- a/tools/test-framework/src/bootstrap/single.rs +++ b/tools/test-framework/src/bootstrap/single.rs @@ -97,6 +97,13 @@ pub fn bootstrap_single_node( Ok(()) })?; + chain_driver.update_chain_config("app.toml", |config| { + config::set_grpc_port(config, chain_driver.grpc_port)?; + config::disable_grpc_web(config)?; + + Ok(()) + })?; + let process = chain_driver.start()?; chain_driver.assert_eventual_wallet_amount(&relayer.address, initial_amount, &denom)?; diff --git a/tools/test-framework/src/chain/config.rs b/tools/test-framework/src/chain/config.rs index e8f70fc008..bec1529485 100644 --- a/tools/test-framework/src/chain/config.rs +++ b/tools/test-framework/src/chain/config.rs @@ -27,8 +27,8 @@ pub fn set_rpc_port(config: &mut Value, port: u16) -> Result<(), Error> { pub fn set_grpc_port(config: &mut Value, port: u16) -> Result<(), Error> { config - .get_mut("grpc-web") - .ok_or_else(|| eyre!("expect grpc-web section"))? + .get_mut("grpc") + .ok_or_else(|| eyre!("expect grpc section"))? .as_table_mut() .ok_or_else(|| eyre!("expect object"))? .insert("address".to_string(), format!("0.0.0.0:{}", port).into()); @@ -36,6 +36,17 @@ pub fn set_grpc_port(config: &mut Value, port: u16) -> Result<(), Error> { Ok(()) } +pub fn disable_grpc_web(config: &mut Value) -> Result<(), Error> { + if let Some(field) = config.get_mut("grpc-web") { + field + .as_table_mut() + .ok_or_else(|| eyre!("expect object"))? + .insert("enable".to_string(), false.into()); + } + + Ok(()) +} + /// Set the `p2p` field in the full node config. pub fn set_p2p_port(config: &mut Value, port: u16) -> Result<(), Error> { config diff --git a/tools/test-framework/src/chain/driver.rs b/tools/test-framework/src/chain/driver.rs index 18f0f3593b..29eebf871c 100644 --- a/tools/test-framework/src/chain/driver.rs +++ b/tools/test-framework/src/chain/driver.rs @@ -7,7 +7,6 @@ use core::time::Duration; use alloc::sync::Arc; use eyre::eyre; -use semver::Version; use serde_json as json; use std::fs; use std::path::PathBuf; @@ -23,7 +22,6 @@ use ibc_relayer::chain::cosmos::types::config::TxConfig; use ibc_relayer::keyring::{HDPath, KeyEntry, KeyFile}; use crate::chain::exec::{simple_exec, ExecOutput}; -use crate::chain::version::get_chain_command_version; use crate::error::{handle_generic_error, Error}; use crate::ibc::denom::Denom; use crate::relayer::tx::{new_tx_config_for_test, simple_send_tx}; @@ -75,8 +73,6 @@ pub struct ChainDriver { */ pub command_path: String, - pub command_version: Option, - /** The ID of the chain. */ @@ -133,10 +129,6 @@ impl ChainDriver { p2p_port: u16, runtime: Arc, ) -> Result { - // Assume we're on Gaia 6 if we can't get a version - // (eg. with `icad`, which returns an empty string). - let command_version = get_chain_command_version(&command_path)?; - let tx_config = new_tx_config_for_test( chain_id.clone(), format!("http://localhost:{}", rpc_port), @@ -145,7 +137,6 @@ impl ChainDriver { Ok(Self { command_path, - command_version, chain_id, home_path, account_prefix, @@ -393,7 +384,9 @@ impl ChainDriver { file: &str, cont: impl FnOnce(&mut toml::Value) -> Result<(), Error>, ) -> Result<(), Error> { - let config1 = self.read_file(&format!("config/{}", file))?; + let config_path = format!("config/{}", file); + + let config1 = self.read_file(&config_path)?; let mut config2 = toml::from_str(&config1).map_err(handle_generic_error)?; @@ -401,18 +394,11 @@ impl ChainDriver { let config3 = toml::to_string_pretty(&config2).map_err(handle_generic_error)?; - self.write_file("config/config.toml", &config3)?; + self.write_file(&config_path, &config3)?; Ok(()) } - pub fn is_v6_or_later(&self) -> bool { - match &self.command_version { - Some(version) => version.major >= 6, - None => true, - } - } - /** Start a full node by running in the background `gaiad start`. @@ -432,20 +418,7 @@ impl ChainDriver { &self.rpc_listen_address(), ]; - // Gaia v6 requires the GRPC web port to be unique, - // but the argument is not available in earlier version - let extra_args = [ - "--grpc-web.address", - &format!("localhost:{}", self.grpc_web_port), - ]; - - let args: Vec<&str> = if self.is_v6_or_later() { - let mut list = base_args.to_vec(); - list.extend_from_slice(&extra_args); - list - } else { - base_args.to_vec() - }; + let args: Vec<&str> = base_args.to_vec(); let mut child = Command::new(&self.command_path) .args(&args) diff --git a/tools/test-framework/src/chain/version.rs b/tools/test-framework/src/chain/version.rs index 2119c4ed14..db27cd0948 100644 --- a/tools/test-framework/src/chain/version.rs +++ b/tools/test-framework/src/chain/version.rs @@ -14,7 +14,7 @@ pub fn get_chain_command_version(command: &str) -> Result, Error output.stdout }; - let version_str = match raw_version_str.strip_prefix('v') { + let version_str = match raw_version_str.trim().strip_prefix('v') { Some(str) => str.trim(), None => raw_version_str.trim(), }; diff --git a/tools/test-framework/src/relayer/tx.rs b/tools/test-framework/src/relayer/tx.rs index e0e85ed1cf..18be12730d 100644 --- a/tools/test-framework/src/relayer/tx.rs +++ b/tools/test-framework/src/relayer/tx.rs @@ -57,7 +57,7 @@ pub fn new_tx_config_for_test( let gas_config = gas_config_for_test(); - let rpc_timeout = Duration::from_secs(10); + let rpc_timeout = Duration::from_secs(30); let address_type = Default::default(); From 1a5fc98c9ebd49e453b7c5353443edac73bd3e98 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Tue, 10 May 2022 12:45:18 +0200 Subject: [PATCH 4/9] Clean up ibc_transfer_token interface on ChainDriver --- .../src/tests/clear_packet.rs | 8 +-- .../src/tests/client_expiration.rs | 8 +-- .../src/tests/connection_delay.rs | 4 +- tools/integration-test/src/tests/memo.rs | 4 +- .../src/tests/ordered_channel.rs | 8 +-- .../src/tests/query_packet.rs | 8 +-- .../integration-test/src/tests/supervisor.rs | 4 +- .../src/tests/ternary_transfer.rs | 16 ++--- tools/integration-test/src/tests/transfer.rs | 7 +-- tools/test-framework/src/chain/driver.rs | 6 +- .../src/chain/driver/transfer.rs | 51 ---------------- tools/test-framework/src/chain/mod.rs | 1 + .../src/chain/{driver => }/tagged.rs | 59 ++++++++++--------- tools/test-framework/src/prelude.rs | 3 +- tools/test-framework/src/relayer/transfer.rs | 43 +++----------- 15 files changed, 77 insertions(+), 153 deletions(-) rename tools/test-framework/src/chain/{driver => }/tagged.rs (86%) diff --git a/tools/integration-test/src/tests/clear_packet.rs b/tools/integration-test/src/tests/clear_packet.rs index 501a214f68..34b115fb83 100644 --- a/tools/integration-test/src/tests/clear_packet.rs +++ b/tools/integration-test/src/tests/clear_packet.rs @@ -51,13 +51,13 @@ impl BinaryChannelTest for ClearPacketTest { amount1 ); - chains.node_a.chain_driver().transfer_token( + 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(), - amount1, &denom_a, + amount1, )?; sleep(Duration::from_secs(1)); @@ -73,13 +73,13 @@ impl BinaryChannelTest for ClearPacketTest { amount2 ); - chains.node_a.chain_driver().transfer_token( + 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(), - amount2, &denom_a, + amount2, )?; sleep(Duration::from_secs(1)); diff --git a/tools/integration-test/src/tests/client_expiration.rs b/tools/integration-test/src/tests/client_expiration.rs index 0a61513d83..c9b177991c 100644 --- a/tools/integration-test/src/tests/client_expiration.rs +++ b/tools/integration-test/src/tests/client_expiration.rs @@ -301,13 +301,13 @@ impl BinaryChainTest for PacketExpirationTest { { info!("sending first IBC transfer after client is expired. this should cause packet worker to fail"); - chains.node_a.chain_driver().transfer_token( + chains.node_a.chain_driver().ibc_transfer_token( &channels.port_a.as_ref(), &channels.channel_id_a.as_ref(), &chains.node_a.wallets().user1(), &chains.node_b.wallets().user1().address(), - 100, &chains.node_a.denom(), + 100, )?; sleep(Duration::from_secs(10)); @@ -329,13 +329,13 @@ impl BinaryChainTest for PacketExpirationTest { { info!("sending a second IBC transfer. there should be no log from packet worker from this point on"); - chains.node_a.chain_driver().transfer_token( + chains.node_a.chain_driver().ibc_transfer_token( &channels.port_a.as_ref(), &channels.channel_id_a.as_ref(), &chains.node_a.wallets().user1(), &chains.node_b.wallets().user1().address(), - 100, &chains.node_a.denom(), + 100, )?; sleep(Duration::from_secs(10)); diff --git a/tools/integration-test/src/tests/connection_delay.rs b/tools/integration-test/src/tests/connection_delay.rs index 54a31a32bd..ea8be39ac8 100644 --- a/tools/integration-test/src/tests/connection_delay.rs +++ b/tools/integration-test/src/tests/connection_delay.rs @@ -49,13 +49,13 @@ impl BinaryChannelTest for ConnectionDelayTest { denom_a ); - chains.node_a.chain_driver().transfer_token( + 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(), - a_to_b_amount, &denom_a, + a_to_b_amount, )?; let time1 = OffsetDateTime::now_utc(); diff --git a/tools/integration-test/src/tests/memo.rs b/tools/integration-test/src/tests/memo.rs index 436593e01d..5a60254b38 100644 --- a/tools/integration-test/src/tests/memo.rs +++ b/tools/integration-test/src/tests/memo.rs @@ -41,13 +41,13 @@ impl BinaryChannelTest for MemoTest { let a_to_b_amount = random_u64_range(1000, 5000); - chains.node_a.chain_driver().transfer_token( + chains.node_a.chain_driver().ibc_transfer_token( &channel.port_a.as_ref(), &channel.channel_id_a.as_ref(), &chains.node_a.wallets().user1(), &chains.node_b.wallets().user1().address(), - a_to_b_amount, &denom_a, + a_to_b_amount, )?; let denom_b = derive_ibc_denom( diff --git a/tools/integration-test/src/tests/ordered_channel.rs b/tools/integration-test/src/tests/ordered_channel.rs index 92e9a7bc58..ea0467dd33 100644 --- a/tools/integration-test/src/tests/ordered_channel.rs +++ b/tools/integration-test/src/tests/ordered_channel.rs @@ -51,13 +51,13 @@ impl BinaryChannelTest for OrderedChannelTest { amount1 ); - chains.node_a.chain_driver().transfer_token( + 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(), - amount1, &denom_a, + amount1, )?; sleep(Duration::from_secs(1)); @@ -72,13 +72,13 @@ impl BinaryChannelTest for OrderedChannelTest { amount2 ); - chains.node_a.chain_driver().transfer_token( + 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(), - amount2, &denom_a, + amount2, )?; sleep(Duration::from_secs(1)); diff --git a/tools/integration-test/src/tests/query_packet.rs b/tools/integration-test/src/tests/query_packet.rs index 3bb326578d..4f91e3d3fe 100644 --- a/tools/integration-test/src/tests/query_packet.rs +++ b/tools/integration-test/src/tests/query_packet.rs @@ -46,13 +46,13 @@ impl BinaryChannelTest for QueryPacketPendingTest { amount1 ); - chains.node_a.chain_driver().transfer_token( + 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(), - amount1, &denom_a, + amount1, )?; sleep(Duration::from_secs(2)); @@ -102,13 +102,13 @@ impl BinaryChannelTest for QueryPacketPendingTest { let denom_b = chains.node_b.denom(); let amount2 = random_u64_range(1000, 5000); - chains.node_b.chain_driver().transfer_token( + chains.node_b.chain_driver().ibc_transfer_token( &channel.port_b.as_ref(), &channel.channel_id_b.as_ref(), &wallet_b.as_ref(), &wallet_a.address(), - amount2, &denom_b, + amount2, )?; info!( diff --git a/tools/integration-test/src/tests/supervisor.rs b/tools/integration-test/src/tests/supervisor.rs index b40be2a3a8..4e739edc58 100644 --- a/tools/integration-test/src/tests/supervisor.rs +++ b/tools/integration-test/src/tests/supervisor.rs @@ -116,13 +116,13 @@ impl BinaryChainTest for SupervisorTest { denom_a ); - chains.node_a.chain_driver().transfer_token( + chains.node_a.chain_driver().ibc_transfer_token( &port_a.as_ref(), &channel_id_a.as_ref(), &wallet_a.as_ref(), &wallet_b.address(), - transfer_amount, &denom_a, + transfer_amount, )?; // During the test, you should see error logs showing "account sequence mismatch". diff --git a/tools/integration-test/src/tests/ternary_transfer.rs b/tools/integration-test/src/tests/ternary_transfer.rs index 9b4da51226..4c23a9eb4b 100644 --- a/tools/integration-test/src/tests/ternary_transfer.rs +++ b/tools/integration-test/src/tests/ternary_transfer.rs @@ -57,13 +57,13 @@ impl NaryChannelTest<3> for TernaryIbcTransferTest { denom_a ); - node_a.chain_driver().transfer_token( + node_a.chain_driver().ibc_transfer_token( &channel_a_to_b.port_a.as_ref(), &channel_a_to_b.channel_id_a.as_ref(), &wallet_a1.as_ref(), &wallet_b1.address(), - a_to_b_amount, &denom_a, + a_to_b_amount, )?; let denom_a_to_b = derive_ibc_denom( @@ -107,13 +107,13 @@ impl NaryChannelTest<3> for TernaryIbcTransferTest { let b_to_c_amount = 2500; - node_b.chain_driver().transfer_token( + node_b.chain_driver().ibc_transfer_token( &channel_b_to_c.port_a.as_ref(), &channel_b_to_c.channel_id_a.as_ref(), &wallet_b1.as_ref(), &wallet_c1.address(), - b_to_c_amount, &denom_a_to_b.as_ref(), + b_to_c_amount, )?; // Chain C will receive ibc/port-c/channel-c/port-b/channel-b/denom @@ -145,13 +145,13 @@ impl NaryChannelTest<3> for TernaryIbcTransferTest { let c_to_a_amount = 800; - node_c.chain_driver().transfer_token( + node_c.chain_driver().ibc_transfer_token( &channel_c_to_a.port_a.as_ref(), &channel_c_to_a.channel_id_a.as_ref(), &wallet_c1.as_ref(), &wallet_a1.address(), - c_to_a_amount, &denom_a_to_c.as_ref(), + c_to_a_amount, )?; // Chain A will receive ibc/port-a/channel-a/port-c/channel-c/port-b/channel-b/denom @@ -175,13 +175,13 @@ impl NaryChannelTest<3> for TernaryIbcTransferTest { let c_to_b_amount = 500; - node_c.chain_driver().transfer_token( + node_c.chain_driver().ibc_transfer_token( &channel_b_to_c.port_b.as_ref(), &channel_b_to_c.channel_id_b.as_ref(), &wallet_c1.as_ref(), &wallet_b2.address(), - c_to_b_amount, &denom_a_to_c.as_ref(), + c_to_b_amount, )?; // Chain B will receive ibc/port-b/channel-b/denom diff --git a/tools/integration-test/src/tests/transfer.rs b/tools/integration-test/src/tests/transfer.rs index 4bcd86a2d8..a5a76750c8 100644 --- a/tools/integration-test/src/tests/transfer.rs +++ b/tools/integration-test/src/tests/transfer.rs @@ -1,6 +1,5 @@ use ibc_test_framework::ibc::denom::derive_ibc_denom; use ibc_test_framework::prelude::*; -use ibc_test_framework::relayer::transfer::ibc_token_transfer; use ibc_test_framework::util::random::random_u64_range; #[test] @@ -71,8 +70,7 @@ impl BinaryChannelTest for IbcTransferTest { denom_a ); - ibc_token_transfer( - &chains.node_a.chain_driver(), + chains.node_a.chain_driver().ibc_transfer_token( &channel.port_a.as_ref(), &channel.channel_id_a.as_ref(), &wallet_a.as_ref(), @@ -125,8 +123,7 @@ impl BinaryChannelTest for IbcTransferTest { denom_b ); - ibc_token_transfer( - &chains.node_b.chain_driver(), + chains.node_b.chain_driver().ibc_transfer_token( &channel.port_b.as_ref(), &channel.channel_id_b.as_ref(), &wallet_b.as_ref(), diff --git a/tools/test-framework/src/chain/driver.rs b/tools/test-framework/src/chain/driver.rs index 29eebf871c..4734967e70 100644 --- a/tools/test-framework/src/chain/driver.rs +++ b/tools/test-framework/src/chain/driver.rs @@ -33,7 +33,6 @@ use crate::util::retry::assert_eventually_succeed; pub mod interchain; pub mod query_txs; -pub mod tagged; pub mod transfer; /** @@ -475,8 +474,9 @@ impl ChainDriver { Ok(amount) } - pub async fn send_tx(&self, wallet: &Wallet, messages: Vec) -> Result<(), Error> { - simple_send_tx(&self.tx_config, &wallet.key, messages).await + pub fn send_tx(&self, wallet: &Wallet, messages: Vec) -> Result<(), Error> { + self.runtime + .block_on(simple_send_tx(&self.tx_config, &wallet.key, messages)) } /** diff --git a/tools/test-framework/src/chain/driver/transfer.rs b/tools/test-framework/src/chain/driver/transfer.rs index 1d746fc5c1..0f6f5fa6c5 100644 --- a/tools/test-framework/src/chain/driver/transfer.rs +++ b/tools/test-framework/src/chain/driver/transfer.rs @@ -2,63 +2,12 @@ Methods for performing IBC token transfer on a chain. */ -use ibc::core::ics24_host::identifier::{ChannelId, PortId}; - use crate::error::Error; use crate::ibc::denom::Denom; use crate::types::wallet::{Wallet, WalletAddress}; use super::ChainDriver; -/** - Submits an IBC token transfer transaction. - - We use gaiad instead of the internal raw tx transfer to transfer tokens, - as the current chain implementation cannot dynamically switch the sender, - and instead always use the configured relayer wallet for sending tokens. -*/ -pub fn transfer_token( - driver: &ChainDriver, - port_id: &PortId, - channel_id: &ChannelId, - sender: &Wallet, - recipient: &WalletAddress, - amount: u64, - denom: &Denom, -) -> Result<(), Error> { - // let message = build_transfer_message( - // port_id, - // channel_id, - // amount.into(), - // denom.as_str().to_string(), - // Signer::new(sender.address.0), - // Signer::new(recipient.0), - // ) - - driver.exec(&[ - "--node", - &driver.rpc_listen_address(), - "tx", - "ibc-transfer", - "transfer", - port_id.as_str(), - &channel_id.to_string(), - &recipient.0, - &format!("{}{}", amount, denom), - "--from", - &sender.address.0, - "--chain-id", - driver.chain_id.as_str(), - "--home", - &driver.home_path, - "--keyring-backend", - "test", - "--yes", - ])?; - - Ok(()) -} - pub fn local_transfer_token( driver: &ChainDriver, sender: &Wallet, diff --git a/tools/test-framework/src/chain/mod.rs b/tools/test-framework/src/chain/mod.rs index d6017f534f..7180f61a41 100644 --- a/tools/test-framework/src/chain/mod.rs +++ b/tools/test-framework/src/chain/mod.rs @@ -18,4 +18,5 @@ pub mod builder; pub mod config; pub mod driver; pub mod exec; +pub mod tagged; pub mod version; diff --git a/tools/test-framework/src/chain/driver/tagged.rs b/tools/test-framework/src/chain/tagged.rs similarity index 86% rename from tools/test-framework/src/chain/driver/tagged.rs rename to tools/test-framework/src/chain/tagged.rs index fdb7ff19c5..5fa9f545c3 100644 --- a/tools/test-framework/src/chain/driver/tagged.rs +++ b/tools/test-framework/src/chain/tagged.rs @@ -2,23 +2,25 @@ Methods for tagged version of the chain driver. */ -use async_trait::async_trait; use ibc_proto::google::protobuf::Any; +use ibc_relayer::chain::cosmos::types::config::TxConfig; use serde::Serialize; use serde_json as json; +use crate::chain::driver::interchain::{ + interchain_submit, query_interchain_account, register_interchain_account, +}; +use crate::chain::driver::query_txs::query_recipient_transactions; +use crate::chain::driver::transfer::local_transfer_token; +use crate::chain::driver::ChainDriver; use crate::error::Error; use crate::ibc::denom::Denom; use crate::prelude::TaggedConnectionIdRef; +use crate::relayer::transfer::ibc_token_transfer; use crate::types::id::{TaggedChainIdRef, TaggedChannelIdRef, TaggedPortIdRef}; use crate::types::tagged::*; use crate::types::wallet::{Wallet, WalletAddress}; -use super::interchain::{interchain_submit, query_interchain_account, register_interchain_account}; -use super::query_txs::query_recipient_transactions; -use super::transfer::{local_transfer_token, transfer_token}; -use super::ChainDriver; - /** A [`ChainDriver`] may be tagged with a `Chain` tag in the form [`MonoTagged`]. @@ -29,15 +31,13 @@ use super::ChainDriver; The tagged chain driver methods help ensure that the `ChainDriver` methods are used with the values associated to the correct chain. */ -#[async_trait] pub trait TaggedChainDriverExt { fn chain_id(&self) -> TaggedChainIdRef; - async fn send_tx( - &self, - wallet: &MonoTagged, - messages: Vec, - ) -> Result<(), Error>; + fn tx_config(&self) -> MonoTagged; + + fn send_tx(&self, wallet: &MonoTagged, messages: Vec) + -> Result<(), Error>; /** Tagged version of [`ChainDriver::query_balance`]. @@ -84,14 +84,14 @@ pub trait TaggedChainDriverExt { - The denomination of the amount on `Chain`. */ - fn transfer_token( + fn ibc_transfer_token( &self, port_id: &TaggedPortIdRef, channel_id: &TaggedChannelIdRef, sender: &MonoTagged, recipient: &MonoTagged, - amount: u64, denom: &MonoTagged, + amount: u64, ) -> Result<(), Error>; fn local_transfer_token( @@ -133,18 +133,21 @@ pub trait TaggedChainDriverExt { ) -> Result<(), Error>; } -#[async_trait] impl<'a, Chain: Send> TaggedChainDriverExt for MonoTagged { fn chain_id(&self) -> TaggedChainIdRef { - MonoTagged::new(&self.value().chain_id) + self.map_ref(|val| &val.chain_id) } - async fn send_tx( + fn tx_config(&self) -> MonoTagged { + self.map_ref(|val| &val.tx_config) + } + + fn send_tx( &self, wallet: &MonoTagged, messages: Vec, ) -> Result<(), Error> { - self.value().send_tx(wallet.value(), messages).await + self.value().send_tx(wallet.value(), messages) } fn query_balance( @@ -165,24 +168,24 @@ impl<'a, Chain: Send> TaggedChainDriverExt for MonoTagged( + fn ibc_transfer_token( &self, port_id: &TaggedPortIdRef, channel_id: &TaggedChannelIdRef, sender: &MonoTagged, recipient: &MonoTagged, - amount: u64, denom: &MonoTagged, + amount: u64, ) -> Result<(), Error> { - transfer_token( - self.value(), - port_id.value(), - channel_id.value(), - sender.value(), - recipient.value(), + self.value().runtime.block_on(ibc_token_transfer( + &self.tx_config(), + port_id, + channel_id, + sender, + recipient, + denom, amount, - denom.value(), - ) + )) } fn local_transfer_token( diff --git a/tools/test-framework/src/prelude.rs b/tools/test-framework/src/prelude.rs index 0ac8385340..b070d98b6a 100644 --- a/tools/test-framework/src/prelude.rs +++ b/tools/test-framework/src/prelude.rs @@ -14,7 +14,8 @@ pub use ibc_relayer::supervisor::SupervisorHandle; pub use std::thread::sleep; pub use tracing::{debug, error, info, warn}; -pub use crate::chain::driver::{tagged::TaggedChainDriverExt, ChainDriver}; +pub use crate::chain::driver::ChainDriver; +pub use crate::chain::tagged::TaggedChainDriverExt; pub use crate::error::{handle_generic_error, Error}; pub use crate::framework::base::HasOverrides; pub use crate::framework::binary::chain::{ diff --git a/tools/test-framework/src/relayer/transfer.rs b/tools/test-framework/src/relayer/transfer.rs index ee08e3611f..fdd9fd518b 100644 --- a/tools/test-framework/src/relayer/transfer.rs +++ b/tools/test-framework/src/relayer/transfer.rs @@ -7,16 +7,16 @@ use core::time::Duration; use ibc::events::IbcEvent; use ibc::signer::Signer; use ibc_relayer::chain::cosmos::query::status::query_status; +use ibc_relayer::chain::cosmos::types::config::TxConfig; use ibc_relayer::chain::handle::ChainHandle; use ibc_relayer::transfer::{ build_and_send_transfer_messages, build_transfer_message, Amount, TransferOptions, TransferTimeout, }; -use crate::chain::driver::tagged::TaggedChainDriverExt; -use crate::chain::driver::ChainDriver; use crate::error::Error; use crate::ibc::denom::Denom; +use crate::relayer::tx::simple_send_tx; use crate::types::binary::channel::ConnectedChannel; use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef}; use crate::types::tagged::*; @@ -73,8 +73,8 @@ pub fn tx_raw_ft_transfer( Ok(events) } -pub fn ibc_token_transfer( - chain_driver: &MonoTagged, +pub async fn ibc_token_transfer( + tx_config: &MonoTagged, port_id: &TaggedPortIdRef<'_, SrcChain, DstChain>, channel_id: &TaggedChannelIdRef<'_, SrcChain, DstChain>, sender: &MonoTagged, @@ -82,37 +82,10 @@ pub fn ibc_token_transfer( denom: &MonoTagged, amount: u64, ) -> Result<(), Error> { - chain_driver - .value() - .runtime - .block_on(async_ibc_token_transfer( - chain_driver, - port_id, - channel_id, - sender, - recipient, - denom, - amount, - )) -} - -pub async fn async_ibc_token_transfer( - chain_driver: &MonoTagged, - port_id: &TaggedPortIdRef<'_, SrcChain, DstChain>, - channel_id: &TaggedChannelIdRef<'_, SrcChain, DstChain>, - sender: &MonoTagged, - recipient: &MonoTagged, - denom: &MonoTagged, - amount: u64, -) -> Result<(), Error> { - let chain_id = chain_driver.chain_id(); - - let tx_config = &chain_driver.value().tx_config; - let status = query_status( - chain_id.value(), - &tx_config.rpc_client, - &tx_config.rpc_address, + &tx_config.value().chain_id, + &tx_config.value().rpc_client, + &tx_config.value().rpc_address, ) .await?; @@ -129,7 +102,7 @@ pub async fn async_ibc_token_transfer Date: Tue, 10 May 2022 14:15:43 +0200 Subject: [PATCH 5/9] Use longer IBC transfer timeout --- tools/test-framework/src/relayer/transfer.rs | 29 +++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/tools/test-framework/src/relayer/transfer.rs b/tools/test-framework/src/relayer/transfer.rs index fdd9fd518b..e930ccafbf 100644 --- a/tools/test-framework/src/relayer/transfer.rs +++ b/tools/test-framework/src/relayer/transfer.rs @@ -3,18 +3,19 @@ `hermes tx raw ft-transfer`. */ +use core::ops::Add; use core::time::Duration; use ibc::events::IbcEvent; use ibc::signer::Signer; -use ibc_relayer::chain::cosmos::query::status::query_status; +use ibc::timestamp::Timestamp; +use ibc::Height; use ibc_relayer::chain::cosmos::types::config::TxConfig; use ibc_relayer::chain::handle::ChainHandle; use ibc_relayer::transfer::{ build_and_send_transfer_messages, build_transfer_message, Amount, TransferOptions, - TransferTimeout, }; -use crate::error::Error; +use crate::error::{handle_generic_error, Error}; use crate::ibc::denom::Denom; use crate::relayer::tx::simple_send_tx; use crate::types::binary::channel::ConnectedChannel; @@ -82,14 +83,16 @@ pub async fn ibc_token_transfer( denom: &MonoTagged, amount: u64, ) -> Result<(), Error> { - let status = query_status( - &tx_config.value().chain_id, - &tx_config.value().rpc_client, - &tx_config.value().rpc_address, - ) - .await?; - - let timeout = TransferTimeout::new(500, Duration::from_secs(60), &status)?; + // During test, all chains should have the same local clock. + // We are also not really interested in setting a timeout for most tests, + // so we just put an approximate 10 minute timeout as the timeout + // field is compulsary. + // + // If tests require explicit timeout, they should explicitly construct the + // transfer message and pass it to send_tx. + let timeout_timestamp = Timestamp::now() + .add(Duration::from_secs(600)) + .map_err(handle_generic_error)?; let message = build_transfer_message( (*port_id.value()).clone(), @@ -98,8 +101,8 @@ pub async fn ibc_token_transfer( denom.value().to_string(), Signer::new(sender.value().address.0.clone()), Signer::new(recipient.value().0.clone()), - timeout.timeout_height, - timeout.timeout_timestamp, + Height::zero(), + timeout_timestamp, ); simple_send_tx(tx_config.value(), &sender.value().key, vec![message]).await?; From de6f63cd18f0be114944176019911a42d3d9089f Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Tue, 10 May 2022 14:32:13 +0200 Subject: [PATCH 6/9] Further increase IBC transfer timeout --- tools/test-framework/src/relayer/transfer.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/test-framework/src/relayer/transfer.rs b/tools/test-framework/src/relayer/transfer.rs index e930ccafbf..7d7cc83494 100644 --- a/tools/test-framework/src/relayer/transfer.rs +++ b/tools/test-framework/src/relayer/transfer.rs @@ -85,13 +85,13 @@ pub async fn ibc_token_transfer( ) -> Result<(), Error> { // During test, all chains should have the same local clock. // We are also not really interested in setting a timeout for most tests, - // so we just put an approximate 10 minute timeout as the timeout - // field is compulsary. + // so we just put an approximate 30 minute timeout as the timeout + // field is compulsary, and we want to avoid IBC timeout on CI. // // If tests require explicit timeout, they should explicitly construct the // transfer message and pass it to send_tx. let timeout_timestamp = Timestamp::now() - .add(Duration::from_secs(600)) + .add(Duration::from_secs(30 * 60)) .map_err(handle_generic_error)?; let message = build_transfer_message( From 84385ef2633f7632f55006d23af3944e0b323fe8 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Tue, 10 May 2022 15:27:18 +0200 Subject: [PATCH 7/9] Fix client expiration test in gaia7 --- .../src/tests/client_expiration.rs | 64 +++++-------------- tools/test-framework/src/relayer/transfer.rs | 4 +- tools/test-framework/src/util/retry.rs | 4 +- 3 files changed, 21 insertions(+), 51 deletions(-) diff --git a/tools/integration-test/src/tests/client_expiration.rs b/tools/integration-test/src/tests/client_expiration.rs index c9b177991c..bfd08b83c6 100644 --- a/tools/integration-test/src/tests/client_expiration.rs +++ b/tools/integration-test/src/tests/client_expiration.rs @@ -287,8 +287,19 @@ impl BinaryChainTest for PacketExpirationTest { )? }; + chains.node_a.chain_driver().ibc_transfer_token( + &channels.port_a.as_ref(), + &channels.channel_id_a.as_ref(), + &chains.node_a.wallets().user1(), + &chains.node_b.wallets().user1().address(), + &chains.node_a.denom(), + 100, + )?; + wait_for_client_expiry(); + info!("Packet worker should fail after client expires"); + relayer.with_supervisor(|| { let denom_a = chains.node_a.denom(); @@ -298,55 +309,14 @@ impl BinaryChainTest for PacketExpirationTest { &denom_a, )?; - { - info!("sending first IBC transfer after client is expired. this should cause packet worker to fail"); - - chains.node_a.chain_driver().ibc_transfer_token( - &channels.port_a.as_ref(), - &channels.channel_id_a.as_ref(), - &chains.node_a.wallets().user1(), - &chains.node_b.wallets().user1().address(), - &chains.node_a.denom(), - 100, - )?; - - sleep(Duration::from_secs(10)); - - // We cannot check for the sender's balance, because - // on Gaia v6 the transaction would just fail on expired client, - // and the fund is not deducted from the user wallet. - // But on Gaia v4 and v5 the fund will still be deducted - // even though the IBC transfer will fail. + sleep(Duration::from_secs(10)); - let balance_b = chains.node_b.chain_driver().query_balance( - &chains.node_b.wallets().user1().address(), - &denom_b.as_ref(), - )?; - - assert_eq("balance on wallet B should remain zero", &balance_b, &0)?; - } - - { - info!("sending a second IBC transfer. there should be no log from packet worker from this point on"); - - chains.node_a.chain_driver().ibc_transfer_token( - &channels.port_a.as_ref(), - &channels.channel_id_a.as_ref(), - &chains.node_a.wallets().user1(), - &chains.node_b.wallets().user1().address(), - &chains.node_a.denom(), - 100, - )?; - - sleep(Duration::from_secs(10)); - - let balance_b = chains.node_b.chain_driver().query_balance( - &chains.node_b.wallets().user1().address(), - &denom_b.as_ref(), - )?; + let balance_b = chains.node_b.chain_driver().query_balance( + &chains.node_b.wallets().user1().address(), + &denom_b.as_ref(), + )?; - assert_eq("balance on wallet B should remain zero", &balance_b, &0)?; - } + assert_eq("balance on wallet B should remain zero", &balance_b, &0)?; Ok(()) }) diff --git a/tools/test-framework/src/relayer/transfer.rs b/tools/test-framework/src/relayer/transfer.rs index 7d7cc83494..4bf4e63e2d 100644 --- a/tools/test-framework/src/relayer/transfer.rs +++ b/tools/test-framework/src/relayer/transfer.rs @@ -85,13 +85,13 @@ pub async fn ibc_token_transfer( ) -> Result<(), Error> { // During test, all chains should have the same local clock. // We are also not really interested in setting a timeout for most tests, - // so we just put an approximate 30 minute timeout as the timeout + // so we just put an approximate 1 minute timeout as the timeout // field is compulsary, and we want to avoid IBC timeout on CI. // // If tests require explicit timeout, they should explicitly construct the // transfer message and pass it to send_tx. let timeout_timestamp = Timestamp::now() - .add(Duration::from_secs(30 * 60)) + .add(Duration::from_secs(60)) .map_err(handle_generic_error)?; let message = build_transfer_message( diff --git a/tools/test-framework/src/util/retry.rs b/tools/test-framework/src/util/retry.rs index 30b208d133..2d88feb2b7 100644 --- a/tools/test-framework/src/util/retry.rs +++ b/tools/test-framework/src/util/retry.rs @@ -4,7 +4,7 @@ use core::time::Duration; use std::thread::sleep; -use tracing::{debug, info}; +use tracing::{info, trace}; use crate::error::Error; @@ -28,7 +28,7 @@ pub fn assert_eventually_succeed( return Ok(res); } Err(e) => { - debug!("retrying task {} that failed with error: {}", task_name, e); + trace!("retrying task {} that failed with error: {}", task_name, e); sleep(interval) } } From ee25158038fa27194ac8a04deca44ebf369bd1c0 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 11 May 2022 11:20:23 +0200 Subject: [PATCH 8/9] Move tx_raw_ft_transfer to simulation test --- tools/integration-test/src/lib.rs | 1 + .../src/tests/manual/simulation.rs | 43 ++++++++++- tools/test-framework/src/chain/tagged.rs | 12 ++-- tools/test-framework/src/prelude.rs | 1 + tools/test-framework/src/relayer/transfer.rs | 72 ++++--------------- 5 files changed, 62 insertions(+), 67 deletions(-) diff --git a/tools/integration-test/src/lib.rs b/tools/integration-test/src/lib.rs index 192cb697cc..75d580024e 100644 --- a/tools/integration-test/src/lib.rs +++ b/tools/integration-test/src/lib.rs @@ -1,2 +1,3 @@ +#[allow(clippy::too_many_arguments)] #[cfg(test)] pub mod tests; diff --git a/tools/integration-test/src/tests/manual/simulation.rs b/tools/integration-test/src/tests/manual/simulation.rs index 71992f4120..e30c4418ee 100644 --- a/tools/integration-test/src/tests/manual/simulation.rs +++ b/tools/integration-test/src/tests/manual/simulation.rs @@ -12,10 +12,10 @@ */ use core::time::Duration; +use ibc::events::IbcEvent; use ibc_relayer::config::{types::MaxMsgNum, Config}; - +use ibc_relayer::transfer::{build_and_send_transfer_messages, Amount, TransferOptions}; use ibc_test_framework::prelude::*; -use ibc_test_framework::relayer::transfer::tx_raw_ft_transfer; #[test] fn test_simulation() -> Result<(), Error> { @@ -57,3 +57,42 @@ impl BinaryChannelTest for SimulationTest { suspend() } } + +/** + Perform the same operation as `hermes tx raw ft-transfer`. + + The function call skips the checks done in the CLI, as we already + have the necessary information given to us by the test framework. + + Note that we cannot change the sender's wallet in this case, + as the current `send_tx` implementation in + [`CosmosSdkChain`](ibc_relayer::chain::cosmos::CosmosSdkChain) + always use the signer wallet configured in the + [`ChainConfig`](ibc_relayer::config::ChainConfig). +*/ +fn tx_raw_ft_transfer( + src_handle: &SrcChain, + dst_handle: &DstChain, + channel: &ConnectedChannel, + recipient: &MonoTagged, + denom: &MonoTagged, + amount: u64, + timeout_height_offset: u64, + timeout_duration: Duration, + number_messages: usize, +) -> Result, Error> { + let transfer_options = TransferOptions { + packet_src_port_id: channel.port_a.value().clone(), + packet_src_channel_id: *channel.channel_id_a.value(), + amount: Amount(amount.into()), + denom: denom.value().to_string(), + receiver: Some(recipient.value().0.clone()), + timeout_height_offset, + timeout_duration, + number_msgs: number_messages, + }; + + let events = build_and_send_transfer_messages(src_handle, dst_handle, &transfer_options)?; + + Ok(events) +} diff --git a/tools/test-framework/src/chain/tagged.rs b/tools/test-framework/src/chain/tagged.rs index 5fa9f545c3..da85694af5 100644 --- a/tools/test-framework/src/chain/tagged.rs +++ b/tools/test-framework/src/chain/tagged.rs @@ -65,8 +65,8 @@ pub trait TaggedChainDriverExt { ) -> Result<(), Error>; /** - Tagged version of [`transfer_token`]. Submits an IBC token transfer - transaction to `Chain` to any other `Counterparty` chain. + Submits an IBC token transfer transaction to `Chain` to any other + `Counterparty` chain. The following parameters are accepted: @@ -76,13 +76,13 @@ pub trait TaggedChainDriverExt { - A `ChannelId` on `Chain` that corresponds to a channel connected to `Counterparty`. - - The wallet address of the sender on `Chain`. + - The [`Wallet`] of the sender on `Chain`. - - The wallet address of the recipient on `Counterparty`. - - - The transfer amount. + - The [`WalletAddress`] address of the recipient on `Counterparty`. - The denomination of the amount on `Chain`. + + - The transfer amount. */ fn ibc_transfer_token( &self, diff --git a/tools/test-framework/src/prelude.rs b/tools/test-framework/src/prelude.rs index b070d98b6a..624ed806a4 100644 --- a/tools/test-framework/src/prelude.rs +++ b/tools/test-framework/src/prelude.rs @@ -45,6 +45,7 @@ pub use crate::framework::nary::connection::{ pub use crate::framework::nary::node::{run_nary_node_test, NaryNodeTest, RunNaryNodeTest}; pub use crate::framework::overrides::TestOverrides; pub use crate::framework::supervisor::RunWithSupervisor; +pub use crate::ibc::denom::Denom; pub use crate::relayer::channel::TaggedChannelEndExt; pub use crate::relayer::connection::{TaggedConnectionEndExt, TaggedConnectionExt}; pub use crate::relayer::driver::RelayerDriver; diff --git a/tools/test-framework/src/relayer/transfer.rs b/tools/test-framework/src/relayer/transfer.rs index 4bf4e63e2d..4e0002b521 100644 --- a/tools/test-framework/src/relayer/transfer.rs +++ b/tools/test-framework/src/relayer/transfer.rs @@ -5,75 +5,36 @@ use core::ops::Add; use core::time::Duration; -use ibc::events::IbcEvent; use ibc::signer::Signer; use ibc::timestamp::Timestamp; use ibc::Height; use ibc_relayer::chain::cosmos::types::config::TxConfig; -use ibc_relayer::chain::handle::ChainHandle; -use ibc_relayer::transfer::{ - build_and_send_transfer_messages, build_transfer_message, Amount, TransferOptions, -}; +use ibc_relayer::transfer::build_transfer_message; use crate::error::{handle_generic_error, Error}; use crate::ibc::denom::Denom; use crate::relayer::tx::simple_send_tx; -use crate::types::binary::channel::ConnectedChannel; use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef}; use crate::types::tagged::*; use crate::types::wallet::{Wallet, WalletAddress}; /** - Perform the same operation as `hermes tx raw ft-transfer`. + Perform a simplified version of IBC token transfer for testing purpose. - The function call skips the checks done in the CLI, as we already - have the necessary information given to us by the test framework. + It makes use of the local time to construct a 60 seconds IBC timeout + for testing. During test, all chains should have the same local clock. + We are also not really interested in setting a timeout for most tests, + so we just put an approximate 1 minute timeout as the timeout + field is compulsary, and we want to avoid IBC timeout on CI. - Note that we cannot change the sender's wallet in this case, - as the current `send_tx` implementation in - [`CosmosSdkChain`](ibc_relayer::chain::cosmos::CosmosSdkChain) - always use the signer wallet configured in the - [`ChainConfig`](ibc_relayer::config::ChainConfig). + The other reason we do not allow precise timeout to be specified is + because it requires accessing the counterparty chain to query for + the parameters. This will complicate the API which is unnecessary + in most cases. - Currently the only way you can transfer using a different wallet - is to create a brand new [`ChainHandle`] with the new wallet - specified in the [`ChainConfig`](ibc_relayer::config::ChainConfig). - - Alternatively, it is recommended that for simple case of IBC token - transfer, test authors should instead use the - [`transfer_token`](crate::chain::driver::transfer::transfer_token) - function provided by [`ChainDriver`](crate::chain::driver::ChainDriver). - That uses the `gaiad tx ibc-transfer` command to do the IBC transfer, - which is much simpler as compared to the current way the relayer code - is organized. + If tests require explicit timeout, they should explicitly construct the + transfer message and pass it to send_tx. */ -pub fn tx_raw_ft_transfer( - src_handle: &SrcChain, - dst_handle: &DstChain, - channel: &ConnectedChannel, - recipient: &MonoTagged, - denom: &MonoTagged, - amount: u64, - timeout_height_offset: u64, - timeout_duration: Duration, - number_messages: usize, -) -> Result, Error> { - let transfer_options = TransferOptions { - packet_src_port_id: channel.port_a.value().clone(), - packet_src_channel_id: *channel.channel_id_a.value(), - amount: Amount(amount.into()), - denom: denom.value().to_string(), - receiver: Some(recipient.value().0.clone()), - timeout_height_offset, - timeout_duration, - number_msgs: number_messages, - }; - - let events = build_and_send_transfer_messages(src_handle, dst_handle, &transfer_options)?; - - Ok(events) -} - pub async fn ibc_token_transfer( tx_config: &MonoTagged, port_id: &TaggedPortIdRef<'_, SrcChain, DstChain>, @@ -83,13 +44,6 @@ pub async fn ibc_token_transfer( denom: &MonoTagged, amount: u64, ) -> Result<(), Error> { - // During test, all chains should have the same local clock. - // We are also not really interested in setting a timeout for most tests, - // so we just put an approximate 1 minute timeout as the timeout - // field is compulsary, and we want to avoid IBC timeout on CI. - // - // If tests require explicit timeout, they should explicitly construct the - // transfer message and pass it to send_tx. let timeout_timestamp = Timestamp::now() .add(Duration::from_secs(60)) .map_err(handle_generic_error)?; From 74d614c1b9b45b0ba26609a67790a47a7b5fd312 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 11 May 2022 15:06:24 +0200 Subject: [PATCH 9/9] Modularize ibc_token_transfer --- tools/test-framework/src/relayer/transfer.rs | 42 +++++++++++++------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/tools/test-framework/src/relayer/transfer.rs b/tools/test-framework/src/relayer/transfer.rs index 4e0002b521..d4ac86aff0 100644 --- a/tools/test-framework/src/relayer/transfer.rs +++ b/tools/test-framework/src/relayer/transfer.rs @@ -8,8 +8,9 @@ use core::time::Duration; use ibc::signer::Signer; use ibc::timestamp::Timestamp; use ibc::Height; +use ibc_proto::google::protobuf::Any; use ibc_relayer::chain::cosmos::types::config::TxConfig; -use ibc_relayer::transfer::build_transfer_message; +use ibc_relayer::transfer::build_transfer_message as raw_build_transfer_message; use crate::error::{handle_generic_error, Error}; use crate::ibc::denom::Denom; @@ -18,6 +19,30 @@ use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef}; use crate::types::tagged::*; use crate::types::wallet::{Wallet, WalletAddress}; +pub fn build_transfer_message( + port_id: &TaggedPortIdRef<'_, SrcChain, DstChain>, + channel_id: &TaggedChannelIdRef<'_, SrcChain, DstChain>, + sender: &MonoTagged, + recipient: &MonoTagged, + denom: &MonoTagged, + amount: u64, +) -> Result { + let timeout_timestamp = Timestamp::now() + .add(Duration::from_secs(60)) + .map_err(handle_generic_error)?; + + Ok(raw_build_transfer_message( + (*port_id.value()).clone(), + **channel_id.value(), + amount.into(), + denom.value().to_string(), + Signer::new(sender.value().address.0.clone()), + Signer::new(recipient.value().0.clone()), + Height::zero(), + timeout_timestamp, + )) +} + /** Perform a simplified version of IBC token transfer for testing purpose. @@ -44,20 +69,7 @@ pub async fn ibc_token_transfer( denom: &MonoTagged, amount: u64, ) -> Result<(), Error> { - let timeout_timestamp = Timestamp::now() - .add(Duration::from_secs(60)) - .map_err(handle_generic_error)?; - - let message = build_transfer_message( - (*port_id.value()).clone(), - **channel_id.value(), - amount.into(), - denom.value().to_string(), - Signer::new(sender.value().address.0.clone()), - Signer::new(recipient.value().0.clone()), - Height::zero(), - timeout_timestamp, - ); + let message = build_transfer_message(port_id, channel_id, sender, recipient, denom, amount)?; simple_send_tx(tx_config.value(), &sender.value().key, vec![message]).await?;