From 1373792064f94660748c2bfdd5015c4ac5063b78 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Fri, 6 May 2022 13:14:57 +0200 Subject: [PATCH 001/113] 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 002/113] 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 003/113] 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 004/113] 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 005/113] 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 006/113] 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 007/113] 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 008/113] 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 9bbc35a97ac8ee31c972db53cf227b748966ef5b Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 11 May 2022 12:57:09 +0200 Subject: [PATCH 009/113] Update protobuf and add basic channel with fee test --- .github/workflows/integration.yaml | 32 + flake.lock | 84 +- flake.nix | 4 +- modules/src/core/ics04_channel/version.rs | 7 + proto/src/COSMOS_SDK_COMMIT | 2 +- proto/src/IBC_GO_COMMIT | 2 +- .../prost/cosmos.base.snapshots.v1beta1.rs | 56 ++ proto/src/prost/cosmos.base.store.v1beta1.rs | 72 +- proto/src/prost/cosmos.staking.v1beta1.rs | 102 +-- proto/src/prost/cosmos.tx.signing.v1beta1.rs | 11 + proto/src/prost/cosmos.tx.v1beta1.rs | 55 +- proto/src/prost/google.protobuf.rs | 234 +++--- proto/src/prost/ibc.applications.fee.v1.rs | 735 ++++++++++++++++++ ...ibc.applications.interchain_accounts.v1.rs | 64 +- .../src/prost/ibc.applications.transfer.v1.rs | 2 +- proto/src/prost/ibc.core.channel.v1.rs | 40 + proto/src/prost/ibc.core.connection.v1.rs | 28 +- tools/integration-test/Cargo.toml | 1 + .../src/tests/fee_middleware.rs | 27 + tools/integration-test/src/tests/mod.rs | 3 + 20 files changed, 1236 insertions(+), 325 deletions(-) create mode 100644 proto/src/prost/ibc.applications.fee.v1.rs create mode 100644 tools/integration-test/src/tests/fee_middleware.rs diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml index fb3a68656e..71f0df67b7 100644 --- a/.github/workflows/integration.yaml +++ b/.github/workflows/integration.yaml @@ -173,3 +173,35 @@ jobs: nix shell .#python .#ica -c cargo \ test -p ibc-integration-test --features ica --no-fail-fast -- \ --nocapture --test-threads=1 test_ica_filter + + ics29-fee-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: cachix/install-nix-action@v15 + with: + install_url: https://nixos-nix-install-tests.cachix.org/serve/vij683ly7sl95nnhb67bdjjfabclr85m/install + install_options: '--tarball-url-prefix https://nixos-nix-install-tests.cachix.org/serve' + extra_nix_config: | + experimental-features = nix-command flakes + - uses: cachix/cachix-action@v10 + with: + name: cosmos + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + - uses: Swatinem/rust-cache@v1 + - uses: actions-rs/cargo@v1 + with: + command: test + args: -p ibc-integration-test --no-fail-fast --no-run + - env: + RUST_LOG: info + RUST_BACKTRACE: 1 + NO_COLOR_LOG: 1 + CHAIN_COMMAND_PATH: simd + run: | + nix shell .#ibc-go-ics29-simapp -c cargo \ + test -p ibc-integration-test --features ics29-fee --no-fail-fast -- \ + --nocapture --test-threads=1 test_channel_with_fee diff --git a/flake.lock b/flake.lock index 3c8414ec3d..371d1acfbf 100644 --- a/flake.lock +++ b/flake.lock @@ -44,11 +44,10 @@ "flake-utils": "flake-utils", "gaia5-src": "gaia5-src", "gaia6-ordered-src": "gaia6-ordered-src", - "gaia6_0_2-src": "gaia6_0_2-src", - "gaia6_0_3-src": "gaia6_0_3-src", - "gaia6_0_4-src": "gaia6_0_4-src", + "gaia6-src": "gaia6-src", "gaia7-src": "gaia7-src", "ibc-go-ics29-src": "ibc-go-ics29-src", + "ibc-go-main-src": "ibc-go-main-src", "ibc-go-v2-src": "ibc-go-v2-src", "ibc-go-v3-src": "ibc-go-v3-src", "ibc-rs-src": "ibc-rs-src", @@ -76,15 +75,16 @@ "wasmvm_1_beta7-src": "wasmvm_1_beta7-src" }, "locked": { - "lastModified": 1650621073, - "narHash": "sha256-/x6oEpNpPbtNU4sC3fenY/4XWmDCBTd/EU1w9h4viIk=", + "lastModified": 1652265349, + "narHash": "sha256-B4LpqfgTQfj7CfHuxe6u+vqc/OdvSaMGrDLLHGX5Ee0=", "owner": "informalsystems", "repo": "cosmos.nix", - "rev": "7cd586a42f1468c077f5d0f5d347d26312bcd6fa", + "rev": "f00d2fc29d7149775f0ad0e47184d7adad4145b6", "type": "github" }, "original": { "owner": "informalsystems", + "ref": "ibc-go-ics29-simapp", "repo": "cosmos.nix", "type": "github" } @@ -234,87 +234,69 @@ "type": "github" } }, - "gaia6_0_2-src": { + "gaia6-src": { "flake": false, "locked": { - "lastModified": 1645118548, - "narHash": "sha256-an1JVPCMcJgQYi+inx4MrAcwYjHTVFvDzw865pJc6C8=", - "owner": "cosmos", - "repo": "gaia", - "rev": "05f3795f196dd32e9233db97ed8742f8559cb483", - "type": "github" - }, - "original": { - "owner": "cosmos", - "ref": "v6.0.2", - "repo": "gaia", - "type": "github" - } - }, - "gaia6_0_3-src": { - "flake": false, - "locked": { - "lastModified": 1645184577, - "narHash": "sha256-a24C1sooMj8mVGYYV2wL7P3kM7xj/MVzfeggj186PQo=", + "lastModified": 1646904235, + "narHash": "sha256-JdD0DTdMo05ggGvpHN5hugEEtGA0/WQ4bhbryDlfGXo=", "owner": "cosmos", "repo": "gaia", - "rev": "8f5dd7549fd21b99099e100da043bd8919d37ac3", + "rev": "305668ab9d962431c79d718bb0ffdeec77a46439", "type": "github" }, "original": { "owner": "cosmos", - "ref": "v6.0.3", + "ref": "v6.0.4", "repo": "gaia", "type": "github" } }, - "gaia6_0_4-src": { + "gaia7-src": { "flake": false, "locked": { - "lastModified": 1646904235, - "narHash": "sha256-JdD0DTdMo05ggGvpHN5hugEEtGA0/WQ4bhbryDlfGXo=", + "lastModified": 1649856981, + "narHash": "sha256-SQCKRnf56uNZp/TCJAkDdHTQNbHJNZXu6BmhXqtNvvs=", "owner": "cosmos", "repo": "gaia", - "rev": "305668ab9d962431c79d718bb0ffdeec77a46439", + "rev": "0664d9ec7c7acbcd944174f2f5326a7df5654bdf", "type": "github" }, "original": { "owner": "cosmos", - "ref": "v6.0.4", + "ref": "v7.0.1", "repo": "gaia", "type": "github" } }, - "gaia7-src": { + "ibc-go-ics29-src": { "flake": false, "locked": { - "lastModified": 1648134734, - "narHash": "sha256-A9EqVHR2GiyuemTrjeaJWyIm6e3XUQ3nSm9dBF9gwvk=", + "lastModified": 1652196479, + "narHash": "sha256-kdSJwSIA2MvPFLguvCPe6TnzMkmQI3pIVJNhN/B7gwU=", "owner": "cosmos", - "repo": "gaia", - "rev": "79fcf71689358b6212ae91f41070de9669421cf5", + "repo": "ibc-go", + "rev": "dcd0681d8f07c624f53b9a9ffe9de2f122486207", "type": "github" }, "original": { "owner": "cosmos", - "ref": "v7.0.0", - "repo": "gaia", + "ref": "ics29-beta2", + "repo": "ibc-go", "type": "github" } }, - "ibc-go-ics29-src": { + "ibc-go-main-src": { "flake": false, "locked": { - "lastModified": 1647958967, - "narHash": "sha256-QZ/BQ+qnz+dmosx7/bptIoAyufeWRdT2i420p2ujqf8=", + "lastModified": 1651571071, + "narHash": "sha256-AwTTN6p5/Q5tnoipuylv1qF8Gw4I7YHASLvIwtLxvLA=", "owner": "cosmos", "repo": "ibc-go", - "rev": "ab90f07e9a776a8aafe333a25f91fa43a0e42560", + "rev": "bd086506f9256c4d5776bc38d2e930b523eb5125", "type": "github" }, "original": { "owner": "cosmos", - "ref": "ics29-fee-middleware", "repo": "ibc-go", "type": "github" } @@ -455,11 +437,11 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1651114127, - "narHash": "sha256-/lLC0wkMZkAdA5e1W76SnJzbhfOGDvync3VRHJMtAKk=", + "lastModified": 1652133925, + "narHash": "sha256-kfATGChLe9/fQVZkXN9G71JAVMlhePv1qDbaRKklkQs=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "6766fb6503ae1ebebc2a9704c162b2aef351f921", + "rev": "51d859cdab1ef58755bd342d45352fc607f5e59b", "type": "github" }, "original": { @@ -485,11 +467,11 @@ }, "nixpkgs_4": { "locked": { - "lastModified": 1651114127, - "narHash": "sha256-/lLC0wkMZkAdA5e1W76SnJzbhfOGDvync3VRHJMtAKk=", + "lastModified": 1651804312, + "narHash": "sha256-DJxOGlxwQccuuwXUS0oRRkcNJbW5UP4fpsL5ga9ZwYw=", "owner": "nixos", "repo": "nixpkgs", - "rev": "6766fb6503ae1ebebc2a9704c162b2aef351f921", + "rev": "d59dd43e49f24b58fe8d5ded38cbdf00c3da4dc2", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 2bb84d56bc..2700da6698 100644 --- a/flake.nix +++ b/flake.nix @@ -4,7 +4,7 @@ inputs = { nixpkgs.url = github:nixos/nixpkgs/nixpkgs-unstable; flake-utils.url = github:numtide/flake-utils; - cosmos-nix.url = github:informalsystems/cosmos.nix; + cosmos-nix.url = github:informalsystems/cosmos.nix/ibc-go-ics29-simapp; }; outputs = inputs: @@ -36,6 +36,8 @@ gaia6-ordered ibc-go-v2-simapp ibc-go-v3-simapp + ibc-go-main-simapp + ibc-go-ics29-simapp ; python = nixpkgs.python3.withPackages (p: [ diff --git a/modules/src/core/ics04_channel/version.rs b/modules/src/core/ics04_channel/version.rs index a5c611bf7a..a3fffefe3e 100644 --- a/modules/src/core/ics04_channel/version.rs +++ b/modules/src/core/ics04_channel/version.rs @@ -27,6 +27,13 @@ impl Version { Self::new(ics20_fungible_token_transfer::VERSION.to_string()) } + pub fn ics20_with_fee() -> Self { + Self::new(format!( + "{{ \"feeVersion\": \"ics29-1\", \"appVersion\": \"{}\" }}", + ics20_fungible_token_transfer::VERSION + )) + } + pub fn empty() -> Self { Self::new("".to_string()) } diff --git a/proto/src/COSMOS_SDK_COMMIT b/proto/src/COSMOS_SDK_COMMIT index c11b353538..0a695d7e1b 100644 --- a/proto/src/COSMOS_SDK_COMMIT +++ b/proto/src/COSMOS_SDK_COMMIT @@ -1 +1 @@ -2646b474c7beb0c93d4fafd395ef345f41afc251 +ad9e5620fb3445c716e9de45cfcdb56e8f1745bf diff --git a/proto/src/IBC_GO_COMMIT b/proto/src/IBC_GO_COMMIT index 28c3c08558..54b567fe07 100644 --- a/proto/src/IBC_GO_COMMIT +++ b/proto/src/IBC_GO_COMMIT @@ -1 +1 @@ -55344184b3a5a5eb2ad2a96a7b0f715a210494f9 +dcd0681d8f07c624f53b9a9ffe9de2f122486207 diff --git a/proto/src/prost/cosmos.base.snapshots.v1beta1.rs b/proto/src/prost/cosmos.base.snapshots.v1beta1.rs index 39aae96577..3550faf02e 100644 --- a/proto/src/prost/cosmos.base.snapshots.v1beta1.rs +++ b/proto/src/prost/cosmos.base.snapshots.v1beta1.rs @@ -19,3 +19,59 @@ pub struct Metadata { #[prost(bytes="vec", repeated, tag="1")] pub chunk_hashes: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, } +/// SnapshotItem is an item contained in a rootmulti.Store snapshot. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SnapshotItem { + /// item is the specific type of snapshot item. + #[prost(oneof="snapshot_item::Item", tags="1, 2, 3, 4")] + pub item: ::core::option::Option, +} +/// Nested message and enum types in `SnapshotItem`. +pub mod snapshot_item { + /// item is the specific type of snapshot item. + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Item { + #[prost(message, tag="1")] + Store(super::SnapshotStoreItem), + #[prost(message, tag="2")] + Iavl(super::SnapshotIavlItem), + #[prost(message, tag="3")] + Extension(super::SnapshotExtensionMeta), + #[prost(message, tag="4")] + ExtensionPayload(super::SnapshotExtensionPayload), + } +} +/// SnapshotStoreItem contains metadata about a snapshotted store. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SnapshotStoreItem { + #[prost(string, tag="1")] + pub name: ::prost::alloc::string::String, +} +/// SnapshotIAVLItem is an exported IAVL node. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SnapshotIavlItem { + #[prost(bytes="vec", tag="1")] + pub key: ::prost::alloc::vec::Vec, + #[prost(bytes="vec", tag="2")] + pub value: ::prost::alloc::vec::Vec, + /// version is block height + #[prost(int64, tag="3")] + pub version: i64, + /// height is depth of the tree. + #[prost(int32, tag="4")] + pub height: i32, +} +/// SnapshotExtensionMeta contains metadata about an external snapshotter. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SnapshotExtensionMeta { + #[prost(string, tag="1")] + pub name: ::prost::alloc::string::String, + #[prost(uint32, tag="2")] + pub format: u32, +} +/// SnapshotExtensionPayload contains payloads of an external snapshotter. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SnapshotExtensionPayload { + #[prost(bytes="vec", tag="1")] + pub payload: ::prost::alloc::vec::Vec, +} diff --git a/proto/src/prost/cosmos.base.store.v1beta1.rs b/proto/src/prost/cosmos.base.store.v1beta1.rs index 7a12088d7a..6600689491 100644 --- a/proto/src/prost/cosmos.base.store.v1beta1.rs +++ b/proto/src/prost/cosmos.base.store.v1beta1.rs @@ -1,57 +1,3 @@ -/// SnapshotItem is an item contained in a rootmulti.Store snapshot. -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct SnapshotItem { - /// item is the specific type of snapshot item. - #[prost(oneof="snapshot_item::Item", tags="1, 2")] - pub item: ::core::option::Option, -} -/// Nested message and enum types in `SnapshotItem`. -pub mod snapshot_item { - /// item is the specific type of snapshot item. - #[derive(Clone, PartialEq, ::prost::Oneof)] - pub enum Item { - #[prost(message, tag="1")] - Store(super::SnapshotStoreItem), - #[prost(message, tag="2")] - Iavl(super::SnapshotIavlItem), - } -} -/// SnapshotStoreItem contains metadata about a snapshotted store. -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct SnapshotStoreItem { - #[prost(string, tag="1")] - pub name: ::prost::alloc::string::String, -} -/// SnapshotIAVLItem is an exported IAVL node. -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct SnapshotIavlItem { - #[prost(bytes="vec", tag="1")] - pub key: ::prost::alloc::vec::Vec, - #[prost(bytes="vec", tag="2")] - pub value: ::prost::alloc::vec::Vec, - #[prost(int64, tag="3")] - pub version: i64, - #[prost(int32, tag="4")] - pub height: i32, -} -/// StoreKVPair is a KVStore KVPair used for listening to state changes (Sets and Deletes) -/// It optionally includes the StoreKey for the originating KVStore and a Boolean flag to distinguish between Sets and -/// Deletes -/// -/// Since: cosmos-sdk 0.43 -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct StoreKvPair { - /// the store key for the KVStore this pair originates from - #[prost(string, tag="1")] - pub store_key: ::prost::alloc::string::String, - /// true indicates a delete operation, false indicates a set operation - #[prost(bool, tag="2")] - pub delete: bool, - #[prost(bytes="vec", tag="3")] - pub key: ::prost::alloc::vec::Vec, - #[prost(bytes="vec", tag="4")] - pub value: ::prost::alloc::vec::Vec, -} /// CommitInfo defines commit information used by the multi-store when committing /// a version/height. #[derive(Clone, PartialEq, ::prost::Message)] @@ -79,3 +25,21 @@ pub struct CommitId { #[prost(bytes="vec", tag="2")] pub hash: ::prost::alloc::vec::Vec, } +/// StoreKVPair is a KVStore KVPair used for listening to state changes (Sets and Deletes) +/// It optionally includes the StoreKey for the originating KVStore and a Boolean flag to distinguish between Sets and +/// Deletes +/// +/// Since: cosmos-sdk 0.43 +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StoreKvPair { + /// the store key for the KVStore this pair originates from + #[prost(string, tag="1")] + pub store_key: ::prost::alloc::string::String, + /// true indicates a delete operation, false indicates a set operation + #[prost(bool, tag="2")] + pub delete: bool, + #[prost(bytes="vec", tag="3")] + pub key: ::prost::alloc::vec::Vec, + #[prost(bytes="vec", tag="4")] + pub value: ::prost::alloc::vec::Vec, +} diff --git a/proto/src/prost/cosmos.staking.v1beta1.rs b/proto/src/prost/cosmos.staking.v1beta1.rs index 652c4ad5b4..18f312a9b7 100644 --- a/proto/src/prost/cosmos.staking.v1beta1.rs +++ b/proto/src/prost/cosmos.staking.v1beta1.rs @@ -552,6 +552,57 @@ pub mod msg_client { } } } +/// StakeAuthorization defines authorization for delegate/undelegate/redelegate. +/// +/// Since: cosmos-sdk 0.43 +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StakeAuthorization { + /// max_tokens specifies the maximum amount of tokens can be delegate to a validator. If it is + /// empty, there is no spend limit and any amount of coins can be delegated. + #[prost(message, optional, tag="1")] + pub max_tokens: ::core::option::Option, + /// authorization_type defines one of AuthorizationType. + #[prost(enumeration="AuthorizationType", tag="4")] + pub authorization_type: i32, + /// validators is the oneof that represents either allow_list or deny_list + #[prost(oneof="stake_authorization::Validators", tags="2, 3")] + pub validators: ::core::option::Option, +} +/// Nested message and enum types in `StakeAuthorization`. +pub mod stake_authorization { + /// Validators defines list of validator addresses. + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct ValidatorsVec { + #[prost(string, repeated, tag="1")] + pub address: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, + } + /// validators is the oneof that represents either allow_list or deny_list + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Validators { + /// allow_list specifies list of validator addresses to whom grantee can delegate tokens on behalf of granter's + /// account. + #[prost(message, tag="2")] + AllowList(ValidatorsVec), + /// deny_list specifies list of validator addresses to whom grantee can not delegate tokens. + #[prost(message, tag="3")] + DenyList(ValidatorsVec), + } +} +/// AuthorizationType defines the type of staking module authorization type +/// +/// Since: cosmos-sdk 0.43 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum AuthorizationType { + /// AUTHORIZATION_TYPE_UNSPECIFIED specifies an unknown authorization type + Unspecified = 0, + /// AUTHORIZATION_TYPE_DELEGATE defines an authorization type for Msg/Delegate + Delegate = 1, + /// AUTHORIZATION_TYPE_UNDELEGATE defines an authorization type for Msg/Undelegate + Undelegate = 2, + /// AUTHORIZATION_TYPE_REDELEGATE defines an authorization type for Msg/BeginRedelegate + Redelegate = 3, +} /// QueryValidatorsRequest is request type for Query/Validators RPC method. #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryValidatorsRequest { @@ -1228,54 +1279,3 @@ pub struct LastValidatorPower { #[prost(int64, tag="2")] pub power: i64, } -/// StakeAuthorization defines authorization for delegate/undelegate/redelegate. -/// -/// Since: cosmos-sdk 0.43 -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct StakeAuthorization { - /// max_tokens specifies the maximum amount of tokens can be delegate to a validator. If it is - /// empty, there is no spend limit and any amount of coins can be delegated. - #[prost(message, optional, tag="1")] - pub max_tokens: ::core::option::Option, - /// authorization_type defines one of AuthorizationType. - #[prost(enumeration="AuthorizationType", tag="4")] - pub authorization_type: i32, - /// validators is the oneof that represents either allow_list or deny_list - #[prost(oneof="stake_authorization::Validators", tags="2, 3")] - pub validators: ::core::option::Option, -} -/// Nested message and enum types in `StakeAuthorization`. -pub mod stake_authorization { - /// Validators defines list of validator addresses. - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct ValidatorVec { - #[prost(string, repeated, tag="1")] - pub address: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, - } - /// validators is the oneof that represents either allow_list or deny_list - #[derive(Clone, PartialEq, ::prost::Oneof)] - pub enum Validators { - /// allow_list specifies list of validator addresses to whom grantee can delegate tokens on behalf of granter's - /// account. - #[prost(message, tag="2")] - AllowList(ValidatorVec), - /// deny_list specifies list of validator addresses to whom grantee can not delegate tokens. - #[prost(message, tag="3")] - DenyList(ValidatorVec), - } -} -/// AuthorizationType defines the type of staking module authorization type -/// -/// Since: cosmos-sdk 0.43 -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum AuthorizationType { - /// AUTHORIZATION_TYPE_UNSPECIFIED specifies an unknown authorization type - Unspecified = 0, - /// AUTHORIZATION_TYPE_DELEGATE defines an authorization type for Msg/Delegate - Delegate = 1, - /// AUTHORIZATION_TYPE_UNDELEGATE defines an authorization type for Msg/Undelegate - Undelegate = 2, - /// AUTHORIZATION_TYPE_REDELEGATE defines an authorization type for Msg/BeginRedelegate - Redelegate = 3, -} diff --git a/proto/src/prost/cosmos.tx.signing.v1beta1.rs b/proto/src/prost/cosmos.tx.signing.v1beta1.rs index afa7835191..670f7dbde9 100644 --- a/proto/src/prost/cosmos.tx.signing.v1beta1.rs +++ b/proto/src/prost/cosmos.tx.signing.v1beta1.rs @@ -82,4 +82,15 @@ pub enum SignMode { /// SIGN_MODE_LEGACY_AMINO_JSON is a backwards compatibility mode which uses /// Amino JSON and will be removed in the future LegacyAminoJson = 127, + /// SIGN_MODE_EIP_191 specifies the sign mode for EIP 191 signing on the Cosmos + /// SDK. Ref: + /// + /// Currently, SIGN_MODE_EIP_191 is registered as a SignMode enum variant, + /// but is not implemented on the SDK by default. To enable EIP-191, you need + /// to pass a custom `TxConfig` that has an implementation of + /// `SignModeHandler` for EIP-191. The SDK may decide to fully support + /// EIP-191 in the future. + /// + /// Since: cosmos-sdk 0.45.2 + Eip191 = 191, } diff --git a/proto/src/prost/cosmos.tx.v1beta1.rs b/proto/src/prost/cosmos.tx.v1beta1.rs index 7de3bb5c8a..0bb20237ec 100644 --- a/proto/src/prost/cosmos.tx.v1beta1.rs +++ b/proto/src/prost/cosmos.tx.v1beta1.rs @@ -195,7 +195,7 @@ pub struct GetTxsEventRequest { /// events is the list of transaction event type. #[prost(string, repeated, tag="1")] pub events: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, - /// pagination defines an pagination for the request. + /// pagination defines a pagination for the request. #[prost(message, optional, tag="2")] pub pagination: ::core::option::Option, #[prost(enumeration="OrderBy", tag="3")] @@ -211,7 +211,7 @@ pub struct GetTxsEventResponse { /// tx_responses is the list of queried TxResponses. #[prost(message, repeated, tag="2")] pub tx_responses: ::prost::alloc::vec::Vec, - /// pagination defines an pagination for the response. + /// pagination defines a pagination for the response. #[prost(message, optional, tag="3")] pub pagination: ::core::option::Option, } @@ -277,6 +277,35 @@ pub struct GetTxResponse { #[prost(message, optional, tag="2")] pub tx_response: ::core::option::Option, } +/// GetBlockWithTxsRequest is the request type for the Service.GetBlockWithTxs +/// RPC method. +/// +/// Since: cosmos-sdk 0.45.2 +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetBlockWithTxsRequest { + /// height is the height of the block to query. + #[prost(int64, tag="1")] + pub height: i64, + /// pagination defines a pagination for the request. + #[prost(message, optional, tag="2")] + pub pagination: ::core::option::Option, +} +/// GetBlockWithTxsResponse is the response type for the Service.GetBlockWithTxs method. +/// +/// Since: cosmos-sdk 0.45.2 +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetBlockWithTxsResponse { + /// txs are the transactions in the block. + #[prost(message, repeated, tag="1")] + pub txs: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag="2")] + pub block_id: ::core::option::Option<::tendermint_proto::types::BlockId>, + #[prost(message, optional, tag="3")] + pub block: ::core::option::Option<::tendermint_proto::types::Block>, + /// pagination defines a pagination for the response. + #[prost(message, optional, tag="4")] + pub pagination: ::core::option::Option, +} /// OrderBy defines the sorting order #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] @@ -449,5 +478,27 @@ pub mod service_client { ); self.inner.unary(request.into_request(), path, codec).await } + /// GetBlockWithTxs fetches a block with decoded txs. + /// + /// Since: cosmos-sdk 0.45.2 + pub async fn get_block_with_txs( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/cosmos.tx.v1beta1.Service/GetBlockWithTxs", + ); + self.inner.unary(request.into_request(), path, codec).await + } } } diff --git a/proto/src/prost/google.protobuf.rs b/proto/src/prost/google.protobuf.rs index 496e093180..fccde2e9af 100644 --- a/proto/src/prost/google.protobuf.rs +++ b/proto/src/prost/google.protobuf.rs @@ -913,6 +913,123 @@ pub mod generated_code_info { pub end: ::core::option::Option, } } +/// `Any` contains an arbitrary serialized protocol buffer message along with a +/// URL that describes the type of the serialized message. +/// +/// Protobuf library provides support to pack/unpack Any values in the form +/// of utility functions or additional generated methods of the Any type. +/// +/// Example 1: Pack and unpack a message in C++. +/// +/// Foo foo = ...; +/// Any any; +/// any.PackFrom(foo); +/// ... +/// if (any.UnpackTo(&foo)) { +/// ... +/// } +/// +/// Example 2: Pack and unpack a message in Java. +/// +/// Foo foo = ...; +/// Any any = Any.pack(foo); +/// ... +/// if (any.is(Foo.class)) { +/// foo = any.unpack(Foo.class); +/// } +/// +/// Example 3: Pack and unpack a message in Python. +/// +/// foo = Foo(...) +/// any = Any() +/// any.Pack(foo) +/// ... +/// if any.Is(Foo.DESCRIPTOR): +/// any.Unpack(foo) +/// ... +/// +/// Example 4: Pack and unpack a message in Go +/// +/// foo := &pb.Foo{...} +/// any, err := ptypes.MarshalAny(foo) +/// ... +/// foo := &pb.Foo{} +/// if err := ptypes.UnmarshalAny(any, foo); err != nil { +/// ... +/// } +/// +/// The pack methods provided by protobuf library will by default use +/// 'type.googleapis.com/full.type.name' as the type URL and the unpack +/// methods only use the fully qualified type name after the last '/' +/// in the type URL, for example "foo.bar.com/x/y.z" will yield type +/// name "y.z". +/// +/// +/// JSON +/// ==== +/// The JSON representation of an `Any` value uses the regular +/// representation of the deserialized, embedded message, with an +/// additional field `@type` which contains the type URL. Example: +/// +/// package google.profile; +/// message Person { +/// string first_name = 1; +/// string last_name = 2; +/// } +/// +/// { +/// "@type": "type.googleapis.com/google.profile.Person", +/// "firstName": , +/// "lastName": +/// } +/// +/// If the embedded message type is well-known and has a custom JSON +/// representation, that representation will be embedded adding a field +/// `value` which holds the custom JSON in addition to the `@type` +/// field. Example (for message \[google.protobuf.Duration][\]): +/// +/// { +/// "@type": "type.googleapis.com/google.protobuf.Duration", +/// "value": "1.212s" +/// } +/// +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Any { + /// A URL/resource name that uniquely identifies the type of the serialized + /// protocol buffer message. This string must contain at least + /// one "/" character. The last segment of the URL's path must represent + /// the fully qualified name of the type (as in + /// `path/google.protobuf.Duration`). The name should be in a canonical form + /// (e.g., leading "." is not accepted). + /// + /// In practice, teams usually precompile into the binary all types that they + /// expect it to use in the context of Any. However, for URLs which use the + /// scheme `http`, `https`, or no scheme, one can optionally set up a type + /// server that maps type URLs to message definitions as follows: + /// + /// * If no scheme is provided, `https` is assumed. + /// * An HTTP GET on the URL must yield a \[google.protobuf.Type][\] + /// value in binary format, or produce an error. + /// * Applications are allowed to cache lookup results based on the + /// URL, or have them precompiled into a binary to avoid any + /// lookup. Therefore, binary compatibility needs to be preserved + /// on changes to types. (Use versioned type names to manage + /// breaking changes.) + /// + /// Note: this functionality is not currently available in the official + /// protobuf release, and it is not used for type URLs beginning with + /// type.googleapis.com. + /// + /// Schemes other than `http`, `https` (or the empty scheme) might be + /// used with implementation specific semantics. + /// + #[prost(string, tag="1")] + pub type_url: ::prost::alloc::string::String, + /// Must be a valid serialized protocol buffer of the above specified type. + #[prost(bytes="vec", tag="2")] + pub value: ::prost::alloc::vec::Vec, +} /// A Timestamp represents a point in time independent of any time zone or local /// calendar, encoded as a count of seconds and fractions of seconds at /// nanosecond resolution. The count is relative to an epoch at UTC midnight on @@ -1098,120 +1215,3 @@ pub struct Duration { #[prost(int32, tag="2")] pub nanos: i32, } -/// `Any` contains an arbitrary serialized protocol buffer message along with a -/// URL that describes the type of the serialized message. -/// -/// Protobuf library provides support to pack/unpack Any values in the form -/// of utility functions or additional generated methods of the Any type. -/// -/// Example 1: Pack and unpack a message in C++. -/// -/// Foo foo = ...; -/// Any any; -/// any.PackFrom(foo); -/// ... -/// if (any.UnpackTo(&foo)) { -/// ... -/// } -/// -/// Example 2: Pack and unpack a message in Java. -/// -/// Foo foo = ...; -/// Any any = Any.pack(foo); -/// ... -/// if (any.is(Foo.class)) { -/// foo = any.unpack(Foo.class); -/// } -/// -/// Example 3: Pack and unpack a message in Python. -/// -/// foo = Foo(...) -/// any = Any() -/// any.Pack(foo) -/// ... -/// if any.Is(Foo.DESCRIPTOR): -/// any.Unpack(foo) -/// ... -/// -/// Example 4: Pack and unpack a message in Go -/// -/// foo := &pb.Foo{...} -/// any, err := ptypes.MarshalAny(foo) -/// ... -/// foo := &pb.Foo{} -/// if err := ptypes.UnmarshalAny(any, foo); err != nil { -/// ... -/// } -/// -/// The pack methods provided by protobuf library will by default use -/// 'type.googleapis.com/full.type.name' as the type URL and the unpack -/// methods only use the fully qualified type name after the last '/' -/// in the type URL, for example "foo.bar.com/x/y.z" will yield type -/// name "y.z". -/// -/// -/// JSON -/// ==== -/// The JSON representation of an `Any` value uses the regular -/// representation of the deserialized, embedded message, with an -/// additional field `@type` which contains the type URL. Example: -/// -/// package google.profile; -/// message Person { -/// string first_name = 1; -/// string last_name = 2; -/// } -/// -/// { -/// "@type": "type.googleapis.com/google.profile.Person", -/// "firstName": , -/// "lastName": -/// } -/// -/// If the embedded message type is well-known and has a custom JSON -/// representation, that representation will be embedded adding a field -/// `value` which holds the custom JSON in addition to the `@type` -/// field. Example (for message \[google.protobuf.Duration][\]): -/// -/// { -/// "@type": "type.googleapis.com/google.protobuf.Duration", -/// "value": "1.212s" -/// } -/// -#[derive(::serde::Serialize, ::serde::Deserialize)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Any { - /// A URL/resource name that uniquely identifies the type of the serialized - /// protocol buffer message. This string must contain at least - /// one "/" character. The last segment of the URL's path must represent - /// the fully qualified name of the type (as in - /// `path/google.protobuf.Duration`). The name should be in a canonical form - /// (e.g., leading "." is not accepted). - /// - /// In practice, teams usually precompile into the binary all types that they - /// expect it to use in the context of Any. However, for URLs which use the - /// scheme `http`, `https`, or no scheme, one can optionally set up a type - /// server that maps type URLs to message definitions as follows: - /// - /// * If no scheme is provided, `https` is assumed. - /// * An HTTP GET on the URL must yield a \[google.protobuf.Type][\] - /// value in binary format, or produce an error. - /// * Applications are allowed to cache lookup results based on the - /// URL, or have them precompiled into a binary to avoid any - /// lookup. Therefore, binary compatibility needs to be preserved - /// on changes to types. (Use versioned type names to manage - /// breaking changes.) - /// - /// Note: this functionality is not currently available in the official - /// protobuf release, and it is not used for type URLs beginning with - /// type.googleapis.com. - /// - /// Schemes other than `http`, `https` (or the empty scheme) might be - /// used with implementation specific semantics. - /// - #[prost(string, tag="1")] - pub type_url: ::prost::alloc::string::String, - /// Must be a valid serialized protocol buffer of the above specified type. - #[prost(bytes="vec", tag="2")] - pub value: ::prost::alloc::vec::Vec, -} diff --git a/proto/src/prost/ibc.applications.fee.v1.rs b/proto/src/prost/ibc.applications.fee.v1.rs new file mode 100644 index 0000000000..038a8c6b00 --- /dev/null +++ b/proto/src/prost/ibc.applications.fee.v1.rs @@ -0,0 +1,735 @@ +/// Metadata defines the ICS29 channel specific metadata encoded into the channel version bytestring +/// See ICS004: +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Metadata { + /// fee_version defines the ICS29 fee version + #[prost(string, tag="1")] + pub fee_version: ::prost::alloc::string::String, + /// app_version defines the underlying application version, which may or may not be a JSON encoded bytestring + #[prost(string, tag="2")] + pub app_version: ::prost::alloc::string::String, +} +/// Fee defines the ICS29 receive, acknowledgement and timeout fees +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Fee { + /// the packet receive fee + #[prost(message, repeated, tag="1")] + pub recv_fee: ::prost::alloc::vec::Vec, + /// the packet acknowledgement fee + #[prost(message, repeated, tag="2")] + pub ack_fee: ::prost::alloc::vec::Vec, + /// the packet timeout fee + #[prost(message, repeated, tag="3")] + pub timeout_fee: ::prost::alloc::vec::Vec, +} +/// PacketFee contains ICS29 relayer fees, refund address and optional list of permitted relayers +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PacketFee { + /// fee encapsulates the recv, ack and timeout fees associated with an IBC packet + #[prost(message, optional, tag="1")] + pub fee: ::core::option::Option, + /// the refund address for unspent fees + #[prost(string, tag="2")] + pub refund_address: ::prost::alloc::string::String, + /// optional list of relayers permitted to receive fees + #[prost(string, repeated, tag="3")] + pub relayers: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, +} +/// PacketFees contains a list of type PacketFee +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PacketFees { + /// list of packet fees + #[prost(message, repeated, tag="1")] + pub packet_fees: ::prost::alloc::vec::Vec, +} +/// IdentifiedPacketFees contains a list of type PacketFee and associated PacketId +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct IdentifiedPacketFees { + /// unique packet identifier comprised of the channel ID, port ID and sequence + #[prost(message, optional, tag="1")] + pub packet_id: ::core::option::Option, + /// list of packet fees + #[prost(message, repeated, tag="2")] + pub packet_fees: ::prost::alloc::vec::Vec, +} +/// MsgRegisterCounterpartyAddress defines the request type for the RegisterCounterpartyAddress rpc +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgRegisterCounterpartyAddress { + /// the relayer address + #[prost(string, tag="1")] + pub address: ::prost::alloc::string::String, + /// the counterparty relayer address + #[prost(string, tag="2")] + pub counterparty_address: ::prost::alloc::string::String, + /// unique channel identifier + #[prost(string, tag="3")] + pub channel_id: ::prost::alloc::string::String, +} +/// MsgRegisterCounterpartyAddressResponse defines the response type for the RegisterCounterpartyAddress rpc +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgRegisterCounterpartyAddressResponse { +} +/// MsgPayPacketFee defines the request type for the PayPacketFee rpc +/// This Msg can be used to pay for a packet at the next sequence send & should be combined with the Msg that will be +/// paid for +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgPayPacketFee { + /// fee encapsulates the recv, ack and timeout fees associated with an IBC packet + #[prost(message, optional, tag="1")] + pub fee: ::core::option::Option, + /// the source port unique identifier + #[prost(string, tag="2")] + pub source_port_id: ::prost::alloc::string::String, + /// the source channel unique identifer + #[prost(string, tag="3")] + pub source_channel_id: ::prost::alloc::string::String, + /// account address to refund fee if necessary + #[prost(string, tag="4")] + pub signer: ::prost::alloc::string::String, + /// optional list of relayers permitted to the receive packet fees + #[prost(string, repeated, tag="5")] + pub relayers: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, +} +/// MsgPayPacketFeeResponse defines the response type for the PayPacketFee rpc +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgPayPacketFeeResponse { +} +/// MsgPayPacketFeeAsync defines the request type for the PayPacketFeeAsync rpc +/// This Msg can be used to pay for a packet at a specified sequence (instead of the next sequence send) +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgPayPacketFeeAsync { + /// unique packet identifier comprised of the channel ID, port ID and sequence + #[prost(message, optional, tag="1")] + pub packet_id: ::core::option::Option, + /// the packet fee associated with a particular IBC packet + #[prost(message, optional, tag="2")] + pub packet_fee: ::core::option::Option, +} +/// MsgPayPacketFeeAsyncResponse defines the response type for the PayPacketFeeAsync rpc +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgPayPacketFeeAsyncResponse { +} +/// Generated client implementations. +#[cfg(feature = "client")] +pub mod msg_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + /// Msg defines the ICS29 Msg service. + #[derive(Debug, Clone)] + pub struct MsgClient { + inner: tonic::client::Grpc, + } + impl MsgClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: std::convert::TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl MsgClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Default + Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> MsgClient> + where + F: tonic::service::Interceptor, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + MsgClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with `gzip`. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_gzip(mut self) -> Self { + self.inner = self.inner.send_gzip(); + self + } + /// Enable decompressing responses with `gzip`. + #[must_use] + pub fn accept_gzip(mut self) -> Self { + self.inner = self.inner.accept_gzip(); + self + } + /// RegisterCounterpartyAddress defines a rpc handler method for MsgRegisterCounterpartyAddress + /// RegisterCounterpartyAddress is called by the relayer on each channelEnd and allows them to specify their + /// counterparty address before relaying. This ensures they will be properly compensated for forward relaying since + /// destination chain must send back relayer's source address (counterparty address) in acknowledgement. This function + /// may be called more than once by a relayer, in which case, latest counterparty address is always used. + pub async fn register_counterparty_address( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/ibc.applications.fee.v1.Msg/RegisterCounterpartyAddress", + ); + self.inner.unary(request.into_request(), path, codec).await + } + /// PayPacketFee defines a rpc handler method for MsgPayPacketFee + /// PayPacketFee is an open callback that may be called by any module/user that wishes to escrow funds in order to + /// incentivize the relaying of the packet at the next sequence + /// NOTE: This method is intended to be used within a multi msg transaction, where the subsequent msg that follows + /// initiates the lifecycle of the incentivized packet + pub async fn pay_packet_fee( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/ibc.applications.fee.v1.Msg/PayPacketFee", + ); + self.inner.unary(request.into_request(), path, codec).await + } + /// PayPacketFeeAsync defines a rpc handler method for MsgPayPacketFeeAsync + /// PayPacketFeeAsync is an open callback that may be called by any module/user that wishes to escrow funds in order to + /// incentivize the relaying of a known packet (i.e. at a particular sequence) + pub async fn pay_packet_fee_async( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/ibc.applications.fee.v1.Msg/PayPacketFeeAsync", + ); + self.inner.unary(request.into_request(), path, codec).await + } + } +} +/// GenesisState defines the ICS29 fee middleware genesis state +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GenesisState { + /// list of identified packet fees + #[prost(message, repeated, tag="1")] + pub identified_fees: ::prost::alloc::vec::Vec, + /// list of fee enabled channels + #[prost(message, repeated, tag="2")] + pub fee_enabled_channels: ::prost::alloc::vec::Vec, + /// list of registered relayer addresses + #[prost(message, repeated, tag="3")] + pub registered_relayers: ::prost::alloc::vec::Vec, + /// list of forward relayer addresses + #[prost(message, repeated, tag="4")] + pub forward_relayers: ::prost::alloc::vec::Vec, +} +/// FeeEnabledChannel contains the PortID & ChannelID for a fee enabled channel +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct FeeEnabledChannel { + /// unique port identifier + #[prost(string, tag="1")] + pub port_id: ::prost::alloc::string::String, + /// unique channel identifier + #[prost(string, tag="2")] + pub channel_id: ::prost::alloc::string::String, +} +/// RegisteredRelayerAddress contains the address and counterparty address for a specific relayer (for distributing fees) +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RegisteredRelayerAddress { + /// the relayer address + #[prost(string, tag="1")] + pub address: ::prost::alloc::string::String, + /// the counterparty relayer address + #[prost(string, tag="2")] + pub counterparty_address: ::prost::alloc::string::String, + /// unique channel identifier + #[prost(string, tag="3")] + pub channel_id: ::prost::alloc::string::String, +} +/// ForwardRelayerAddress contains the forward relayer address and PacketId used for async acknowledgements +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ForwardRelayerAddress { + /// the forward relayer address + #[prost(string, tag="1")] + pub address: ::prost::alloc::string::String, + /// unique packet identifer comprised of the channel ID, port ID and sequence + #[prost(message, optional, tag="2")] + pub packet_id: ::core::option::Option, +} +/// QueryIncentivizedPacketsRequest defines the request type for the IncentivizedPackets rpc +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryIncentivizedPacketsRequest { + /// pagination defines an optional pagination for the request. + #[prost(message, optional, tag="1")] + pub pagination: ::core::option::Option, + /// block height at which to query + #[prost(uint64, tag="2")] + pub query_height: u64, +} +/// QueryIncentivizedPacketsResponse defines the response type for the IncentivizedPackets rpc +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryIncentivizedPacketsResponse { + /// list of identified fees for incentivized packets + #[prost(message, repeated, tag="1")] + pub incentivized_packets: ::prost::alloc::vec::Vec, +} +/// QueryIncentivizedPacketRequest defines the request type for the IncentivizedPacket rpc +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryIncentivizedPacketRequest { + /// unique packet identifier comprised of channel ID, port ID and sequence + #[prost(message, optional, tag="1")] + pub packet_id: ::core::option::Option, + /// block height at which to query + #[prost(uint64, tag="2")] + pub query_height: u64, +} +/// QueryIncentivizedPacketsResponse defines the response type for the IncentivizedPacket rpc +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryIncentivizedPacketResponse { + /// the identified fees for the incentivized packet + #[prost(message, optional, tag="1")] + pub incentivized_packet: ::core::option::Option, +} +/// QueryIncentivizedPacketsForChannelRequest defines the request type for querying for all incentivized packets +/// for a specific channel +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryIncentivizedPacketsForChannelRequest { + /// pagination defines an optional pagination for the request. + #[prost(message, optional, tag="1")] + pub pagination: ::core::option::Option, + #[prost(string, tag="2")] + pub port_id: ::prost::alloc::string::String, + #[prost(string, tag="3")] + pub channel_id: ::prost::alloc::string::String, + /// Height to query at + #[prost(uint64, tag="4")] + pub query_height: u64, +} +/// QueryIncentivizedPacketsResponse defines the response type for the incentivized packets RPC +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryIncentivizedPacketsForChannelResponse { + /// Map of all incentivized_packets + #[prost(message, repeated, tag="1")] + pub incentivized_packets: ::prost::alloc::vec::Vec, +} +/// QueryTotalRecvFeesRequest defines the request type for the TotalRecvFees rpc +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryTotalRecvFeesRequest { + /// the packet identifier for the associated fees + #[prost(message, optional, tag="1")] + pub packet_id: ::core::option::Option, +} +/// QueryTotalRecvFeesResponse defines the response type for the TotalRecvFees rpc +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryTotalRecvFeesResponse { + /// the total packet receive fees + #[prost(message, repeated, tag="1")] + pub recv_fees: ::prost::alloc::vec::Vec, +} +/// QueryTotalAckFeesRequest defines the request type for the TotalAckFees rpc +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryTotalAckFeesRequest { + /// the packet identifier for the associated fees + #[prost(message, optional, tag="1")] + pub packet_id: ::core::option::Option, +} +/// QueryTotalAckFeesResponse defines the response type for the TotalAckFees rpc +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryTotalAckFeesResponse { + /// the total packet acknowledgement fees + #[prost(message, repeated, tag="1")] + pub ack_fees: ::prost::alloc::vec::Vec, +} +/// QueryTotalTimeoutFeesRequest defines the request type for the TotalTimeoutFees rpc +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryTotalTimeoutFeesRequest { + /// the packet identifier for the associated fees + #[prost(message, optional, tag="1")] + pub packet_id: ::core::option::Option, +} +/// QueryTotalTimeoutFeesResponse defines the response type for the TotalTimeoutFees rpc +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryTotalTimeoutFeesResponse { + /// the total packet timeout fees + #[prost(message, repeated, tag="1")] + pub timeout_fees: ::prost::alloc::vec::Vec, +} +/// QueryCounterpartyAddressRequest defines the request type for the CounterpartyAddress rpc +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryCounterpartyAddressRequest { + /// unique channel identifier + #[prost(string, tag="1")] + pub channel_id: ::prost::alloc::string::String, + /// the relayer address to which the counterparty is registered + #[prost(string, tag="2")] + pub relayer_address: ::prost::alloc::string::String, +} +/// QueryCounterpartyAddressResponse defines the response type for the CounterpartyAddress rpc +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryCounterpartyAddressResponse { + /// the counterparty address used to compensate forward relaying + #[prost(string, tag="1")] + pub counterparty_address: ::prost::alloc::string::String, +} +/// QueryFeeEnabledChannelsRequest defines the request type for the FeeEnabledChannels rpc +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryFeeEnabledChannelsRequest { + /// pagination defines an optional pagination for the request. + #[prost(message, optional, tag="1")] + pub pagination: ::core::option::Option, + /// block height at which to query + #[prost(uint64, tag="2")] + pub query_height: u64, +} +/// QueryFeeEnabledChannelsResponse defines the response type for the FeeEnabledChannels rpc +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryFeeEnabledChannelsResponse { + /// list of fee enabled channels + #[prost(message, repeated, tag="1")] + pub fee_enabled_channels: ::prost::alloc::vec::Vec, +} +/// QueryFeeEnabledChannelRequest defines the request type for the FeeEnabledChannel rpc +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryFeeEnabledChannelRequest { + /// unique port identifier + #[prost(string, tag="1")] + pub port_id: ::prost::alloc::string::String, + /// unique channel identifier + #[prost(string, tag="2")] + pub channel_id: ::prost::alloc::string::String, +} +/// QueryFeeEnabledChannelResponse defines the response type for the FeeEnabledChannel rpc +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryFeeEnabledChannelResponse { + /// boolean flag representing the fee enabled channel status + #[prost(bool, tag="1")] + pub fee_enabled: bool, +} +/// Generated client implementations. +#[cfg(feature = "client")] +pub mod query_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + /// Query defines the ICS29 gRPC querier service. + #[derive(Debug, Clone)] + pub struct QueryClient { + inner: tonic::client::Grpc, + } + impl QueryClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: std::convert::TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl QueryClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Default + Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> QueryClient> + where + F: tonic::service::Interceptor, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + QueryClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with `gzip`. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_gzip(mut self) -> Self { + self.inner = self.inner.send_gzip(); + self + } + /// Enable decompressing responses with `gzip`. + #[must_use] + pub fn accept_gzip(mut self) -> Self { + self.inner = self.inner.accept_gzip(); + self + } + /// IncentivizedPackets returns all incentivized packets and their associated fees + pub async fn incentivized_packets( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/ibc.applications.fee.v1.Query/IncentivizedPackets", + ); + self.inner.unary(request.into_request(), path, codec).await + } + /// IncentivizedPacket returns all packet fees for a packet given its identifier + pub async fn incentivized_packet( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/ibc.applications.fee.v1.Query/IncentivizedPacket", + ); + self.inner.unary(request.into_request(), path, codec).await + } + /// Gets all incentivized packets for a specific channel + pub async fn incentivized_packets_for_channel( + &mut self, + request: impl tonic::IntoRequest< + super::QueryIncentivizedPacketsForChannelRequest, + >, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/ibc.applications.fee.v1.Query/IncentivizedPacketsForChannel", + ); + self.inner.unary(request.into_request(), path, codec).await + } + /// TotalRecvFees returns the total receive fees for a packet given its identifier + pub async fn total_recv_fees( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/ibc.applications.fee.v1.Query/TotalRecvFees", + ); + self.inner.unary(request.into_request(), path, codec).await + } + /// TotalAckFees returns the total acknowledgement fees for a packet given its identifier + pub async fn total_ack_fees( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/ibc.applications.fee.v1.Query/TotalAckFees", + ); + self.inner.unary(request.into_request(), path, codec).await + } + /// TotalTimeoutFees returns the total timeout fees for a packet given its identifier + pub async fn total_timeout_fees( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/ibc.applications.fee.v1.Query/TotalTimeoutFees", + ); + self.inner.unary(request.into_request(), path, codec).await + } + /// CounterpartyAddress returns the registered counterparty address for forward relaying + pub async fn counterparty_address( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/ibc.applications.fee.v1.Query/CounterpartyAddress", + ); + self.inner.unary(request.into_request(), path, codec).await + } + /// FeeEnabledChannels returns a list of all fee enabled channels + pub async fn fee_enabled_channels( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/ibc.applications.fee.v1.Query/FeeEnabledChannels", + ); + self.inner.unary(request.into_request(), path, codec).await + } + /// FeeEnabledChannel returns true if the provided port and channel identifiers belong to a fee enabled channel + pub async fn fee_enabled_channel( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/ibc.applications.fee.v1.Query/FeeEnabledChannel", + ); + self.inner.unary(request.into_request(), path, codec).await + } + } +} +/// IncentivizedAcknowledgement is the acknowledgement format to be used by applications wrapped in the fee middleware +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct IncentivizedAcknowledgement { + /// the underlying app acknowledgement bytes + #[prost(bytes="vec", tag="1")] + pub app_acknowledgement: ::prost::alloc::vec::Vec, + /// the relayer address which submits the recv packet message + #[prost(string, tag="2")] + pub forward_relayer_address: ::prost::alloc::string::String, + /// success flag of the base application callback + #[prost(bool, tag="3")] + pub underlying_app_success: bool, +} diff --git a/proto/src/prost/ibc.applications.interchain_accounts.v1.rs b/proto/src/prost/ibc.applications.interchain_accounts.v1.rs index 2b5d4b0a98..35ed553094 100644 --- a/proto/src/prost/ibc.applications.interchain_accounts.v1.rs +++ b/proto/src/prost/ibc.applications.interchain_accounts.v1.rs @@ -1,3 +1,35 @@ +/// Metadata defines a set of protocol specific data encoded into the ICS27 channel version bytestring +/// See ICS004: +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Metadata { + /// version defines the ICS27 protocol version + #[prost(string, tag="1")] + pub version: ::prost::alloc::string::String, + /// controller_connection_id is the connection identifier associated with the controller chain + #[prost(string, tag="2")] + pub controller_connection_id: ::prost::alloc::string::String, + /// host_connection_id is the connection identifier associated with the host chain + #[prost(string, tag="3")] + pub host_connection_id: ::prost::alloc::string::String, + /// address defines the interchain account address to be fulfilled upon the OnChanOpenTry handshake step + /// NOTE: the address field is empty on the OnChanOpenInit handshake step + #[prost(string, tag="4")] + pub address: ::prost::alloc::string::String, + /// encoding defines the supported codec format + #[prost(string, tag="5")] + pub encoding: ::prost::alloc::string::String, + /// tx_type defines the type of transactions the interchain account can execute + #[prost(string, tag="6")] + pub tx_type: ::prost::alloc::string::String, +} +/// An InterchainAccount is defined as a BaseAccount & the address of the account owner on the controller chain +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct InterchainAccount { + #[prost(message, optional, tag="1")] + pub base_account: ::core::option::Option, + #[prost(string, tag="2")] + pub account_owner: ::prost::alloc::string::String, +} /// InterchainAccountPacketData is comprised of a raw transaction, type of transaction and optional memo field. #[derive(Clone, PartialEq, ::prost::Message)] pub struct InterchainAccountPacketData { @@ -24,30 +56,6 @@ pub enum Type { /// Execute a transaction on an interchain accounts host chain ExecuteTx = 1, } -/// Metadata defines a set of protocol specific data encoded into the ICS27 channel version bytestring -/// See ICS004: -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Metadata { - /// version defines the ICS27 protocol version - #[prost(string, tag="1")] - pub version: ::prost::alloc::string::String, - /// controller_connection_id is the connection identifier associated with the controller chain - #[prost(string, tag="2")] - pub controller_connection_id: ::prost::alloc::string::String, - /// host_connection_id is the connection identifier associated with the host chain - #[prost(string, tag="3")] - pub host_connection_id: ::prost::alloc::string::String, - /// address defines the interchain account address to be fulfilled upon the OnChanOpenTry handshake step - /// NOTE: the address field is empty on the OnChanOpenInit handshake step - #[prost(string, tag="4")] - pub address: ::prost::alloc::string::String, - /// encoding defines the supported codec format - #[prost(string, tag="5")] - pub encoding: ::prost::alloc::string::String, - /// tx_type defines the type of transactions the interchain account can execute - #[prost(string, tag="6")] - pub tx_type: ::prost::alloc::string::String, -} /// GenesisState defines the interchain accounts genesis state #[derive(Clone, PartialEq, ::prost::Message)] pub struct GenesisState { @@ -100,11 +108,3 @@ pub struct RegisteredInterchainAccount { #[prost(string, tag="3")] pub account_address: ::prost::alloc::string::String, } -/// An InterchainAccount is defined as a BaseAccount & the address of the account owner on the controller chain -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct InterchainAccount { - #[prost(message, optional, tag="1")] - pub base_account: ::core::option::Option, - #[prost(string, tag="2")] - pub account_owner: ::prost::alloc::string::String, -} diff --git a/proto/src/prost/ibc.applications.transfer.v1.rs b/proto/src/prost/ibc.applications.transfer.v1.rs index cbd8978def..22e7de5e44 100644 --- a/proto/src/prost/ibc.applications.transfer.v1.rs +++ b/proto/src/prost/ibc.applications.transfer.v1.rs @@ -206,7 +206,7 @@ pub struct QueryParamsResponse { #[derive(::serde::Serialize, ::serde::Deserialize)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryDenomHashRequest { - /// The denomination trace (\[port_id\]/\[channel_id\])+/\[denom\] + /// The denomination trace `([port_id]/[channel_id])+/[denom]` #[prost(string, tag="1")] pub trace: ::prost::alloc::string::String, } diff --git a/proto/src/prost/ibc.core.channel.v1.rs b/proto/src/prost/ibc.core.channel.v1.rs index 699c45ee05..97ba443585 100644 --- a/proto/src/prost/ibc.core.channel.v1.rs +++ b/proto/src/prost/ibc.core.channel.v1.rs @@ -113,6 +113,22 @@ pub struct PacketState { #[prost(bytes="vec", tag="4")] pub data: ::prost::alloc::vec::Vec, } +/// PacketId is an identifer for a unique Packet +/// Source chains refer to packets by source port/channel +/// Destination chains refer to packets by destination port/channel +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PacketId { + /// channel port identifier + #[prost(string, tag="1")] + pub port_id: ::prost::alloc::string::String, + /// channel unique identifier + #[prost(string, tag="2")] + pub channel_id: ::prost::alloc::string::String, + /// packet sequence + #[prost(uint64, tag="3")] + pub sequence: u64, +} /// Acknowledgement is the recommended acknowledgement format to be used by /// app-specific protocols. /// NOTE: The field numbers 21 and 22 were explicitly chosen to avoid accidental @@ -223,6 +239,8 @@ pub struct MsgChannelOpenInit { pub struct MsgChannelOpenInitResponse { #[prost(string, tag="1")] pub channel_id: ::prost::alloc::string::String, + #[prost(string, tag="2")] + pub version: ::prost::alloc::string::String, } /// MsgChannelOpenInit defines a msg sent by a Relayer to try to open a channel /// on Chain B. The version field within the Channel field has been deprecated. Its @@ -252,6 +270,8 @@ pub struct MsgChannelOpenTry { #[derive(::serde::Serialize, ::serde::Deserialize)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgChannelOpenTryResponse { + #[prost(string, tag="1")] + pub version: ::prost::alloc::string::String, } /// MsgChannelOpenAck defines a msg sent by a Relayer to Chain A to acknowledge /// the change of channel state to TRYOPEN on Chain B. @@ -356,6 +376,8 @@ pub struct MsgRecvPacket { #[derive(::serde::Serialize, ::serde::Deserialize)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgRecvPacketResponse { + #[prost(enumeration="ResponseResultType", tag="1")] + pub result: i32, } /// MsgTimeout receives timed-out packet #[derive(::serde::Serialize, ::serde::Deserialize)] @@ -376,6 +398,8 @@ pub struct MsgTimeout { #[derive(::serde::Serialize, ::serde::Deserialize)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgTimeoutResponse { + #[prost(enumeration="ResponseResultType", tag="1")] + pub result: i32, } /// MsgTimeoutOnClose timed-out packet upon counterparty channel closure. #[derive(::serde::Serialize, ::serde::Deserialize)] @@ -398,6 +422,8 @@ pub struct MsgTimeoutOnClose { #[derive(::serde::Serialize, ::serde::Deserialize)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgTimeoutOnCloseResponse { + #[prost(enumeration="ResponseResultType", tag="1")] + pub result: i32, } /// MsgAcknowledgement receives incoming IBC acknowledgement #[derive(::serde::Serialize, ::serde::Deserialize)] @@ -418,6 +444,20 @@ pub struct MsgAcknowledgement { #[derive(::serde::Serialize, ::serde::Deserialize)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgAcknowledgementResponse { + #[prost(enumeration="ResponseResultType", tag="1")] + pub result: i32, +} +/// ResponseResultType defines the possible outcomes of the execution of a message +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum ResponseResultType { + /// Default zero value enumeration + Unspecified = 0, + /// The message did not call the IBC application callbacks (because, for example, the packet had already been relayed) + Noop = 1, + /// The message was executed successfully + Success = 2, } /// Generated client implementations. #[cfg(feature = "client")] diff --git a/proto/src/prost/ibc.core.connection.v1.rs b/proto/src/prost/ibc.core.connection.v1.rs index bd8a019235..169aa6d71d 100644 --- a/proto/src/prost/ibc.core.connection.v1.rs +++ b/proto/src/prost/ibc.core.connection.v1.rs @@ -128,20 +128,6 @@ pub enum State { /// A connection end has completed the handshake. Open = 3, } -/// GenesisState defines the ibc connection submodule's genesis state. -#[derive(::serde::Serialize, ::serde::Deserialize)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GenesisState { - #[prost(message, repeated, tag="1")] - pub connections: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag="2")] - pub client_connection_paths: ::prost::alloc::vec::Vec, - /// the sequence for the next generated connection identifier - #[prost(uint64, tag="3")] - pub next_connection_sequence: u64, - #[prost(message, optional, tag="4")] - pub params: ::core::option::Option, -} /// MsgConnectionOpenInit defines the msg sent by an account on Chain A to /// initialize a connection with Chain B. #[derive(::serde::Serialize, ::serde::Deserialize)] @@ -727,3 +713,17 @@ pub mod query_client { } } } +/// GenesisState defines the ibc connection submodule's genesis state. +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GenesisState { + #[prost(message, repeated, tag="1")] + pub connections: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag="2")] + pub client_connection_paths: ::prost::alloc::vec::Vec, + /// the sequence for the next generated connection identifier + #[prost(uint64, tag="3")] + pub next_connection_sequence: u64, + #[prost(message, optional, tag="4")] + pub params: ::core::option::Option, +} diff --git a/tools/integration-test/Cargo.toml b/tools/integration-test/Cargo.toml index b01057166f..f591583730 100644 --- a/tools/integration-test/Cargo.toml +++ b/tools/integration-test/Cargo.toml @@ -32,6 +32,7 @@ example = [] manual = [] ordered = [] ica = [] +ics29-fee = [] experimental = [] [[bin]] diff --git a/tools/integration-test/src/tests/fee_middleware.rs b/tools/integration-test/src/tests/fee_middleware.rs new file mode 100644 index 0000000000..d910beba91 --- /dev/null +++ b/tools/integration-test/src/tests/fee_middleware.rs @@ -0,0 +1,27 @@ +use ibc::core::ics04_channel::Version; +use ibc_test_framework::prelude::*; + +#[test] +fn test_channel_with_fee() -> Result<(), Error> { + run_binary_channel_test(&ChannelWithFeeTest) +} + +pub struct ChannelWithFeeTest; + +impl TestOverrides for ChannelWithFeeTest { + fn channel_version(&self) -> Version { + Version::ics20_with_fee() + } +} + +impl BinaryChannelTest for ChannelWithFeeTest { + fn run( + &self, + _config: &TestConfig, + _relayer: RelayerDriver, + _chains: ConnectedChains, + _channel: ConnectedChannel, + ) -> Result<(), Error> { + Ok(()) + } +} diff --git a/tools/integration-test/src/tests/mod.rs b/tools/integration-test/src/tests/mod.rs index f6aaf4ad1e..2438d66055 100644 --- a/tools/integration-test/src/tests/mod.rs +++ b/tools/integration-test/src/tests/mod.rs @@ -16,6 +16,9 @@ pub mod supervisor; pub mod ternary_transfer; pub mod transfer; +#[cfg(any(doc, feature = "ics29-fee"))] +pub mod fee_middleware; + #[cfg(any(doc, feature = "ordered"))] pub mod ordered_channel; From 00089eca9eb2ae16d918d415bace51313506c62c Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 11 May 2022 14:50:52 +0200 Subject: [PATCH 010/113] Basic transfer with pay packet is working --- Cargo.lock | 1 + modules/src/applications/ics29_fee/mod.rs | 1 + .../src/applications/ics29_fee/msgs/mod.rs | 3 + .../applications/ics29_fee/msgs/pay_packet.rs | 21 ++++ modules/src/applications/mod.rs | 1 + proto/src/lib.rs | 5 + relayer/src/transfer.rs | 24 +++-- .../src/tests/fee_middleware.rs | 87 ++++++++++++++++- tools/integration-test/src/tests/transfer.rs | 1 - tools/test-framework/Cargo.toml | 1 + tools/test-framework/src/prelude.rs | 1 + tools/test-framework/src/relayer/fee.rs | 96 +++++++++++++++++++ tools/test-framework/src/relayer/mod.rs | 1 + tools/test-framework/src/relayer/transfer.rs | 42 +++++--- 14 files changed, 254 insertions(+), 31 deletions(-) create mode 100644 modules/src/applications/ics29_fee/mod.rs create mode 100644 modules/src/applications/ics29_fee/msgs/mod.rs create mode 100644 modules/src/applications/ics29_fee/msgs/pay_packet.rs create mode 100644 tools/test-framework/src/relayer/fee.rs diff --git a/Cargo.lock b/Cargo.lock index 2dafc1ce04..bf7a429468 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1640,6 +1640,7 @@ dependencies = [ "ibc-relayer", "ibc-relayer-cli", "itertools", + "prost", "rand 0.8.5", "semver", "serde", diff --git a/modules/src/applications/ics29_fee/mod.rs b/modules/src/applications/ics29_fee/mod.rs new file mode 100644 index 0000000000..159c4b7c03 --- /dev/null +++ b/modules/src/applications/ics29_fee/mod.rs @@ -0,0 +1 @@ +mod msgs; diff --git a/modules/src/applications/ics29_fee/msgs/mod.rs b/modules/src/applications/ics29_fee/msgs/mod.rs new file mode 100644 index 0000000000..f1d22a0b71 --- /dev/null +++ b/modules/src/applications/ics29_fee/msgs/mod.rs @@ -0,0 +1,3 @@ +mod pay_packet; + +pub use pay_packet::*; diff --git a/modules/src/applications/ics29_fee/msgs/pay_packet.rs b/modules/src/applications/ics29_fee/msgs/pay_packet.rs new file mode 100644 index 0000000000..7c081dec75 --- /dev/null +++ b/modules/src/applications/ics29_fee/msgs/pay_packet.rs @@ -0,0 +1,21 @@ +use ibc_proto::ibc::applications::fee::v1::MsgPayPacketFee; + +use crate::prelude::*; +use crate::tx_msg::Msg; + +pub const TYPE_URL: &str = "/ibc.applications.transfer.v1.MsgTransfer"; + +pub enum Error {} + +impl Msg for MsgPayPacketFee { + type ValidationError = Error; + type Raw = MsgPayPacketFee; + + fn route(&self) -> String { + crate::keys::ROUTER_KEY.to_string() + } + + fn type_url(&self) -> String { + TYPE_URL.to_string() + } +} diff --git a/modules/src/applications/mod.rs b/modules/src/applications/mod.rs index 9e6905bb39..5e8244dbfb 100644 --- a/modules/src/applications/mod.rs +++ b/modules/src/applications/mod.rs @@ -1,3 +1,4 @@ //! Various packet encoding semantics which underpin the various types of transactions. pub mod ics20_fungible_token_transfer; +pub mod ics29_fee; diff --git a/proto/src/lib.rs b/proto/src/lib.rs index d07b717776..dc78b49391 100644 --- a/proto/src/lib.rs +++ b/proto/src/lib.rs @@ -140,6 +140,11 @@ pub mod ibc { include_proto!("ibc.applications.transfer.v1.rs"); } } + pub mod fee { + pub mod v1 { + include_proto!("ibc.applications.fee.v1.rs"); + } + } pub mod interchain_accounts { pub mod v1 { include_proto!("ibc.applications.interchain_accounts.v1.rs"); diff --git a/relayer/src/transfer.rs b/relayer/src/transfer.rs index e44b04cda9..3c0a3b0b1e 100644 --- a/relayer/src/transfer.rs +++ b/relayer/src/transfer.rs @@ -10,6 +10,7 @@ use ibc::signer::Signer; use ibc::timestamp::{Timestamp, TimestampOverflowError}; use ibc::tx_msg::Msg; use ibc::Height; +use ibc_proto::cosmos::base::v1beta1::Coin; use ibc_proto::google::protobuf::Any; use uint::FromStrRadixErr; @@ -150,7 +151,7 @@ pub fn build_transfer_message( let msg = MsgTransfer { source_port: packet_src_port_id, source_channel: packet_src_channel_id, - token: Some(ibc_proto::cosmos::base::v1beta1::Coin { + token: Some(Coin { denom, amount: amount.to_string(), }), @@ -185,21 +186,18 @@ pub fn build_and_send_transfer_messages Result<(), Error> { @@ -19,9 +20,91 @@ impl BinaryChannelTest for ChannelWithFeeTest { &self, _config: &TestConfig, _relayer: RelayerDriver, - _chains: ConnectedChains, - _channel: ConnectedChannel, + chains: ConnectedChains, + channel: ConnectedChannel, ) -> Result<(), Error> { + let chain_driver_a = chains.node_a.chain_driver(); + let chain_driver_b = chains.node_b.chain_driver(); + + let denom_a = chains.node_a.denom(); + let tx_config_a = chain_driver_a.tx_config(); + + let port_a = &channel.port_a.as_ref(); + let channel_id_a = &channel.channel_id_a.as_ref(); + + let wallets_a = chains.node_a.wallets(); + let wallets_b = chains.node_b.wallets(); + + let user_a1 = wallets_a.user1(); + let user_b1 = wallets_b.user1(); + + let relayer_a = wallets_a.relayer(); + + let balance_a = chain_driver_a.query_balance(&user_a1.address(), &denom_a)?; + + let relayer_balance_a = chain_driver_a.query_balance(&relayer_a.address(), &denom_a)?; + + let send_amount = 1000; + let receive_fee = 300; + let ack_fee = 200; + let timeout_fee = 100; + + let total_sent = send_amount + receive_fee + ack_fee + timeout_fee; + + chain_driver_a + .value() + .runtime + .block_on(ibc_token_transfer_with_fee( + &tx_config_a, + port_a, + channel_id_a, + &user_a1, + &user_b1.address(), + &denom_a, + send_amount, + receive_fee, + ack_fee, + timeout_fee, + ))?; + + let denom_b = derive_ibc_denom( + &channel.port_b.as_ref(), + &channel.channel_id_b.as_ref(), + &denom_a, + )?; + + info!( + "User A's balance after transfer: {}", + balance_a - total_sent + ); + + chain_driver_a.assert_eventual_wallet_amount( + &user_a1.address(), + balance_a - total_sent, + &denom_a, + )?; + + chain_driver_b.assert_eventual_wallet_amount( + &user_b1.address(), + send_amount, + &denom_b.as_ref(), + )?; + + // // receive fee and timeout fee should be refunded, + // // as there is no counterparty address registered. + // chain_driver_a.assert_eventual_wallet_amount( + // &user_a1.address(), + // balance_a - send_amount - ack_fee, + // &denom_a, + // )?; + + // chain_driver_a.assert_eventual_wallet_amount( + // &relayer_a.address(), + // relayer_balance_a + ack_fee, + // &denom_a, + // )?; + + // suspend() Ok(()) } } diff --git a/tools/integration-test/src/tests/transfer.rs b/tools/integration-test/src/tests/transfer.rs index a5a76750c8..afac3170d6 100644 --- a/tools/integration-test/src/tests/transfer.rs +++ b/tools/integration-test/src/tests/transfer.rs @@ -1,4 +1,3 @@ -use ibc_test_framework::ibc::denom::derive_ibc_denom; use ibc_test_framework::prelude::*; use ibc_test_framework::util::random::random_u64_range; diff --git a/tools/test-framework/Cargo.toml b/tools/test-framework/Cargo.toml index a1729b95f3..cec69ed6b5 100644 --- a/tools/test-framework/Cargo.toml +++ b/tools/test-framework/Cargo.toml @@ -41,3 +41,4 @@ sha2 = "0.10.2" crossbeam-channel = "0.5.4" semver = "1.0.7" flex-error = "0.4.4" +prost = { version = "0.10" } diff --git a/tools/test-framework/src/prelude.rs b/tools/test-framework/src/prelude.rs index 624ed806a4..4abe634ef4 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::derive_ibc_denom; pub use crate::ibc::denom::Denom; pub use crate::relayer::channel::TaggedChannelEndExt; pub use crate::relayer::connection::{TaggedConnectionEndExt, TaggedConnectionExt}; diff --git a/tools/test-framework/src/relayer/fee.rs b/tools/test-framework/src/relayer/fee.rs new file mode 100644 index 0000000000..5a6a9be608 --- /dev/null +++ b/tools/test-framework/src/relayer/fee.rs @@ -0,0 +1,96 @@ +use ibc_proto::cosmos::base::v1beta1::Coin; +use ibc_proto::google::protobuf::Any; +use ibc_proto::ibc::applications::fee::v1::{Fee, MsgPayPacketFee}; +use ibc_relayer::chain::cosmos::types::config::TxConfig; +use prost::{EncodeError, Message}; + +use crate::error::{handle_generic_error, Error}; +use crate::ibc::denom::Denom; +use crate::relayer::transfer::build_transfer_message; +use crate::relayer::tx::simple_send_tx; +use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef}; +use crate::types::tagged::MonoTagged; +use crate::types::wallet::TaggedWallet; +use crate::types::wallet::{Wallet, WalletAddress}; + +fn encode_message(message: &M) -> Result, EncodeError> { + let mut buf = Vec::new(); + Message::encode(message, &mut buf)?; + Ok(buf) +} + +pub fn build_pay_packet_message( + port_id: &TaggedPortIdRef, + channel_id: &TaggedChannelIdRef, + payer: &MonoTagged, + denom: &MonoTagged, + receive_fee: u64, + ack_fee: u64, + timeout_fee: u64, +) -> Result { + const TYPE_URL: &str = "/ibc.applications.fee.v1.MsgPayPacketFee"; + + let denom_str = denom.value().to_string(); + + let fee = Fee { + recv_fee: vec![Coin { + denom: denom_str.clone(), + amount: receive_fee.to_string(), + }], + ack_fee: vec![Coin { + denom: denom_str.clone(), + amount: ack_fee.to_string(), + }], + timeout_fee: vec![Coin { + denom: denom_str, + amount: timeout_fee.to_string(), + }], + }; + + let message = MsgPayPacketFee { + fee: Some(fee), + source_port_id: port_id.value().to_string(), + source_channel_id: channel_id.value().to_string(), + signer: payer.value().0.clone(), + relayers: Vec::new(), + }; + + let encoded = encode_message(&message).map_err(handle_generic_error)?; + + Ok(Any { + type_url: TYPE_URL.to_string(), + value: encoded, + }) +} + +pub async fn ibc_token_transfer_with_fee( + tx_config: &MonoTagged, + port_id: &TaggedPortIdRef<'_, SrcChain, DstChain>, + channel_id: &TaggedChannelIdRef<'_, SrcChain, DstChain>, + sender: &MonoTagged, + recipient: &MonoTagged, + denom: &MonoTagged, + send_amount: u64, + receive_fee: u64, + ack_fee: u64, + timeout_fee: u64, +) -> Result<(), Error> { + let transfer_message = + build_transfer_message(port_id, channel_id, sender, recipient, denom, send_amount)?; + + let pay_message = build_pay_packet_message( + port_id, + channel_id, + &sender.address(), + denom, + receive_fee, + ack_fee, + timeout_fee, + )?; + + let messages = vec![transfer_message, pay_message]; + + simple_send_tx(tx_config.value(), &sender.value().key, messages).await?; + + Ok(()) +} diff --git a/tools/test-framework/src/relayer/mod.rs b/tools/test-framework/src/relayer/mod.rs index 44a848d41e..0f90d7b1be 100644 --- a/tools/test-framework/src/relayer/mod.rs +++ b/tools/test-framework/src/relayer/mod.rs @@ -22,6 +22,7 @@ pub mod chain; pub mod channel; pub mod connection; pub mod driver; +pub mod fee; pub mod foreign_client; pub mod refresh; pub mod transfer; 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?; From 74d614c1b9b45b0ba26609a67790a47a7b5fd312 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 11 May 2022 15:06:24 +0200 Subject: [PATCH 011/113] 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?; From 79829778546c35a6e63943ea941bff7692e3968e Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 11 May 2022 21:38:09 +0200 Subject: [PATCH 012/113] Basic relayer fee payment working --- .../src/tests/fee_middleware.rs | 55 +++++++++++-------- tools/test-framework/src/relayer/fee.rs | 2 +- 2 files changed, 33 insertions(+), 24 deletions(-) diff --git a/tools/integration-test/src/tests/fee_middleware.rs b/tools/integration-test/src/tests/fee_middleware.rs index d98ef2e3f9..dfe9572861 100644 --- a/tools/integration-test/src/tests/fee_middleware.rs +++ b/tools/integration-test/src/tests/fee_middleware.rs @@ -40,7 +40,7 @@ impl BinaryChannelTest for ChannelWithFeeTest { let relayer_a = wallets_a.relayer(); - let balance_a = chain_driver_a.query_balance(&user_a1.address(), &denom_a)?; + let balance_a1 = chain_driver_a.query_balance(&user_a1.address(), &denom_a)?; let relayer_balance_a = chain_driver_a.query_balance(&relayer_a.address(), &denom_a)?; @@ -51,6 +51,8 @@ impl BinaryChannelTest for ChannelWithFeeTest { let total_sent = send_amount + receive_fee + ack_fee + timeout_fee; + let balance_a2 = balance_a1 - total_sent; + chain_driver_a .value() .runtime @@ -73,38 +75,45 @@ impl BinaryChannelTest for ChannelWithFeeTest { &denom_a, )?; + info!("Expect user A's balance after transfer: {}", balance_a2); + + chain_driver_a.assert_eventual_wallet_amount(&user_a1.address(), balance_a2, &denom_a)?; + + chain_driver_b.assert_eventual_wallet_amount( + &user_b1.address(), + send_amount, + &denom_b.as_ref(), + )?; + info!( - "User A's balance after transfer: {}", - balance_a - total_sent + "Expect user to be refunded receive fee {} and timeout fee {} and go from {} to {}", + receive_fee, + timeout_fee, + balance_a2, + balance_a2 + receive_fee + timeout_fee ); + // receive fee and timeout fee should be refunded, + // as there is no counterparty address registered. chain_driver_a.assert_eventual_wallet_amount( &user_a1.address(), - balance_a - total_sent, + balance_a2 + receive_fee + timeout_fee, &denom_a, )?; - chain_driver_b.assert_eventual_wallet_amount( - &user_b1.address(), - send_amount, - &denom_b.as_ref(), + info!( + "Expect relayer to receive ack fee {} and go from {} to {}", + ack_fee, + relayer_balance_a, + relayer_balance_a + ack_fee + ); + + chain_driver_a.assert_eventual_wallet_amount( + &relayer_a.address(), + relayer_balance_a + ack_fee, + &denom_a, )?; - // // receive fee and timeout fee should be refunded, - // // as there is no counterparty address registered. - // chain_driver_a.assert_eventual_wallet_amount( - // &user_a1.address(), - // balance_a - send_amount - ack_fee, - // &denom_a, - // )?; - - // chain_driver_a.assert_eventual_wallet_amount( - // &relayer_a.address(), - // relayer_balance_a + ack_fee, - // &denom_a, - // )?; - - // suspend() Ok(()) } } diff --git a/tools/test-framework/src/relayer/fee.rs b/tools/test-framework/src/relayer/fee.rs index 5a6a9be608..47a73ebe77 100644 --- a/tools/test-framework/src/relayer/fee.rs +++ b/tools/test-framework/src/relayer/fee.rs @@ -88,7 +88,7 @@ pub async fn ibc_token_transfer_with_fee( timeout_fee, )?; - let messages = vec![transfer_message, pay_message]; + let messages = vec![pay_message, transfer_message]; simple_send_tx(tx_config.value(), &sender.value().key, messages).await?; From 4d5a7e53960c3bdbf7613bb064497333a457239d Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Thu, 12 May 2022 11:26:28 +0200 Subject: [PATCH 013/113] Implementing registering counterparty address --- tools/integration-test/src/tests/fee.rs | 156 ++++++++++++++++++ .../src/tests/fee_middleware.rs | 119 ------------- tools/integration-test/src/tests/mod.rs | 2 +- tools/test-framework/src/relayer/fee.rs | 96 ++++++++--- 4 files changed, 226 insertions(+), 147 deletions(-) create mode 100644 tools/integration-test/src/tests/fee.rs delete mode 100644 tools/integration-test/src/tests/fee_middleware.rs diff --git a/tools/integration-test/src/tests/fee.rs b/tools/integration-test/src/tests/fee.rs new file mode 100644 index 0000000000..67a99ea385 --- /dev/null +++ b/tools/integration-test/src/tests/fee.rs @@ -0,0 +1,156 @@ +use ibc::core::ics04_channel::Version; +use ibc_test_framework::prelude::*; +use ibc_test_framework::relayer::fee::{ + ibc_token_transfer_with_fee, register_counterparty_address, +}; + +#[test] +fn test_channel_with_fee() -> Result<(), Error> { + run_binary_channel_test(&ChannelWithFeeTest) +} + +pub struct ChannelWithFeeTest; + +impl TestOverrides for ChannelWithFeeTest { + fn should_spawn_supervisor(&self) -> bool { + false + } + + fn channel_version(&self) -> Version { + Version::ics20_with_fee() + } +} + +impl BinaryChannelTest for ChannelWithFeeTest { + fn run( + &self, + _config: &TestConfig, + relayer: RelayerDriver, + chains: ConnectedChains, + channel: ConnectedChannel, + ) -> Result<(), Error> { + let chain_driver_a = chains.node_a.chain_driver(); + let chain_driver_b = chains.node_b.chain_driver(); + + let chain_id_a = chain_driver_a.chain_id(); + let chain_id_b = chain_driver_b.chain_id(); + + let denom_a = chains.node_a.denom(); + let tx_config_a = chain_driver_a.tx_config(); + let tx_config_b = chain_driver_b.tx_config(); + + let port_a = channel.port_a.as_ref(); + let channel_id_a = channel.channel_id_a.as_ref(); + + let channel_id_b = channel.channel_id_b.as_ref(); + + let wallets_a = chains.node_a.wallets(); + let wallets_b = chains.node_b.wallets(); + + let relayer_a = wallets_a.relayer(); + let relayer_b = wallets_b.relayer(); + + info!( + "registering counterparty address of relayer {} on chain {} to be {} on chain {}", + relayer_b.address(), + chain_id_b, + relayer_a.address(), + chain_id_a + ); + + chain_driver_b + .value() + .runtime + .block_on(register_counterparty_address( + &tx_config_b, + &relayer_b, + &relayer_a.address(), + &channel_id_b, + ))?; + + relayer.with_supervisor(move || { + let user_a = wallets_a.user1(); + let user_b = wallets_b.user1(); + + let balance_a1 = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; + + let relayer_balance_a = chain_driver_a.query_balance(&relayer_a.address(), &denom_a)?; + + let send_amount = 1000; + let receive_fee = 300; + let ack_fee = 200; + let timeout_fee = 100; + + let total_sent = send_amount + receive_fee + ack_fee + timeout_fee; + + let balance_a2 = balance_a1 - total_sent; + + chain_driver_a + .value() + .runtime + .block_on(ibc_token_transfer_with_fee( + &tx_config_a, + &port_a, + &channel_id_a, + &user_a, + &user_b.address(), + &denom_a, + send_amount, + receive_fee, + ack_fee, + timeout_fee, + ))?; + + let denom_b = derive_ibc_denom( + &channel.port_b.as_ref(), + &channel.channel_id_b.as_ref(), + &denom_a, + )?; + + info!("Expect user A's balance after transfer: {}", balance_a2); + + chain_driver_a.assert_eventual_wallet_amount( + &user_a.address(), + balance_a2, + &denom_a, + )?; + + chain_driver_b.assert_eventual_wallet_amount( + &user_b.address(), + send_amount, + &denom_b.as_ref(), + )?; + + info!( + "Expect user to be refunded receive timeout fee {} and go from {} to {}", + timeout_fee, + balance_a2, + balance_a2 + timeout_fee + ); + + // receive fee and timeout fee should be refunded, + // as there is no counterparty address registered. + chain_driver_a.assert_eventual_wallet_amount( + &user_a.address(), + balance_a2 + receive_fee + timeout_fee, + &denom_a, + )?; + + info!( + "Expect relayer to receive ack fee {} and receive fee {} and go from {} to {}", + ack_fee, + receive_fee, + relayer_balance_a, + relayer_balance_a + ack_fee + receive_fee, + ); + + chain_driver_a.assert_eventual_wallet_amount( + &relayer_a.address(), + relayer_balance_a + ack_fee, + &denom_a, + )?; + + Ok(()) + }) + } +} diff --git a/tools/integration-test/src/tests/fee_middleware.rs b/tools/integration-test/src/tests/fee_middleware.rs deleted file mode 100644 index dfe9572861..0000000000 --- a/tools/integration-test/src/tests/fee_middleware.rs +++ /dev/null @@ -1,119 +0,0 @@ -use ibc::core::ics04_channel::Version; -use ibc_test_framework::prelude::*; -use ibc_test_framework::relayer::fee::ibc_token_transfer_with_fee; - -#[test] -fn test_channel_with_fee() -> Result<(), Error> { - run_binary_channel_test(&ChannelWithFeeTest) -} - -pub struct ChannelWithFeeTest; - -impl TestOverrides for ChannelWithFeeTest { - fn channel_version(&self) -> Version { - Version::ics20_with_fee() - } -} - -impl BinaryChannelTest for ChannelWithFeeTest { - fn run( - &self, - _config: &TestConfig, - _relayer: RelayerDriver, - chains: ConnectedChains, - channel: ConnectedChannel, - ) -> Result<(), Error> { - let chain_driver_a = chains.node_a.chain_driver(); - let chain_driver_b = chains.node_b.chain_driver(); - - let denom_a = chains.node_a.denom(); - let tx_config_a = chain_driver_a.tx_config(); - - let port_a = &channel.port_a.as_ref(); - let channel_id_a = &channel.channel_id_a.as_ref(); - - let wallets_a = chains.node_a.wallets(); - let wallets_b = chains.node_b.wallets(); - - let user_a1 = wallets_a.user1(); - let user_b1 = wallets_b.user1(); - - let relayer_a = wallets_a.relayer(); - - let balance_a1 = chain_driver_a.query_balance(&user_a1.address(), &denom_a)?; - - let relayer_balance_a = chain_driver_a.query_balance(&relayer_a.address(), &denom_a)?; - - let send_amount = 1000; - let receive_fee = 300; - let ack_fee = 200; - let timeout_fee = 100; - - let total_sent = send_amount + receive_fee + ack_fee + timeout_fee; - - let balance_a2 = balance_a1 - total_sent; - - chain_driver_a - .value() - .runtime - .block_on(ibc_token_transfer_with_fee( - &tx_config_a, - port_a, - channel_id_a, - &user_a1, - &user_b1.address(), - &denom_a, - send_amount, - receive_fee, - ack_fee, - timeout_fee, - ))?; - - let denom_b = derive_ibc_denom( - &channel.port_b.as_ref(), - &channel.channel_id_b.as_ref(), - &denom_a, - )?; - - info!("Expect user A's balance after transfer: {}", balance_a2); - - chain_driver_a.assert_eventual_wallet_amount(&user_a1.address(), balance_a2, &denom_a)?; - - chain_driver_b.assert_eventual_wallet_amount( - &user_b1.address(), - send_amount, - &denom_b.as_ref(), - )?; - - info!( - "Expect user to be refunded receive fee {} and timeout fee {} and go from {} to {}", - receive_fee, - timeout_fee, - balance_a2, - balance_a2 + receive_fee + timeout_fee - ); - - // receive fee and timeout fee should be refunded, - // as there is no counterparty address registered. - chain_driver_a.assert_eventual_wallet_amount( - &user_a1.address(), - balance_a2 + receive_fee + timeout_fee, - &denom_a, - )?; - - info!( - "Expect relayer to receive ack fee {} and go from {} to {}", - ack_fee, - relayer_balance_a, - relayer_balance_a + ack_fee - ); - - chain_driver_a.assert_eventual_wallet_amount( - &relayer_a.address(), - relayer_balance_a + ack_fee, - &denom_a, - )?; - - Ok(()) - } -} diff --git a/tools/integration-test/src/tests/mod.rs b/tools/integration-test/src/tests/mod.rs index 2438d66055..e9d90d3b73 100644 --- a/tools/integration-test/src/tests/mod.rs +++ b/tools/integration-test/src/tests/mod.rs @@ -17,7 +17,7 @@ pub mod ternary_transfer; pub mod transfer; #[cfg(any(doc, feature = "ics29-fee"))] -pub mod fee_middleware; +pub mod fee; #[cfg(any(doc, feature = "ordered"))] pub mod ordered_channel; diff --git a/tools/test-framework/src/relayer/fee.rs b/tools/test-framework/src/relayer/fee.rs index 47a73ebe77..cd9c7d3ee3 100644 --- a/tools/test-framework/src/relayer/fee.rs +++ b/tools/test-framework/src/relayer/fee.rs @@ -1,6 +1,6 @@ use ibc_proto::cosmos::base::v1beta1::Coin; use ibc_proto::google::protobuf::Any; -use ibc_proto::ibc::applications::fee::v1::{Fee, MsgPayPacketFee}; +use ibc_proto::ibc::applications::fee::v1::{Fee, MsgPayPacketFee, MsgRegisterCounterpartyAddress}; use ibc_relayer::chain::cosmos::types::config::TxConfig; use prost::{EncodeError, Message}; @@ -13,6 +13,57 @@ use crate::types::tagged::MonoTagged; use crate::types::wallet::TaggedWallet; use crate::types::wallet::{Wallet, WalletAddress}; +pub async fn ibc_token_transfer_with_fee( + tx_config: &MonoTagged, + port_id: &TaggedPortIdRef<'_, SrcChain, DstChain>, + channel_id: &TaggedChannelIdRef<'_, SrcChain, DstChain>, + sender: &MonoTagged, + recipient: &MonoTagged, + denom: &MonoTagged, + send_amount: u64, + receive_fee: u64, + ack_fee: u64, + timeout_fee: u64, +) -> Result<(), Error> { + let transfer_message = + build_transfer_message(port_id, channel_id, sender, recipient, denom, send_amount)?; + + let pay_message = build_pay_packet_message( + port_id, + channel_id, + &sender.address(), + denom, + receive_fee, + ack_fee, + timeout_fee, + )?; + + let messages = vec![pay_message, transfer_message]; + + simple_send_tx(tx_config.value(), &sender.value().key, messages).await?; + + Ok(()) +} + +pub async fn register_counterparty_address( + tx_config: &MonoTagged, + wallet: &MonoTagged, + counterparty_address: &MonoTagged, + channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, +) -> Result<(), Error> { + let message = build_register_counterparty_address_message( + &wallet.address(), + counterparty_address, + channel_id, + )?; + + let messages = vec![message.into_value()]; + + simple_send_tx(tx_config.value(), &wallet.value().key, messages).await?; + + Ok(()) +} + fn encode_message(message: &M) -> Result, EncodeError> { let mut buf = Vec::new(); Message::encode(message, &mut buf)?; @@ -63,34 +114,25 @@ pub fn build_pay_packet_message( }) } -pub async fn ibc_token_transfer_with_fee( - tx_config: &MonoTagged, - port_id: &TaggedPortIdRef<'_, SrcChain, DstChain>, - channel_id: &TaggedChannelIdRef<'_, SrcChain, DstChain>, - sender: &MonoTagged, - recipient: &MonoTagged, - denom: &MonoTagged, - send_amount: u64, - receive_fee: u64, - ack_fee: u64, - timeout_fee: u64, -) -> Result<(), Error> { - let transfer_message = - build_transfer_message(port_id, channel_id, sender, recipient, denom, send_amount)?; +pub fn build_register_counterparty_address_message( + address: &MonoTagged, + counterparty_address: &MonoTagged, + channel_id: &TaggedChannelIdRef, +) -> Result, Error> { + const TYPE_URL: &str = "/ibc.applications.fee.v1.MsgRegisterCounterpartyAddress"; - let pay_message = build_pay_packet_message( - port_id, - channel_id, - &sender.address(), - denom, - receive_fee, - ack_fee, - timeout_fee, - )?; + let message = MsgRegisterCounterpartyAddress { + address: address.value().0.clone(), + counterparty_address: counterparty_address.value().0.clone(), + channel_id: channel_id.value().to_string(), + }; - let messages = vec![pay_message, transfer_message]; + let encoded = encode_message(&message).map_err(handle_generic_error)?; - simple_send_tx(tx_config.value(), &sender.value().key, messages).await?; + let wrapped = Any { + type_url: TYPE_URL.to_string(), + value: encoded, + }; - Ok(()) + Ok(MonoTagged::new(wrapped)) } From 5d6c44c48daec09d9960ed9cd6acf6e5aa69904a Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Thu, 12 May 2022 12:04:13 +0200 Subject: [PATCH 014/113] Fix fee calculation with register counterparty address working --- relayer/src/chain/cosmos/query/tx.rs | 3 ++ relayer/src/chain/cosmos/wait.rs | 2 + tools/integration-test/src/tests/fee.rs | 6 +-- tools/test-framework/src/relayer/tx.rs | 56 ++++++++++++++----------- 4 files changed, 39 insertions(+), 28 deletions(-) diff --git a/relayer/src/chain/cosmos/query/tx.rs b/relayer/src/chain/cosmos/query/tx.rs index dab694a53c..f169df1317 100644 --- a/relayer/src/chain/cosmos/query/tx.rs +++ b/relayer/src/chain/cosmos/query/tx.rs @@ -10,6 +10,7 @@ use ibc::Height as ICSHeight; use tendermint::abci::Event; use tendermint_rpc::endpoint::tx::Response as ResultTx; use tendermint_rpc::{Client, HttpClient, Order, Url}; +use tracing::trace; use crate::chain::cosmos::query::{header_query, packet_query, tx_hash_query}; use crate::error::Error; @@ -122,6 +123,8 @@ pub async fn query_txs( .await .map_err(|e| Error::rpc(rpc_address.clone(), e))?; + trace!("response from tx_hash_query for {:?}: {:?}", tx, response); + if response.txs.is_empty() { Ok(vec![]) } else { diff --git a/relayer/src/chain/cosmos/wait.rs b/relayer/src/chain/cosmos/wait.rs index 953395fef2..a588ab079c 100644 --- a/relayer/src/chain/cosmos/wait.rs +++ b/relayer/src/chain/cosmos/wait.rs @@ -92,6 +92,8 @@ async fn update_tx_sync_result( ) .await?; + trace!("events_per_tx: {:?}", events_per_tx); + // If we get events back, progress was made, so we replace the events // with the new ones. in both cases we will check in the next iteration // whether or not the transaction was fully committed. diff --git a/tools/integration-test/src/tests/fee.rs b/tools/integration-test/src/tests/fee.rs index 67a99ea385..d84aee8b97 100644 --- a/tools/integration-test/src/tests/fee.rs +++ b/tools/integration-test/src/tests/fee.rs @@ -125,14 +125,14 @@ impl BinaryChannelTest for ChannelWithFeeTest { "Expect user to be refunded receive timeout fee {} and go from {} to {}", timeout_fee, balance_a2, - balance_a2 + timeout_fee + balance_a2 + timeout_fee + ack_fee ); // receive fee and timeout fee should be refunded, // as there is no counterparty address registered. chain_driver_a.assert_eventual_wallet_amount( &user_a.address(), - balance_a2 + receive_fee + timeout_fee, + balance_a2 + timeout_fee, &denom_a, )?; @@ -146,7 +146,7 @@ impl BinaryChannelTest for ChannelWithFeeTest { chain_driver_a.assert_eventual_wallet_amount( &relayer_a.address(), - relayer_balance_a + ack_fee, + relayer_balance_a + ack_fee + receive_fee, &denom_a, )?; diff --git a/tools/test-framework/src/relayer/tx.rs b/tools/test-framework/src/relayer/tx.rs index 18be12730d..6102c64a82 100644 --- a/tools/test-framework/src/relayer/tx.rs +++ b/tools/test-framework/src/relayer/tx.rs @@ -99,31 +99,37 @@ pub async fn simple_send_tx( estimate_fee_and_send_tx(config, key_entry, &account, &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))); - } - } - } + tokio::time::sleep(Duration::from_secs(2)).await; + + // There are issues with wait_for_block_commits, as the event from + // `MsgRegisterCounterpartyAddress` gets ignored when confirming TX, + // and the transaction times out. + + // 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(()) } From f9e7336fe14196761d1bab6c8b1598f69c0be892 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Thu, 19 May 2022 13:19:54 +0200 Subject: [PATCH 015/113] Wait for TX confirmation straight from TxResponse --- flake.nix | 1 + tools/test-framework/src/relayer/tx.rs | 88 ++++++++++++++++---------- 2 files changed, 55 insertions(+), 34 deletions(-) diff --git a/flake.nix b/flake.nix index 2700da6698..75beaec499 100644 --- a/flake.nix +++ b/flake.nix @@ -38,6 +38,7 @@ ibc-go-v3-simapp ibc-go-main-simapp ibc-go-ics29-simapp + wasmd ; python = nixpkgs.python3.withPackages (p: [ diff --git a/tools/test-framework/src/relayer/tx.rs b/tools/test-framework/src/relayer/tx.rs index 6102c64a82..49be183db1 100644 --- a/tools/test-framework/src/relayer/tx.rs +++ b/tools/test-framework/src/relayer/tx.rs @@ -3,18 +3,22 @@ use core::time::Duration; use eyre::eyre; use http::uri::Uri; use ibc::core::ics24_host::identifier::ChainId; -use ibc::events::IbcEvent; +use ibc::query::QueryTxHash; 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::query::tx_hash_query; 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 std::time::Instant; +use tendermint::abci::transaction::Hash as TxHash; +use tendermint_rpc::endpoint::tx::Response as TxResponse; +use tendermint_rpc::Client; +use tendermint_rpc::Order; use tendermint_rpc::{HttpClient, Url}; use crate::error::{handle_generic_error, Error}; @@ -93,43 +97,59 @@ pub async fn simple_send_tx( .await? .into(); - let message_count = messages.len(); - let response = estimate_fee_and_send_tx(config, key_entry, &account, &Default::default(), messages) .await?; - tokio::time::sleep(Duration::from_secs(2)).await; - - // There are issues with wait_for_block_commits, as the event from - // `MsgRegisterCounterpartyAddress` gets ignored when confirming TX, - // and the transaction times out. - - // let events_per_tx = vec![IbcEvent::default(); message_count]; - - // let tx_sync_result = TxSyncResult { - // response, - // events: events_per_tx, - // }; + if response.code.is_err() { + return Err(eyre!("error in TX response: {:?}", response).into()); + } - // let mut tx_sync_results = vec![tx_sync_result]; + wait_tx_succeed(&config.rpc_client, &config.rpc_timeout, &response.hash).await?; - // wait_for_block_commits( - // &config.chain_id, - // &config.rpc_client, - // &config.rpc_address, - // &config.rpc_timeout, - // &mut tx_sync_results, - // ) - // .await?; + Ok(()) +} - // 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))); - // } - // } - // } +pub async fn wait_tx_succeed( + rpc_client: &HttpClient, + timeout: &Duration, + tx_hash: &TxHash, +) -> Result<(), Error> { + let start_time = Instant::now(); + + loop { + let responses = query_tx_response(rpc_client, tx_hash).await?; + + if responses.is_empty() { + let elapsed = start_time.elapsed(); + if &elapsed > timeout { + return Err(eyre!("tx no confirmation").into()); + } + } else { + for response in responses.iter() { + if response.tx_result.code.is_err() { + return Err(eyre!("error in TX response: {:?}", response).into()); + } + } + return Ok(()); + } + } +} - Ok(()) +pub async fn query_tx_response( + rpc_client: &HttpClient, + tx_hash: &TxHash, +) -> Result, Error> { + let response = rpc_client + .tx_search( + tx_hash_query(&QueryTxHash(*tx_hash)), + false, + 1, + 1, // get only the first Tx matching the query + Order::Ascending, + ) + .await + .map_err(handle_generic_error)?; + + Ok(response.txs) } From 22c979687d46e54b5bc7714744b88a7b54beccf1 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Thu, 19 May 2022 21:22:56 +0200 Subject: [PATCH 016/113] Introduce Token type to encapsulate Denom and amount --- relayer/src/transfer.rs | 6 + .../src/tests/clear_packet.rs | 32 ++-- .../src/tests/client_expiration.rs | 9 +- .../src/tests/connection_delay.rs | 13 +- tools/integration-test/src/tests/fee.rs | 30 ++-- tools/integration-test/src/tests/ica.rs | 19 +-- tools/integration-test/src/tests/memo.rs | 10 +- .../src/tests/ordered_channel.rs | 18 +-- .../src/tests/query_packet.rs | 12 +- .../integration-test/src/tests/supervisor.rs | 15 +- .../src/tests/ternary_transfer.rs | 42 +++--- tools/integration-test/src/tests/transfer.rs | 31 ++-- tools/test-framework/src/bootstrap/single.rs | 30 ++-- tools/test-framework/src/chain/config.rs | 9 ++ tools/test-framework/src/chain/driver.rs | 36 ++--- .../src/chain/driver/transfer.rs | 7 +- tools/test-framework/src/chain/tagged.rs | 36 ++--- tools/test-framework/src/ibc/denom.rs | 23 +++ tools/test-framework/src/ibc/mod.rs | 1 + tools/test-framework/src/ibc/token.rs | 140 ++++++++++++++++++ tools/test-framework/src/prelude.rs | 1 + tools/test-framework/src/relayer/fee.rs | 35 ++--- tools/test-framework/src/relayer/transfer.rs | 14 +- tools/test-framework/src/util/random.rs | 11 ++ 24 files changed, 349 insertions(+), 231 deletions(-) create mode 100644 tools/test-framework/src/ibc/token.rs diff --git a/relayer/src/transfer.rs b/relayer/src/transfer.rs index 1e9530a245..f4a23d3082 100644 --- a/relayer/src/transfer.rs +++ b/relayer/src/transfer.rs @@ -84,6 +84,12 @@ impl From for Amount { } } +impl From for Amount { + fn from(amount: u128) -> Self { + Self(amount.into()) + } +} + #[derive(Copy, Clone)] pub struct TransferTimeout { pub timeout_height: Height, diff --git a/tools/integration-test/src/tests/clear_packet.rs b/tools/integration-test/src/tests/clear_packet.rs index 34b115fb83..20fee8fab1 100644 --- a/tools/integration-test/src/tests/clear_packet.rs +++ b/tools/integration-test/src/tests/clear_packet.rs @@ -1,6 +1,5 @@ -use ibc_test_framework::ibc::denom::derive_ibc_denom; use ibc_test_framework::prelude::*; -use ibc_test_framework::util::random::random_u64_range; +use ibc_test_framework::util::random::random_u128_range; #[test] fn test_clear_packet() -> Result<(), Error> { @@ -44,7 +43,7 @@ impl BinaryChannelTest for ClearPacketTest { .chain_driver() .query_balance(&wallet_a.address(), &denom_a)?; - let amount1 = random_u64_range(1000, 5000); + let amount1 = denom_a.with_amount(random_u128_range(1000, 5000)); info!( "Performing IBC transfer with amount {}, which should *not* be relayed", @@ -56,8 +55,7 @@ impl BinaryChannelTest for ClearPacketTest { &channel.channel_id_a.as_ref(), &wallet_a.as_ref(), &wallet_b.address(), - &denom_a, - amount1, + &amount1.as_ref(), )?; sleep(Duration::from_secs(1)); @@ -66,7 +64,7 @@ impl BinaryChannelTest for ClearPacketTest { relayer.with_supervisor(|| { sleep(Duration::from_secs(1)); - let amount2 = random_u64_range(1000, 5000); + let amount2 = denom_a.with_amount(random_u128_range(1000, 5000)); info!( "Performing IBC transfer with amount {}, which should be relayed", @@ -78,31 +76,25 @@ impl BinaryChannelTest for ClearPacketTest { &channel.channel_id_a.as_ref(), &wallet_a.as_ref(), &wallet_b.address(), - &denom_a, - amount2, + &amount2.as_ref(), )?; sleep(Duration::from_secs(1)); - let denom_b = derive_ibc_denom( - &channel.port_b.as_ref(), - &channel.channel_id_b.as_ref(), - &denom_a, - )?; + let amount_b = + amount2.transfer(&channel.port_b.as_ref(), &channel.channel_id_b.as_ref())?; // Wallet on chain A should have both amount deducted. chains.node_a.chain_driver().assert_eventual_wallet_amount( &wallet_a.address(), - balance_a - amount1 - amount2, - &denom_a, + &(balance_a - amount1.amount() - amount2.amount()).as_ref(), )?; // Wallet on chain B should only receive the second IBC transfer - chains.node_b.chain_driver().assert_eventual_wallet_amount( - &wallet_b.address(), - amount2, - &denom_b.as_ref(), - )?; + chains + .node_b + .chain_driver() + .assert_eventual_wallet_amount(&wallet_b.address(), &amount_b.as_ref())?; Ok(()) }) diff --git a/tools/integration-test/src/tests/client_expiration.rs b/tools/integration-test/src/tests/client_expiration.rs index bfd08b83c6..414cd774ab 100644 --- a/tools/integration-test/src/tests/client_expiration.rs +++ b/tools/integration-test/src/tests/client_expiration.rs @@ -292,8 +292,7 @@ impl BinaryChainTest for PacketExpirationTest { &channels.channel_id_a.as_ref(), &chains.node_a.wallets().user1(), &chains.node_b.wallets().user1().address(), - &chains.node_a.denom(), - 100, + &chains.node_a.denom().with_amount(100).as_ref(), )?; wait_for_client_expiry(); @@ -316,7 +315,11 @@ impl BinaryChainTest for PacketExpirationTest { &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.amount(), + &0, + )?; Ok(()) }) diff --git a/tools/integration-test/src/tests/connection_delay.rs b/tools/integration-test/src/tests/connection_delay.rs index ea8be39ac8..db73cfe7ee 100644 --- a/tools/integration-test/src/tests/connection_delay.rs +++ b/tools/integration-test/src/tests/connection_delay.rs @@ -3,7 +3,7 @@ use time::OffsetDateTime; use ibc_test_framework::ibc::denom::derive_ibc_denom; use ibc_test_framework::prelude::*; -use ibc_test_framework::util::random::random_u64_range; +use ibc_test_framework::util::random::random_u128_range; const CONNECTION_DELAY: Duration = Duration::from_secs(10); @@ -39,7 +39,7 @@ impl BinaryChannelTest for ConnectionDelayTest { .chain_driver() .query_balance(&wallet_a.address(), &denom_a)?; - let a_to_b_amount = random_u64_range(1000, 5000); + let a_to_b_amount = random_u128_range(1000, 5000); info!( "Sending IBC transfer from chain {} to chain {} with amount of {} {}", @@ -54,8 +54,7 @@ impl BinaryChannelTest for ConnectionDelayTest { &channel.channel_id_a.as_ref(), &wallet_a.as_ref(), &wallet_b.address(), - &denom_a, - a_to_b_amount, + &denom_a.with_amount(a_to_b_amount).as_ref(), )?; let time1 = OffsetDateTime::now_utc(); @@ -73,14 +72,12 @@ impl BinaryChannelTest for ConnectionDelayTest { chains.node_a.chain_driver().assert_eventual_wallet_amount( &wallet_a.address(), - balance_a - a_to_b_amount, - &denom_a, + &(balance_a - a_to_b_amount).as_ref(), )?; chains.node_b.chain_driver().assert_eventual_wallet_amount( &wallet_b.address(), - a_to_b_amount, - &denom_b.as_ref(), + &denom_b.with_amount(a_to_b_amount).as_ref(), )?; info!( diff --git a/tools/integration-test/src/tests/fee.rs b/tools/integration-test/src/tests/fee.rs index d84aee8b97..f7d2f86324 100644 --- a/tools/integration-test/src/tests/fee.rs +++ b/tools/integration-test/src/tests/fee.rs @@ -77,6 +77,7 @@ impl BinaryChannelTest for ChannelWithFeeTest { let relayer_balance_a = chain_driver_a.query_balance(&relayer_a.address(), &denom_a)?; let send_amount = 1000; + let receive_fee = 300; let ack_fee = 200; let timeout_fee = 100; @@ -94,11 +95,10 @@ impl BinaryChannelTest for ChannelWithFeeTest { &channel_id_a, &user_a, &user_b.address(), - &denom_a, - send_amount, - receive_fee, - ack_fee, - timeout_fee, + &denom_a.with_amount(send_amount).as_ref(), + &denom_a.with_amount(receive_fee).as_ref(), + &denom_a.with_amount(ack_fee).as_ref(), + &denom_a.with_amount(timeout_fee).as_ref(), ))?; let denom_b = derive_ibc_denom( @@ -109,31 +109,26 @@ impl BinaryChannelTest for ChannelWithFeeTest { info!("Expect user A's balance after transfer: {}", balance_a2); - chain_driver_a.assert_eventual_wallet_amount( - &user_a.address(), - balance_a2, - &denom_a, - )?; + chain_driver_a + .assert_eventual_wallet_amount(&user_a.address(), &balance_a2.as_ref())?; chain_driver_b.assert_eventual_wallet_amount( &user_b.address(), - send_amount, - &denom_b.as_ref(), + &denom_b.with_amount(send_amount).as_ref(), )?; info!( "Expect user to be refunded receive timeout fee {} and go from {} to {}", timeout_fee, balance_a2, - balance_a2 + timeout_fee + ack_fee + balance_a2.amount() + timeout_fee + ack_fee ); // receive fee and timeout fee should be refunded, // as there is no counterparty address registered. chain_driver_a.assert_eventual_wallet_amount( &user_a.address(), - balance_a2 + timeout_fee, - &denom_a, + &(balance_a2 + timeout_fee).as_ref(), )?; info!( @@ -141,13 +136,12 @@ impl BinaryChannelTest for ChannelWithFeeTest { ack_fee, receive_fee, relayer_balance_a, - relayer_balance_a + ack_fee + receive_fee, + relayer_balance_a.amount() + ack_fee + receive_fee, ); chain_driver_a.assert_eventual_wallet_amount( &relayer_a.address(), - relayer_balance_a + ack_fee + receive_fee, - &denom_a, + &(relayer_balance_a + ack_fee + receive_fee).as_ref(), )?; Ok(()) diff --git a/tools/integration-test/src/tests/ica.rs b/tools/integration-test/src/tests/ica.rs index 0e2db7aec5..ea6d2fdee6 100644 --- a/tools/integration-test/src/tests/ica.rs +++ b/tools/integration-test/src/tests/ica.rs @@ -111,7 +111,11 @@ impl BinaryConnectionTest for IcaFilterTestAllow { .chain_driver() .query_balance(&ica_address.as_ref(), &stake_denom.as_ref())?; - assert_eq("balance of ICA account should be 0", &ica_balance, &0)?; + assert_eq( + "balance of ICA account should be 0", + &ica_balance.amount(), + &0, + )?; // Send funds to the interchain account. let ica_fund = 42000; @@ -119,15 +123,7 @@ impl BinaryConnectionTest for IcaFilterTestAllow { chains.node_b.chain_driver().local_transfer_token( &chains.node_b.wallets().user1(), &ica_address.as_ref(), - ica_fund, - &stake_denom.as_ref(), - )?; - - // Check that the balance has been updated. - chains.node_b.chain_driver().assert_eventual_wallet_amount( - &ica_address.as_ref(), - ica_fund, - &stake_denom.as_ref(), + &stake_denom.with_amount(ica_fund).as_ref(), )?; #[derive(Serialize)] @@ -168,8 +164,7 @@ impl BinaryConnectionTest for IcaFilterTestAllow { // Check that the ICA account's balance has been debited the sent amount. chains.node_b.chain_driver().assert_eventual_wallet_amount( &ica_address.as_ref(), - ica_fund - amount, - &stake_denom.as_ref(), + &stake_denom.with_amount(ica_fund - amount).as_ref(), )?; Ok(()) diff --git a/tools/integration-test/src/tests/memo.rs b/tools/integration-test/src/tests/memo.rs index b77f501e50..e0fbe0f6a1 100644 --- a/tools/integration-test/src/tests/memo.rs +++ b/tools/integration-test/src/tests/memo.rs @@ -3,7 +3,7 @@ use serde_json as json; use ibc_test_framework::ibc::denom::derive_ibc_denom; use ibc_test_framework::prelude::*; -use ibc_test_framework::util::random::{random_string, random_u64_range}; +use ibc_test_framework::util::random::{random_string, random_u128_range}; #[test] fn test_memo() -> Result<(), Error> { @@ -39,15 +39,14 @@ impl BinaryChannelTest for MemoTest { let denom_a = chains.node_a.denom(); - let a_to_b_amount = random_u64_range(1000, 5000); + let a_to_b_amount = random_u128_range(1000, 5000); 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(), - &denom_a, - a_to_b_amount, + &denom_a.with_amount(a_to_b_amount).as_ref(), )?; let denom_b = derive_ibc_denom( @@ -58,8 +57,7 @@ impl BinaryChannelTest for MemoTest { chains.node_b.chain_driver().assert_eventual_wallet_amount( &chains.node_b.wallets().user1().address(), - a_to_b_amount, - &denom_b.as_ref(), + &denom_b.with_amount(a_to_b_amount).as_ref(), )?; let tx_info = chains diff --git a/tools/integration-test/src/tests/ordered_channel.rs b/tools/integration-test/src/tests/ordered_channel.rs index ea0467dd33..e33c57bc32 100644 --- a/tools/integration-test/src/tests/ordered_channel.rs +++ b/tools/integration-test/src/tests/ordered_channel.rs @@ -1,6 +1,6 @@ use ibc_test_framework::ibc::denom::derive_ibc_denom; use ibc_test_framework::prelude::*; -use ibc_test_framework::util::random::random_u64_range; +use ibc_test_framework::util::random::random_u128_range; #[test] fn test_ordered_channel() -> Result<(), Error> { @@ -44,7 +44,7 @@ impl BinaryChannelTest for OrderedChannelTest { .chain_driver() .query_balance(&wallet_a.address(), &denom_a)?; - let amount1 = random_u64_range(1000, 5000); + let amount1 = random_u128_range(1000, 5000); info!( "Performing IBC transfer with amount {}, which should be relayed because its an ordered channel", @@ -56,8 +56,7 @@ impl BinaryChannelTest for OrderedChannelTest { &channel.channel_id_a.as_ref(), &wallet_a.as_ref(), &wallet_b.address(), - &denom_a, - amount1, + &denom_a.with_amount(amount1).as_ref(), )?; sleep(Duration::from_secs(1)); @@ -65,7 +64,7 @@ impl BinaryChannelTest for OrderedChannelTest { relayer.with_supervisor(|| { sleep(Duration::from_secs(1)); - let amount2 = random_u64_range(1000, 5000); + let amount2 = random_u128_range(1000, 5000); info!( "Performing IBC transfer with amount {}, which should be relayed", @@ -77,8 +76,7 @@ impl BinaryChannelTest for OrderedChannelTest { &channel.channel_id_a.as_ref(), &wallet_a.as_ref(), &wallet_b.address(), - &denom_a, - amount2, + &denom_a.with_amount(amount2).as_ref(), )?; sleep(Duration::from_secs(1)); @@ -92,15 +90,13 @@ impl BinaryChannelTest for OrderedChannelTest { // Wallet on chain A should have both amount deducted. chains.node_a.chain_driver().assert_eventual_wallet_amount( &wallet_a.address(), - balance_a - amount1 - amount2, - &denom_a, + &(balance_a - amount1 - amount2).as_ref(), )?; // Wallet on chain B should receive both IBC transfers chains.node_b.chain_driver().assert_eventual_wallet_amount( &wallet_b.address(), - amount1 + amount2, - &denom_b.as_ref(), + &denom_b.with_amount(amount1 + amount2).as_ref(), )?; Ok(()) diff --git a/tools/integration-test/src/tests/query_packet.rs b/tools/integration-test/src/tests/query_packet.rs index 7a7fc57b49..1bae5052ff 100644 --- a/tools/integration-test/src/tests/query_packet.rs +++ b/tools/integration-test/src/tests/query_packet.rs @@ -4,7 +4,7 @@ use ibc_relayer::link::{Link, LinkParameters}; use ibc_test_framework::prelude::*; use ibc_test_framework::relayer::channel::query_identified_channel_end; use ibc_test_framework::relayer::connection::query_identified_connection_end; -use ibc_test_framework::util::random::random_u64_range; +use ibc_test_framework::util::random::random_u128_range; #[test] fn test_query_packet_pending() -> Result<(), Error> { @@ -39,7 +39,7 @@ impl BinaryChannelTest for QueryPacketPendingTest { let wallet_a = chains.node_a.wallets().user1().cloned(); let wallet_b = chains.node_b.wallets().user1().cloned(); - let amount1 = random_u64_range(1000, 5000); + let amount1 = random_u128_range(1000, 5000); info!( "Performing IBC transfer with amount {}, which should *not* be relayed", @@ -51,8 +51,7 @@ impl BinaryChannelTest for QueryPacketPendingTest { &channel.channel_id_a.as_ref(), &wallet_a.as_ref(), &wallet_b.address(), - &denom_a, - amount1, + &denom_a.with_amount(amount1).as_ref(), )?; sleep(Duration::from_secs(2)); @@ -100,15 +99,14 @@ impl BinaryChannelTest for QueryPacketPendingTest { assert!(summary.unreceived_acks.is_empty()); let denom_b = chains.node_b.denom(); - let amount2 = random_u64_range(1000, 5000); + let amount2 = random_u128_range(1000, 5000); 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(), - &denom_b, - amount2, + &denom_b.with_amount(amount2).as_ref(), )?; info!( diff --git a/tools/integration-test/src/tests/supervisor.rs b/tools/integration-test/src/tests/supervisor.rs index 4e739edc58..4bbe93c6c8 100644 --- a/tools/integration-test/src/tests/supervisor.rs +++ b/tools/integration-test/src/tests/supervisor.rs @@ -97,15 +97,13 @@ impl BinaryChainTest for SupervisorTest { chains.node_a.chain_driver().local_transfer_token( &chains.node_a.wallets().relayer(), &chains.node_a.wallets().user2().address(), - 1000, - &denom_a, + &denom_a.with_amount(1000).as_ref(), )?; chains.node_b.chain_driver().local_transfer_token( &chains.node_b.wallets().relayer(), &chains.node_b.wallets().user2().address(), - 1000, - &chains.node_b.denom(), + &chains.node_b.denom().with_amount(1000).as_ref(), )?; info!( @@ -121,8 +119,7 @@ impl BinaryChainTest for SupervisorTest { &channel_id_a.as_ref(), &wallet_a.as_ref(), &wallet_b.address(), - &denom_a, - transfer_amount, + &denom_a.with_amount(transfer_amount).as_ref(), )?; // During the test, you should see error logs showing "account sequence mismatch". @@ -132,14 +129,12 @@ impl BinaryChainTest for SupervisorTest { chains.node_a.chain_driver().assert_eventual_wallet_amount( &wallet_a.address(), - balance_a - transfer_amount, - &denom_a, + &(balance_a - transfer_amount).as_ref(), )?; chains.node_b.chain_driver().assert_eventual_wallet_amount( &wallet_b.address(), - transfer_amount, - &denom_b.as_ref(), + &denom_b.with_amount(transfer_amount).as_ref(), )?; std::thread::sleep(core::time::Duration::from_secs(10)); diff --git a/tools/integration-test/src/tests/ternary_transfer.rs b/tools/integration-test/src/tests/ternary_transfer.rs index 4c23a9eb4b..6fc5184c9e 100644 --- a/tools/integration-test/src/tests/ternary_transfer.rs +++ b/tools/integration-test/src/tests/ternary_transfer.rs @@ -62,8 +62,7 @@ impl NaryChannelTest<3> for TernaryIbcTransferTest { &channel_a_to_b.channel_id_a.as_ref(), &wallet_a1.as_ref(), &wallet_b1.address(), - &denom_a, - a_to_b_amount, + &denom_a.with_amount(a_to_b_amount).as_ref(), )?; let denom_a_to_b = derive_ibc_denom( @@ -81,14 +80,12 @@ impl NaryChannelTest<3> for TernaryIbcTransferTest { node_a.chain_driver().assert_eventual_wallet_amount( &wallet_a1.address(), - balance_a - a_to_b_amount, - &denom_a, + &(balance_a - a_to_b_amount).as_ref(), )?; node_b.chain_driver().assert_eventual_wallet_amount( &wallet_b1.address(), - a_to_b_amount, - &denom_a_to_b.as_ref(), + &denom_a_to_b.with_amount(a_to_b_amount).as_ref(), )?; info!( @@ -112,8 +109,7 @@ impl NaryChannelTest<3> for TernaryIbcTransferTest { &channel_b_to_c.channel_id_a.as_ref(), &wallet_b1.as_ref(), &wallet_c1.address(), - &denom_a_to_b.as_ref(), - b_to_c_amount, + &denom_a_to_b.with_amount(b_to_c_amount).as_ref(), )?; // Chain C will receive ibc/port-c/channel-c/port-b/channel-b/denom @@ -125,14 +121,14 @@ impl NaryChannelTest<3> for TernaryIbcTransferTest { node_b.chain_driver().assert_eventual_wallet_amount( &wallet_b1.address(), - a_to_b_amount - b_to_c_amount, - &denom_a_to_b.as_ref(), + &denom_a_to_b + .with_amount(a_to_b_amount - b_to_c_amount) + .as_ref(), )?; node_c.chain_driver().assert_eventual_wallet_amount( &wallet_c1.address(), - b_to_c_amount, - &denom_a_to_c.as_ref(), + &denom_a_to_c.with_amount(b_to_c_amount).as_ref(), )?; let channel_c_to_a = channels.channel_at::<2, 0>()?; @@ -150,8 +146,7 @@ impl NaryChannelTest<3> for TernaryIbcTransferTest { &channel_c_to_a.channel_id_a.as_ref(), &wallet_c1.as_ref(), &wallet_a1.address(), - &denom_a_to_c.as_ref(), - c_to_a_amount, + &denom_a_to_c.with_amount(c_to_a_amount).as_ref(), )?; // Chain A will receive ibc/port-a/channel-a/port-c/channel-c/port-b/channel-b/denom @@ -163,14 +158,14 @@ impl NaryChannelTest<3> for TernaryIbcTransferTest { node_c.chain_driver().assert_eventual_wallet_amount( &wallet_c1.address(), - b_to_c_amount - c_to_a_amount, - &denom_a_to_c.as_ref(), + &denom_a_to_c + .with_amount(b_to_c_amount - c_to_a_amount) + .as_ref(), )?; node_a.chain_driver().assert_eventual_wallet_amount( &wallet_a1.address(), - c_to_a_amount, - &denom_a_to_c_to_a.as_ref(), + &denom_a_to_c_to_a.with_amount(c_to_a_amount).as_ref(), )?; let c_to_b_amount = 500; @@ -180,8 +175,7 @@ impl NaryChannelTest<3> for TernaryIbcTransferTest { &channel_b_to_c.channel_id_b.as_ref(), &wallet_c1.as_ref(), &wallet_b2.address(), - &denom_a_to_c.as_ref(), - c_to_b_amount, + &denom_a_to_c.with_amount(c_to_b_amount).as_ref(), )?; // Chain B will receive ibc/port-b/channel-b/denom @@ -193,14 +187,14 @@ impl NaryChannelTest<3> for TernaryIbcTransferTest { node_c.chain_driver().assert_eventual_wallet_amount( &wallet_c1.address(), - b_to_c_amount - c_to_a_amount - c_to_b_amount, - &denom_a_to_c.as_ref(), + &denom_a_to_c + .with_amount(b_to_c_amount - c_to_a_amount - c_to_b_amount) + .as_ref(), )?; node_b.chain_driver().assert_eventual_wallet_amount( &wallet_b2.address(), - c_to_b_amount, - &denom_a_to_b.as_ref(), + &denom_a_to_b.with_amount(c_to_b_amount).as_ref(), )?; Ok(()) diff --git a/tools/integration-test/src/tests/transfer.rs b/tools/integration-test/src/tests/transfer.rs index afac3170d6..d51e3be616 100644 --- a/tools/integration-test/src/tests/transfer.rs +++ b/tools/integration-test/src/tests/transfer.rs @@ -1,5 +1,5 @@ use ibc_test_framework::prelude::*; -use ibc_test_framework::util::random::random_u64_range; +use ibc_test_framework::util::random::random_u128_range; #[test] fn test_ibc_transfer() -> Result<(), Error> { @@ -59,7 +59,7 @@ impl BinaryChannelTest for IbcTransferTest { .chain_driver() .query_balance(&wallet_a.address(), &denom_a)?; - let a_to_b_amount = random_u64_range(1000, 5000); + let a_to_b_amount = random_u128_range(1000, 5000); info!( "Sending IBC transfer from chain {} to chain {} with amount of {} {}", @@ -74,8 +74,7 @@ impl BinaryChannelTest for IbcTransferTest { &channel.channel_id_a.as_ref(), &wallet_a.as_ref(), &wallet_b.address(), - &denom_a, - a_to_b_amount, + &denom_a.with_amount(a_to_b_amount).as_ref(), )?; let denom_b = derive_ibc_denom( @@ -85,20 +84,18 @@ impl BinaryChannelTest for IbcTransferTest { )?; info!( - "Waiting for user on chain B to receive IBC transferred amount of {} {}", - a_to_b_amount, denom_b + "Waiting for user on chain B to receive IBC transferred amount of {}", + a_to_b_amount ); chains.node_a.chain_driver().assert_eventual_wallet_amount( &wallet_a.address(), - balance_a - a_to_b_amount, - &denom_a, + &(balance_a - a_to_b_amount).as_ref(), )?; chains.node_b.chain_driver().assert_eventual_wallet_amount( &wallet_b.address(), - a_to_b_amount, - &denom_b.as_ref(), + &denom_b.with_amount(a_to_b_amount).as_ref(), )?; info!( @@ -112,14 +109,13 @@ impl BinaryChannelTest for IbcTransferTest { .chain_driver() .query_balance(&wallet_c.address(), &denom_a)?; - let b_to_a_amount = random_u64_range(500, a_to_b_amount); + let b_to_a_amount = random_u128_range(500, a_to_b_amount); info!( - "Sending IBC transfer from chain {} to chain {} with amount of {} {}", + "Sending IBC transfer from chain {} to chain {} with amount of {}", chains.chain_id_b(), chains.chain_id_a(), b_to_a_amount, - denom_b ); chains.node_b.chain_driver().ibc_transfer_token( @@ -127,20 +123,17 @@ impl BinaryChannelTest for IbcTransferTest { &channel.channel_id_b.as_ref(), &wallet_b.as_ref(), &wallet_c.address(), - &denom_b.as_ref(), - b_to_a_amount, + &denom_b.with_amount(b_to_a_amount).as_ref(), )?; chains.node_b.chain_driver().assert_eventual_wallet_amount( &wallet_b.address(), - a_to_b_amount - b_to_a_amount, - &denom_b.as_ref(), + &denom_b.with_amount(a_to_b_amount - b_to_a_amount).as_ref(), )?; chains.node_a.chain_driver().assert_eventual_wallet_amount( &wallet_c.address(), - balance_c + b_to_a_amount, - &denom_a, + &(balance_c + b_to_a_amount).as_ref(), )?; info!( diff --git a/tools/test-framework/src/bootstrap/single.rs b/tools/test-framework/src/bootstrap/single.rs index f64e1a0f9d..a49ed5062e 100644 --- a/tools/test-framework/src/bootstrap/single.rs +++ b/tools/test-framework/src/bootstrap/single.rs @@ -11,9 +11,10 @@ use crate::chain::config; use crate::chain::driver::ChainDriver; use crate::error::Error; use crate::ibc::denom::Denom; +use crate::ibc::token::Token; use crate::types::single::node::FullNode; use crate::types::wallet::{TestWallets, Wallet}; -use crate::util::random::{random_u32, random_u64_range}; +use crate::util::random::{random_u128_range, random_u32}; /** Bootstrap a single full node with the provided [`ChainBuilder`] and @@ -49,7 +50,10 @@ pub fn bootstrap_single_node( Denom::base("samoleans") }; - let initial_amount = random_u64_range(1_000_000_000_000, 9_000_000_000_000); + let initial_amount = random_u128_range(1_000_000_000_000, 9_000_000_000_000); + + let initial_stake = Token::new(stake_denom, initial_amount); + let initial_coin = Token::new(denom.clone(), initial_amount); let chain_driver = builder.new_chain(prefix, use_random_id)?; @@ -62,24 +66,15 @@ pub fn bootstrap_single_node( let user1 = add_wallet(&chain_driver, "user1", use_random_id)?; let user2 = add_wallet(&chain_driver, "user2", use_random_id)?; - chain_driver.add_genesis_account(&validator.address, &[(&stake_denom, initial_amount)])?; + chain_driver.add_genesis_account(&validator.address, &[&initial_stake])?; - chain_driver.add_genesis_validator(&validator.id, &stake_denom, initial_amount)?; + chain_driver.add_genesis_validator(&validator.id, &initial_stake)?; - chain_driver.add_genesis_account( - &user1.address, - &[(&stake_denom, initial_amount), (&denom, initial_amount)], - )?; + chain_driver.add_genesis_account(&user1.address, &[&initial_stake, &initial_coin])?; - chain_driver.add_genesis_account( - &user2.address, - &[(&stake_denom, initial_amount), (&denom, initial_amount)], - )?; + chain_driver.add_genesis_account(&user2.address, &[&initial_stake, &initial_coin])?; - chain_driver.add_genesis_account( - &relayer.address, - &[(&stake_denom, initial_amount), (&denom, initial_amount)], - )?; + chain_driver.add_genesis_account(&relayer.address, &[&initial_stake, &initial_coin])?; chain_driver.collect_gen_txs()?; @@ -100,13 +95,14 @@ pub fn bootstrap_single_node( chain_driver.update_chain_config("app.toml", |config| { config::set_grpc_port(config, chain_driver.grpc_port)?; config::disable_grpc_web(config)?; + config::set_minimum_gas_price(config, "0stake")?; Ok(()) })?; let process = chain_driver.start()?; - chain_driver.assert_eventual_wallet_amount(&relayer.address, initial_amount, &denom)?; + chain_driver.assert_eventual_wallet_amount(&relayer.address, &initial_coin)?; info!( "started new chain {} at with home path {} and RPC address {}.", diff --git a/tools/test-framework/src/chain/config.rs b/tools/test-framework/src/chain/config.rs index bec1529485..1ff6d1ff59 100644 --- a/tools/test-framework/src/chain/config.rs +++ b/tools/test-framework/src/chain/config.rs @@ -101,3 +101,12 @@ pub fn set_log_level(config: &mut Value, log_level: &str) -> Result<(), Error> { Ok(()) } + +pub fn set_minimum_gas_price(config: &mut Value, price: &str) -> Result<(), Error> { + config + .as_table_mut() + .ok_or_else(|| eyre!("expect object"))? + .insert("minimum-gas-prices".to_string(), price.into()); + + Ok(()) +} diff --git a/tools/test-framework/src/chain/driver.rs b/tools/test-framework/src/chain/driver.rs index 4734967e70..22ae37383c 100644 --- a/tools/test-framework/src/chain/driver.rs +++ b/tools/test-framework/src/chain/driver.rs @@ -24,6 +24,7 @@ use ibc_relayer::keyring::{HDPath, KeyEntry, KeyFile}; use crate::chain::exec::{simple_exec, ExecOutput}; use crate::error::{handle_generic_error, Error}; use crate::ibc::denom::Denom; +use crate::ibc::token::Token; use crate::relayer::tx::{new_tx_config_for_test, simple_send_tx}; use crate::types::env::{EnvWriter, ExportEnv}; use crate::types::process::ChildProcess; @@ -319,14 +320,9 @@ impl ChainDriver { pub fn add_genesis_account( &self, wallet: &WalletAddress, - amounts: &[(&Denom, u64)], + amounts: &[&Token], ) -> Result<(), Error> { - let amounts_str = itertools::join( - amounts - .iter() - .map(|(denom, amount)| format!("{}{}", amount, denom)), - ",", - ); + let amounts_str = itertools::join(amounts.iter().map(|t| t.to_string()), ","); self.exec(&[ "--home", @@ -343,14 +339,7 @@ impl ChainDriver { Add a wallet ID with the given stake amount to be the genesis validator for an uninitialized chain. */ - pub fn add_genesis_validator( - &self, - wallet_id: &WalletId, - denom: &Denom, - amount: u64, - ) -> Result<(), Error> { - let amount_str = format!("{}{}", amount, denom); - + pub fn add_genesis_validator(&self, wallet_id: &WalletId, token: &Token) -> Result<(), Error> { self.exec(&[ "--home", &self.home_path, @@ -360,7 +349,7 @@ impl ChainDriver { "test", "--chain-id", self.chain_id.as_str(), - &amount_str, + &token.to_string(), ])?; Ok(()) @@ -445,7 +434,7 @@ impl ChainDriver { /** Query for the balances for a given wallet address and denomination */ - pub fn query_balance(&self, wallet_id: &WalletAddress, denom: &Denom) -> Result { + pub fn query_balance(&self, wallet_id: &WalletAddress, denom: &Denom) -> Result { let res = self .exec(&[ "--node", @@ -469,7 +458,7 @@ impl ChainDriver { .ok_or_else(|| eyre!("expected string field"))? .to_string(); - let amount = u64::from_str(&amount_str).map_err(handle_generic_error)?; + let amount = u128::from_str(&amount_str).map_err(handle_generic_error)?; Ok(amount) } @@ -486,24 +475,23 @@ impl ChainDriver { pub fn assert_eventual_wallet_amount( &self, wallet: &WalletAddress, - target_amount: u64, - denom: &Denom, + token: &Token, ) -> Result<(), Error> { assert_eventually_succeed( - &format!("wallet reach {} amount {} {}", wallet, target_amount, denom), + &format!("wallet reach {} amount {}", wallet, token), WAIT_WALLET_AMOUNT_ATTEMPTS, Duration::from_secs(1), || { - let amount = self.query_balance(wallet, denom)?; + let amount = self.query_balance(wallet, &token.denom)?; - if amount == target_amount { + if amount == token.amount { Ok(()) } else { Err(Error::generic(eyre!( "current balance of account {} with amount {} does not match the target amount {}", wallet, amount, - target_amount + token ))) } }, diff --git a/tools/test-framework/src/chain/driver/transfer.rs b/tools/test-framework/src/chain/driver/transfer.rs index 0f6f5fa6c5..58cdfda73b 100644 --- a/tools/test-framework/src/chain/driver/transfer.rs +++ b/tools/test-framework/src/chain/driver/transfer.rs @@ -3,7 +3,7 @@ */ use crate::error::Error; -use crate::ibc::denom::Denom; +use crate::ibc::token::Token; use crate::types::wallet::{Wallet, WalletAddress}; use super::ChainDriver; @@ -12,8 +12,7 @@ pub fn local_transfer_token( driver: &ChainDriver, sender: &Wallet, recipient: &WalletAddress, - amount: u64, - denom: &Denom, + token: &Token, ) -> Result<(), Error> { driver.exec(&[ "--node", @@ -23,7 +22,7 @@ pub fn local_transfer_token( "send", &sender.address.0, &recipient.0, - &format!("{}{}", amount, denom), + &token.to_string(), "--chain-id", driver.chain_id.as_str(), "--home", diff --git a/tools/test-framework/src/chain/tagged.rs b/tools/test-framework/src/chain/tagged.rs index da85694af5..fe7f8b9279 100644 --- a/tools/test-framework/src/chain/tagged.rs +++ b/tools/test-framework/src/chain/tagged.rs @@ -15,6 +15,7 @@ use crate::chain::driver::transfer::local_transfer_token; use crate::chain::driver::ChainDriver; use crate::error::Error; use crate::ibc::denom::Denom; +use crate::ibc::token::{TaggedDenomExt, TaggedToken, TaggedTokenRef}; use crate::prelude::TaggedConnectionIdRef; use crate::relayer::transfer::ibc_token_transfer; use crate::types::id::{TaggedChainIdRef, TaggedChannelIdRef, TaggedPortIdRef}; @@ -49,7 +50,7 @@ pub trait TaggedChainDriverExt { &self, wallet_id: &MonoTagged, denom: &MonoTagged, - ) -> Result; + ) -> Result, Error>; /** Tagged version of [`ChainDriver::assert_eventual_wallet_amount`]. @@ -60,8 +61,7 @@ pub trait TaggedChainDriverExt { fn assert_eventual_wallet_amount( &self, user: &MonoTagged, - target_amount: u64, - denom: &MonoTagged, + token: &TaggedTokenRef, ) -> Result<(), Error>; /** @@ -90,16 +90,14 @@ pub trait TaggedChainDriverExt { channel_id: &TaggedChannelIdRef, sender: &MonoTagged, recipient: &MonoTagged, - denom: &MonoTagged, - amount: u64, + token: &TaggedTokenRef, ) -> Result<(), Error>; fn local_transfer_token( &self, sender: &MonoTagged, recipient: &MonoTagged, - amount: u64, - denom: &MonoTagged, + token: &TaggedTokenRef, ) -> Result<(), Error>; /** @@ -154,18 +152,20 @@ impl<'a, Chain: Send> TaggedChainDriverExt for MonoTagged, denom: &MonoTagged, - ) -> Result { - self.value().query_balance(wallet_id.value(), denom.value()) + ) -> Result, Error> { + let balance = self + .value() + .query_balance(wallet_id.value(), denom.value())?; + Ok(denom.with_amount(balance)) } fn assert_eventual_wallet_amount( &self, user: &MonoTagged, - target_amount: u64, - denom: &MonoTagged, + token: &TaggedTokenRef, ) -> Result<(), Error> { self.value() - .assert_eventual_wallet_amount(user.value(), target_amount, denom.value()) + .assert_eventual_wallet_amount(user.value(), token.value()) } fn ibc_transfer_token( @@ -174,8 +174,7 @@ impl<'a, Chain: Send> TaggedChainDriverExt for MonoTagged, sender: &MonoTagged, recipient: &MonoTagged, - denom: &MonoTagged, - amount: u64, + token: &TaggedTokenRef, ) -> Result<(), Error> { self.value().runtime.block_on(ibc_token_transfer( &self.tx_config(), @@ -183,8 +182,7 @@ impl<'a, Chain: Send> TaggedChainDriverExt for MonoTagged TaggedChainDriverExt for MonoTagged, recipient: &MonoTagged, - amount: u64, - denom: &MonoTagged, + token: &TaggedTokenRef, ) -> Result<(), Error> { local_transfer_token( self.value(), sender.value(), recipient.value(), - amount, - denom.value(), + token.value(), ) } diff --git a/tools/test-framework/src/ibc/denom.rs b/tools/test-framework/src/ibc/denom.rs index e0059c3887..a9a8446692 100644 --- a/tools/test-framework/src/ibc/denom.rs +++ b/tools/test-framework/src/ibc/denom.rs @@ -106,3 +106,26 @@ impl Display for Denom { } } } + +impl PartialEq for Denom { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::Base(d1), Self::Base(d2)) => d1 == d2, + ( + Self::Ibc { + path: p1, + denom: d1, + hashed: h1, + }, + Self::Ibc { + path: p2, + denom: d2, + hashed: h2, + }, + ) => p1 == p2 && d1 == d2 && h1 == h2, + _ => false, + } + } +} + +impl Eq for Denom {} diff --git a/tools/test-framework/src/ibc/mod.rs b/tools/test-framework/src/ibc/mod.rs index e389251e1c..514ec8e59d 100644 --- a/tools/test-framework/src/ibc/mod.rs +++ b/tools/test-framework/src/ibc/mod.rs @@ -4,3 +4,4 @@ */ pub mod denom; +pub mod token; diff --git a/tools/test-framework/src/ibc/token.rs b/tools/test-framework/src/ibc/token.rs new file mode 100644 index 0000000000..f889474e5d --- /dev/null +++ b/tools/test-framework/src/ibc/token.rs @@ -0,0 +1,140 @@ +use core::fmt::{self, Display}; +use core::ops::{Add, Sub}; + +use crate::error::Error; +use crate::ibc::denom::{derive_ibc_denom, Denom, TaggedDenom, TaggedDenomRef}; +use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef}; +use crate::types::tagged::MonoTagged; + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct Token { + pub denom: Denom, + pub amount: u128, +} + +pub type TaggedToken = MonoTagged; +pub type TaggedTokenRef<'a, Chain> = MonoTagged; + +pub trait TaggedTokenExt { + fn denom(&self) -> TaggedDenomRef; + + fn amount(&self) -> u128; + + fn transfer( + &self, + port_id: &TaggedPortIdRef, + channel_id: &TaggedChannelIdRef, + ) -> Result, Error>; +} + +pub trait TaggedDenomExt { + fn with_amount(&self, amount: u128) -> TaggedToken; +} + +impl Token { + pub fn new(denom: Denom, amount: u128) -> Self { + Self { denom, amount } + } +} + +impl TaggedTokenExt for TaggedToken { + fn denom(&self) -> TaggedDenomRef { + self.map_ref(|t| &t.denom) + } + + fn amount(&self) -> u128 { + self.value().amount + } + + fn transfer( + &self, + port_id: &TaggedPortIdRef, + channel_id: &TaggedChannelIdRef, + ) -> Result, Error> { + let denom = derive_ibc_denom(port_id, channel_id, &self.denom())?; + + Ok(denom.with_amount(self.value().amount)) + } +} + +impl<'a, Chain> TaggedTokenExt for TaggedTokenRef<'a, Chain> { + fn denom(&self) -> TaggedDenomRef { + self.map_ref(|t| &t.denom) + } + + fn amount(&self) -> u128 { + self.value().amount + } + + fn transfer( + &self, + port_id: &TaggedPortIdRef, + channel_id: &TaggedChannelIdRef, + ) -> Result, Error> { + let denom = derive_ibc_denom(port_id, channel_id, &self.denom())?; + + Ok(denom.with_amount(self.value().amount)) + } +} + +impl TaggedDenomExt for TaggedDenom { + fn with_amount(&self, amount: u128) -> TaggedToken { + self.map(|denom| Token { + denom: denom.clone(), + amount, + }) + } +} + +impl<'a, Chain> TaggedDenomExt for TaggedDenomRef<'a, Chain> { + fn with_amount(&self, amount: u128) -> TaggedToken { + self.map(|denom| Token { + denom: (*denom).clone(), + amount, + }) + } +} + +impl Add for Token { + type Output = Self; + + fn add(self, amount: u128) -> Self { + Self { + denom: self.denom, + amount: self.amount + amount, + } + } +} + +impl Sub for Token { + type Output = Self; + + fn sub(self, amount: u128) -> Self { + Self { + denom: self.denom, + amount: self.amount - amount, + } + } +} + +impl Add for MonoTagged { + type Output = Self; + + fn add(self, amount: u128) -> Self { + self.map_into(|t| t + amount) + } +} + +impl Sub for MonoTagged { + type Output = Self; + + fn sub(self, amount: u128) -> Self { + self.map_into(|t| t - amount) + } +} + +impl Display for Token { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}{}", self.amount, self.denom) + } +} diff --git a/tools/test-framework/src/prelude.rs b/tools/test-framework/src/prelude.rs index 4abe634ef4..08e703874d 100644 --- a/tools/test-framework/src/prelude.rs +++ b/tools/test-framework/src/prelude.rs @@ -47,6 +47,7 @@ pub use crate::framework::overrides::TestOverrides; pub use crate::framework::supervisor::RunWithSupervisor; pub use crate::ibc::denom::derive_ibc_denom; pub use crate::ibc::denom::Denom; +pub use crate::ibc::token::{TaggedDenomExt, TaggedToken, TaggedTokenExt, TaggedTokenRef, Token}; 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/fee.rs b/tools/test-framework/src/relayer/fee.rs index cd9c7d3ee3..0ee83886b1 100644 --- a/tools/test-framework/src/relayer/fee.rs +++ b/tools/test-framework/src/relayer/fee.rs @@ -5,7 +5,7 @@ use ibc_relayer::chain::cosmos::types::config::TxConfig; use prost::{EncodeError, Message}; use crate::error::{handle_generic_error, Error}; -use crate::ibc::denom::Denom; +use crate::ibc::token::TaggedTokenRef; use crate::relayer::transfer::build_transfer_message; use crate::relayer::tx::simple_send_tx; use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef}; @@ -19,20 +19,18 @@ pub async fn ibc_token_transfer_with_fee( channel_id: &TaggedChannelIdRef<'_, SrcChain, DstChain>, sender: &MonoTagged, recipient: &MonoTagged, - denom: &MonoTagged, - send_amount: u64, - receive_fee: u64, - ack_fee: u64, - timeout_fee: u64, + send_amount: &TaggedTokenRef<'_, SrcChain>, + receive_fee: &TaggedTokenRef<'_, SrcChain>, + ack_fee: &TaggedTokenRef<'_, SrcChain>, + timeout_fee: &TaggedTokenRef<'_, SrcChain>, ) -> Result<(), Error> { let transfer_message = - build_transfer_message(port_id, channel_id, sender, recipient, denom, send_amount)?; + build_transfer_message(port_id, channel_id, sender, recipient, send_amount)?; let pay_message = build_pay_packet_message( port_id, channel_id, &sender.address(), - denom, receive_fee, ack_fee, timeout_fee, @@ -74,27 +72,24 @@ pub fn build_pay_packet_message( port_id: &TaggedPortIdRef, channel_id: &TaggedChannelIdRef, payer: &MonoTagged, - denom: &MonoTagged, - receive_fee: u64, - ack_fee: u64, - timeout_fee: u64, + receive_fee: &TaggedTokenRef<'_, Chain>, + ack_fee: &TaggedTokenRef<'_, Chain>, + timeout_fee: &TaggedTokenRef<'_, Chain>, ) -> Result { const TYPE_URL: &str = "/ibc.applications.fee.v1.MsgPayPacketFee"; - let denom_str = denom.value().to_string(); - let fee = Fee { recv_fee: vec![Coin { - denom: denom_str.clone(), - amount: receive_fee.to_string(), + denom: receive_fee.value().denom.to_string(), + amount: receive_fee.value().amount.to_string(), }], ack_fee: vec![Coin { - denom: denom_str.clone(), - amount: ack_fee.to_string(), + denom: ack_fee.value().denom.to_string(), + amount: ack_fee.value().amount.to_string(), }], timeout_fee: vec![Coin { - denom: denom_str, - amount: timeout_fee.to_string(), + denom: timeout_fee.value().denom.to_string(), + amount: timeout_fee.value().amount.to_string(), }], }; diff --git a/tools/test-framework/src/relayer/transfer.rs b/tools/test-framework/src/relayer/transfer.rs index d4ac86aff0..4e5c1cea8a 100644 --- a/tools/test-framework/src/relayer/transfer.rs +++ b/tools/test-framework/src/relayer/transfer.rs @@ -13,7 +13,7 @@ use ibc_relayer::chain::cosmos::types::config::TxConfig; use ibc_relayer::transfer::build_transfer_message as raw_build_transfer_message; use crate::error::{handle_generic_error, Error}; -use crate::ibc::denom::Denom; +use crate::ibc::token::TaggedTokenRef; use crate::relayer::tx::simple_send_tx; use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef}; use crate::types::tagged::*; @@ -24,8 +24,7 @@ pub fn build_transfer_message( channel_id: &TaggedChannelIdRef<'_, SrcChain, DstChain>, sender: &MonoTagged, recipient: &MonoTagged, - denom: &MonoTagged, - amount: u64, + token: &TaggedTokenRef<'_, SrcChain>, ) -> Result { let timeout_timestamp = Timestamp::now() .add(Duration::from_secs(60)) @@ -34,8 +33,8 @@ pub fn build_transfer_message( Ok(raw_build_transfer_message( (*port_id.value()).clone(), **channel_id.value(), - amount.into(), - denom.value().to_string(), + token.value().amount.into(), + token.value().denom.to_string(), Signer::new(sender.value().address.0.clone()), Signer::new(recipient.value().0.clone()), Height::zero(), @@ -66,10 +65,9 @@ pub async fn ibc_token_transfer( channel_id: &TaggedChannelIdRef<'_, SrcChain, DstChain>, sender: &MonoTagged, recipient: &MonoTagged, - denom: &MonoTagged, - amount: u64, + token: &TaggedTokenRef<'_, SrcChain>, ) -> Result<(), Error> { - let message = build_transfer_message(port_id, channel_id, sender, recipient, denom, amount)?; + let message = build_transfer_message(port_id, channel_id, sender, recipient, token)?; simple_send_tx(tx_config.value(), &sender.value().key, vec![message]).await?; diff --git a/tools/test-framework/src/util/random.rs b/tools/test-framework/src/util/random.rs index 4bb47295cf..01bda39c1b 100644 --- a/tools/test-framework/src/util/random.rs +++ b/tools/test-framework/src/util/random.rs @@ -17,12 +17,23 @@ pub fn random_u64() -> u64 { rng.gen() } +pub fn random_u128() -> u128 { + let mut rng = rand::thread_rng(); + rng.gen() +} + /// Generates a random `u64` value between the given min and max. pub fn random_u64_range(min: u64, max: u64) -> u64 { let mut rng = rand::thread_rng(); rng.gen_range(min..max) } +/// Generates a random `u64` value between the given min and max. +pub fn random_u128_range(min: u128, max: u128) -> u128 { + let mut rng = rand::thread_rng(); + rng.gen_range(min..max) +} + /// Generates a random string value, in the form of `u64` hex for simplicity. pub fn random_string() -> String { format!("{:x}", random_u64()) From 234e0b107453d0e63d8ac7af503986ad54eaf4d7 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Fri, 20 May 2022 11:03:58 +0200 Subject: [PATCH 017/113] Set full node config mode to "validator" Set minimum price on node bootstrap --- tools/test-framework/src/bootstrap/single.rs | 2 ++ tools/test-framework/src/chain/config.rs | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/tools/test-framework/src/bootstrap/single.rs b/tools/test-framework/src/bootstrap/single.rs index f64e1a0f9d..918d7fb957 100644 --- a/tools/test-framework/src/bootstrap/single.rs +++ b/tools/test-framework/src/bootstrap/single.rs @@ -91,6 +91,7 @@ pub fn bootstrap_single_node( config::set_p2p_port(config, chain_driver.p2p_port)?; config::set_timeout_commit(config, Duration::from_secs(1))?; config::set_timeout_propose(config, Duration::from_secs(1))?; + config::set_mode(config, "validator")?; config_modifier(config)?; @@ -100,6 +101,7 @@ pub fn bootstrap_single_node( chain_driver.update_chain_config("app.toml", |config| { config::set_grpc_port(config, chain_driver.grpc_port)?; config::disable_grpc_web(config)?; + config::set_minimum_gas_price(config, "0stake")?; Ok(()) })?; diff --git a/tools/test-framework/src/chain/config.rs b/tools/test-framework/src/chain/config.rs index bec1529485..2e80696047 100644 --- a/tools/test-framework/src/chain/config.rs +++ b/tools/test-framework/src/chain/config.rs @@ -101,3 +101,21 @@ pub fn set_log_level(config: &mut Value, log_level: &str) -> Result<(), Error> { Ok(()) } + +pub fn set_minimum_gas_price(config: &mut Value, price: &str) -> Result<(), Error> { + config + .as_table_mut() + .ok_or_else(|| eyre!("expect object"))? + .insert("minimum-gas-prices".to_string(), price.into()); + + Ok(()) +} + +pub fn set_mode(config: &mut Value, mode: &str) -> Result<(), Error> { + config + .as_table_mut() + .ok_or_else(|| eyre!("expect object"))? + .insert("mode".to_string(), mode.into()); + + Ok(()) +} From 43add2e282a1b201bf3d3e6c1a53e170d5920ab2 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Fri, 20 May 2022 12:41:26 +0200 Subject: [PATCH 018/113] Refactor wait_tx to work with all responses --- relayer/src/chain/cosmos/batch.rs | 28 ++--- relayer/src/chain/cosmos/query/tx.rs | 28 ++++- relayer/src/chain/cosmos/wait.rs | 155 +++++++++++++------------ relayer/src/error.rs | 17 ++- tools/test-framework/src/relayer/tx.rs | 30 +---- 5 files changed, 132 insertions(+), 126 deletions(-) diff --git a/relayer/src/chain/cosmos/batch.rs b/relayer/src/chain/cosmos/batch.rs index 867a1989b3..1466aa777e 100644 --- a/relayer/src/chain/cosmos/batch.rs +++ b/relayer/src/chain/cosmos/batch.rs @@ -1,12 +1,12 @@ use ibc::events::IbcEvent; use ibc_proto::google::protobuf::Any; use prost::Message; +use tendermint::abci::transaction::Hash as TxHash; use tendermint_rpc::endpoint::broadcast::tx_sync::Response; 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::{MaxMsgNum, MaxTxSize, Memo}; use crate::error::Error; @@ -25,7 +25,7 @@ pub async fn send_batched_messages_and_wait_commit( return Ok(Vec::new()); } - let mut tx_sync_results = send_messages_as_batches( + let tx_hashes = send_messages_as_batches( config, max_msg_num, max_tx_size, @@ -36,20 +36,15 @@ pub async fn send_batched_messages_and_wait_commit( ) .await?; - wait_for_block_commits( + let events = wait_for_block_commits( &config.chain_id, &config.rpc_client, &config.rpc_address, &config.rpc_timeout, - &mut tx_sync_results, + &tx_hashes, ) .await?; - let events = tx_sync_results - .into_iter() - .flat_map(|el| el.events) - .collect(); - Ok(events) } @@ -89,31 +84,24 @@ async fn send_messages_as_batches( account: &mut Account, tx_memo: &Memo, messages: Vec, -) -> Result, Error> { +) -> Result, Error> { if messages.is_empty() { return Ok(Vec::new()); } let batches = batch_messages(max_msg_num, max_tx_size, messages)?; - let mut tx_sync_results = Vec::new(); + let mut tx_hashes = Vec::new(); 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, tx_memo, batch, 0) .await?; - let tx_sync_result = TxSyncResult { - response, - events: events_per_tx, - }; - - tx_sync_results.push(tx_sync_result); + tx_hashes.push(response.hash); } - Ok(tx_sync_results) + Ok(tx_hashes) } fn batch_messages( diff --git a/relayer/src/chain/cosmos/query/tx.rs b/relayer/src/chain/cosmos/query/tx.rs index dab694a53c..4c966acdf6 100644 --- a/relayer/src/chain/cosmos/query/tx.rs +++ b/relayer/src/chain/cosmos/query/tx.rs @@ -5,10 +5,12 @@ use ibc::core::ics04_channel::events as ChannelEvents; use ibc::core::ics04_channel::packet::{Packet, Sequence}; use ibc::core::ics24_host::identifier::ChainId; use ibc::events::{from_tx_response_event, IbcEvent}; -use ibc::query::QueryTxRequest; +use ibc::query::{QueryTxHash, QueryTxRequest}; use ibc::Height as ICSHeight; +use tendermint::abci::transaction::Hash as TxHash; use tendermint::abci::Event; use tendermint_rpc::endpoint::tx::Response as ResultTx; +use tendermint_rpc::endpoint::tx_search::Response as TxSearchResponse; use tendermint_rpc::{Client, HttpClient, Order, Url}; use crate::chain::cosmos::query::{header_query, packet_query, tx_hash_query}; @@ -230,7 +232,29 @@ fn filter_matching_event( } } -fn all_ibc_events_from_tx_search_response(chain_id: &ChainId, response: ResultTx) -> Vec { +pub async fn query_tx_response( + rpc_client: &HttpClient, + rpc_address: &Url, + tx_hash: &TxHash, +) -> Result { + let response = rpc_client + .tx_search( + tx_hash_query(&QueryTxHash(*tx_hash)), + false, + 1, + 1, // get only the first Tx matching the query + Order::Ascending, + ) + .await + .map_err(|e| Error::rpc(rpc_address.clone(), e))?; + + Ok(response) +} + +pub fn all_ibc_events_from_tx_search_response( + chain_id: &ChainId, + response: ResultTx, +) -> Vec { let height = ICSHeight::new(chain_id.version(), u64::from(response.height)); let deliver_tx_result = response.tx_result; if deliver_tx_result.code.is_err() { diff --git a/relayer/src/chain/cosmos/wait.rs b/relayer/src/chain/cosmos/wait.rs index 953395fef2..45459104b1 100644 --- a/relayer/src/chain/cosmos/wait.rs +++ b/relayer/src/chain/cosmos/wait.rs @@ -1,20 +1,20 @@ use core::time::Duration; use ibc::core::ics24_host::identifier::ChainId; use ibc::events::IbcEvent; -use ibc::query::{QueryTxHash, QueryTxRequest}; -use itertools::Itertools; -use std::thread; use std::time::Instant; +use tendermint::abci::transaction::Hash as TxHash; +use tendermint_rpc::endpoint::tx_search::Response as TxSearchResponse; use tendermint_rpc::{HttpClient, Url}; -use tracing::{info, trace}; +use tokio::task; +use tokio::time::sleep; +use tracing::info; -use crate::chain::cosmos::query::tx::query_txs; -use crate::chain::cosmos::types::tx::TxSyncResult; +use crate::chain::cosmos::query::tx::{all_ibc_events_from_tx_search_response, query_tx_response}; use crate::error::Error; const WAIT_BACKOFF: Duration = Duration::from_millis(300); -/// Given a vector of `TxSyncResult` elements, +/// Given a vector of `TxHash` elements, /// each including a transaction response hash for one or more messages, periodically queries the chain /// with the transaction hashes to get the list of IbcEvents included in those transactions. pub async fn wait_for_block_commits( @@ -22,93 +22,96 @@ pub async fn wait_for_block_commits( rpc_client: &HttpClient, rpc_address: &Url, rpc_timeout: &Duration, - tx_sync_results: &mut [TxSyncResult], -) -> Result<(), Error> { - let start_time = Instant::now(); - - let hashes = tx_sync_results - .iter() - .map(|res| res.response.hash.to_string()) - .join(", "); - + tx_hashes: &[TxHash], +) -> Result, Error> { info!( id = %chain_id, - "wait_for_block_commits: waiting for commit of tx hashes(s) {}", - hashes + "wait_for_block_commits: waiting for commit of tx hashes(s) {:?}", + tx_hashes ); - loop { - let elapsed = start_time.elapsed(); - - if all_tx_results_found(tx_sync_results) { - trace!( - id = %chain_id, - "wait_for_block_commits: retrieved {} tx results after {}ms", - tx_sync_results.len(), - elapsed.as_millis(), - ); - - return Ok(()); - } else if &elapsed > rpc_timeout { - return Err(Error::tx_no_confirmation()); - } else { - thread::sleep(WAIT_BACKOFF); + let responses = wait_tx_hashes(rpc_client, rpc_address, rpc_timeout, tx_hashes).await?; - for tx_sync_result in tx_sync_results.iter_mut() { - // ignore error - let _ = - update_tx_sync_result(chain_id, rpc_client, rpc_address, tx_sync_result).await; - } + let mut all_events = Vec::new(); + + for response in responses.into_iter() { + for tx_response in response.txs.into_iter() { + let mut events = all_ibc_events_from_tx_search_response(chain_id, tx_response); + all_events.append(&mut events); } } + + Ok(all_events) } -async fn update_tx_sync_result( - chain_id: &ChainId, +pub async fn wait_tx_hashes( rpc_client: &HttpClient, rpc_address: &Url, - tx_sync_result: &mut TxSyncResult, + timeout: &Duration, + tx_hashes: &[TxHash], +) -> Result, Error> { + let mut join_handles = Vec::new(); + + for tx_hash in tx_hashes.iter() { + let rpc_client = rpc_client.clone(); + let rpc_address = rpc_address.clone(); + let timeout = *timeout; + let tx_hash = *tx_hash; + + let handle = task::spawn(async move { + wait_tx_hash(&rpc_client, &rpc_address, &timeout, &tx_hash).await + }); + join_handles.push(handle); + } + + let mut responses = Vec::new(); + + for handle in join_handles.into_iter() { + let response = handle.await.map_err(Error::join)??; + responses.push(response); + } + + Ok(responses) +} + +pub async fn wait_tx_succeed( + rpc_client: &HttpClient, + rpc_address: &Url, + timeout: &Duration, + tx_hash: &TxHash, ) -> Result<(), Error> { - let TxSyncResult { response, events } = tx_sync_result; - - // If this transaction was not committed, determine whether it was because it failed - // or because it hasn't been committed yet. - if empty_event_present(events) { - // If the transaction failed, replace the events with an error, - // so that we don't attempt to resolve the transaction later on. - if response.code.value() != 0 { - *events = vec![IbcEvent::ChainError(format!( - "deliver_tx on chain {} for Tx hash {} reports error: code={:?}, log={:?}", - chain_id, response.hash, response.code, response.log - ))]; - } + let response = wait_tx_hash(rpc_client, rpc_address, timeout, tx_hash).await?; - // Otherwise, try to resolve transaction hash to the corresponding events. - let events_per_tx = query_txs( - chain_id, - rpc_client, - rpc_address, - QueryTxRequest::Transaction(QueryTxHash(response.hash)), - ) - .await?; - - // If we get events back, progress was made, so we replace the events - // with the new ones. in both cases we will check in the next iteration - // whether or not the transaction was fully committed. - if !events_per_tx.is_empty() { - *events = events_per_tx; + for response in response.txs { + let response_code = response.tx_result.code; + if response_code.is_err() { + return Err(Error::rpc_response(format!("{}", response_code.value()))); } } Ok(()) } -fn empty_event_present(events: &[IbcEvent]) -> bool { - events.iter().any(|ev| matches!(ev, IbcEvent::Empty(_))) -} +pub async fn wait_tx_hash( + rpc_client: &HttpClient, + rpc_address: &Url, + timeout: &Duration, + tx_hash: &TxHash, +) -> Result { + let start_time = Instant::now(); -fn all_tx_results_found(tx_sync_results: &[TxSyncResult]) -> bool { - tx_sync_results - .iter() - .all(|r| !empty_event_present(&r.events)) + loop { + let responses = query_tx_response(rpc_client, rpc_address, tx_hash).await?; + + if responses.txs.is_empty() { + let elapsed = start_time.elapsed(); + if &elapsed > timeout { + return Err(Error::tx_no_confirmation()); + } else { + sleep(WAIT_BACKOFF).await; + } + } else { + return Ok(responses); + } + } } diff --git a/relayer/src/error.rs b/relayer/src/error.rs index 61e1e53b0a..9e48a2d77d 100644 --- a/relayer/src/error.rs +++ b/relayer/src/error.rs @@ -2,7 +2,7 @@ use core::time::Duration; -use flex_error::{define_error, DisplayOnly, TraceClone, TraceError}; +use flex_error::{define_error, DisplayOnly, TraceError}; use http::uri::InvalidUri; use humantime::format_duration; use prost::{DecodeError, EncodeError}; @@ -15,6 +15,7 @@ use tendermint_proto::Error as TendermintProtoError; use tendermint_rpc::endpoint::abci_query::AbciQuery; use tendermint_rpc::endpoint::broadcast::tx_commit::TxResult; use tendermint_rpc::Error as TendermintRpcError; +use tokio::task::JoinError; use tonic::{ metadata::errors::InvalidMetadataValue, transport::Error as TransportError, Status as GrpcStatus, @@ -46,7 +47,7 @@ define_error! { Rpc { url: tendermint_rpc::Url } - [ TraceClone ] + [ TendermintRpcError ] |e| { format!("RPC error to endpoint {}", e.url) }, AbciQuery @@ -91,7 +92,7 @@ define_error! { |e| { format!("missing parameter in GRPC response: {}", e.param) }, Decode - [ TraceError ] + [ TendermintProtoError ] |_| { "error decoding protobuf" }, LightClientVerification @@ -122,7 +123,7 @@ define_error! { |_| { "bad notification" }, ConversionFromAny - [ TraceError ] + [ TendermintProtoError ] |_| { "conversion from a protobuf `Any` into a domain type failed" }, EmptyUpgradedClientState @@ -141,6 +142,10 @@ define_error! { EmptyResponseProof |_| { "empty response proof" }, + RpcResponse + { detail: String } + | e | { format!("RPC client returns error response: {}", e.detail) }, + MalformedProof [ ProofError ] |_| { "malformed proof" }, @@ -500,6 +505,10 @@ define_error! { e.chain_id ) }, + + Join + [ TraceError ] + | _ | { "error joining tokio tasks" }, } } diff --git a/tools/test-framework/src/relayer/tx.rs b/tools/test-framework/src/relayer/tx.rs index 18be12730d..253c3c7f46 100644 --- a/tools/test-framework/src/relayer/tx.rs +++ b/tools/test-framework/src/relayer/tx.rs @@ -3,7 +3,6 @@ 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; @@ -11,8 +10,7 @@ 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::chain::cosmos::wait::wait_tx_succeed; use ibc_relayer::config::GasPrice; use ibc_relayer::keyring::KeyEntry; use tendermint_rpc::{HttpClient, Url}; @@ -93,37 +91,21 @@ pub async fn simple_send_tx( .await? .into(); - let message_count = messages.len(); - let response = estimate_fee_and_send_tx(config, key_entry, &account, &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]; + if response.code.is_err() { + return Err(eyre!("send_tx returns error response: {:?}", response).into()); + } - wait_for_block_commits( - &config.chain_id, + wait_tx_succeed( &config.rpc_client, &config.rpc_address, &config.rpc_timeout, - &mut tx_sync_results, + &response.hash, ) .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(()) } From 362b5b710ca6940af327cec7b46898038cfe9f88 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Fri, 20 May 2022 15:44:57 +0200 Subject: [PATCH 019/113] Add fee methods to ChainDriver --- tools/integration-test/src/tests/fee.rs | 55 +++++++++++----------- tools/test-framework/src/chain/tagged.rs | 58 ++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 29 deletions(-) diff --git a/tools/integration-test/src/tests/fee.rs b/tools/integration-test/src/tests/fee.rs index f7d2f86324..3aed733c50 100644 --- a/tools/integration-test/src/tests/fee.rs +++ b/tools/integration-test/src/tests/fee.rs @@ -1,8 +1,5 @@ use ibc::core::ics04_channel::Version; use ibc_test_framework::prelude::*; -use ibc_test_framework::relayer::fee::{ - ibc_token_transfer_with_fee, register_counterparty_address, -}; #[test] fn test_channel_with_fee() -> Result<(), Error> { @@ -11,7 +8,17 @@ fn test_channel_with_fee() -> Result<(), Error> { pub struct ChannelWithFeeTest; -impl TestOverrides for ChannelWithFeeTest { +pub struct FeeOverrides; + +impl HasOverrides for ChannelWithFeeTest { + type Overrides = FeeOverrides; + + fn get_overrides(&self) -> &Self::Overrides { + &FeeOverrides + } +} + +impl TestOverrides for FeeOverrides { fn should_spawn_supervisor(&self) -> bool { false } @@ -36,8 +43,6 @@ impl BinaryChannelTest for ChannelWithFeeTest { let chain_id_b = chain_driver_b.chain_id(); let denom_a = chains.node_a.denom(); - let tx_config_a = chain_driver_a.tx_config(); - let tx_config_b = chain_driver_b.tx_config(); let port_a = channel.port_a.as_ref(); let channel_id_a = channel.channel_id_a.as_ref(); @@ -58,15 +63,11 @@ impl BinaryChannelTest for ChannelWithFeeTest { chain_id_a ); - chain_driver_b - .value() - .runtime - .block_on(register_counterparty_address( - &tx_config_b, - &relayer_b, - &relayer_a.address(), - &channel_id_b, - ))?; + chain_driver_b.register_counterparty_address( + &relayer_b, + &relayer_a.address(), + &channel_id_b, + )?; relayer.with_supervisor(move || { let user_a = wallets_a.user1(); @@ -86,20 +87,16 @@ impl BinaryChannelTest for ChannelWithFeeTest { let balance_a2 = balance_a1 - total_sent; - chain_driver_a - .value() - .runtime - .block_on(ibc_token_transfer_with_fee( - &tx_config_a, - &port_a, - &channel_id_a, - &user_a, - &user_b.address(), - &denom_a.with_amount(send_amount).as_ref(), - &denom_a.with_amount(receive_fee).as_ref(), - &denom_a.with_amount(ack_fee).as_ref(), - &denom_a.with_amount(timeout_fee).as_ref(), - ))?; + chain_driver_a.ibc_token_transfer_with_fee( + &port_a, + &channel_id_a, + &user_a, + &user_b.address(), + &denom_a.with_amount(send_amount).as_ref(), + &denom_a.with_amount(receive_fee).as_ref(), + &denom_a.with_amount(ack_fee).as_ref(), + &denom_a.with_amount(timeout_fee).as_ref(), + )?; let denom_b = derive_ibc_denom( &channel.port_b.as_ref(), diff --git a/tools/test-framework/src/chain/tagged.rs b/tools/test-framework/src/chain/tagged.rs index fe7f8b9279..d2cce702f6 100644 --- a/tools/test-framework/src/chain/tagged.rs +++ b/tools/test-framework/src/chain/tagged.rs @@ -17,6 +17,7 @@ use crate::error::Error; use crate::ibc::denom::Denom; use crate::ibc::token::{TaggedDenomExt, TaggedToken, TaggedTokenRef}; use crate::prelude::TaggedConnectionIdRef; +use crate::relayer::fee::{ibc_token_transfer_with_fee, register_counterparty_address}; use crate::relayer::transfer::ibc_token_transfer; use crate::types::id::{TaggedChainIdRef, TaggedChannelIdRef, TaggedPortIdRef}; use crate::types::tagged::*; @@ -100,6 +101,18 @@ pub trait TaggedChainDriverExt { token: &TaggedTokenRef, ) -> Result<(), Error>; + fn ibc_token_transfer_with_fee( + &self, + port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, + channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, + sender: &MonoTagged, + recipient: &MonoTagged, + send_amount: &TaggedTokenRef<'_, Chain>, + receive_fee: &TaggedTokenRef<'_, Chain>, + ack_fee: &TaggedTokenRef<'_, Chain>, + timeout_fee: &TaggedTokenRef<'_, Chain>, + ) -> Result<(), Error>; + /** Taggged version of [`query_recipient_transactions`]. @@ -111,6 +124,13 @@ pub trait TaggedChainDriverExt { recipient_address: &MonoTagged, ) -> Result; + fn register_counterparty_address( + &self, + wallet: &MonoTagged, + counterparty_address: &MonoTagged, + channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, + ) -> Result<(), Error>; + fn register_interchain_account( &self, from: &MonoTagged, @@ -200,6 +220,30 @@ impl<'a, Chain: Send> TaggedChainDriverExt for MonoTagged( + &self, + port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, + channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, + sender: &MonoTagged, + recipient: &MonoTagged, + send_amount: &TaggedTokenRef<'_, Chain>, + receive_fee: &TaggedTokenRef<'_, Chain>, + ack_fee: &TaggedTokenRef<'_, Chain>, + timeout_fee: &TaggedTokenRef<'_, Chain>, + ) -> Result<(), Error> { + self.value().runtime.block_on(ibc_token_transfer_with_fee( + &self.tx_config(), + port_id, + channel_id, + sender, + recipient, + send_amount, + receive_fee, + ack_fee, + timeout_fee, + )) + } + fn query_recipient_transactions( &self, recipient_address: &MonoTagged, @@ -207,6 +251,20 @@ impl<'a, Chain: Send> TaggedChainDriverExt for MonoTagged( + &self, + wallet: &MonoTagged, + counterparty_address: &MonoTagged, + channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, + ) -> Result<(), Error> { + self.value().runtime.block_on(register_counterparty_address( + &self.tx_config(), + wallet, + counterparty_address, + channel_id, + )) + } + fn register_interchain_account( &self, from: &MonoTagged, From 898a0995cc1826195c558bc0462e434c6bbdb628 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Fri, 20 May 2022 15:52:46 +0200 Subject: [PATCH 020/113] Add back test with no forward relayer setup --- tools/integration-test/src/tests/fee.rs | 269 ++++++++++++++++-------- 1 file changed, 185 insertions(+), 84 deletions(-) diff --git a/tools/integration-test/src/tests/fee.rs b/tools/integration-test/src/tests/fee.rs index 3aed733c50..61c189387b 100644 --- a/tools/integration-test/src/tests/fee.rs +++ b/tools/integration-test/src/tests/fee.rs @@ -1,16 +1,23 @@ use ibc::core::ics04_channel::Version; use ibc_test_framework::prelude::*; +use ibc_test_framework::util::random::random_u128_range; #[test] -fn test_channel_with_fee() -> Result<(), Error> { - run_binary_channel_test(&ChannelWithFeeTest) +fn test_no_forward_relayer() -> Result<(), Error> { + run_binary_channel_test(&NoForwardRelayerTest) } -pub struct ChannelWithFeeTest; +#[test] +fn test_forward_relayer() -> Result<(), Error> { + run_binary_channel_test(&ForwardRelayerTest) +} + +struct ForwardRelayerTest; +struct NoForwardRelayerTest; -pub struct FeeOverrides; +struct FeeOverrides; -impl HasOverrides for ChannelWithFeeTest { +impl HasOverrides for ForwardRelayerTest { type Overrides = FeeOverrides; fn get_overrides(&self) -> &Self::Overrides { @@ -18,21 +25,119 @@ impl HasOverrides for ChannelWithFeeTest { } } -impl TestOverrides for FeeOverrides { - fn should_spawn_supervisor(&self) -> bool { - false +impl HasOverrides for NoForwardRelayerTest { + type Overrides = FeeOverrides; + + fn get_overrides(&self) -> &Self::Overrides { + &FeeOverrides } +} +impl TestOverrides for FeeOverrides { fn channel_version(&self) -> Version { Version::ics20_with_fee() } } -impl BinaryChannelTest for ChannelWithFeeTest { +impl BinaryChannelTest for NoForwardRelayerTest { + fn run( + &self, + _config: &TestConfig, + _relayer: RelayerDriver, + chains: ConnectedChains, + channel: ConnectedChannel, + ) -> Result<(), Error> { + let chain_driver_a = chains.node_a.chain_driver(); + let chain_driver_b = chains.node_b.chain_driver(); + + let denom_a = chains.node_a.denom(); + + let port_a = channel.port_a.as_ref(); + let channel_id_a = channel.channel_id_a.as_ref(); + + let wallets_a = chains.node_a.wallets(); + let wallets_b = chains.node_b.wallets(); + + let relayer_a = wallets_a.relayer(); + + let user_a = wallets_a.user1(); + let user_b = wallets_b.user1(); + + let balance_a1 = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; + + let relayer_balance_a = chain_driver_a.query_balance(&relayer_a.address(), &denom_a)?; + + let send_amount = random_u128_range(1000, 2000); + let receive_fee = random_u128_range(300, 400); + let ack_fee = random_u128_range(200, 300); + let timeout_fee = random_u128_range(100, 200); + + let total_sent = send_amount + receive_fee + ack_fee + timeout_fee; + + let balance_a2 = balance_a1 - total_sent; + + chain_driver_a.ibc_token_transfer_with_fee( + &port_a, + &channel_id_a, + &user_a, + &user_b.address(), + &denom_a.with_amount(send_amount).as_ref(), + &denom_a.with_amount(receive_fee).as_ref(), + &denom_a.with_amount(ack_fee).as_ref(), + &denom_a.with_amount(timeout_fee).as_ref(), + )?; + + let denom_b = derive_ibc_denom( + &channel.port_b.as_ref(), + &channel.channel_id_b.as_ref(), + &denom_a, + )?; + + info!("Expect user A's balance after transfer: {}", balance_a2); + + chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a2.as_ref())?; + + chain_driver_b.assert_eventual_wallet_amount( + &user_b.address(), + &denom_b.with_amount(send_amount).as_ref(), + )?; + + info!( + "Expect user to be refunded receive fee {} and timeout fee {} and go from {} to {}", + receive_fee, + timeout_fee, + balance_a2, + balance_a2.amount() + receive_fee + timeout_fee + ); + + // receive fee and timeout fee should be refunded, + // as there is no counterparty address registered. + chain_driver_a.assert_eventual_wallet_amount( + &user_a.address(), + &(balance_a2 + receive_fee + timeout_fee).as_ref(), + )?; + + info!( + "Expect relayer to receive ack fee {} and go from {} to {}", + ack_fee, + relayer_balance_a, + relayer_balance_a.amount() + ack_fee, + ); + + chain_driver_a.assert_eventual_wallet_amount( + &relayer_a.address(), + &(relayer_balance_a + ack_fee).as_ref(), + )?; + + Ok(()) + } +} + +impl BinaryChannelTest for ForwardRelayerTest { fn run( &self, _config: &TestConfig, - relayer: RelayerDriver, + _relayer: RelayerDriver, chains: ConnectedChains, channel: ConnectedChannel, ) -> Result<(), Error> { @@ -69,79 +174,75 @@ impl BinaryChannelTest for ChannelWithFeeTest { &channel_id_b, )?; - relayer.with_supervisor(move || { - let user_a = wallets_a.user1(); - let user_b = wallets_b.user1(); - - let balance_a1 = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; - - let relayer_balance_a = chain_driver_a.query_balance(&relayer_a.address(), &denom_a)?; - - let send_amount = 1000; - - let receive_fee = 300; - let ack_fee = 200; - let timeout_fee = 100; - - let total_sent = send_amount + receive_fee + ack_fee + timeout_fee; - - let balance_a2 = balance_a1 - total_sent; - - chain_driver_a.ibc_token_transfer_with_fee( - &port_a, - &channel_id_a, - &user_a, - &user_b.address(), - &denom_a.with_amount(send_amount).as_ref(), - &denom_a.with_amount(receive_fee).as_ref(), - &denom_a.with_amount(ack_fee).as_ref(), - &denom_a.with_amount(timeout_fee).as_ref(), - )?; - - let denom_b = derive_ibc_denom( - &channel.port_b.as_ref(), - &channel.channel_id_b.as_ref(), - &denom_a, - )?; - - info!("Expect user A's balance after transfer: {}", balance_a2); - - chain_driver_a - .assert_eventual_wallet_amount(&user_a.address(), &balance_a2.as_ref())?; - - chain_driver_b.assert_eventual_wallet_amount( - &user_b.address(), - &denom_b.with_amount(send_amount).as_ref(), - )?; - - info!( - "Expect user to be refunded receive timeout fee {} and go from {} to {}", - timeout_fee, - balance_a2, - balance_a2.amount() + timeout_fee + ack_fee - ); - - // receive fee and timeout fee should be refunded, - // as there is no counterparty address registered. - chain_driver_a.assert_eventual_wallet_amount( - &user_a.address(), - &(balance_a2 + timeout_fee).as_ref(), - )?; - - info!( - "Expect relayer to receive ack fee {} and receive fee {} and go from {} to {}", - ack_fee, - receive_fee, - relayer_balance_a, - relayer_balance_a.amount() + ack_fee + receive_fee, - ); - - chain_driver_a.assert_eventual_wallet_amount( - &relayer_a.address(), - &(relayer_balance_a + ack_fee + receive_fee).as_ref(), - )?; - - Ok(()) - }) + let user_a = wallets_a.user1(); + let user_b = wallets_b.user1(); + + let balance_a1 = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; + + let relayer_balance_a = chain_driver_a.query_balance(&relayer_a.address(), &denom_a)?; + + let send_amount = random_u128_range(1000, 2000); + let receive_fee = random_u128_range(300, 400); + let ack_fee = random_u128_range(200, 300); + let timeout_fee = random_u128_range(100, 200); + + let total_sent = send_amount + receive_fee + ack_fee + timeout_fee; + + let balance_a2 = balance_a1 - total_sent; + + chain_driver_a.ibc_token_transfer_with_fee( + &port_a, + &channel_id_a, + &user_a, + &user_b.address(), + &denom_a.with_amount(send_amount).as_ref(), + &denom_a.with_amount(receive_fee).as_ref(), + &denom_a.with_amount(ack_fee).as_ref(), + &denom_a.with_amount(timeout_fee).as_ref(), + )?; + + let denom_b = derive_ibc_denom( + &channel.port_b.as_ref(), + &channel.channel_id_b.as_ref(), + &denom_a, + )?; + + info!("Expect user A's balance after transfer: {}", balance_a2); + + chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a2.as_ref())?; + + chain_driver_b.assert_eventual_wallet_amount( + &user_b.address(), + &denom_b.with_amount(send_amount).as_ref(), + )?; + + info!( + "Expect user to be refunded receive timeout fee {} and go from {} to {}", + timeout_fee, + balance_a2, + balance_a2.amount() + timeout_fee + ack_fee + ); + + // receive fee and timeout fee should be refunded, + // as there is no counterparty address registered. + chain_driver_a.assert_eventual_wallet_amount( + &user_a.address(), + &(balance_a2 + timeout_fee).as_ref(), + )?; + + info!( + "Expect relayer to receive ack fee {} and receive fee {} and go from {} to {}", + ack_fee, + receive_fee, + relayer_balance_a, + relayer_balance_a.amount() + ack_fee + receive_fee, + ); + + chain_driver_a.assert_eventual_wallet_amount( + &relayer_a.address(), + &(relayer_balance_a + ack_fee + receive_fee).as_ref(), + )?; + + Ok(()) } } From da61d1f07362e3e2f05af0ea90c85b1a0e00f30f Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Fri, 20 May 2022 16:12:47 +0200 Subject: [PATCH 021/113] Add timeout fee test --- tools/integration-test/src/tests/fee.rs | 123 ++++++++++++++++--- tools/test-framework/src/chain/tagged.rs | 4 + tools/test-framework/src/relayer/fee.rs | 4 +- tools/test-framework/src/relayer/transfer.rs | 12 +- 4 files changed, 125 insertions(+), 18 deletions(-) diff --git a/tools/integration-test/src/tests/fee.rs b/tools/integration-test/src/tests/fee.rs index 61c189387b..ccab087357 100644 --- a/tools/integration-test/src/tests/fee.rs +++ b/tools/integration-test/src/tests/fee.rs @@ -1,6 +1,7 @@ use ibc::core::ics04_channel::Version; use ibc_test_framework::prelude::*; use ibc_test_framework::util::random::random_u128_range; +use std::thread; #[test] fn test_no_forward_relayer() -> Result<(), Error> { @@ -12,28 +13,32 @@ fn test_forward_relayer() -> Result<(), Error> { run_binary_channel_test(&ForwardRelayerTest) } +#[test] +fn test_timeout_fee() -> Result<(), Error> { + run_binary_channel_test(&TimeoutFeeTest) +} + struct ForwardRelayerTest; struct NoForwardRelayerTest; +struct TimeoutFeeTest; -struct FeeOverrides; - -impl HasOverrides for ForwardRelayerTest { - type Overrides = FeeOverrides; - - fn get_overrides(&self) -> &Self::Overrides { - &FeeOverrides +impl TestOverrides for ForwardRelayerTest { + fn channel_version(&self) -> Version { + Version::ics20_with_fee() } } -impl HasOverrides for NoForwardRelayerTest { - type Overrides = FeeOverrides; - - fn get_overrides(&self) -> &Self::Overrides { - &FeeOverrides +impl TestOverrides for NoForwardRelayerTest { + fn channel_version(&self) -> Version { + Version::ics20_with_fee() } } -impl TestOverrides for FeeOverrides { +impl TestOverrides for TimeoutFeeTest { + fn should_spawn_supervisor(&self) -> bool { + false + } + fn channel_version(&self) -> Version { Version::ics20_with_fee() } @@ -85,6 +90,7 @@ impl BinaryChannelTest for NoForwardRelayerTest { &denom_a.with_amount(receive_fee).as_ref(), &denom_a.with_amount(ack_fee).as_ref(), &denom_a.with_amount(timeout_fee).as_ref(), + Duration::from_secs(60), )?; let denom_b = derive_ibc_denom( @@ -199,6 +205,7 @@ impl BinaryChannelTest for ForwardRelayerTest { &denom_a.with_amount(receive_fee).as_ref(), &denom_a.with_amount(ack_fee).as_ref(), &denom_a.with_amount(timeout_fee).as_ref(), + Duration::from_secs(60), )?; let denom_b = derive_ibc_denom( @@ -223,8 +230,6 @@ impl BinaryChannelTest for ForwardRelayerTest { balance_a2.amount() + timeout_fee + ack_fee ); - // receive fee and timeout fee should be refunded, - // as there is no counterparty address registered. chain_driver_a.assert_eventual_wallet_amount( &user_a.address(), &(balance_a2 + timeout_fee).as_ref(), @@ -246,3 +251,91 @@ impl BinaryChannelTest for ForwardRelayerTest { Ok(()) } } + +impl BinaryChannelTest for TimeoutFeeTest { + fn run( + &self, + _config: &TestConfig, + relayer: RelayerDriver, + chains: ConnectedChains, + channel: ConnectedChannel, + ) -> Result<(), Error> { + let chain_driver_a = chains.node_a.chain_driver(); + let chain_driver_b = chains.node_b.chain_driver(); + + let denom_a = chains.node_a.denom(); + + let port_a = channel.port_a.as_ref(); + let channel_id_a = channel.channel_id_a.as_ref(); + + let wallets_a = chains.node_a.wallets(); + let wallets_b = chains.node_b.wallets(); + + let relayer_a = wallets_a.relayer(); + + let user_a = wallets_a.user1(); + let user_b = wallets_b.user1(); + + let balance_a1 = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; + + let relayer_balance_a = chain_driver_a.query_balance(&relayer_a.address(), &denom_a)?; + + let send_amount = random_u128_range(1000, 2000); + let receive_fee = random_u128_range(300, 400); + let ack_fee = random_u128_range(200, 300); + let timeout_fee = random_u128_range(100, 200); + + let total_sent = send_amount + receive_fee + ack_fee + timeout_fee; + + let balance_a2 = balance_a1 - total_sent; + + chain_driver_a.ibc_token_transfer_with_fee( + &port_a, + &channel_id_a, + &user_a, + &user_b.address(), + &denom_a.with_amount(send_amount).as_ref(), + &denom_a.with_amount(receive_fee).as_ref(), + &denom_a.with_amount(ack_fee).as_ref(), + &denom_a.with_amount(timeout_fee).as_ref(), + Duration::from_secs(5), + )?; + + info!("Expect user A's balance after transfer: {}", balance_a2); + + chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a2.as_ref())?; + + // Sleep to wait for IBC packet to timeout before start relaying + thread::sleep(Duration::from_secs(6)); + + relayer.with_supervisor(|| { + info!( + "Expect user to be refunded send amount {}, receive fee {} and ack fee {} and go from {} to {}", + send_amount, + receive_fee, + ack_fee, + balance_a2, + balance_a2.amount() + send_amount + receive_fee + ack_fee + ); + + chain_driver_a.assert_eventual_wallet_amount( + &user_a.address(), + &(balance_a2 + send_amount + receive_fee + ack_fee).as_ref(), + )?; + + info!( + "Expect relayer to receive timeout fee {} and go from {} to {}", + timeout_fee, + relayer_balance_a, + relayer_balance_a.amount() + timeout_fee, + ); + + chain_driver_a.assert_eventual_wallet_amount( + &relayer_a.address(), + &(relayer_balance_a + timeout_fee).as_ref(), + )?; + + Ok(()) + }) + } +} diff --git a/tools/test-framework/src/chain/tagged.rs b/tools/test-framework/src/chain/tagged.rs index d2cce702f6..8e713ed902 100644 --- a/tools/test-framework/src/chain/tagged.rs +++ b/tools/test-framework/src/chain/tagged.rs @@ -2,6 +2,7 @@ Methods for tagged version of the chain driver. */ +use core::time::Duration; use ibc_proto::google::protobuf::Any; use ibc_relayer::chain::cosmos::types::config::TxConfig; use serde::Serialize; @@ -111,6 +112,7 @@ pub trait TaggedChainDriverExt { receive_fee: &TaggedTokenRef<'_, Chain>, ack_fee: &TaggedTokenRef<'_, Chain>, timeout_fee: &TaggedTokenRef<'_, Chain>, + timeout: Duration, ) -> Result<(), Error>; /** @@ -230,6 +232,7 @@ impl<'a, Chain: Send> TaggedChainDriverExt for MonoTagged, ack_fee: &TaggedTokenRef<'_, Chain>, timeout_fee: &TaggedTokenRef<'_, Chain>, + timeout: Duration, ) -> Result<(), Error> { self.value().runtime.block_on(ibc_token_transfer_with_fee( &self.tx_config(), @@ -241,6 +244,7 @@ impl<'a, Chain: Send> TaggedChainDriverExt for MonoTagged( receive_fee: &TaggedTokenRef<'_, SrcChain>, ack_fee: &TaggedTokenRef<'_, SrcChain>, timeout_fee: &TaggedTokenRef<'_, SrcChain>, + timeout: Duration, ) -> Result<(), Error> { let transfer_message = - build_transfer_message(port_id, channel_id, sender, recipient, send_amount)?; + build_transfer_message(port_id, channel_id, sender, recipient, send_amount, timeout)?; let pay_message = build_pay_packet_message( port_id, diff --git a/tools/test-framework/src/relayer/transfer.rs b/tools/test-framework/src/relayer/transfer.rs index 4e5c1cea8a..8e7dfc44cb 100644 --- a/tools/test-framework/src/relayer/transfer.rs +++ b/tools/test-framework/src/relayer/transfer.rs @@ -25,9 +25,10 @@ pub fn build_transfer_message( sender: &MonoTagged, recipient: &MonoTagged, token: &TaggedTokenRef<'_, SrcChain>, + timeout: Duration, ) -> Result { let timeout_timestamp = Timestamp::now() - .add(Duration::from_secs(60)) + .add(timeout) .map_err(handle_generic_error)?; Ok(raw_build_transfer_message( @@ -67,7 +68,14 @@ pub async fn ibc_token_transfer( recipient: &MonoTagged, token: &TaggedTokenRef<'_, SrcChain>, ) -> Result<(), Error> { - let message = build_transfer_message(port_id, channel_id, sender, recipient, token)?; + let message = build_transfer_message( + port_id, + channel_id, + sender, + recipient, + token, + Duration::from_secs(60), + )?; simple_send_tx(tx_config.value(), &sender.value().key, vec![message]).await?; From 87f98da8d5c515e174a2431239ee529d511fc2f0 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Mon, 23 May 2022 09:54:01 +0200 Subject: [PATCH 022/113] Simplify wait control flow using iterator and streams --- relayer/src/chain/cosmos/wait.rs | 48 +++++++++++++------------------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/relayer/src/chain/cosmos/wait.rs b/relayer/src/chain/cosmos/wait.rs index 45459104b1..21a76742d0 100644 --- a/relayer/src/chain/cosmos/wait.rs +++ b/relayer/src/chain/cosmos/wait.rs @@ -1,11 +1,11 @@ use core::time::Duration; +use futures::stream::{FuturesOrdered, StreamExt}; use ibc::core::ics24_host::identifier::ChainId; use ibc::events::IbcEvent; use std::time::Instant; use tendermint::abci::transaction::Hash as TxHash; use tendermint_rpc::endpoint::tx_search::Response as TxSearchResponse; use tendermint_rpc::{HttpClient, Url}; -use tokio::task; use tokio::time::sleep; use tracing::info; @@ -32,14 +32,14 @@ pub async fn wait_for_block_commits( let responses = wait_tx_hashes(rpc_client, rpc_address, rpc_timeout, tx_hashes).await?; - let mut all_events = Vec::new(); - - for response in responses.into_iter() { - for tx_response in response.txs.into_iter() { - let mut events = all_ibc_events_from_tx_search_response(chain_id, tx_response); - all_events.append(&mut events); - } - } + let all_events = responses + .into_iter() + .flat_map(|response| { + response.txs.into_iter().flat_map(|tx_response| { + all_ibc_events_from_tx_search_response(chain_id, tx_response) + }) + }) + .collect(); Ok(all_events) } @@ -50,26 +50,16 @@ pub async fn wait_tx_hashes( timeout: &Duration, tx_hashes: &[TxHash], ) -> Result, Error> { - let mut join_handles = Vec::new(); - - for tx_hash in tx_hashes.iter() { - let rpc_client = rpc_client.clone(); - let rpc_address = rpc_address.clone(); - let timeout = *timeout; - let tx_hash = *tx_hash; - - let handle = task::spawn(async move { - wait_tx_hash(&rpc_client, &rpc_address, &timeout, &tx_hash).await - }); - join_handles.push(handle); - } - - let mut responses = Vec::new(); - - for handle in join_handles.into_iter() { - let response = handle.await.map_err(Error::join)??; - responses.push(response); - } + let tasks = tx_hashes + .iter() + .map(|tx_hash| async { wait_tx_hash(rpc_client, rpc_address, timeout, tx_hash).await }) + .collect::>(); + + let responses = tasks + .collect::>() + .await + .into_iter() + .collect::, _>>()?; Ok(responses) } From 9696cbee9039b14ed528af1c3e56ccc7883ac791 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Mon, 23 May 2022 10:51:59 +0200 Subject: [PATCH 023/113] Implement pay packet fee async --- tools/integration-test/src/tests/fee.rs | 1 - tools/test-framework/src/relayer/fee.rs | 87 ++++++++++++++++++++++++- 2 files changed, 85 insertions(+), 3 deletions(-) diff --git a/tools/integration-test/src/tests/fee.rs b/tools/integration-test/src/tests/fee.rs index ccab087357..a18df3ad97 100644 --- a/tools/integration-test/src/tests/fee.rs +++ b/tools/integration-test/src/tests/fee.rs @@ -261,7 +261,6 @@ impl BinaryChannelTest for TimeoutFeeTest { channel: ConnectedChannel, ) -> Result<(), Error> { let chain_driver_a = chains.node_a.chain_driver(); - let chain_driver_b = chains.node_b.chain_driver(); let denom_a = chains.node_a.denom(); diff --git a/tools/test-framework/src/relayer/fee.rs b/tools/test-framework/src/relayer/fee.rs index 026026fe98..b2e7ded622 100644 --- a/tools/test-framework/src/relayer/fee.rs +++ b/tools/test-framework/src/relayer/fee.rs @@ -1,7 +1,12 @@ use core::time::Duration; +use ibc::core::ics04_channel::packet::Sequence; use ibc_proto::cosmos::base::v1beta1::Coin; use ibc_proto::google::protobuf::Any; -use ibc_proto::ibc::applications::fee::v1::{Fee, MsgPayPacketFee, MsgRegisterCounterpartyAddress}; +use ibc_proto::ibc::core::channel::v1::PacketId; +use ibc_proto::ibc::applications::fee::v1::{ + Fee, PacketFee, MsgPayPacketFee, + MsgPayPacketFeeAsync, MsgRegisterCounterpartyAddress +}; use ibc_relayer::chain::cosmos::types::config::TxConfig; use prost::{EncodeError, Message}; @@ -10,7 +15,7 @@ use crate::ibc::token::TaggedTokenRef; use crate::relayer::transfer::build_transfer_message; use crate::relayer::tx::simple_send_tx; use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef}; -use crate::types::tagged::MonoTagged; +use crate::types::tagged::{MonoTagged, DualTagged}; use crate::types::wallet::TaggedWallet; use crate::types::wallet::{Wallet, WalletAddress}; @@ -45,6 +50,32 @@ pub async fn ibc_token_transfer_with_fee( Ok(()) } + +pub async fn pay_packet_fee( + tx_config: &MonoTagged, + port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, + channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, + sequence: &DualTagged, + payer: &MonoTagged, + receive_fee: &TaggedTokenRef<'_, Chain>, + ack_fee: &TaggedTokenRef<'_, Chain>, + timeout_fee: &TaggedTokenRef<'_, Chain>, +) -> Result<(), Error> { + let message = build_pay_packet_fee_async_message( + port_id, + channel_id, + sequence, + &payer.address(), + receive_fee, + ack_fee, + timeout_fee, + )?; + + simple_send_tx(tx_config.value(), &payer.value().key, vec![message]).await?; + + Ok(()) +} + pub async fn register_counterparty_address( tx_config: &MonoTagged, wallet: &MonoTagged, @@ -111,6 +142,58 @@ pub fn build_pay_packet_message( }) } + +pub fn build_pay_packet_fee_async_message( + port_id: &TaggedPortIdRef, + channel_id: &TaggedChannelIdRef, + sequence: &DualTagged, + payer: &MonoTagged, + receive_fee: &TaggedTokenRef<'_, Chain>, + ack_fee: &TaggedTokenRef<'_, Chain>, + timeout_fee: &TaggedTokenRef<'_, Chain>, +) -> Result { + const TYPE_URL: &str = "/ibc.applications.fee.v1.MsgPayPacketFeeAsync"; + + let fee = Fee { + recv_fee: vec![Coin { + denom: receive_fee.value().denom.to_string(), + amount: receive_fee.value().amount.to_string(), + }], + ack_fee: vec![Coin { + denom: ack_fee.value().denom.to_string(), + amount: ack_fee.value().amount.to_string(), + }], + timeout_fee: vec![Coin { + denom: timeout_fee.value().denom.to_string(), + amount: timeout_fee.value().amount.to_string(), + }], + }; + + let packet_fee = PacketFee { + fee: Some(fee), + refund_address: payer.value().0.clone(), + relayers: Vec::new(), + }; + + let packet_id = PacketId { + port_id: port_id.value().to_string(), + channel_id: channel_id.value().to_string(), + sequence: (*sequence.value()).into(), + }; + + let message = MsgPayPacketFeeAsync { + packet_fee: Some(packet_fee), + packet_id: Some(packet_id), + }; + + let encoded = encode_message(&message).map_err(handle_generic_error)?; + + Ok(Any { + type_url: TYPE_URL.to_string(), + value: encoded, + }) +} + pub fn build_register_counterparty_address_message( address: &MonoTagged, counterparty_address: &MonoTagged, From f2a8a271ed5ae6548cf541fe6383c91dc5a1408f Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Mon, 23 May 2022 14:55:53 +0200 Subject: [PATCH 024/113] Relaying of pay packet fee async is somehow not working --- relayer/src/chain/cosmos/wait.rs | 7 +- tools/integration-test/src/tests/fee.rs | 155 ++++++++++++++++++++++- tools/test-framework/src/chain/driver.rs | 5 +- tools/test-framework/src/chain/tagged.rs | 14 +- tools/test-framework/src/relayer/fee.rs | 16 +-- tools/test-framework/src/relayer/tx.rs | 13 +- 6 files changed, 187 insertions(+), 23 deletions(-) diff --git a/relayer/src/chain/cosmos/wait.rs b/relayer/src/chain/cosmos/wait.rs index 21a76742d0..f9cf1d0473 100644 --- a/relayer/src/chain/cosmos/wait.rs +++ b/relayer/src/chain/cosmos/wait.rs @@ -4,6 +4,7 @@ use ibc::core::ics24_host::identifier::ChainId; use ibc::events::IbcEvent; use std::time::Instant; use tendermint::abci::transaction::Hash as TxHash; +use tendermint_rpc::endpoint::tx::Response as TxResponse; use tendermint_rpc::endpoint::tx_search::Response as TxSearchResponse; use tendermint_rpc::{HttpClient, Url}; use tokio::time::sleep; @@ -69,17 +70,17 @@ pub async fn wait_tx_succeed( rpc_address: &Url, timeout: &Duration, tx_hash: &TxHash, -) -> Result<(), Error> { +) -> Result, Error> { let response = wait_tx_hash(rpc_client, rpc_address, timeout, tx_hash).await?; - for response in response.txs { + for response in response.txs.iter() { let response_code = response.tx_result.code; if response_code.is_err() { return Err(Error::rpc_response(format!("{}", response_code.value()))); } } - Ok(()) + Ok(response.txs) } pub async fn wait_tx_hash( diff --git a/tools/integration-test/src/tests/fee.rs b/tools/integration-test/src/tests/fee.rs index a18df3ad97..a07b8c8a7c 100644 --- a/tools/integration-test/src/tests/fee.rs +++ b/tools/integration-test/src/tests/fee.rs @@ -1,5 +1,7 @@ use ibc::core::ics04_channel::Version; +use ibc::events::IbcEvent; use ibc_test_framework::prelude::*; +use ibc_test_framework::relayer::fee::pay_packet_fee; use ibc_test_framework::util::random::random_u128_range; use std::thread; @@ -18,9 +20,15 @@ fn test_timeout_fee() -> Result<(), Error> { run_binary_channel_test(&TimeoutFeeTest) } +#[test] +fn test_pay_packet_fee_async() -> Result<(), Error> { + run_binary_channel_test(&PayPacketFeeAsyncTest) +} + struct ForwardRelayerTest; struct NoForwardRelayerTest; struct TimeoutFeeTest; +struct PayPacketFeeAsyncTest; impl TestOverrides for ForwardRelayerTest { fn channel_version(&self) -> Version { @@ -44,6 +52,16 @@ impl TestOverrides for TimeoutFeeTest { } } +impl TestOverrides for PayPacketFeeAsyncTest { + fn should_spawn_supervisor(&self) -> bool { + false + } + + fn channel_version(&self) -> Version { + Version::ics20_with_fee() + } +} + impl BinaryChannelTest for NoForwardRelayerTest { fn run( &self, @@ -227,7 +245,7 @@ impl BinaryChannelTest for ForwardRelayerTest { "Expect user to be refunded receive timeout fee {} and go from {} to {}", timeout_fee, balance_a2, - balance_a2.amount() + timeout_fee + ack_fee + balance_a2.amount() + timeout_fee ); chain_driver_a.assert_eventual_wallet_amount( @@ -338,3 +356,138 @@ impl BinaryChannelTest for TimeoutFeeTest { }) } } + +impl BinaryChannelTest for PayPacketFeeAsyncTest { + fn run( + &self, + _config: &TestConfig, + relayer: RelayerDriver, + chains: ConnectedChains, + channel: ConnectedChannel, + ) -> Result<(), Error> { + let chain_driver_a = chains.node_a.chain_driver(); + let chain_driver_b = chains.node_b.chain_driver(); + + let chain_id_a = chain_driver_a.chain_id(); + let chain_id_b = chain_driver_b.chain_id(); + + let denom_a = chains.node_a.denom(); + + let port_a = channel.port_a.as_ref(); + let channel_id_a = channel.channel_id_a.as_ref(); + + let channel_id_b = channel.channel_id_b.as_ref(); + + let wallets_a = chains.node_a.wallets(); + let wallets_b = chains.node_b.wallets(); + + let relayer_a = wallets_a.relayer(); + let relayer_b = wallets_b.relayer(); + + info!( + "registering counterparty address of relayer {} on chain {} to be {} on chain {}", + relayer_b.address(), + chain_id_b, + relayer_a.address(), + chain_id_a + ); + + chain_driver_b.register_counterparty_address( + &relayer_b, + &relayer_a.address(), + &channel_id_b, + )?; + + let user_a = wallets_a.user1(); + let user_b = wallets_b.user1(); + + let balance_a1 = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; + + let relayer_balance_a = chain_driver_a.query_balance(&relayer_a.address(), &denom_a)?; + + let send_amount = random_u128_range(1000, 2000); + let receive_fee = random_u128_range(300, 400); + let ack_fee = random_u128_range(200, 300); + let timeout_fee = random_u128_range(100, 200); + + let events = chain_driver_a.ibc_token_transfer_with_fee( + &port_a, + &channel_id_a, + &user_a, + &user_b.address(), + &denom_a.with_amount(send_amount).as_ref(), + &denom_a.with_amount(receive_fee).as_ref(), + &denom_a.with_amount(ack_fee).as_ref(), + &denom_a.with_amount(timeout_fee).as_ref(), + Duration::from_secs(60), + )?; + + let total_sent = send_amount + receive_fee + ack_fee + timeout_fee; + let balance_a2 = balance_a1 - total_sent; + info!("Expect user A's balance after transfer: {}", balance_a2); + + chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a2.as_ref())?; + + let send_packet_event = events + .into_iter() + .find_map(|event| match event { + IbcEvent::SendPacket(e) => Some(e), + _ => None, + }) + .ok_or_else(|| eyre!("expect send packet event"))?; + + let sequence = send_packet_event.packet.sequence; + + let receive_fee_2 = random_u128_range(300, 400); + let ack_fee_2 = random_u128_range(200, 300); + let timeout_fee_2 = random_u128_range(100, 200); + + chain_driver_a.value().runtime.block_on(async { + pay_packet_fee( + &chain_driver_a.tx_config(), + &port_a, + &channel_id_a, + &DualTagged::new(sequence), + &user_a, + &denom_a.with_amount(receive_fee_2).as_ref(), + &denom_a.with_amount(ack_fee_2).as_ref(), + &denom_a.with_amount(timeout_fee_2).as_ref(), + ) + .await + })?; + + let total_sent_2 = receive_fee_2 + ack_fee_2 + timeout_fee_2; + let balance_a3 = balance_a2 - total_sent_2; + + chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a3.as_ref())?; + + relayer.with_supervisor(|| { + info!( + "Expect user to be refunded receive timeout fee {} and go from {} to {}", + timeout_fee + timeout_fee_2, + balance_a3, + balance_a3.amount() + timeout_fee + timeout_fee_2 + ); + + chain_driver_a.assert_eventual_wallet_amount( + &user_a.address(), + &(balance_a3 + timeout_fee + timeout_fee_2).as_ref(), + )?; + + // info!( + // "Expect relayer to receive ack fee {} and receive fee {} and go from {} to {}", + // ack_fee + ack_fee_2, + // receive_fee + receive_fee_2, + // relayer_balance_a, + // relayer_balance_a.amount() + ack_fee + receive_fee + ack_fee_2 + receive_fee_2, + // ); + + // chain_driver_a.assert_eventual_wallet_amount( + // &relayer_a.address(), + // &(relayer_balance_a + ack_fee + receive_fee + ack_fee_2 + receive_fee_2).as_ref(), + // )?; + + Ok(()) + }) + } +} diff --git a/tools/test-framework/src/chain/driver.rs b/tools/test-framework/src/chain/driver.rs index 22ae37383c..12ecb2d0d5 100644 --- a/tools/test-framework/src/chain/driver.rs +++ b/tools/test-framework/src/chain/driver.rs @@ -17,6 +17,7 @@ use toml; use tracing::debug; use ibc::core::ics24_host::identifier::ChainId; +use ibc::events::IbcEvent; use ibc_proto::google::protobuf::Any; use ibc_relayer::chain::cosmos::types::config::TxConfig; use ibc_relayer::keyring::{HDPath, KeyEntry, KeyFile}; @@ -47,7 +48,7 @@ pub mod transfer; test is taking much longer to reach eventual consistency, it might be indication of some underlying performance issues. */ -const WAIT_WALLET_AMOUNT_ATTEMPTS: u16 = 60; +const WAIT_WALLET_AMOUNT_ATTEMPTS: u16 = 90; const COSMOS_HD_PATH: &str = "m/44'/118'/0'/0/0"; @@ -463,7 +464,7 @@ impl ChainDriver { Ok(amount) } - pub fn send_tx(&self, wallet: &Wallet, messages: Vec) -> Result<(), Error> { + 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/tagged.rs b/tools/test-framework/src/chain/tagged.rs index 8e713ed902..5a81d830bb 100644 --- a/tools/test-framework/src/chain/tagged.rs +++ b/tools/test-framework/src/chain/tagged.rs @@ -3,6 +3,7 @@ */ use core::time::Duration; +use ibc::events::IbcEvent; use ibc_proto::google::protobuf::Any; use ibc_relayer::chain::cosmos::types::config::TxConfig; use serde::Serialize; @@ -39,8 +40,11 @@ pub trait TaggedChainDriverExt { fn tx_config(&self) -> MonoTagged; - fn send_tx(&self, wallet: &MonoTagged, messages: Vec) - -> Result<(), Error>; + fn send_tx( + &self, + wallet: &MonoTagged, + messages: Vec, + ) -> Result, Error>; /** Tagged version of [`ChainDriver::query_balance`]. @@ -113,7 +117,7 @@ pub trait TaggedChainDriverExt { ack_fee: &TaggedTokenRef<'_, Chain>, timeout_fee: &TaggedTokenRef<'_, Chain>, timeout: Duration, - ) -> Result<(), Error>; + ) -> Result, Error>; /** Taggged version of [`query_recipient_transactions`]. @@ -166,7 +170,7 @@ impl<'a, Chain: Send> TaggedChainDriverExt for MonoTagged, messages: Vec, - ) -> Result<(), Error> { + ) -> Result, Error> { self.value().send_tx(wallet.value(), messages) } @@ -233,7 +237,7 @@ impl<'a, Chain: Send> TaggedChainDriverExt for MonoTagged, timeout_fee: &TaggedTokenRef<'_, Chain>, timeout: Duration, - ) -> Result<(), Error> { + ) -> Result, Error> { self.value().runtime.block_on(ibc_token_transfer_with_fee( &self.tx_config(), port_id, diff --git a/tools/test-framework/src/relayer/fee.rs b/tools/test-framework/src/relayer/fee.rs index b2e7ded622..3a760e5d74 100644 --- a/tools/test-framework/src/relayer/fee.rs +++ b/tools/test-framework/src/relayer/fee.rs @@ -1,12 +1,12 @@ use core::time::Duration; use ibc::core::ics04_channel::packet::Sequence; +use ibc::events::IbcEvent; use ibc_proto::cosmos::base::v1beta1::Coin; use ibc_proto::google::protobuf::Any; -use ibc_proto::ibc::core::channel::v1::PacketId; use ibc_proto::ibc::applications::fee::v1::{ - Fee, PacketFee, MsgPayPacketFee, - MsgPayPacketFeeAsync, MsgRegisterCounterpartyAddress + Fee, MsgPayPacketFee, MsgPayPacketFeeAsync, MsgRegisterCounterpartyAddress, PacketFee, }; +use ibc_proto::ibc::core::channel::v1::PacketId; use ibc_relayer::chain::cosmos::types::config::TxConfig; use prost::{EncodeError, Message}; @@ -15,7 +15,7 @@ use crate::ibc::token::TaggedTokenRef; use crate::relayer::transfer::build_transfer_message; use crate::relayer::tx::simple_send_tx; use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef}; -use crate::types::tagged::{MonoTagged, DualTagged}; +use crate::types::tagged::{DualTagged, MonoTagged}; use crate::types::wallet::TaggedWallet; use crate::types::wallet::{Wallet, WalletAddress}; @@ -30,7 +30,7 @@ pub async fn ibc_token_transfer_with_fee( ack_fee: &TaggedTokenRef<'_, SrcChain>, timeout_fee: &TaggedTokenRef<'_, SrcChain>, timeout: Duration, -) -> Result<(), Error> { +) -> Result, Error> { let transfer_message = build_transfer_message(port_id, channel_id, sender, recipient, send_amount, timeout)?; @@ -45,12 +45,11 @@ pub async fn ibc_token_transfer_with_fee( let messages = vec![pay_message, transfer_message]; - simple_send_tx(tx_config.value(), &sender.value().key, messages).await?; + let events = simple_send_tx(tx_config.value(), &sender.value().key, messages).await?; - Ok(()) + Ok(events) } - pub async fn pay_packet_fee( tx_config: &MonoTagged, port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, @@ -142,7 +141,6 @@ pub fn build_pay_packet_message( }) } - pub fn build_pay_packet_fee_async_message( port_id: &TaggedPortIdRef, channel_id: &TaggedChannelIdRef, diff --git a/tools/test-framework/src/relayer/tx.rs b/tools/test-framework/src/relayer/tx.rs index 253c3c7f46..d421cebd7c 100644 --- a/tools/test-framework/src/relayer/tx.rs +++ b/tools/test-framework/src/relayer/tx.rs @@ -3,10 +3,12 @@ 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::query::tx::all_ibc_events_from_tx_search_response; 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; @@ -86,7 +88,7 @@ pub async fn simple_send_tx( config: &TxConfig, key_entry: &KeyEntry, messages: Vec, -) -> Result<(), Error> { +) -> Result, Error> { let account = query_account(&config.grpc_address, &key_entry.account) .await? .into(); @@ -99,7 +101,7 @@ pub async fn simple_send_tx( return Err(eyre!("send_tx returns error response: {:?}", response).into()); } - wait_tx_succeed( + let responses = wait_tx_succeed( &config.rpc_client, &config.rpc_address, &config.rpc_timeout, @@ -107,5 +109,10 @@ pub async fn simple_send_tx( ) .await?; - Ok(()) + let events = responses + .into_iter() + .flat_map(|response| all_ibc_events_from_tx_search_response(&config.chain_id, response)) + .collect(); + + Ok(events) } From 3b17f6ebdacccd90988b508d689e81dd93f58a38 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Mon, 23 May 2022 15:23:59 +0200 Subject: [PATCH 025/113] Reproduce execute_schedule slowdown --- tools/integration-test/src/tests/fee.rs | 36 +++++++++++++++++------- tools/test-framework/src/chain/driver.rs | 2 +- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/tools/integration-test/src/tests/fee.rs b/tools/integration-test/src/tests/fee.rs index a07b8c8a7c..0729ec1122 100644 --- a/tools/integration-test/src/tests/fee.rs +++ b/tools/integration-test/src/tests/fee.rs @@ -461,19 +461,35 @@ impl BinaryChannelTest for PayPacketFeeAsyncTest { chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a3.as_ref())?; - relayer.with_supervisor(|| { - info!( - "Expect user to be refunded receive timeout fee {} and go from {} to {}", - timeout_fee + timeout_fee_2, - balance_a3, - balance_a3.amount() + timeout_fee + timeout_fee_2 - ); + let denom_b = derive_ibc_denom( + &channel.port_b.as_ref(), + &channel.channel_id_b.as_ref(), + &denom_a, + )?; - chain_driver_a.assert_eventual_wallet_amount( - &user_a.address(), - &(balance_a3 + timeout_fee + timeout_fee_2).as_ref(), + relayer.with_supervisor(|| { + chain_driver_b.assert_eventual_wallet_amount( + &user_b.address(), + &denom_b.with_amount(send_amount).as_ref(), )?; + // info!( + // "Expect user to be refunded receive timeout fee {} and go from {} to {}", + // timeout_fee + timeout_fee_2, + // balance_a3, + // balance_a3.amount() + timeout_fee + timeout_fee_2 + // ); + + // chain_driver_a.assert_eventual_wallet_amount( + // &user_a.address(), + // &(balance_a3 + timeout_fee + timeout_fee_2).as_ref(), + // )?; + + // chain_driver_a.assert_eventual_wallet_amount( + // &user_a.address(), + // &(balance_a3 + timeout_fee + timeout_fee_2 + receive_fee + receive_fee_2).as_ref(), + // )?; + // info!( // "Expect relayer to receive ack fee {} and receive fee {} and go from {} to {}", // ack_fee + ack_fee_2, diff --git a/tools/test-framework/src/chain/driver.rs b/tools/test-framework/src/chain/driver.rs index 12ecb2d0d5..ab19fe6b14 100644 --- a/tools/test-framework/src/chain/driver.rs +++ b/tools/test-framework/src/chain/driver.rs @@ -48,7 +48,7 @@ pub mod transfer; test is taking much longer to reach eventual consistency, it might be indication of some underlying performance issues. */ -const WAIT_WALLET_AMOUNT_ATTEMPTS: u16 = 90; +const WAIT_WALLET_AMOUNT_ATTEMPTS: u16 = 180; const COSMOS_HD_PATH: &str = "m/44'/118'/0'/0/0"; From 20d4f564c77901524297d5728534eebe41d08238 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Tue, 24 May 2022 14:59:53 +0200 Subject: [PATCH 026/113] Add test to reproduce clear packet failure --- .../src/tests/clear_packet.rs | 146 ++++++++++++++++++ 1 file changed, 146 insertions(+) diff --git a/tools/integration-test/src/tests/clear_packet.rs b/tools/integration-test/src/tests/clear_packet.rs index 34b115fb83..9c0caff40f 100644 --- a/tools/integration-test/src/tests/clear_packet.rs +++ b/tools/integration-test/src/tests/clear_packet.rs @@ -6,7 +6,20 @@ use ibc_test_framework::util::random::random_u64_range; fn test_clear_packet() -> Result<(), Error> { run_binary_channel_test(&ClearPacketTest) } + +#[test] +fn test_clear_packet_recovery_dst() -> Result<(), Error> { + run_binary_channel_test(&ClearPacketRecoveryDstTest) +} + +#[test] +fn test_clear_packet_recovery_src() -> Result<(), Error> { + run_binary_channel_test(&ClearPacketRecoverySrcTest) +} + pub struct ClearPacketTest; +pub struct ClearPacketRecoveryDstTest; +pub struct ClearPacketRecoverySrcTest; impl TestOverrides for ClearPacketTest { fn modify_relayer_config(&self, config: &mut Config) { @@ -26,6 +39,28 @@ impl TestOverrides for ClearPacketTest { } } +impl TestOverrides for ClearPacketRecoveryDstTest { + fn modify_relayer_config(&self, config: &mut Config) { + config.mode.packets.enabled = true; + config.mode.packets.clear_on_start = true; + } + + fn should_spawn_supervisor(&self) -> bool { + false + } +} + +impl TestOverrides for ClearPacketRecoverySrcTest { + fn modify_relayer_config(&self, config: &mut Config) { + config.mode.packets.enabled = true; + config.mode.packets.clear_on_start = true; + } + + fn should_spawn_supervisor(&self) -> bool { + false + } +} + impl BinaryChannelTest for ClearPacketTest { fn run( &self, @@ -108,3 +143,114 @@ impl BinaryChannelTest for ClearPacketTest { }) } } + +impl BinaryChannelTest for ClearPacketRecoveryDstTest { + fn run( + &self, + _config: &TestConfig, + relayer: RelayerDriver, + chains: ConnectedChains, + channel: ConnectedChannel, + ) -> Result<(), Error> { + let denom_a = chains.node_a.denom(); + let denom_b1 = chains.node_b.denom(); + + let wallet_a = chains.node_a.wallets().user1().cloned(); + let wallet_b = chains.node_b.wallets().user1().cloned(); + + let relayer_wallet_b = chains.node_b.wallets().relayer().cloned(); + + // mess up the cached account sequence in ChainHandle of chain B + // commenting out this local transfer would make the test pass + chains.node_b.chain_driver().local_transfer_token( + &relayer_wallet_b.as_ref(), + &wallet_b.address(), + 100, + &denom_b1, + )?; + + let amount1 = random_u64_range(1000, 5000); + + chains.node_a.chain_driver().ibc_transfer_token( + &channel.port_a.as_ref(), + &channel.channel_id_a.as_ref(), + &wallet_a.as_ref(), + &wallet_b.address(), + &denom_a, + amount1, + )?; + + let denom_b2 = derive_ibc_denom( + &channel.port_b.as_ref(), + &channel.channel_id_b.as_ref(), + &denom_a, + )?; + + relayer.with_supervisor(|| { + chains.node_b.chain_driver().assert_eventual_wallet_amount( + &wallet_b.address(), + amount1, + &denom_b2.as_ref(), + )?; + + Ok(()) + }) + } +} + +impl BinaryChannelTest for ClearPacketRecoverySrcTest { + fn run( + &self, + _config: &TestConfig, + relayer: RelayerDriver, + chains: ConnectedChains, + channel: ConnectedChannel, + ) -> Result<(), Error> { + let denom_a = chains.node_a.denom(); + + let wallet_a = chains.node_a.wallets().user1().cloned(); + let wallet_b = chains.node_b.wallets().user1().cloned(); + + let relayer_wallet_a = chains.node_a.wallets().relayer().cloned(); + + // mess up the cached account sequence in ChainHandle of chain A + // commenting out this local transfer would make the test pass + chains.node_a.chain_driver().local_transfer_token( + &relayer_wallet_a.as_ref(), + &wallet_a.address(), + 100, + &denom_a, + )?; + + let amount1 = random_u64_range(1000, 5000); + + chains.node_a.chain_driver().ibc_transfer_token( + &channel.port_a.as_ref(), + &channel.channel_id_a.as_ref(), + &wallet_a.as_ref(), + &wallet_b.address(), + &denom_a, + amount1, + )?; + + let denom_b2 = derive_ibc_denom( + &channel.port_b.as_ref(), + &channel.channel_id_b.as_ref(), + &denom_a, + )?; + + relayer.with_supervisor(|| { + chains.node_b.chain_driver().assert_eventual_wallet_amount( + &wallet_b.address(), + amount1, + &denom_b2.as_ref(), + )?; + + // The test would pass, but the ack probably fails. + // Sleep to observe the failure in ack relaying. + std::thread::sleep(Duration::from_secs(10)); + + Ok(()) + }) + } +} From 748c36fb31577f46227ec0b16733690caafb5b51 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Tue, 24 May 2022 17:00:13 +0200 Subject: [PATCH 027/113] Apply dirty hack fix --- relayer/src/worker/packet.rs | 12 +++ .../src/tests/clear_packet.rs | 85 ++----------------- 2 files changed, 17 insertions(+), 80 deletions(-) diff --git a/relayer/src/worker/packet.rs b/relayer/src/worker/packet.rs index 5c090bde32..444da92be6 100644 --- a/relayer/src/worker/packet.rs +++ b/relayer/src/worker/packet.rs @@ -152,6 +152,9 @@ fn handle_packet_cmd( cmd: WorkerCmd, index: u64, ) -> RetryResult<(), u64> { + // this is set to true if `schedule_packet_clearing` is called. + let mut scheduled_packet_clearing = false; + trace!("handling command {}", cmd); let result = match cmd { WorkerCmd::IbcEvents { batch } => link.a_to_b.update_schedule(batch), @@ -172,6 +175,7 @@ fn handle_packet_cmd( clear_interval, height, ) { + scheduled_packet_clearing = true; link.a_to_b.schedule_packet_clearing(Some(height)) } else { Ok(()) @@ -218,6 +222,14 @@ fn handle_packet_cmd( "will retry: schedule execution encountered error: {}", e, ); + + // Reset the `is_first_run` flag if `execute_schedule` encountered + // any error after `schedule_packet_clearing`. This helps ensure that + // packets being cleared will be retried instead of dropped. + if scheduled_packet_clearing { + *is_first_run = true; + } + return RetryResult::Retry(index); } } diff --git a/tools/integration-test/src/tests/clear_packet.rs b/tools/integration-test/src/tests/clear_packet.rs index 9c0caff40f..5ffef15349 100644 --- a/tools/integration-test/src/tests/clear_packet.rs +++ b/tools/integration-test/src/tests/clear_packet.rs @@ -8,18 +8,12 @@ fn test_clear_packet() -> Result<(), Error> { } #[test] -fn test_clear_packet_recovery_dst() -> Result<(), Error> { - run_binary_channel_test(&ClearPacketRecoveryDstTest) -} - -#[test] -fn test_clear_packet_recovery_src() -> Result<(), Error> { - run_binary_channel_test(&ClearPacketRecoverySrcTest) +fn test_clear_packet_recovery() -> Result<(), Error> { + run_binary_channel_test(&ClearPacketRecoveryTest) } pub struct ClearPacketTest; -pub struct ClearPacketRecoveryDstTest; -pub struct ClearPacketRecoverySrcTest; +pub struct ClearPacketRecoveryTest; impl TestOverrides for ClearPacketTest { fn modify_relayer_config(&self, config: &mut Config) { @@ -39,18 +33,7 @@ impl TestOverrides for ClearPacketTest { } } -impl TestOverrides for ClearPacketRecoveryDstTest { - fn modify_relayer_config(&self, config: &mut Config) { - config.mode.packets.enabled = true; - config.mode.packets.clear_on_start = true; - } - - fn should_spawn_supervisor(&self) -> bool { - false - } -} - -impl TestOverrides for ClearPacketRecoverySrcTest { +impl TestOverrides for ClearPacketRecoveryTest { fn modify_relayer_config(&self, config: &mut Config) { config.mode.packets.enabled = true; config.mode.packets.clear_on_start = true; @@ -144,7 +127,7 @@ impl BinaryChannelTest for ClearPacketTest { } } -impl BinaryChannelTest for ClearPacketRecoveryDstTest { +impl BinaryChannelTest for ClearPacketRecoveryTest { fn run( &self, _config: &TestConfig, @@ -161,7 +144,6 @@ impl BinaryChannelTest for ClearPacketRecoveryDstTest { let relayer_wallet_b = chains.node_b.wallets().relayer().cloned(); // mess up the cached account sequence in ChainHandle of chain B - // commenting out this local transfer would make the test pass chains.node_b.chain_driver().local_transfer_token( &relayer_wallet_b.as_ref(), &wallet_b.address(), @@ -197,60 +179,3 @@ impl BinaryChannelTest for ClearPacketRecoveryDstTest { }) } } - -impl BinaryChannelTest for ClearPacketRecoverySrcTest { - fn run( - &self, - _config: &TestConfig, - relayer: RelayerDriver, - chains: ConnectedChains, - channel: ConnectedChannel, - ) -> Result<(), Error> { - let denom_a = chains.node_a.denom(); - - let wallet_a = chains.node_a.wallets().user1().cloned(); - let wallet_b = chains.node_b.wallets().user1().cloned(); - - let relayer_wallet_a = chains.node_a.wallets().relayer().cloned(); - - // mess up the cached account sequence in ChainHandle of chain A - // commenting out this local transfer would make the test pass - chains.node_a.chain_driver().local_transfer_token( - &relayer_wallet_a.as_ref(), - &wallet_a.address(), - 100, - &denom_a, - )?; - - let amount1 = random_u64_range(1000, 5000); - - chains.node_a.chain_driver().ibc_transfer_token( - &channel.port_a.as_ref(), - &channel.channel_id_a.as_ref(), - &wallet_a.as_ref(), - &wallet_b.address(), - &denom_a, - amount1, - )?; - - let denom_b2 = derive_ibc_denom( - &channel.port_b.as_ref(), - &channel.channel_id_b.as_ref(), - &denom_a, - )?; - - relayer.with_supervisor(|| { - chains.node_b.chain_driver().assert_eventual_wallet_amount( - &wallet_b.address(), - amount1, - &denom_b2.as_ref(), - )?; - - // The test would pass, but the ack probably fails. - // Sleep to observe the failure in ack relaying. - std::thread::sleep(Duration::from_secs(10)); - - Ok(()) - }) - } -} From cfb8886a7432398f1b6389a814f7575483c075d4 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Tue, 24 May 2022 21:43:00 +0200 Subject: [PATCH 028/113] Fix merge error --- tools/integration-test/src/tests/clear_packet.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/tools/integration-test/src/tests/clear_packet.rs b/tools/integration-test/src/tests/clear_packet.rs index ed9ac38ce0..a765dcabfe 100644 --- a/tools/integration-test/src/tests/clear_packet.rs +++ b/tools/integration-test/src/tests/clear_packet.rs @@ -139,19 +139,17 @@ impl BinaryChannelTest for ClearPacketRecoveryTest { chains.node_b.chain_driver().local_transfer_token( &relayer_wallet_b.as_ref(), &wallet_b.address(), - 100, - &denom_b1, + &denom_b1.with_amount(100).as_ref(), )?; - let amount1 = random_u64_range(1000, 5000); + let amount1 = random_u128_range(1000, 5000); chains.node_a.chain_driver().ibc_transfer_token( &channel.port_a.as_ref(), &channel.channel_id_a.as_ref(), &wallet_a.as_ref(), &wallet_b.address(), - &denom_a, - amount1, + &denom_a.with_amount(amount1).as_ref(), )?; let denom_b2 = derive_ibc_denom( @@ -163,8 +161,7 @@ impl BinaryChannelTest for ClearPacketRecoveryTest { relayer.with_supervisor(|| { chains.node_b.chain_driver().assert_eventual_wallet_amount( &wallet_b.address(), - amount1, - &denom_b2.as_ref(), + &denom_b2.with_amount(amount1).as_ref(), )?; Ok(()) From 256a0b9653e35f0da6bfd9b150854e2b900e12e0 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Tue, 24 May 2022 21:45:41 +0200 Subject: [PATCH 029/113] Pay packet fee async test is now working --- tools/integration-test/src/tests/fee.rs | 38 ++++++------------------- 1 file changed, 9 insertions(+), 29 deletions(-) diff --git a/tools/integration-test/src/tests/fee.rs b/tools/integration-test/src/tests/fee.rs index 0729ec1122..82b9d97e38 100644 --- a/tools/integration-test/src/tests/fee.rs +++ b/tools/integration-test/src/tests/fee.rs @@ -473,35 +473,15 @@ impl BinaryChannelTest for PayPacketFeeAsyncTest { &denom_b.with_amount(send_amount).as_ref(), )?; - // info!( - // "Expect user to be refunded receive timeout fee {} and go from {} to {}", - // timeout_fee + timeout_fee_2, - // balance_a3, - // balance_a3.amount() + timeout_fee + timeout_fee_2 - // ); - - // chain_driver_a.assert_eventual_wallet_amount( - // &user_a.address(), - // &(balance_a3 + timeout_fee + timeout_fee_2).as_ref(), - // )?; - - // chain_driver_a.assert_eventual_wallet_amount( - // &user_a.address(), - // &(balance_a3 + timeout_fee + timeout_fee_2 + receive_fee + receive_fee_2).as_ref(), - // )?; - - // info!( - // "Expect relayer to receive ack fee {} and receive fee {} and go from {} to {}", - // ack_fee + ack_fee_2, - // receive_fee + receive_fee_2, - // relayer_balance_a, - // relayer_balance_a.amount() + ack_fee + receive_fee + ack_fee_2 + receive_fee_2, - // ); - - // chain_driver_a.assert_eventual_wallet_amount( - // &relayer_a.address(), - // &(relayer_balance_a + ack_fee + receive_fee + ack_fee_2 + receive_fee_2).as_ref(), - // )?; + chain_driver_a.assert_eventual_wallet_amount( + &user_a.address(), + &(balance_a3 + timeout_fee + timeout_fee_2).as_ref(), + )?; + + chain_driver_a.assert_eventual_wallet_amount( + &relayer_a.address(), + &(relayer_balance_a + ack_fee + receive_fee + ack_fee_2 + receive_fee_2).as_ref(), + )?; Ok(()) }) From 60f30599003f24642b43be1e66e25e73282427b4 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 25 May 2022 14:33:30 +0200 Subject: [PATCH 030/113] Refactor ChainDriver methods into separate extension traits --- tools/integration-test/src/tests/fee.rs | 24 +-- tools/test-framework/src/chain/ext/fee.rs | 111 +++++++++++ tools/test-framework/src/chain/ext/ica.rs | 59 ++++++ tools/test-framework/src/chain/ext/mod.rs | 3 + .../test-framework/src/chain/ext/transfer.rs | 81 ++++++++ tools/test-framework/src/chain/mod.rs | 1 + tools/test-framework/src/chain/tagged.rs | 184 +----------------- tools/test-framework/src/prelude.rs | 3 + 8 files changed, 269 insertions(+), 197 deletions(-) create mode 100644 tools/test-framework/src/chain/ext/fee.rs create mode 100644 tools/test-framework/src/chain/ext/ica.rs create mode 100644 tools/test-framework/src/chain/ext/mod.rs create mode 100644 tools/test-framework/src/chain/ext/transfer.rs diff --git a/tools/integration-test/src/tests/fee.rs b/tools/integration-test/src/tests/fee.rs index 82b9d97e38..7cbf5caff4 100644 --- a/tools/integration-test/src/tests/fee.rs +++ b/tools/integration-test/src/tests/fee.rs @@ -1,7 +1,6 @@ use ibc::core::ics04_channel::Version; use ibc::events::IbcEvent; use ibc_test_framework::prelude::*; -use ibc_test_framework::relayer::fee::pay_packet_fee; use ibc_test_framework::util::random::random_u128_range; use std::thread; @@ -399,6 +398,7 @@ impl BinaryChannelTest for PayPacketFeeAsyncTest { )?; let user_a = wallets_a.user1(); + let user_b = wallets_b.user1(); let balance_a1 = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; @@ -442,19 +442,15 @@ impl BinaryChannelTest for PayPacketFeeAsyncTest { let ack_fee_2 = random_u128_range(200, 300); let timeout_fee_2 = random_u128_range(100, 200); - chain_driver_a.value().runtime.block_on(async { - pay_packet_fee( - &chain_driver_a.tx_config(), - &port_a, - &channel_id_a, - &DualTagged::new(sequence), - &user_a, - &denom_a.with_amount(receive_fee_2).as_ref(), - &denom_a.with_amount(ack_fee_2).as_ref(), - &denom_a.with_amount(timeout_fee_2).as_ref(), - ) - .await - })?; + chain_driver_a.pay_packet_fee( + &port_a, + &channel_id_a, + &DualTagged::new(sequence), + &user_a, + &denom_a.with_amount(receive_fee_2).as_ref(), + &denom_a.with_amount(ack_fee_2).as_ref(), + &denom_a.with_amount(timeout_fee_2).as_ref(), + )?; let total_sent_2 = receive_fee_2 + ack_fee_2 + timeout_fee_2; let balance_a3 = balance_a2 - total_sent_2; diff --git a/tools/test-framework/src/chain/ext/fee.rs b/tools/test-framework/src/chain/ext/fee.rs new file mode 100644 index 0000000000..f1600049a2 --- /dev/null +++ b/tools/test-framework/src/chain/ext/fee.rs @@ -0,0 +1,111 @@ +use core::time::Duration; +use ibc::core::ics04_channel::packet::Sequence; +use ibc::events::IbcEvent; + +use crate::chain::driver::ChainDriver; +use crate::chain::tagged::TaggedChainDriverExt; +use crate::error::Error; +use crate::ibc::token::TaggedTokenRef; +use crate::relayer::fee::{ + ibc_token_transfer_with_fee, pay_packet_fee, register_counterparty_address, +}; +use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef}; +use crate::types::tagged::*; +use crate::types::wallet::{Wallet, WalletAddress}; + +pub trait ChainFeeMethodsExt { + fn ibc_token_transfer_with_fee( + &self, + port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, + channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, + sender: &MonoTagged, + recipient: &MonoTagged, + send_amount: &TaggedTokenRef<'_, Chain>, + receive_fee: &TaggedTokenRef<'_, Chain>, + ack_fee: &TaggedTokenRef<'_, Chain>, + timeout_fee: &TaggedTokenRef<'_, Chain>, + timeout: Duration, + ) -> Result, Error>; + + fn pay_packet_fee( + &self, + port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, + channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, + sequence: &DualTagged, + payer: &MonoTagged, + receive_fee: &TaggedTokenRef<'_, Chain>, + ack_fee: &TaggedTokenRef<'_, Chain>, + timeout_fee: &TaggedTokenRef<'_, Chain>, + ) -> Result<(), Error>; + + fn register_counterparty_address( + &self, + wallet: &MonoTagged, + counterparty_address: &MonoTagged, + channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, + ) -> Result<(), Error>; +} + +impl<'a, Chain: Send> ChainFeeMethodsExt for MonoTagged { + fn ibc_token_transfer_with_fee( + &self, + port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, + channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, + sender: &MonoTagged, + recipient: &MonoTagged, + send_amount: &TaggedTokenRef<'_, Chain>, + receive_fee: &TaggedTokenRef<'_, Chain>, + ack_fee: &TaggedTokenRef<'_, Chain>, + timeout_fee: &TaggedTokenRef<'_, Chain>, + timeout: Duration, + ) -> Result, Error> { + self.value().runtime.block_on(ibc_token_transfer_with_fee( + &self.tx_config(), + port_id, + channel_id, + sender, + recipient, + send_amount, + receive_fee, + ack_fee, + timeout_fee, + timeout, + )) + } + + fn pay_packet_fee( + &self, + port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, + channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, + sequence: &DualTagged, + payer: &MonoTagged, + receive_fee: &TaggedTokenRef<'_, Chain>, + ack_fee: &TaggedTokenRef<'_, Chain>, + timeout_fee: &TaggedTokenRef<'_, Chain>, + ) -> Result<(), Error> { + self.value().runtime.block_on(pay_packet_fee( + &self.tx_config(), + port_id, + channel_id, + sequence, + payer, + receive_fee, + ack_fee, + timeout_fee, + )) + } + + fn register_counterparty_address( + &self, + wallet: &MonoTagged, + counterparty_address: &MonoTagged, + channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, + ) -> Result<(), Error> { + self.value().runtime.block_on(register_counterparty_address( + &self.tx_config(), + wallet, + counterparty_address, + channel_id, + )) + } +} diff --git a/tools/test-framework/src/chain/ext/ica.rs b/tools/test-framework/src/chain/ext/ica.rs new file mode 100644 index 0000000000..c730c5e847 --- /dev/null +++ b/tools/test-framework/src/chain/ext/ica.rs @@ -0,0 +1,59 @@ +use serde::Serialize; + +use crate::chain::driver::interchain::{ + interchain_submit, query_interchain_account, register_interchain_account, +}; +use crate::chain::driver::ChainDriver; +use crate::error::Error; +use crate::prelude::TaggedConnectionIdRef; +use crate::types::tagged::*; +use crate::types::wallet::WalletAddress; + +pub trait InterchainAccountMethodsExt { + fn register_interchain_account( + &self, + from: &MonoTagged, + connection_id: &TaggedConnectionIdRef, + ) -> Result<(), Error>; + + fn query_interchain_account( + &self, + from: &MonoTagged, + connection_id: &TaggedConnectionIdRef, + ) -> Result, Error>; + + fn interchain_submit( + &self, + from: &MonoTagged, + connection_id: &TaggedConnectionIdRef, + msg: &T, + ) -> Result<(), Error>; +} + +impl<'a, Chain: Send> InterchainAccountMethodsExt for MonoTagged { + fn register_interchain_account( + &self, + from: &MonoTagged, + connection_id: &TaggedConnectionIdRef, + ) -> Result<(), Error> { + register_interchain_account(self.value(), from.value(), connection_id.value()) + } + + fn query_interchain_account( + &self, + from: &MonoTagged, + connection_id: &TaggedConnectionIdRef, + ) -> Result, Error> { + query_interchain_account(self.value(), from.value(), connection_id.value()) + .map(MonoTagged::new) + } + + fn interchain_submit( + &self, + from: &MonoTagged, + connection_id: &TaggedConnectionIdRef, + msg: &T, + ) -> Result<(), Error> { + interchain_submit(self.value(), from.value(), connection_id.value(), msg) + } +} diff --git a/tools/test-framework/src/chain/ext/mod.rs b/tools/test-framework/src/chain/ext/mod.rs new file mode 100644 index 0000000000..c6edcee505 --- /dev/null +++ b/tools/test-framework/src/chain/ext/mod.rs @@ -0,0 +1,3 @@ +pub mod fee; +pub mod ica; +pub mod transfer; diff --git a/tools/test-framework/src/chain/ext/transfer.rs b/tools/test-framework/src/chain/ext/transfer.rs new file mode 100644 index 0000000000..115b1d2e57 --- /dev/null +++ b/tools/test-framework/src/chain/ext/transfer.rs @@ -0,0 +1,81 @@ +use crate::chain::driver::transfer::local_transfer_token; +use crate::chain::driver::ChainDriver; +use crate::chain::tagged::TaggedChainDriverExt; +use crate::error::Error; +use crate::ibc::token::TaggedTokenRef; +use crate::relayer::transfer::ibc_token_transfer; +use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef}; +use crate::types::tagged::*; +use crate::types::wallet::{Wallet, WalletAddress}; + +pub trait ChainTransferMethodsExt { + /** + Submits an IBC token transfer transaction to `Chain` to any other + `Counterparty` chain. + + The following parameters are accepted: + + - A `PortId` on `Chain` that corresponds to a channel connected to + `Counterparty`. + + - A `ChannelId` on `Chain` that corresponds to a channel connected to + `Counterparty`. + + - The [`Wallet`] of the sender on `Chain`. + + - The [`WalletAddress`] address of the recipient on `Counterparty`. + + - The denomination of the amount on `Chain`. + + - The transfer amount. + */ + fn ibc_transfer_token( + &self, + port_id: &TaggedPortIdRef, + channel_id: &TaggedChannelIdRef, + sender: &MonoTagged, + recipient: &MonoTagged, + token: &TaggedTokenRef, + ) -> Result<(), Error>; + + fn local_transfer_token( + &self, + sender: &MonoTagged, + recipient: &MonoTagged, + token: &TaggedTokenRef, + ) -> Result<(), Error>; +} + +impl<'a, Chain: Send> ChainTransferMethodsExt for MonoTagged { + fn ibc_transfer_token( + &self, + port_id: &TaggedPortIdRef, + channel_id: &TaggedChannelIdRef, + sender: &MonoTagged, + recipient: &MonoTagged, + token: &TaggedTokenRef, + ) -> Result<(), Error> { + self.value().runtime.block_on(ibc_token_transfer( + &self.tx_config(), + port_id, + channel_id, + sender, + recipient, + token, + )) + } + + fn local_transfer_token( + &self, + sender: &MonoTagged, + recipient: &MonoTagged, + token: &TaggedTokenRef, + ) -> Result<(), Error> { + local_transfer_token( + self.value(), + sender.value(), + recipient.value(), + token.value(), + ) + } +} diff --git a/tools/test-framework/src/chain/mod.rs b/tools/test-framework/src/chain/mod.rs index 7180f61a41..486e56e5cd 100644 --- a/tools/test-framework/src/chain/mod.rs +++ b/tools/test-framework/src/chain/mod.rs @@ -18,5 +18,6 @@ pub mod builder; pub mod config; pub mod driver; pub mod exec; +pub mod ext; pub mod tagged; pub mod version; diff --git a/tools/test-framework/src/chain/tagged.rs b/tools/test-framework/src/chain/tagged.rs index 5a81d830bb..44bd84eac8 100644 --- a/tools/test-framework/src/chain/tagged.rs +++ b/tools/test-framework/src/chain/tagged.rs @@ -2,26 +2,17 @@ Methods for tagged version of the chain driver. */ -use core::time::Duration; use ibc::events::IbcEvent; 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::ibc::token::{TaggedDenomExt, TaggedToken, TaggedTokenRef}; -use crate::prelude::TaggedConnectionIdRef; -use crate::relayer::fee::{ibc_token_transfer_with_fee, register_counterparty_address}; -use crate::relayer::transfer::ibc_token_transfer; -use crate::types::id::{TaggedChainIdRef, TaggedChannelIdRef, TaggedPortIdRef}; +use crate::types::id::TaggedChainIdRef; use crate::types::tagged::*; use crate::types::wallet::{Wallet, WalletAddress}; @@ -70,55 +61,6 @@ pub trait TaggedChainDriverExt { token: &TaggedTokenRef, ) -> Result<(), Error>; - /** - Submits an IBC token transfer transaction to `Chain` to any other - `Counterparty` chain. - - The following parameters are accepted: - - - A `PortId` on `Chain` that corresponds to a channel connected to - `Counterparty`. - - - A `ChannelId` on `Chain` that corresponds to a channel connected to - `Counterparty`. - - - The [`Wallet`] of the sender on `Chain`. - - - The [`WalletAddress`] address of the recipient on `Counterparty`. - - - The denomination of the amount on `Chain`. - - - The transfer amount. - */ - fn ibc_transfer_token( - &self, - port_id: &TaggedPortIdRef, - channel_id: &TaggedChannelIdRef, - sender: &MonoTagged, - recipient: &MonoTagged, - token: &TaggedTokenRef, - ) -> Result<(), Error>; - - fn local_transfer_token( - &self, - sender: &MonoTagged, - recipient: &MonoTagged, - token: &TaggedTokenRef, - ) -> Result<(), Error>; - - fn ibc_token_transfer_with_fee( - &self, - port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, - channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, - sender: &MonoTagged, - recipient: &MonoTagged, - send_amount: &TaggedTokenRef<'_, Chain>, - receive_fee: &TaggedTokenRef<'_, Chain>, - ack_fee: &TaggedTokenRef<'_, Chain>, - timeout_fee: &TaggedTokenRef<'_, Chain>, - timeout: Duration, - ) -> Result, Error>; - /** Taggged version of [`query_recipient_transactions`]. @@ -129,32 +71,6 @@ pub trait TaggedChainDriverExt { &self, recipient_address: &MonoTagged, ) -> Result; - - fn register_counterparty_address( - &self, - wallet: &MonoTagged, - counterparty_address: &MonoTagged, - channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, - ) -> Result<(), Error>; - - fn register_interchain_account( - &self, - from: &MonoTagged, - connection_id: &TaggedConnectionIdRef, - ) -> Result<(), Error>; - - fn query_interchain_account( - &self, - from: &MonoTagged, - connection_id: &TaggedConnectionIdRef, - ) -> Result, Error>; - - fn interchain_submit( - &self, - from: &MonoTagged, - connection_id: &TaggedConnectionIdRef, - msg: &T, - ) -> Result<(), Error>; } impl<'a, Chain: Send> TaggedChainDriverExt for MonoTagged { @@ -194,108 +110,10 @@ impl<'a, Chain: Send> TaggedChainDriverExt for MonoTagged( - &self, - port_id: &TaggedPortIdRef, - channel_id: &TaggedChannelIdRef, - sender: &MonoTagged, - recipient: &MonoTagged, - token: &TaggedTokenRef, - ) -> Result<(), Error> { - self.value().runtime.block_on(ibc_token_transfer( - &self.tx_config(), - port_id, - channel_id, - sender, - recipient, - token, - )) - } - - fn local_transfer_token( - &self, - sender: &MonoTagged, - recipient: &MonoTagged, - token: &TaggedTokenRef, - ) -> Result<(), Error> { - local_transfer_token( - self.value(), - sender.value(), - recipient.value(), - token.value(), - ) - } - - fn ibc_token_transfer_with_fee( - &self, - port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, - channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, - sender: &MonoTagged, - recipient: &MonoTagged, - send_amount: &TaggedTokenRef<'_, Chain>, - receive_fee: &TaggedTokenRef<'_, Chain>, - ack_fee: &TaggedTokenRef<'_, Chain>, - timeout_fee: &TaggedTokenRef<'_, Chain>, - timeout: Duration, - ) -> Result, Error> { - self.value().runtime.block_on(ibc_token_transfer_with_fee( - &self.tx_config(), - port_id, - channel_id, - sender, - recipient, - send_amount, - receive_fee, - ack_fee, - timeout_fee, - timeout, - )) - } - fn query_recipient_transactions( &self, recipient_address: &MonoTagged, ) -> Result { query_recipient_transactions(self.value(), recipient_address.value()) } - - fn register_counterparty_address( - &self, - wallet: &MonoTagged, - counterparty_address: &MonoTagged, - channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, - ) -> Result<(), Error> { - self.value().runtime.block_on(register_counterparty_address( - &self.tx_config(), - wallet, - counterparty_address, - channel_id, - )) - } - - fn register_interchain_account( - &self, - from: &MonoTagged, - connection_id: &TaggedConnectionIdRef, - ) -> Result<(), Error> { - register_interchain_account(self.value(), from.value(), connection_id.value()) - } - - fn query_interchain_account( - &self, - from: &MonoTagged, - connection_id: &TaggedConnectionIdRef, - ) -> Result, Error> { - query_interchain_account(self.value(), from.value(), connection_id.value()) - .map(MonoTagged::new) - } - - fn interchain_submit( - &self, - from: &MonoTagged, - connection_id: &TaggedConnectionIdRef, - msg: &T, - ) -> Result<(), Error> { - interchain_submit(self.value(), from.value(), connection_id.value(), msg) - } } diff --git a/tools/test-framework/src/prelude.rs b/tools/test-framework/src/prelude.rs index 08e703874d..fb4fc9c608 100644 --- a/tools/test-framework/src/prelude.rs +++ b/tools/test-framework/src/prelude.rs @@ -15,6 +15,9 @@ pub use std::thread::sleep; pub use tracing::{debug, error, info, warn}; pub use crate::chain::driver::ChainDriver; +pub use crate::chain::ext::fee::ChainFeeMethodsExt; +pub use crate::chain::ext::ica::InterchainAccountMethodsExt; +pub use crate::chain::ext::transfer::ChainTransferMethodsExt; pub use crate::chain::tagged::TaggedChainDriverExt; pub use crate::error::{handle_generic_error, Error}; pub use crate::framework::base::HasOverrides; From 0778a1b010fadf5e73788f596a073ddf2fbb9be1 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 25 May 2022 15:03:29 +0200 Subject: [PATCH 031/113] Refactor chain bootstrap CLI functions --- .../test-framework/src/chain/cli/bootstrap.rs | 163 ++++++++++++++++++ tools/test-framework/src/chain/cli/mod.rs | 1 + tools/test-framework/src/chain/driver.rs | 106 +++--------- tools/test-framework/src/chain/mod.rs | 1 + 4 files changed, 189 insertions(+), 82 deletions(-) create mode 100644 tools/test-framework/src/chain/cli/bootstrap.rs create mode 100644 tools/test-framework/src/chain/cli/mod.rs diff --git a/tools/test-framework/src/chain/cli/bootstrap.rs b/tools/test-framework/src/chain/cli/bootstrap.rs new file mode 100644 index 0000000000..447680162f --- /dev/null +++ b/tools/test-framework/src/chain/cli/bootstrap.rs @@ -0,0 +1,163 @@ +use eyre::eyre; +use std::process::{Command, Stdio}; +use std::str; + +use ibc::core::ics24_host::identifier::ChainId; + +use crate::chain::exec::simple_exec; +use crate::error::Error; +use crate::types::process::ChildProcess; +use crate::util::file::pipe_to_file; + +pub fn initialize(chain_id: &ChainId, command_path: &str, home_path: &str) -> Result<(), Error> { + simple_exec( + chain_id.as_str(), + command_path, + &[ + "--home", + home_path, + "--chain-id", + chain_id.as_str(), + "init", + chain_id.as_str(), + ], + )?; + + Ok(()) +} +pub fn add_wallet( + chain_id: &ChainId, + command_path: &str, + home_path: &str, + wallet_id: &str, +) -> Result { + let output = simple_exec( + chain_id.as_str(), + command_path, + &[ + "--home", + home_path, + "keys", + "add", + wallet_id, + "--keyring-backend", + "test", + "--output", + "json", + ], + )?; + + // gaia6 somehow displays result in stderr instead of stdout + if output.stdout.is_empty() { + Ok(output.stderr) + } else { + Ok(output.stdout) + } +} + +pub fn add_genesis_account( + chain_id: &ChainId, + command_path: &str, + home_path: &str, + wallet_address: &str, + amounts: &[String], +) -> Result<(), Error> { + let amounts_str = itertools::join(amounts, ","); + + simple_exec( + chain_id.as_str(), + command_path, + &[ + "--home", + home_path, + "add-genesis-account", + wallet_address, + &amounts_str, + ], + )?; + + Ok(()) +} + +pub fn add_genesis_validator( + chain_id: &ChainId, + command_path: &str, + home_path: &str, + wallet_id: &str, + amount: &str, +) -> Result<(), Error> { + simple_exec( + chain_id.as_str(), + command_path, + &[ + "--home", + home_path, + "gentx", + wallet_id, + "--keyring-backend", + "test", + "--chain-id", + chain_id.as_str(), + amount, + ], + )?; + + Ok(()) +} + +pub fn collect_gen_txs( + chain_id: &ChainId, + command_path: &str, + home_path: &str, +) -> Result<(), Error> { + simple_exec( + chain_id.as_str(), + command_path, + &["--home", home_path, "collect-gentxs"], + )?; + + Ok(()) +} + +pub fn start_chain( + command_path: &str, + home_path: &str, + rpc_listen_address: &str, + grpc_listen_address: &str, +) -> Result { + let base_args = [ + "--home", + home_path, + "start", + "--pruning", + "nothing", + "--grpc.address", + grpc_listen_address, + "--rpc.laddr", + rpc_listen_address, + ]; + + let args: Vec<&str> = base_args.to_vec(); + + let mut child = Command::new(&command_path) + .args(&args) + .stdin(Stdio::null()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn()?; + + let stdout = child + .stdout + .take() + .ok_or_else(|| eyre!("expected stdout to be present in child process"))?; + + let stderr = child + .stderr + .take() + .ok_or_else(|| eyre!("expected stderr to be present in child process"))?; + + pipe_to_file(stdout, &format!("{}/stdout.log", home_path))?; + pipe_to_file(stderr, &format!("{}/stderr.log", home_path))?; + + Ok(ChildProcess::new(child)) +} diff --git a/tools/test-framework/src/chain/cli/mod.rs b/tools/test-framework/src/chain/cli/mod.rs new file mode 100644 index 0000000000..4c8bab29b4 --- /dev/null +++ b/tools/test-framework/src/chain/cli/mod.rs @@ -0,0 +1 @@ +pub mod bootstrap; diff --git a/tools/test-framework/src/chain/driver.rs b/tools/test-framework/src/chain/driver.rs index ab19fe6b14..8b38cdbbf6 100644 --- a/tools/test-framework/src/chain/driver.rs +++ b/tools/test-framework/src/chain/driver.rs @@ -10,7 +10,6 @@ use eyre::eyre; use serde_json as json; use std::fs; use std::path::PathBuf; -use std::process::{Command, Stdio}; use std::str; use tokio::runtime::Runtime; use toml; @@ -22,6 +21,10 @@ use ibc_proto::google::protobuf::Any; use ibc_relayer::chain::cosmos::types::config::TxConfig; use ibc_relayer::keyring::{HDPath, KeyEntry, KeyFile}; +use crate::chain::cli::bootstrap::{ + add_genesis_account, add_genesis_validator, add_wallet, collect_gen_txs, initialize, + start_chain, +}; use crate::chain::exec::{simple_exec, ExecOutput}; use crate::error::{handle_generic_error, Error}; use crate::ibc::denom::Denom; @@ -30,7 +33,6 @@ 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}; -use crate::util::file::pipe_to_file; use crate::util::retry::assert_eventually_succeed; pub mod interchain; @@ -210,16 +212,7 @@ impl ChainDriver { [`bootstrap_single_node`](crate::bootstrap::single::bootstrap_single_node). */ pub fn initialize(&self) -> Result<(), Error> { - self.exec(&[ - "--home", - &self.home_path, - "--chain-id", - self.chain_id.as_str(), - "init", - self.chain_id.as_str(), - ])?; - - Ok(()) + initialize(&self.chain_id, &self.command_path, &self.home_path) } /** @@ -273,24 +266,12 @@ impl ChainDriver { Add a wallet with the given ID to the full node's keyring. */ pub fn add_wallet(&self, wallet_id: &str) -> Result { - let output = self.exec(&[ - "--home", - self.home_path.as_str(), - "keys", - "add", + let seed_content = add_wallet( + &self.chain_id, + &self.command_path, + &self.home_path, wallet_id, - "--keyring-backend", - "test", - "--output", - "json", - ])?; - - // gaia6 somehow displays result in stderr instead of stdout - let seed_content = if output.stdout.is_empty() { - output.stderr - } else { - output.stdout - }; + )?; let json_val: json::Value = json::from_str(&seed_content).map_err(handle_generic_error)?; @@ -323,17 +304,15 @@ impl ChainDriver { wallet: &WalletAddress, amounts: &[&Token], ) -> Result<(), Error> { - let amounts_str = itertools::join(amounts.iter().map(|t| t.to_string()), ","); + let amounts_str = amounts.iter().map(|t| t.to_string()).collect::>(); - self.exec(&[ - "--home", + add_genesis_account( + &self.chain_id, + &self.command_path, &self.home_path, - "add-genesis-account", &wallet.0, &amounts_str, - ])?; - - Ok(()) + ) } /** @@ -341,28 +320,20 @@ impl ChainDriver { for an uninitialized chain. */ pub fn add_genesis_validator(&self, wallet_id: &WalletId, token: &Token) -> Result<(), Error> { - self.exec(&[ - "--home", + add_genesis_validator( + &self.chain_id, + &self.command_path, &self.home_path, - "gentx", &wallet_id.0, - "--keyring-backend", - "test", - "--chain-id", - self.chain_id.as_str(), &token.to_string(), - ])?; - - Ok(()) + ) } /** Call `gaiad collect-gentxs` to generate the genesis transactions. */ pub fn collect_gen_txs(&self) -> Result<(), Error> { - self.exec(&["--home", &self.home_path, "collect-gentxs"])?; - - Ok(()) + collect_gen_txs(&self.chain_id, &self.command_path, &self.home_path) } /** @@ -395,41 +366,12 @@ impl ChainDriver { value is dropped. */ pub fn start(&self) -> Result { - let base_args = [ - "--home", + start_chain( + &self.command_path, &self.home_path, - "start", - "--pruning", - "nothing", - "--grpc.address", - &self.grpc_listen_address(), - "--rpc.laddr", &self.rpc_listen_address(), - ]; - - let args: Vec<&str> = base_args.to_vec(); - - let mut child = Command::new(&self.command_path) - .args(&args) - .stdin(Stdio::null()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn()?; - - let stdout = child - .stdout - .take() - .ok_or_else(|| eyre!("expected stdout to be present in child process"))?; - - let stderr = child - .stderr - .take() - .ok_or_else(|| eyre!("expected stderr to be present in child process"))?; - - pipe_to_file(stdout, &format!("{}/stdout.log", self.home_path))?; - pipe_to_file(stderr, &format!("{}/stderr.log", self.home_path))?; - - Ok(ChildProcess::new(child)) + &self.grpc_listen_address(), + ) } /** diff --git a/tools/test-framework/src/chain/mod.rs b/tools/test-framework/src/chain/mod.rs index 486e56e5cd..a34afa8b72 100644 --- a/tools/test-framework/src/chain/mod.rs +++ b/tools/test-framework/src/chain/mod.rs @@ -15,6 +15,7 @@ */ pub mod builder; +pub mod cli; pub mod config; pub mod driver; pub mod exec; From b3d4b4370344e1ce966e15c20c7c34118d3dbcbe Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 25 May 2022 22:41:27 +0200 Subject: [PATCH 032/113] Move query CLI functions --- .../test-framework/src/chain/cli/bootstrap.rs | 32 ++++++-------- tools/test-framework/src/chain/cli/mod.rs | 1 + tools/test-framework/src/chain/cli/query.rs | 44 +++++++++++++++++++ tools/test-framework/src/chain/driver.rs | 44 ++++++------------- 4 files changed, 71 insertions(+), 50 deletions(-) create mode 100644 tools/test-framework/src/chain/cli/query.rs diff --git a/tools/test-framework/src/chain/cli/bootstrap.rs b/tools/test-framework/src/chain/cli/bootstrap.rs index 447680162f..45732e1bce 100644 --- a/tools/test-framework/src/chain/cli/bootstrap.rs +++ b/tools/test-framework/src/chain/cli/bootstrap.rs @@ -2,37 +2,35 @@ use eyre::eyre; use std::process::{Command, Stdio}; use std::str; -use ibc::core::ics24_host::identifier::ChainId; - use crate::chain::exec::simple_exec; use crate::error::Error; use crate::types::process::ChildProcess; use crate::util::file::pipe_to_file; -pub fn initialize(chain_id: &ChainId, command_path: &str, home_path: &str) -> Result<(), Error> { +pub fn initialize(chain_id: &str, command_path: &str, home_path: &str) -> Result<(), Error> { simple_exec( - chain_id.as_str(), + chain_id, command_path, &[ "--home", home_path, "--chain-id", - chain_id.as_str(), + chain_id, "init", - chain_id.as_str(), + chain_id, ], )?; Ok(()) } pub fn add_wallet( - chain_id: &ChainId, + chain_id: &str, command_path: &str, home_path: &str, wallet_id: &str, ) -> Result { let output = simple_exec( - chain_id.as_str(), + chain_id, command_path, &[ "--home", @@ -56,7 +54,7 @@ pub fn add_wallet( } pub fn add_genesis_account( - chain_id: &ChainId, + chain_id: &str, command_path: &str, home_path: &str, wallet_address: &str, @@ -65,7 +63,7 @@ pub fn add_genesis_account( let amounts_str = itertools::join(amounts, ","); simple_exec( - chain_id.as_str(), + chain_id, command_path, &[ "--home", @@ -80,14 +78,14 @@ pub fn add_genesis_account( } pub fn add_genesis_validator( - chain_id: &ChainId, + chain_id: &str, command_path: &str, home_path: &str, wallet_id: &str, amount: &str, ) -> Result<(), Error> { simple_exec( - chain_id.as_str(), + chain_id, command_path, &[ "--home", @@ -97,7 +95,7 @@ pub fn add_genesis_validator( "--keyring-backend", "test", "--chain-id", - chain_id.as_str(), + chain_id, amount, ], )?; @@ -105,13 +103,9 @@ pub fn add_genesis_validator( Ok(()) } -pub fn collect_gen_txs( - chain_id: &ChainId, - command_path: &str, - home_path: &str, -) -> Result<(), Error> { +pub fn collect_gen_txs(chain_id: &str, command_path: &str, home_path: &str) -> Result<(), Error> { simple_exec( - chain_id.as_str(), + chain_id, command_path, &["--home", home_path, "collect-gentxs"], )?; diff --git a/tools/test-framework/src/chain/cli/mod.rs b/tools/test-framework/src/chain/cli/mod.rs index 4c8bab29b4..7b362c2aed 100644 --- a/tools/test-framework/src/chain/cli/mod.rs +++ b/tools/test-framework/src/chain/cli/mod.rs @@ -1 +1,2 @@ pub mod bootstrap; +pub mod query; diff --git a/tools/test-framework/src/chain/cli/query.rs b/tools/test-framework/src/chain/cli/query.rs new file mode 100644 index 0000000000..70e6c53353 --- /dev/null +++ b/tools/test-framework/src/chain/cli/query.rs @@ -0,0 +1,44 @@ +use core::str::FromStr; +use eyre::eyre; +use serde_json as json; + +use crate::chain::exec::simple_exec; +use crate::error::{handle_generic_error, Error}; + +pub fn query_balance( + chain_id: &str, + command_path: &str, + rpc_listen_address: &str, + wallet_id: &str, + denom: &str, +) -> Result { + let res = simple_exec( + chain_id, + command_path, + &[ + "--node", + rpc_listen_address, + "query", + "bank", + "balances", + wallet_id, + "--denom", + denom, + "--output", + "json", + ], + )? + .stdout; + + let amount_str = json::from_str::(&res) + .map_err(handle_generic_error)? + .get("amount") + .ok_or_else(|| eyre!("expected amount field"))? + .as_str() + .ok_or_else(|| eyre!("expected string field"))? + .to_string(); + + let amount = u128::from_str(&amount_str).map_err(handle_generic_error)?; + + Ok(amount) +} diff --git a/tools/test-framework/src/chain/driver.rs b/tools/test-framework/src/chain/driver.rs index 8b38cdbbf6..6069f0346c 100644 --- a/tools/test-framework/src/chain/driver.rs +++ b/tools/test-framework/src/chain/driver.rs @@ -25,6 +25,7 @@ use crate::chain::cli::bootstrap::{ add_genesis_account, add_genesis_validator, add_wallet, collect_gen_txs, initialize, start_chain, }; +use crate::chain::cli::query::query_balance; use crate::chain::exec::{simple_exec, ExecOutput}; use crate::error::{handle_generic_error, Error}; use crate::ibc::denom::Denom; @@ -212,7 +213,7 @@ impl ChainDriver { [`bootstrap_single_node`](crate::bootstrap::single::bootstrap_single_node). */ pub fn initialize(&self) -> Result<(), Error> { - initialize(&self.chain_id, &self.command_path, &self.home_path) + initialize(self.chain_id.as_str(), &self.command_path, &self.home_path) } /** @@ -267,7 +268,7 @@ impl ChainDriver { */ pub fn add_wallet(&self, wallet_id: &str) -> Result { let seed_content = add_wallet( - &self.chain_id, + self.chain_id.as_str(), &self.command_path, &self.home_path, wallet_id, @@ -307,7 +308,7 @@ impl ChainDriver { let amounts_str = amounts.iter().map(|t| t.to_string()).collect::>(); add_genesis_account( - &self.chain_id, + self.chain_id.as_str(), &self.command_path, &self.home_path, &wallet.0, @@ -321,7 +322,7 @@ impl ChainDriver { */ pub fn add_genesis_validator(&self, wallet_id: &WalletId, token: &Token) -> Result<(), Error> { add_genesis_validator( - &self.chain_id, + self.chain_id.as_str(), &self.command_path, &self.home_path, &wallet_id.0, @@ -333,7 +334,7 @@ impl ChainDriver { Call `gaiad collect-gentxs` to generate the genesis transactions. */ pub fn collect_gen_txs(&self) -> Result<(), Error> { - collect_gen_txs(&self.chain_id, &self.command_path, &self.home_path) + collect_gen_txs(self.chain_id.as_str(), &self.command_path, &self.home_path) } /** @@ -378,32 +379,13 @@ impl ChainDriver { Query for the balances for a given wallet address and denomination */ pub fn query_balance(&self, wallet_id: &WalletAddress, denom: &Denom) -> Result { - let res = self - .exec(&[ - "--node", - &self.rpc_listen_address(), - "query", - "bank", - "balances", - &wallet_id.0, - "--denom", - denom.as_str(), - "--output", - "json", - ])? - .stdout; - - let amount_str = json::from_str::(&res) - .map_err(handle_generic_error)? - .get("amount") - .ok_or_else(|| eyre!("expected amount field"))? - .as_str() - .ok_or_else(|| eyre!("expected string field"))? - .to_string(); - - let amount = u128::from_str(&amount_str).map_err(handle_generic_error)?; - - Ok(amount) + query_balance( + self.chain_id.as_str(), + &self.command_path, + &self.rpc_listen_address(), + &wallet_id.0, + &denom.to_string(), + ) } pub fn send_tx(&self, wallet: &Wallet, messages: Vec) -> Result, Error> { From fecaf7cad1a2daf4e936c67e6601aa36a4adadbc Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 25 May 2022 23:11:32 +0200 Subject: [PATCH 033/113] Refactor all remaining CLI methods --- .../{driver/interchain.rs => cli/ica.rs} | 81 ++++++++++--------- tools/test-framework/src/chain/cli/mod.rs | 2 + tools/test-framework/src/chain/cli/query.rs | 53 ++++++++++++ .../test-framework/src/chain/cli/transfer.rs | 40 +++++++++ tools/test-framework/src/chain/driver.rs | 4 - .../src/chain/driver/query_txs.rs | 58 ------------- .../src/chain/driver/transfer.rs | 36 --------- tools/test-framework/src/chain/ext/ica.rs | 38 +++++++-- .../test-framework/src/chain/ext/transfer.rs | 14 ++-- tools/test-framework/src/chain/tagged.rs | 10 ++- tools/test-framework/src/types/wallet.rs | 8 +- 11 files changed, 193 insertions(+), 151 deletions(-) rename tools/test-framework/src/chain/{driver/interchain.rs => cli/ica.rs} (66%) create mode 100644 tools/test-framework/src/chain/cli/transfer.rs delete mode 100644 tools/test-framework/src/chain/driver/query_txs.rs delete mode 100644 tools/test-framework/src/chain/driver/transfer.rs diff --git a/tools/test-framework/src/chain/driver/interchain.rs b/tools/test-framework/src/chain/cli/ica.rs similarity index 66% rename from tools/test-framework/src/chain/driver/interchain.rs rename to tools/test-framework/src/chain/cli/ica.rs index 80480e36d4..ec5c675547 100644 --- a/tools/test-framework/src/chain/driver/interchain.rs +++ b/tools/test-framework/src/chain/cli/ica.rs @@ -1,43 +1,41 @@ use eyre::eyre; -use serde::Serialize; use serde_json as json; -use ibc::core::ics24_host::identifier::ConnectionId; - +use crate::chain::exec::simple_exec; use crate::error::{handle_generic_error, Error}; -use crate::prelude::WalletAddress; - -use super::ChainDriver; /// Register a new interchain account controlled by the given account /// over the given connection. pub fn register_interchain_account( - driver: &ChainDriver, - from: &WalletAddress, - connection_id: &ConnectionId, + chain_id: &str, + command_path: &str, + home_path: &str, + rpc_listen_address: &str, + from: &str, + connection_id: &str, ) -> Result<(), Error> { let args = &[ "--home", - &driver.home_path, + home_path, "--node", - &driver.rpc_listen_address(), + rpc_listen_address, "--output", "json", "tx", "intertx", "register", "--from", - &from.0, + from, "--connection-id", - connection_id.as_str(), + connection_id, "--chain-id", - driver.chain_id.as_str(), + chain_id, "--keyring-backend", "test", "-y", ]; - let res = driver.exec(args)?.stdout; + let res = simple_exec(chain_id, command_path, args)?.stdout; check_result_code(&res)?; Ok(()) @@ -46,25 +44,28 @@ pub fn register_interchain_account( /// Query the address of the interchain account /// corresponding to the given controller account. pub fn query_interchain_account( - driver: &ChainDriver, - account: &WalletAddress, - connection_id: &ConnectionId, -) -> Result { + chain_id: &str, + command_path: &str, + home_path: &str, + rpc_listen_address: &str, + account: &str, + connection_id: &str, +) -> Result { let args = &[ "--home", - &driver.home_path, + home_path, "--node", - &driver.rpc_listen_address(), + rpc_listen_address, "--output", "json", "query", "intertx", "interchainaccounts", - connection_id.as_str(), - &account.0, + connection_id, + account, ]; - let res = driver.exec(args)?.stdout; + let res = simple_exec(chain_id, command_path, args)?.stdout; let json_res = json::from_str::(&res).map_err(handle_generic_error)?; let address = json_res @@ -73,43 +74,43 @@ pub fn query_interchain_account( .as_str() .ok_or_else(|| eyre!("expected string field"))?; - Ok(WalletAddress(address.to_string())) + Ok(address.to_string()) } /// Submit a msg from a controller account over an ICA channel /// using the given connection. -pub fn interchain_submit( - driver: &ChainDriver, - from: &WalletAddress, - connection_id: &ConnectionId, - msg: &T, +pub fn interchain_submit( + chain_id: &str, + command_path: &str, + home_path: &str, + rpc_listen_address: &str, + from: &str, + connection_id: &str, + msg: &str, ) -> Result<(), Error> { - let msg_json = serde_json::to_string_pretty(msg).unwrap(); - println!("{}", msg_json); - let args = &[ "--home", - &driver.home_path, + home_path, "--node", - &driver.rpc_listen_address(), + rpc_listen_address, "--output", "json", "tx", "intertx", "submit", - &msg_json, + msg, "--connection-id", - connection_id.as_str(), + connection_id, "--from", - &from.0, + from, "--chain-id", - driver.chain_id.as_str(), + chain_id, "--keyring-backend", "test", "-y", ]; - let res = driver.exec(args)?.stdout; + let res = simple_exec(chain_id, command_path, args)?.stdout; check_result_code(&res)?; Ok(()) diff --git a/tools/test-framework/src/chain/cli/mod.rs b/tools/test-framework/src/chain/cli/mod.rs index 7b362c2aed..8973d9825d 100644 --- a/tools/test-framework/src/chain/cli/mod.rs +++ b/tools/test-framework/src/chain/cli/mod.rs @@ -1,2 +1,4 @@ pub mod bootstrap; +pub mod ica; pub mod query; +pub mod transfer; diff --git a/tools/test-framework/src/chain/cli/query.rs b/tools/test-framework/src/chain/cli/query.rs index 70e6c53353..7cf556d576 100644 --- a/tools/test-framework/src/chain/cli/query.rs +++ b/tools/test-framework/src/chain/cli/query.rs @@ -1,6 +1,7 @@ use core::str::FromStr; use eyre::eyre; use serde_json as json; +use serde_yaml as yaml; use crate::chain::exec::simple_exec; use crate::error::{handle_generic_error, Error}; @@ -42,3 +43,55 @@ pub fn query_balance( Ok(amount) } + +/** + Query for the transactions related to a wallet on `Chain` + receiving token transfer from others. +*/ +pub fn query_recipient_transactions( + chain_id: &str, + command_path: &str, + rpc_listen_address: &str, + recipient_address: &str, +) -> Result { + let res = simple_exec( + chain_id, + command_path, + &[ + "--node", + rpc_listen_address, + "query", + "txs", + "--events", + &format!("transfer.recipient={}", recipient_address), + ], + )? + .stdout; + + tracing::debug!("parsing tx result: {}", res); + + match json::from_str(&res) { + Ok(res) => Ok(res), + _ => { + let value: yaml::Value = yaml::from_str(&res).map_err(handle_generic_error)?; + Ok(yaml_to_json_value(value)?) + } + } +} + +// Hack to convert yaml::Value to json::Value. Unfortunately there is +// no builtin conversion provided even though both Value types are +// essentially the same. We just convert the two types to and from +// strings as a shortcut. +// +// TODO: properly implement a common trait that is implemented by +// dynamic types like json::Value, yaml::Value, and toml::Value. +// That way we can write generic functions that work with any of +// the dynamic value types for testing purposes. +fn yaml_to_json_value(value: yaml::Value) -> Result { + let json_str = json::to_string(&value).map_err(handle_generic_error)?; + + let parsed = json::from_str(&json_str).map_err(handle_generic_error)?; + + Ok(parsed) +} diff --git a/tools/test-framework/src/chain/cli/transfer.rs b/tools/test-framework/src/chain/cli/transfer.rs new file mode 100644 index 0000000000..287e516d4b --- /dev/null +++ b/tools/test-framework/src/chain/cli/transfer.rs @@ -0,0 +1,40 @@ +/*! + Methods for performing IBC token transfer on a chain. +*/ + +use crate::chain::exec::simple_exec; +use crate::error::Error; + +pub fn local_transfer_token( + chain_id: &str, + command_path: &str, + home_path: &str, + rpc_listen_address: &str, + sender: &str, + recipient: &str, + token: &str, +) -> Result<(), Error> { + simple_exec( + chain_id, + command_path, + &[ + "--node", + rpc_listen_address, + "tx", + "bank", + "send", + sender, + recipient, + token, + "--chain-id", + chain_id, + "--home", + home_path, + "--keyring-backend", + "test", + "--yes", + ], + )?; + + Ok(()) +} diff --git a/tools/test-framework/src/chain/driver.rs b/tools/test-framework/src/chain/driver.rs index 6069f0346c..ed23480701 100644 --- a/tools/test-framework/src/chain/driver.rs +++ b/tools/test-framework/src/chain/driver.rs @@ -36,10 +36,6 @@ use crate::types::process::ChildProcess; use crate::types::wallet::{Wallet, WalletAddress, WalletId}; use crate::util::retry::assert_eventually_succeed; -pub mod interchain; -pub mod query_txs; -pub mod transfer; - /** Number of times (seconds) to try and query a wallet to reach the target amount, as used by [`assert_eventual_wallet_amount`]. diff --git a/tools/test-framework/src/chain/driver/query_txs.rs b/tools/test-framework/src/chain/driver/query_txs.rs deleted file mode 100644 index d824e9bc9a..0000000000 --- a/tools/test-framework/src/chain/driver/query_txs.rs +++ /dev/null @@ -1,58 +0,0 @@ -/*! - Methods for querying transactions on a chain. -*/ - -use serde_json as json; -use serde_yaml as yaml; - -use crate::error::{handle_generic_error, Error}; -use crate::types::wallet::WalletAddress; - -use super::ChainDriver; - -/** - Query for the transactions related to a wallet on `Chain` - receiving token transfer from others. -*/ -pub fn query_recipient_transactions( - driver: &ChainDriver, - recipient_address: &WalletAddress, -) -> Result { - let res = driver - .exec(&[ - "--node", - &driver.rpc_listen_address(), - "query", - "txs", - "--events", - &format!("transfer.recipient={}", recipient_address), - ])? - .stdout; - - tracing::debug!("parsing tx result: {}", res); - - match json::from_str(&res) { - Ok(res) => Ok(res), - _ => { - let value: yaml::Value = yaml::from_str(&res).map_err(handle_generic_error)?; - Ok(yaml_to_json_value(value)?) - } - } -} - -// Hack to convert yaml::Value to json::Value. Unfortunately there is -// no builtin conversion provided even though both Value types are -// essentially the same. We just convert the two types to and from -// strings as a shortcut. -// -// TODO: properly implement a common trait that is implemented by -// dynamic types like json::Value, yaml::Value, and toml::Value. -// That way we can write generic functions that work with any of -// the dynamic value types for testing purposes. -fn yaml_to_json_value(value: yaml::Value) -> Result { - let json_str = json::to_string(&value).map_err(handle_generic_error)?; - - let parsed = json::from_str(&json_str).map_err(handle_generic_error)?; - - Ok(parsed) -} diff --git a/tools/test-framework/src/chain/driver/transfer.rs b/tools/test-framework/src/chain/driver/transfer.rs deleted file mode 100644 index 58cdfda73b..0000000000 --- a/tools/test-framework/src/chain/driver/transfer.rs +++ /dev/null @@ -1,36 +0,0 @@ -/*! - Methods for performing IBC token transfer on a chain. -*/ - -use crate::error::Error; -use crate::ibc::token::Token; -use crate::types::wallet::{Wallet, WalletAddress}; - -use super::ChainDriver; - -pub fn local_transfer_token( - driver: &ChainDriver, - sender: &Wallet, - recipient: &WalletAddress, - token: &Token, -) -> Result<(), Error> { - driver.exec(&[ - "--node", - &driver.rpc_listen_address(), - "tx", - "bank", - "send", - &sender.address.0, - &recipient.0, - &token.to_string(), - "--chain-id", - driver.chain_id.as_str(), - "--home", - &driver.home_path, - "--keyring-backend", - "test", - "--yes", - ])?; - - Ok(()) -} diff --git a/tools/test-framework/src/chain/ext/ica.rs b/tools/test-framework/src/chain/ext/ica.rs index c730c5e847..2395a77121 100644 --- a/tools/test-framework/src/chain/ext/ica.rs +++ b/tools/test-framework/src/chain/ext/ica.rs @@ -1,6 +1,6 @@ use serde::Serialize; -use crate::chain::driver::interchain::{ +use crate::chain::cli::ica::{ interchain_submit, query_interchain_account, register_interchain_account, }; use crate::chain::driver::ChainDriver; @@ -36,7 +36,15 @@ impl<'a, Chain: Send> InterchainAccountMethodsExt for MonoTagged, connection_id: &TaggedConnectionIdRef, ) -> Result<(), Error> { - register_interchain_account(self.value(), from.value(), connection_id.value()) + let driver = *self.value(); + register_interchain_account( + driver.chain_id.as_str(), + &driver.command_path, + &driver.home_path, + &driver.rpc_listen_address(), + from.value().as_str(), + connection_id.value().as_str(), + ) } fn query_interchain_account( @@ -44,8 +52,17 @@ impl<'a, Chain: Send> InterchainAccountMethodsExt for MonoTagged, connection_id: &TaggedConnectionIdRef, ) -> Result, Error> { - query_interchain_account(self.value(), from.value(), connection_id.value()) - .map(MonoTagged::new) + let driver = *self.value(); + let address = query_interchain_account( + driver.chain_id.as_str(), + &driver.command_path, + &driver.home_path, + &driver.rpc_listen_address(), + from.value().as_str(), + connection_id.value().as_str(), + )?; + + Ok(MonoTagged::new(WalletAddress(address))) } fn interchain_submit( @@ -54,6 +71,17 @@ impl<'a, Chain: Send> InterchainAccountMethodsExt for MonoTagged, msg: &T, ) -> Result<(), Error> { - interchain_submit(self.value(), from.value(), connection_id.value(), msg) + let driver = *self.value(); + let msg_json = serde_json::to_string_pretty(msg).unwrap(); + + interchain_submit( + driver.chain_id.as_str(), + &driver.command_path, + &driver.home_path, + &driver.rpc_listen_address(), + from.value().as_str(), + connection_id.value().as_str(), + &msg_json, + ) } } diff --git a/tools/test-framework/src/chain/ext/transfer.rs b/tools/test-framework/src/chain/ext/transfer.rs index 115b1d2e57..c838ab637f 100644 --- a/tools/test-framework/src/chain/ext/transfer.rs +++ b/tools/test-framework/src/chain/ext/transfer.rs @@ -1,4 +1,4 @@ -use crate::chain::driver::transfer::local_transfer_token; +use crate::chain::cli::transfer::local_transfer_token; use crate::chain::driver::ChainDriver; use crate::chain::tagged::TaggedChainDriverExt; use crate::error::Error; @@ -71,11 +71,15 @@ impl<'a, Chain: Send> ChainTransferMethodsExt for MonoTagged, token: &TaggedTokenRef, ) -> Result<(), Error> { + let driver = *self.value(); local_transfer_token( - self.value(), - sender.value(), - recipient.value(), - token.value(), + driver.chain_id.as_str(), + &driver.command_path, + &driver.home_path, + &driver.rpc_listen_address(), + sender.value().address.as_str(), + recipient.value().as_str(), + &token.value().to_string(), ) } } diff --git a/tools/test-framework/src/chain/tagged.rs b/tools/test-framework/src/chain/tagged.rs index 44bd84eac8..3a42cbec39 100644 --- a/tools/test-framework/src/chain/tagged.rs +++ b/tools/test-framework/src/chain/tagged.rs @@ -7,7 +7,7 @@ use ibc_proto::google::protobuf::Any; use ibc_relayer::chain::cosmos::types::config::TxConfig; use serde_json as json; -use crate::chain::driver::query_txs::query_recipient_transactions; +use crate::chain::cli::query::query_recipient_transactions; use crate::chain::driver::ChainDriver; use crate::error::Error; use crate::ibc::denom::Denom; @@ -114,6 +114,12 @@ impl<'a, Chain: Send> TaggedChainDriverExt for MonoTagged, ) -> Result { - query_recipient_transactions(self.value(), recipient_address.value()) + let driver = *self.value(); + query_recipient_transactions( + driver.chain_id.as_str(), + &driver.command_path, + &driver.rpc_listen_address(), + &recipient_address.value().0, + ) } } diff --git a/tools/test-framework/src/types/wallet.rs b/tools/test-framework/src/types/wallet.rs index c9a6c950f5..2ec15d0e37 100644 --- a/tools/test-framework/src/types/wallet.rs +++ b/tools/test-framework/src/types/wallet.rs @@ -2,10 +2,10 @@ Types for information about a chain wallet. */ -use crate::types::env::{prefix_writer, EnvWriter, ExportEnv}; use core::fmt::{self, Display}; use ibc_relayer::keyring::KeyEntry; +use crate::types::env::{prefix_writer, EnvWriter, ExportEnv}; use crate::types::tagged::*; /** @@ -115,6 +115,12 @@ impl Wallet { } } +impl WalletAddress { + pub fn as_str(&self) -> &str { + self.0.as_str() + } +} + impl TaggedWallet for MonoTagged { fn id(&self) -> MonoTagged { self.map_ref(|w| &w.id) From 7c29f5c5c2f4a0b47c314eab5bb7fccf17469105 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 25 May 2022 23:26:35 +0200 Subject: [PATCH 034/113] Refactor ChainDriver bootstrap methods into extension trait --- tools/test-framework/src/bootstrap/single.rs | 1 + tools/test-framework/src/chain/driver.rs | 214 +---------------- .../test-framework/src/chain/ext/bootstrap.rs | 220 ++++++++++++++++++ tools/test-framework/src/chain/ext/mod.rs | 1 + tools/test-framework/src/chain/tagged.rs | 7 +- 5 files changed, 231 insertions(+), 212 deletions(-) create mode 100644 tools/test-framework/src/chain/ext/bootstrap.rs diff --git a/tools/test-framework/src/bootstrap/single.rs b/tools/test-framework/src/bootstrap/single.rs index d8b88c88b4..8280c0101f 100644 --- a/tools/test-framework/src/bootstrap/single.rs +++ b/tools/test-framework/src/bootstrap/single.rs @@ -9,6 +9,7 @@ use tracing::info; use crate::chain::builder::ChainBuilder; use crate::chain::config; use crate::chain::driver::ChainDriver; +use crate::chain::ext::bootstrap::ChainBootstrapMethodsExt; use crate::error::Error; use crate::ibc::denom::Denom; use crate::ibc::token::Token; diff --git a/tools/test-framework/src/chain/driver.rs b/tools/test-framework/src/chain/driver.rs index ed23480701..251bd964e6 100644 --- a/tools/test-framework/src/chain/driver.rs +++ b/tools/test-framework/src/chain/driver.rs @@ -2,38 +2,22 @@ Implementation of [`ChainDriver`]. */ -use core::str::FromStr; use core::time::Duration; use alloc::sync::Arc; use eyre::eyre; -use serde_json as json; -use std::fs; -use std::path::PathBuf; -use std::str; use tokio::runtime::Runtime; -use toml; -use tracing::debug; use ibc::core::ics24_host::identifier::ChainId; -use ibc::events::IbcEvent; -use ibc_proto::google::protobuf::Any; use ibc_relayer::chain::cosmos::types::config::TxConfig; -use ibc_relayer::keyring::{HDPath, KeyEntry, KeyFile}; -use crate::chain::cli::bootstrap::{ - add_genesis_account, add_genesis_validator, add_wallet, collect_gen_txs, initialize, - start_chain, -}; use crate::chain::cli::query::query_balance; -use crate::chain::exec::{simple_exec, ExecOutput}; -use crate::error::{handle_generic_error, Error}; +use crate::error::Error; use crate::ibc::denom::Denom; use crate::ibc::token::Token; -use crate::relayer::tx::{new_tx_config_for_test, simple_send_tx}; +use crate::relayer::tx::new_tx_config_for_test; use crate::types::env::{EnvWriter, ExportEnv}; -use crate::types::process::ChildProcess; -use crate::types::wallet::{Wallet, WalletAddress, WalletId}; +use crate::types::wallet::WalletAddress; use crate::util::retry::assert_eventually_succeed; /** @@ -49,8 +33,6 @@ use crate::util::retry::assert_eventually_succeed; */ const WAIT_WALLET_AMOUNT_ATTEMPTS: u16 = 180; -const COSMOS_HD_PATH: &str = "m/44'/118'/0'/0/0"; - /** A driver for interacting with a chain full nodes through command line. @@ -186,191 +168,6 @@ impl ChainDriver { format!("localhost:{}", self.grpc_port) } - /** - Execute the gaiad command with the given command line arguments, and - returns the STDOUT result as String. - - This is not the most efficient way of interacting with the CLI, but - is sufficient for testing purposes of interacting with the `gaiad` - commmand. - - The function also output debug logs that show what command is being - executed, so that users can manually re-run the commands by - copying from the logs. - */ - pub fn exec(&self, args: &[&str]) -> Result { - simple_exec(self.chain_id.as_str(), &self.command_path, args) - } - - /** - Initialized the chain data stores. - - This is used by - [`bootstrap_single_node`](crate::bootstrap::single::bootstrap_single_node). - */ - pub fn initialize(&self) -> Result<(), Error> { - initialize(self.chain_id.as_str(), &self.command_path, &self.home_path) - } - - /** - Modify the Gaia genesis file. - */ - pub fn update_genesis_file( - &self, - file: &str, - cont: impl FnOnce(&mut serde_json::Value) -> Result<(), Error>, - ) -> Result<(), Error> { - let config1 = self.read_file(&format!("config/{}", file))?; - - let mut config2 = serde_json::from_str(&config1).map_err(handle_generic_error)?; - - cont(&mut config2)?; - - let config3 = serde_json::to_string_pretty(&config2).map_err(handle_generic_error)?; - - self.write_file("config/genesis.json", &config3)?; - - Ok(()) - } - - /** - Write the string content to a file path relative to the chain home - directory. - - This is not efficient but is sufficient for testing purposes. - */ - pub fn write_file(&self, file_path: &str, content: &str) -> Result<(), Error> { - let full_path = PathBuf::from(&self.home_path).join(file_path); - let full_path_str = format!("{}", full_path.display()); - fs::write(full_path, content)?; - debug!("created new file {:?}", full_path_str); - Ok(()) - } - - /** - Read the content at a file path relative to the chain home - directory, and return the result as a string. - - This is not efficient but is sufficient for testing purposes. - */ - pub fn read_file(&self, file_path: &str) -> Result { - let full_path = PathBuf::from(&self.home_path).join(file_path); - let res = fs::read_to_string(full_path)?; - Ok(res) - } - - /** - Add a wallet with the given ID to the full node's keyring. - */ - pub fn add_wallet(&self, wallet_id: &str) -> Result { - let seed_content = add_wallet( - self.chain_id.as_str(), - &self.command_path, - &self.home_path, - wallet_id, - )?; - - let json_val: json::Value = json::from_str(&seed_content).map_err(handle_generic_error)?; - - let wallet_address = json_val - .get("address") - .ok_or_else(|| eyre!("expect address string field to be present in json result"))? - .as_str() - .ok_or_else(|| eyre!("expect address string field to be present in json result"))? - .to_string(); - - let seed_path = format!("{}-seed.json", wallet_id); - self.write_file(&seed_path, &seed_content)?; - - let hd_path = HDPath::from_str(COSMOS_HD_PATH) - .map_err(|e| eyre!("failed to create HDPath: {:?}", e))?; - - let key_file: KeyFile = json::from_str(&seed_content).map_err(handle_generic_error)?; - - let key = KeyEntry::from_key_file(key_file, &hd_path).map_err(handle_generic_error)?; - - Ok(Wallet::new(wallet_id.to_string(), wallet_address, key)) - } - - /** - Add a wallet address to the genesis account list for an uninitialized - full node. - */ - pub fn add_genesis_account( - &self, - wallet: &WalletAddress, - amounts: &[&Token], - ) -> Result<(), Error> { - let amounts_str = amounts.iter().map(|t| t.to_string()).collect::>(); - - add_genesis_account( - self.chain_id.as_str(), - &self.command_path, - &self.home_path, - &wallet.0, - &amounts_str, - ) - } - - /** - Add a wallet ID with the given stake amount to be the genesis validator - for an uninitialized chain. - */ - pub fn add_genesis_validator(&self, wallet_id: &WalletId, token: &Token) -> Result<(), Error> { - add_genesis_validator( - self.chain_id.as_str(), - &self.command_path, - &self.home_path, - &wallet_id.0, - &token.to_string(), - ) - } - - /** - Call `gaiad collect-gentxs` to generate the genesis transactions. - */ - pub fn collect_gen_txs(&self) -> Result<(), Error> { - collect_gen_txs(self.chain_id.as_str(), &self.command_path, &self.home_path) - } - - /** - Modify the Gaia chain config which is saved in toml format. - */ - pub fn update_chain_config( - &self, - file: &str, - cont: impl FnOnce(&mut toml::Value) -> Result<(), Error>, - ) -> Result<(), Error> { - 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)?; - - cont(&mut config2)?; - - let config3 = toml::to_string_pretty(&config2).map_err(handle_generic_error)?; - - self.write_file(&config_path, &config3)?; - - Ok(()) - } - - /** - Start a full node by running in the background `gaiad start`. - - Returns a [`ChildProcess`] that stops the full node process when the - value is dropped. - */ - pub fn start(&self) -> Result { - start_chain( - &self.command_path, - &self.home_path, - &self.rpc_listen_address(), - &self.grpc_listen_address(), - ) - } - /** Query for the balances for a given wallet address and denomination */ @@ -384,11 +181,6 @@ impl ChainDriver { ) } - pub fn send_tx(&self, wallet: &Wallet, messages: Vec) -> Result, Error> { - self.runtime - .block_on(simple_send_tx(&self.tx_config, &wallet.key, messages)) - } - /** Assert that a wallet should eventually have the expected amount in the given denomination. diff --git a/tools/test-framework/src/chain/ext/bootstrap.rs b/tools/test-framework/src/chain/ext/bootstrap.rs new file mode 100644 index 0000000000..ee28d533af --- /dev/null +++ b/tools/test-framework/src/chain/ext/bootstrap.rs @@ -0,0 +1,220 @@ +use core::str::FromStr; + +use eyre::eyre; +use serde_json as json; +use std::fs; +use std::path::PathBuf; +use std::str; +use toml; +use tracing::debug; + +use ibc_relayer::keyring::{HDPath, KeyEntry, KeyFile}; + +use crate::chain::cli::bootstrap::{ + add_genesis_account, add_genesis_validator, add_wallet, collect_gen_txs, initialize, + start_chain, +}; +use crate::chain::driver::ChainDriver; +use crate::error::{handle_generic_error, Error}; +use crate::ibc::token::Token; +use crate::types::process::ChildProcess; +use crate::types::wallet::{Wallet, WalletAddress, WalletId}; + +const COSMOS_HD_PATH: &str = "m/44'/118'/0'/0/0"; + +pub trait ChainBootstrapMethodsExt { + /** + Read the content at a file path relative to the chain home + directory, and return the result as a string. + + This is not efficient but is sufficient for testing purposes. + */ + fn read_file(&self, file_path: &str) -> Result; + + /** + Write the string content to a file path relative to the chain home + directory. + + This is not efficient but is sufficient for testing purposes. + */ + fn write_file(&self, file_path: &str, content: &str) -> Result<(), Error>; + + /** + Modify the Gaia chain config which is saved in toml format. + */ + fn update_chain_config( + &self, + file: &str, + cont: impl FnOnce(&mut toml::Value) -> Result<(), Error>, + ) -> Result<(), Error>; + + /** + Initialized the chain data stores. + + This is used by + [`bootstrap_single_node`](crate::bootstrap::single::bootstrap_single_node). + */ + fn initialize(&self) -> Result<(), Error>; + + /** + Modify the Gaia genesis file. + */ + fn update_genesis_file( + &self, + file: &str, + cont: impl FnOnce(&mut serde_json::Value) -> Result<(), Error>, + ) -> Result<(), Error>; + + /** + Add a wallet with the given ID to the full node's keyring. + */ + fn add_wallet(&self, wallet_id: &str) -> Result; + + /** + Add a wallet address to the genesis account list for an uninitialized + full node. + */ + fn add_genesis_account(&self, wallet: &WalletAddress, amounts: &[&Token]) -> Result<(), Error>; + + /** + Add a wallet ID with the given stake amount to be the genesis validator + for an uninitialized chain. + */ + fn add_genesis_validator(&self, wallet_id: &WalletId, token: &Token) -> Result<(), Error>; + + /** + Call `gaiad collect-gentxs` to generate the genesis transactions. + */ + fn collect_gen_txs(&self) -> Result<(), Error>; + + /** + Start a full node by running in the background `gaiad start`. + + Returns a [`ChildProcess`] that stops the full node process when the + value is dropped. + */ + fn start(&self) -> Result; +} + +impl ChainBootstrapMethodsExt for ChainDriver { + fn read_file(&self, file_path: &str) -> Result { + let full_path = PathBuf::from(&self.home_path).join(file_path); + let res = fs::read_to_string(full_path)?; + Ok(res) + } + + fn write_file(&self, file_path: &str, content: &str) -> Result<(), Error> { + let full_path = PathBuf::from(&self.home_path).join(file_path); + let full_path_str = format!("{}", full_path.display()); + fs::write(full_path, content)?; + debug!("created new file {:?}", full_path_str); + Ok(()) + } + + fn update_chain_config( + &self, + file: &str, + cont: impl FnOnce(&mut toml::Value) -> Result<(), Error>, + ) -> Result<(), Error> { + 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)?; + + cont(&mut config2)?; + + let config3 = toml::to_string_pretty(&config2).map_err(handle_generic_error)?; + + self.write_file(&config_path, &config3)?; + + Ok(()) + } + + fn initialize(&self) -> Result<(), Error> { + initialize(self.chain_id.as_str(), &self.command_path, &self.home_path) + } + + fn update_genesis_file( + &self, + file: &str, + cont: impl FnOnce(&mut serde_json::Value) -> Result<(), Error>, + ) -> Result<(), Error> { + let config1 = self.read_file(&format!("config/{}", file))?; + + let mut config2 = serde_json::from_str(&config1).map_err(handle_generic_error)?; + + cont(&mut config2)?; + + let config3 = serde_json::to_string_pretty(&config2).map_err(handle_generic_error)?; + + self.write_file("config/genesis.json", &config3)?; + + Ok(()) + } + + fn add_wallet(&self, wallet_id: &str) -> Result { + let seed_content = add_wallet( + self.chain_id.as_str(), + &self.command_path, + &self.home_path, + wallet_id, + )?; + + let json_val: json::Value = json::from_str(&seed_content).map_err(handle_generic_error)?; + + let wallet_address = json_val + .get("address") + .ok_or_else(|| eyre!("expect address string field to be present in json result"))? + .as_str() + .ok_or_else(|| eyre!("expect address string field to be present in json result"))? + .to_string(); + + let seed_path = format!("{}-seed.json", wallet_id); + self.write_file(&seed_path, &seed_content)?; + + let hd_path = HDPath::from_str(COSMOS_HD_PATH) + .map_err(|e| eyre!("failed to create HDPath: {:?}", e))?; + + let key_file: KeyFile = json::from_str(&seed_content).map_err(handle_generic_error)?; + + let key = KeyEntry::from_key_file(key_file, &hd_path).map_err(handle_generic_error)?; + + Ok(Wallet::new(wallet_id.to_string(), wallet_address, key)) + } + + fn add_genesis_account(&self, wallet: &WalletAddress, amounts: &[&Token]) -> Result<(), Error> { + let amounts_str = amounts.iter().map(|t| t.to_string()).collect::>(); + + add_genesis_account( + self.chain_id.as_str(), + &self.command_path, + &self.home_path, + &wallet.0, + &amounts_str, + ) + } + + fn add_genesis_validator(&self, wallet_id: &WalletId, token: &Token) -> Result<(), Error> { + add_genesis_validator( + self.chain_id.as_str(), + &self.command_path, + &self.home_path, + &wallet_id.0, + &token.to_string(), + ) + } + + fn collect_gen_txs(&self) -> Result<(), Error> { + collect_gen_txs(self.chain_id.as_str(), &self.command_path, &self.home_path) + } + + fn start(&self) -> Result { + start_chain( + &self.command_path, + &self.home_path, + &self.rpc_listen_address(), + &self.grpc_listen_address(), + ) + } +} diff --git a/tools/test-framework/src/chain/ext/mod.rs b/tools/test-framework/src/chain/ext/mod.rs index c6edcee505..e1cf7d83b9 100644 --- a/tools/test-framework/src/chain/ext/mod.rs +++ b/tools/test-framework/src/chain/ext/mod.rs @@ -1,3 +1,4 @@ +pub mod bootstrap; pub mod fee; pub mod ica; pub mod transfer; diff --git a/tools/test-framework/src/chain/tagged.rs b/tools/test-framework/src/chain/tagged.rs index 3a42cbec39..c35da55fe1 100644 --- a/tools/test-framework/src/chain/tagged.rs +++ b/tools/test-framework/src/chain/tagged.rs @@ -12,6 +12,7 @@ use crate::chain::driver::ChainDriver; use crate::error::Error; use crate::ibc::denom::Denom; use crate::ibc::token::{TaggedDenomExt, TaggedToken, TaggedTokenRef}; +use crate::relayer::tx::simple_send_tx; use crate::types::id::TaggedChainIdRef; use crate::types::tagged::*; use crate::types::wallet::{Wallet, WalletAddress}; @@ -87,7 +88,11 @@ impl<'a, Chain: Send> TaggedChainDriverExt for MonoTagged, messages: Vec, ) -> Result, Error> { - self.value().send_tx(wallet.value(), messages) + self.value().runtime.block_on(simple_send_tx( + &self.value().tx_config, + &wallet.value().key, + messages, + )) } fn query_balance( From 4dbd85122206dfd8503b757ebce322d3c4c38376 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Mon, 30 May 2022 13:06:10 +0200 Subject: [PATCH 035/113] Refactor packet workers to simplify control flow --- relayer/src/worker.rs | 15 +- relayer/src/worker/packet.rs | 188 ++++++++---------- relayer/src/worker/retry_strategy.rs | 2 +- .../src/tests/execute_schedule.rs | 2 +- 4 files changed, 102 insertions(+), 105 deletions(-) diff --git a/relayer/src/worker.rs b/relayer/src/worker.rs index 0cab65e732..1107bd7283 100644 --- a/relayer/src/worker.rs +++ b/relayer/src/worker.rs @@ -1,5 +1,6 @@ use alloc::sync::Arc; use core::fmt; +use ibc::core::ics04_channel::channel::Order; use serde::{Deserialize, Serialize}; use std::sync::Mutex; use tracing::error; @@ -121,13 +122,23 @@ pub fn spawn_worker_tasks( match link_res { Ok(link) => { - let (cmd_tx, cmd_rx) = crossbeam_channel::unbounded(); + let channel_ordering = link.a_to_b.channel().ordering; let link = Arc::new(Mutex::new(link)); + + if packets_config.clear_on_start || channel_ordering == Order::Ordered { + let clear_on_start_task = packet::spawn_clear_packet_on_start_worker( + link.clone(), + packets_config.clear_interval, + path.clone(), + ); + task_handles.push(clear_on_start_task); + } + + let (cmd_tx, cmd_rx) = crossbeam_channel::unbounded(); let resubmit = Resubmit::from_clear_interval(packets_config.clear_interval); let packet_task = packet::spawn_packet_cmd_worker( cmd_rx, link.clone(), - packets_config.clear_on_start, packets_config.clear_interval, path.clone(), ); diff --git a/relayer/src/worker/packet.rs b/relayer/src/worker/packet.rs index f562d8ffbc..623821e7d5 100644 --- a/relayer/src/worker/packet.rs +++ b/relayer/src/worker/packet.rs @@ -2,12 +2,12 @@ use core::time::Duration; use std::sync::{Arc, Mutex}; use crossbeam_channel::Receiver; -use tracing::{error, error_span, trace, warn}; +use tracing::{error_span, trace}; -use ibc::core::ics04_channel::channel::Order; use ibc::Height; use crate::chain::handle::ChainHandle; +use crate::event::monitor::EventBatch; use crate::foreign_client::HasExpiredOrFrozenError; use crate::link::Resubmit; use crate::link::{error::LinkError, Link}; @@ -20,31 +20,6 @@ use crate::worker::retry_strategy; use super::error::RunError; use super::WorkerCmd; -/// Whether or not to clear pending packets at this `step` for the given height. -/// Packets are cleared on the first iteration if this is an ordered channel, or -/// if `clear_on_start` is true. -/// Subsequently, packets are cleared only if `clear_interval` is not `0` and -/// if we have reached the interval. -fn should_clear_packets( - is_first_run: &mut bool, - clear_on_start: bool, - channel_ordering: Order, - clear_interval: u64, - height: Height, -) -> bool { - if *is_first_run { - *is_first_run = false; - if channel_ordering == Order::Ordered { - warn!("ordered channel: will clear packets because this is the first run"); - true - } else { - clear_on_start - } - } else { - clear_interval != 0 && height.revision_height % clear_interval == 0 - } -} - fn handle_link_error_in_task(e: LinkError) -> TaskError { if e.is_expired_or_frozen_error() { TaskError::Fatal(RunError::link(e)) @@ -100,11 +75,9 @@ pub fn spawn_packet_cmd_worker( cmd_rx: Receiver, // Mutex is used to prevent race condition between the packet workers link: Arc>>, - clear_on_start: bool, clear_interval: u64, path: Packet, ) -> TaskHandle { - let mut is_first_run: bool = true; let span = { let relay_path = &link.lock().unwrap().a_to_b; error_span!( @@ -117,16 +90,19 @@ pub fn spawn_packet_cmd_worker( }; spawn_background_task(span, Some(Duration::from_millis(200)), move || { if let Ok(cmd) = cmd_rx.try_recv() { - retry_with_index(retry_strategy::worker_stubborn_strategy(), |index| { - handle_packet_cmd( - &mut is_first_run, + retry_with_index(retry_strategy::worker_stubborn_strategy(), |i| { + let result = handle_packet_cmd( &mut link.lock().unwrap(), - clear_on_start, clear_interval, &path, cmd.clone(), - index, - ) + ); + + match result { + Ok(()) => RetryResult::Ok(()), + Err(TaskError::Ignore(_)) => RetryResult::Retry(i), + Err(TaskError::Fatal(_)) => RetryResult::Err(i), + } }) .map_err(|e| TaskError::Fatal(RunError::retry(e)))?; } @@ -135,6 +111,29 @@ pub fn spawn_packet_cmd_worker( }) } +pub fn spawn_clear_packet_on_start_worker( + link: Arc>>, + clear_interval: u64, + path: Packet, +) -> TaskHandle { + let span = { + let relay_path = &link.lock().unwrap().a_to_b; + error_span!( + "clear_packet_on_start", + src_chain = %relay_path.src_chain().id(), + src_port = %relay_path.src_port_id(), + src_channel = %relay_path.src_channel_id(), + dst_chain = %relay_path.dst_chain().id(), + ) + }; + + spawn_background_task(span, Some(Duration::from_secs(1)), move || { + handle_clear_packet(&mut link.lock().unwrap(), clear_interval, &path, None)?; + + Ok(Next::Abort) + }) +} + /// Receives worker commands, which may be: /// - IbcEvent => then it updates schedule /// - NewBlock => schedules packet clearing @@ -144,20 +143,13 @@ pub fn spawn_packet_cmd_worker( /// also refreshes and executes any scheduled operational /// data that is ready. fn handle_packet_cmd( - is_first_run: &mut bool, link: &mut Link, - clear_on_start: bool, clear_interval: u64, path: &Packet, cmd: WorkerCmd, - index: u64, -) -> RetryResult<(), u64> { - // this is set to true if `schedule_packet_clearing` is called. - let mut scheduled_packet_clearing = false; - - trace!("handling command {}", cmd); - let result = match cmd { - WorkerCmd::IbcEvents { batch } => link.a_to_b.update_schedule(batch), +) -> Result<(), TaskError> { + match cmd { + WorkerCmd::IbcEvents { batch } => handle_update_schedule(link, clear_interval, path, batch), // Handle the arrival of an event signaling that the // source chain has advanced to a new block. @@ -168,73 +160,67 @@ fn handle_packet_cmd( // Decide if packet clearing should be scheduled. // Packet clearing may happen once at start, // and then at predefined block intervals. - if should_clear_packets( - is_first_run, - clear_on_start, - link.a_to_b.channel().ordering, - clear_interval, - height, - ) { - scheduled_packet_clearing = true; - link.a_to_b.schedule_packet_clearing(Some(height)) + if should_clear_packets(clear_interval, height) { + handle_clear_packet(link, clear_interval, path, Some(height)) } else { Ok(()) } } - WorkerCmd::ClearPendingPackets => link.a_to_b.schedule_packet_clearing(None), - }; + WorkerCmd::ClearPendingPackets => handle_clear_packet(link, clear_interval, path, None), + } +} - if let Err(e) = result { - error!( - path = %path.short_name(), - retry_index = %index, - "will retry: handling command encountered error: {}", - e - ); +/// Whether or not to clear pending packets at this `step` for the given height. +/// Packets are cleared on the first iteration if this is an ordered channel, or +/// if `clear_on_start` is true. +/// Subsequently, packets are cleared only if `clear_interval` is not `0` and +/// if we have reached the interval. +fn should_clear_packets(clear_interval: u64, height: Height) -> bool { + clear_interval != 0 && height.revision_height % clear_interval == 0 +} - return RetryResult::Retry(index); - } +fn handle_update_schedule( + link: &mut Link, + clear_interval: u64, + path: &Packet, + batch: EventBatch, +) -> Result<(), TaskError> { + link.a_to_b + .update_schedule(batch) + .map_err(handle_link_error_in_task)?; - // The calls to refresh_schedule and execute_schedule depends on - // earlier calls to update_schedule and schedule_packet_clearing. - // Hence they must be retried in the same function body so that - // the same WorkerCmd is used for retrying the whole execution. - // - // The worker for spawn_packet_worker is still needed to handle - // the case when no PacketCmd arriving, so that it can still - // do the refresh and execute schedule. - // This follows the original logic here: - // https://github.com/informalsystems/ibc-rs/blob/e7a6403888f48754ddb80e35ebe2281fb7c51c04/relayer/src/worker/packet.rs#L127-L133 - - let schedule_result = link - .a_to_b + handle_execute_schedule(link, clear_interval, path) +} + +fn handle_clear_packet( + link: &mut Link, + clear_interval: u64, + path: &Packet, + height: Option, +) -> Result<(), TaskError> { + link.a_to_b + .schedule_packet_clearing(height) + .map_err(handle_link_error_in_task)?; + + handle_execute_schedule(link, clear_interval, path) +} + +fn handle_execute_schedule( + link: &mut Link, + clear_interval: u64, + path: &Packet, +) -> Result<(), TaskError> { + link.a_to_b .refresh_schedule() - .and_then(|_| link.a_to_b.execute_schedule()); - - if let Err(e) = schedule_result { - if e.is_expired_or_frozen_error() { - error!("aborting due to expired or frozen client"); - return RetryResult::Err(index); - } else { - error!( - retry_index = %index, - "will retry: schedule execution encountered error: {}", - e, - ); - - // Reset the `is_first_run` flag if `execute_schedule` encountered - // any error after `schedule_packet_clearing`. This helps ensure that - // packets being cleared will be retried instead of dropped. - if scheduled_packet_clearing { - *is_first_run = true; - } + .map_err(handle_link_error_in_task)?; - return RetryResult::Retry(index); - } - } + link.a_to_b + .execute_schedule() + .map_err(handle_link_error_in_task)?; let resubmit = Resubmit::from_clear_interval(clear_interval); + let summary = link.a_to_b.process_pending_txs(resubmit); if !summary.is_empty() { @@ -243,7 +229,7 @@ fn handle_packet_cmd( telemetry!(packet_metrics(path, &summary)); - RetryResult::Ok(()) + Ok(()) } #[cfg(feature = "telemetry")] diff --git a/relayer/src/worker/retry_strategy.rs b/relayer/src/worker/retry_strategy.rs index 9fefdcb328..5c5199b0fd 100644 --- a/relayer/src/worker/retry_strategy.rs +++ b/relayer/src/worker/retry_strategy.rs @@ -21,7 +21,7 @@ pub fn worker_default_strategy() -> impl Iterator { /// 10ms at every step. The strategy delay is /// not capped, so it will retry indefinitely. /// -/// See the `stubbord_strategy` test below. +/// See the `stubborn_strategy` test below. pub fn worker_stubborn_strategy() -> impl Iterator { ConstantGrowth::new(Duration::from_secs(1), Duration::from_millis(10)) } diff --git a/tools/integration-test/src/tests/execute_schedule.rs b/tools/integration-test/src/tests/execute_schedule.rs index 0a75ca6d26..96f374e609 100644 --- a/tools/integration-test/src/tests/execute_schedule.rs +++ b/tools/integration-test/src/tests/execute_schedule.rs @@ -45,7 +45,7 @@ impl BinaryChannelTest for ExecuteScheduleTest { let chain_a_link_opts = LinkParameters { src_port_id: channel.port_a.clone().into_value(), - src_channel_id: channel.channel_id_a.clone().into_value(), + src_channel_id: channel.channel_id_a.into_value(), }; let chain_a_link = Link::new_from_opts( From a3c0de17f9d6e9e43955b1f839454ba02bd77123 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Mon, 30 May 2022 16:38:23 +0200 Subject: [PATCH 036/113] Provide latest height for clear_packet_on_start_worker --- relayer/src/worker/error.rs | 9 +++++++-- relayer/src/worker/packet.rs | 11 ++++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/relayer/src/worker/error.rs b/relayer/src/worker/error.rs index d2ba4e8547..4d3c679163 100644 --- a/relayer/src/worker/error.rs +++ b/relayer/src/worker/error.rs @@ -1,10 +1,11 @@ use crossbeam_channel::RecvError; use flex_error::{define_error, DisplayOnly}; +use ibc::core::ics02_client::error::Error as Ics02Error; use crate::channel::ChannelError; use crate::connection::ConnectionError; +use crate::error::Error as RelayerError; use crate::link::error::LinkError; -use ibc::core::ics02_client::error::Error as Ics02Error; define_error! { RunError { @@ -30,6 +31,10 @@ define_error! { Recv [ DisplayOnly ] - | _ | { "error receiving from channel: sender end has been closed" } + | _ | { "error receiving from channel: sender end has been closed" }, + + Relayer + [ RelayerError ] + | _ | { "relayer error" }, } } diff --git a/relayer/src/worker/packet.rs b/relayer/src/worker/packet.rs index 623821e7d5..630b7976c8 100644 --- a/relayer/src/worker/packet.rs +++ b/relayer/src/worker/packet.rs @@ -128,7 +128,16 @@ pub fn spawn_clear_packet_on_start_worker Date: Mon, 30 May 2022 18:52:05 +0200 Subject: [PATCH 037/113] Still trying to fix Python test --- e2e/run.py | 2 +- relayer/src/worker/packet.rs | 6 ++---- tools/integration-test/src/tests/python.rs | 2 ++ 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/e2e/run.py b/e2e/run.py index 721be3f386..f9343c6562 100755 --- a/e2e/run.py +++ b/e2e/run.py @@ -81,7 +81,7 @@ def passive_packets( proc = relayer.start(c) # 5. wait for the relayer to initialize and pick up pending packets - sleep(20.0) + sleep(30.0) # 6. verify that there are no pending packets # hermes query packet unreceived-packets ibc-1 transfer channel-1 diff --git a/relayer/src/worker/packet.rs b/relayer/src/worker/packet.rs index 630b7976c8..60540e2261 100644 --- a/relayer/src/worker/packet.rs +++ b/relayer/src/worker/packet.rs @@ -127,13 +127,11 @@ pub fn spawn_clear_packet_on_start_worker Date: Tue, 31 May 2022 10:02:45 +0200 Subject: [PATCH 038/113] Clear on start can only be performed within packet cmd worker --- relayer/src/worker.rs | 13 ++++------- relayer/src/worker/packet.rs | 42 +++++++----------------------------- 2 files changed, 12 insertions(+), 43 deletions(-) diff --git a/relayer/src/worker.rs b/relayer/src/worker.rs index 1107bd7283..f7da193906 100644 --- a/relayer/src/worker.rs +++ b/relayer/src/worker.rs @@ -125,20 +125,15 @@ pub fn spawn_worker_tasks( let channel_ordering = link.a_to_b.channel().ordering; let link = Arc::new(Mutex::new(link)); - if packets_config.clear_on_start || channel_ordering == Order::Ordered { - let clear_on_start_task = packet::spawn_clear_packet_on_start_worker( - link.clone(), - packets_config.clear_interval, - path.clone(), - ); - task_handles.push(clear_on_start_task); - } - let (cmd_tx, cmd_rx) = crossbeam_channel::unbounded(); let resubmit = Resubmit::from_clear_interval(packets_config.clear_interval); + let should_clear_on_start = + packets_config.clear_on_start || channel_ordering == Order::Ordered; + let packet_task = packet::spawn_packet_cmd_worker( cmd_rx, link.clone(), + should_clear_on_start, packets_config.clear_interval, path.clone(), ); diff --git a/relayer/src/worker/packet.rs b/relayer/src/worker/packet.rs index 60540e2261..ac88a3074b 100644 --- a/relayer/src/worker/packet.rs +++ b/relayer/src/worker/packet.rs @@ -75,6 +75,7 @@ pub fn spawn_packet_cmd_worker( cmd_rx: Receiver, // Mutex is used to prevent race condition between the packet workers link: Arc>>, + mut should_clear_on_start: bool, clear_interval: u64, path: Packet, ) -> TaskHandle { @@ -93,6 +94,7 @@ pub fn spawn_packet_cmd_worker( retry_with_index(retry_strategy::worker_stubborn_strategy(), |i| { let result = handle_packet_cmd( &mut link.lock().unwrap(), + &mut should_clear_on_start, clear_interval, &path, cmd.clone(), @@ -111,36 +113,6 @@ pub fn spawn_packet_cmd_worker( }) } -pub fn spawn_clear_packet_on_start_worker( - link: Arc>>, - clear_interval: u64, - path: Packet, -) -> TaskHandle { - let span = { - let relay_path = &link.lock().unwrap().a_to_b; - error_span!( - "clear_packet_on_start", - src_chain = %relay_path.src_chain().id(), - src_port = %relay_path.src_port_id(), - src_channel = %relay_path.src_channel_id(), - dst_chain = %relay_path.dst_chain().id(), - ) - }; - - spawn_background_task(span, Some(Duration::from_millis(200)), move || { - let link = &mut link.lock().unwrap(); - let latest_height = link - .a_to_b - .src_chain() - .query_latest_height() - .map_err(|e| TaskError::Ignore(RunError::relayer(e)))?; - - handle_clear_packet(link, clear_interval, &path, Some(latest_height))?; - - Ok(Next::Abort) - }) -} - /// Receives worker commands, which may be: /// - IbcEvent => then it updates schedule /// - NewBlock => schedules packet clearing @@ -151,6 +123,7 @@ pub fn spawn_clear_packet_on_start_worker( link: &mut Link, + should_clear_on_start: &mut bool, clear_interval: u64, path: &Packet, cmd: WorkerCmd, @@ -164,10 +137,11 @@ fn handle_packet_cmd( height, new_block: _, } => { - // Decide if packet clearing should be scheduled. - // Packet clearing may happen once at start, - // and then at predefined block intervals. - if should_clear_packets(clear_interval, height) { + if *should_clear_on_start { + handle_clear_packet(link, clear_interval, path, Some(height))?; + *should_clear_on_start = false; + Ok(()) + } else if should_clear_packets(clear_interval, height) { handle_clear_packet(link, clear_interval, path, Some(height)) } else { Ok(()) From 2f1f5854243cd6aae8fa18b29aa4d819024638d4 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Tue, 31 May 2022 15:22:49 +0200 Subject: [PATCH 039/113] Fix merge conflict --- .../src/commands/query/channel_client.rs | 2 +- tools/integration-test/src/mbt/handlers.rs | 20 ++++++++----------- tools/integration-test/src/mbt/state.rs | 8 ++++---- tools/integration-test/src/mbt/utils.rs | 4 ++-- .../src/tests/execute_schedule.rs | 7 +++---- 5 files changed, 18 insertions(+), 23 deletions(-) diff --git a/relayer-cli/src/commands/query/channel_client.rs b/relayer-cli/src/commands/query/channel_client.rs index c803e6ccb5..fef376e3a7 100644 --- a/relayer-cli/src/commands/query/channel_client.rs +++ b/relayer-cli/src/commands/query/channel_client.rs @@ -35,7 +35,7 @@ impl Runnable for QueryChannelClientCmd { match chain.query_channel_client_state(QueryChannelClientStateRequest { port_id: self.port_id.clone(), - channel_id: self.channel_id.clone(), + channel_id: self.channel_id, }) { Ok(cs) => Output::success(cs).exit(), Err(e) => Output::error(format!("{}", e)).exit(), diff --git a/tools/integration-test/src/mbt/handlers.rs b/tools/integration-test/src/mbt/handlers.rs index 1ad10c628b..6a21d29beb 100644 --- a/tools/integration-test/src/mbt/handlers.rs +++ b/tools/integration-test/src/mbt/handlers.rs @@ -38,10 +38,10 @@ pub fn setup_chains( pub fn local_transfer_handler( node: Tagged, - source: u64, - target: u64, - denom: u64, - amount: u64, + source: u128, + target: u128, + denom: u128, + amount: u128, ) -> Result<(), Error> { let wallets = node.wallets(); @@ -52,8 +52,7 @@ pub fn local_transfer_handler( node.chain_driver().local_transfer_token( &source_wallet, &target_wallet.address(), - amount, - &denom, + &denom.with_amount(amount).as_ref(), )?; Ok(()) @@ -195,14 +194,12 @@ pub fn ibc_transfer_send_packet( &channel_id_source, &wallet_source, &wallet_target.address(), - &denom_source, - amount_source_to_target, + &denom_source.with_amount(amount_source_to_target).as_ref(), )?; node_source.chain_driver().assert_eventual_wallet_amount( &wallet_source.address(), - balance_source - amount_source_to_target, - &denom_source, + &(balance_source - amount_source_to_target).as_ref(), )?; Ok(()) @@ -238,8 +235,7 @@ pub fn ibc_transfer_receive_packet( node_target.chain_driver().assert_eventual_wallet_amount( &wallet_target.address(), - amount_source_to_target, - &denom_target.as_ref(), + &denom_target.with_amount(amount_source_to_target).as_ref(), )?; Ok(()) diff --git a/tools/integration-test/src/mbt/state.rs b/tools/integration-test/src/mbt/state.rs index 129983c67d..b9ddf34e9e 100644 --- a/tools/integration-test/src/mbt/state.rs +++ b/tools/integration-test/src/mbt/state.rs @@ -2,11 +2,11 @@ use serde::{Deserialize, Serialize}; use super::itf::{Map, Set}; -pub type ChainId = u64; +pub type ChainId = u128; pub type DenomId = ChainId; -pub type AccountId = u64; -pub type PacketId = u64; -pub type Balance = u64; +pub type AccountId = u128; +pub type PacketId = u128; +pub type Balance = u128; #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] diff --git a/tools/integration-test/src/mbt/utils.rs b/tools/integration-test/src/mbt/utils.rs index 97af0c01cc..e8a345fb2a 100644 --- a/tools/integration-test/src/mbt/utils.rs +++ b/tools/integration-test/src/mbt/utils.rs @@ -19,7 +19,7 @@ pub const CLIENT_EXPIRY: Duration = Duration::from_secs(15); pub fn get_chain( chains: &ConnectedChains, - chain_id: u64, + chain_id: u128, ) -> Tagged where ChainA: ChainHandle, @@ -35,7 +35,7 @@ where pub fn get_wallet<'a, ChainX>( wallets: &'a Tagged, - user: u64, + user: u128, ) -> Tagged { match user { 1 => wallets.user1(), diff --git a/tools/integration-test/src/tests/execute_schedule.rs b/tools/integration-test/src/tests/execute_schedule.rs index 96f374e609..1040f12f85 100644 --- a/tools/integration-test/src/tests/execute_schedule.rs +++ b/tools/integration-test/src/tests/execute_schedule.rs @@ -13,7 +13,7 @@ //! exist in the pending queue. use ibc_test_framework::prelude::*; -use ibc_test_framework::util::random::random_u64_range; +use ibc_test_framework::util::random::random_u128_range; use ibc_relayer::link::{Link, LinkParameters}; @@ -41,7 +41,7 @@ impl BinaryChannelTest for ExecuteScheduleTest { chains: ConnectedChains, channel: ConnectedChannel, ) -> Result<(), Error> { - let amount1 = random_u64_range(1000, 5000); + let amount1 = random_u128_range(1000, 5000); let chain_a_link_opts = LinkParameters { src_port_id: channel.port_a.clone().into_value(), @@ -64,8 +64,7 @@ impl BinaryChannelTest for ExecuteScheduleTest { &channel.channel_id_a.as_ref(), &chains.node_a.wallets().user1(), &chains.node_b.wallets().user1().address(), - &chains.node_a.denom(), - amount1, + &chains.node_a.denom().with_amount(amount1).as_ref(), )?; relay_path_a_to_b.schedule_packet_clearing(None)?; From 25ce71a34623c2d9dedbdd376a8b2035d0e94853 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Tue, 31 May 2022 22:07:25 +0200 Subject: [PATCH 040/113] Clean up for review --- e2e/run.py | 2 +- .../src/commands/query/channel_client.rs | 2 +- relayer/src/worker.rs | 6 +++--- relayer/src/worker/error.rs | 5 ----- relayer/src/worker/packet.rs | 20 +++++++++++++------ tools/integration-test/src/tests/python.rs | 2 -- 6 files changed, 19 insertions(+), 18 deletions(-) diff --git a/e2e/run.py b/e2e/run.py index f9343c6562..721be3f386 100755 --- a/e2e/run.py +++ b/e2e/run.py @@ -81,7 +81,7 @@ def passive_packets( proc = relayer.start(c) # 5. wait for the relayer to initialize and pick up pending packets - sleep(30.0) + sleep(20.0) # 6. verify that there are no pending packets # hermes query packet unreceived-packets ibc-1 transfer channel-1 diff --git a/relayer-cli/src/commands/query/channel_client.rs b/relayer-cli/src/commands/query/channel_client.rs index c803e6ccb5..fef376e3a7 100644 --- a/relayer-cli/src/commands/query/channel_client.rs +++ b/relayer-cli/src/commands/query/channel_client.rs @@ -35,7 +35,7 @@ impl Runnable for QueryChannelClientCmd { match chain.query_channel_client_state(QueryChannelClientStateRequest { port_id: self.port_id.clone(), - channel_id: self.channel_id.clone(), + channel_id: self.channel_id, }) { Ok(cs) => Output::success(cs).exit(), Err(e) => Output::error(format!("{}", e)).exit(), diff --git a/relayer/src/worker.rs b/relayer/src/worker.rs index f7da193906..8496761ef4 100644 --- a/relayer/src/worker.rs +++ b/relayer/src/worker.rs @@ -123,12 +123,12 @@ pub fn spawn_worker_tasks( match link_res { Ok(link) => { let channel_ordering = link.a_to_b.channel().ordering; - let link = Arc::new(Mutex::new(link)); + let should_clear_on_start = + packets_config.clear_on_start || channel_ordering == Order::Ordered; let (cmd_tx, cmd_rx) = crossbeam_channel::unbounded(); + let link = Arc::new(Mutex::new(link)); let resubmit = Resubmit::from_clear_interval(packets_config.clear_interval); - let should_clear_on_start = - packets_config.clear_on_start || channel_ordering == Order::Ordered; let packet_task = packet::spawn_packet_cmd_worker( cmd_rx, diff --git a/relayer/src/worker/error.rs b/relayer/src/worker/error.rs index 4d3c679163..4ea5d7b4b7 100644 --- a/relayer/src/worker/error.rs +++ b/relayer/src/worker/error.rs @@ -4,7 +4,6 @@ use ibc::core::ics02_client::error::Error as Ics02Error; use crate::channel::ChannelError; use crate::connection::ConnectionError; -use crate::error::Error as RelayerError; use crate::link::error::LinkError; define_error! { @@ -32,9 +31,5 @@ define_error! { Recv [ DisplayOnly ] | _ | { "error receiving from channel: sender end has been closed" }, - - Relayer - [ RelayerError ] - | _ | { "relayer error" }, } } diff --git a/relayer/src/worker/packet.rs b/relayer/src/worker/packet.rs index ac88a3074b..2e59a326d6 100644 --- a/relayer/src/worker/packet.rs +++ b/relayer/src/worker/packet.rs @@ -2,7 +2,7 @@ use core::time::Duration; use std::sync::{Arc, Mutex}; use crossbeam_channel::Receiver; -use tracing::{error_span, trace}; +use tracing::{error, error_span, trace}; use ibc::Height; @@ -100,6 +100,9 @@ pub fn spawn_packet_cmd_worker( cmd.clone(), ); + // Hack to use TaskError inside retry loop. Otherwise we + // will have to refactor all use of `retry_with_index` to + // make retry-able error handling more ergonomic. match result { Ok(()) => RetryResult::Ok(()), Err(TaskError::Ignore(_)) => RetryResult::Retry(i), @@ -139,6 +142,8 @@ fn handle_packet_cmd( } => { if *should_clear_on_start { handle_clear_packet(link, clear_interval, path, Some(height))?; + + // Clear the flag only if handle_clear_packet succeeds *should_clear_on_start = false; Ok(()) } else if should_clear_packets(clear_interval, height) { @@ -153,10 +158,7 @@ fn handle_packet_cmd( } /// Whether or not to clear pending packets at this `step` for the given height. -/// Packets are cleared on the first iteration if this is an ordered channel, or -/// if `clear_on_start` is true. -/// Subsequently, packets are cleared only if `clear_interval` is not `0` and -/// if we have reached the interval. +/// Packets are cleared if `clear_interval` is not `0` and if we have reached the interval. fn should_clear_packets(clear_interval: u64, height: Height) -> bool { clear_interval != 0 && height.revision_height % clear_interval == 0 } @@ -198,7 +200,13 @@ fn handle_execute_schedule( link.a_to_b .execute_schedule() - .map_err(handle_link_error_in_task)?; + .map_err(handle_link_error_in_task) + .map_err(|e| { + if let TaskError::Ignore(e) = &e { + error!("will retry: schedule execution encountered error: {}", e,); + } + e + })?; let resubmit = Resubmit::from_clear_interval(clear_interval); diff --git a/tools/integration-test/src/tests/python.rs b/tools/integration-test/src/tests/python.rs index db9139a03d..89cdfb588c 100644 --- a/tools/integration-test/src/tests/python.rs +++ b/tools/integration-test/src/tests/python.rs @@ -11,8 +11,6 @@ impl TestOverrides for PythonTest { } fn modify_relayer_config(&self, config: &mut Config) { - config.mode.packets.clear_on_start = true; - for mut chain in config.chains.iter_mut() { // Modify the key store type to `Store::Test` so that the wallet // keys are stored to ~/.hermes/keys so that we can use them From 679b4286e4fcd6cd761bbe3fbf05adf96c0049ad Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Tue, 31 May 2022 22:14:55 +0200 Subject: [PATCH 041/113] Refactor common code from spawn_packet_worker to handle_execute_schedule --- relayer/src/worker/packet.rs | 32 ++++++-------------------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/relayer/src/worker/packet.rs b/relayer/src/worker/packet.rs index 2e59a326d6..c00f533611 100644 --- a/relayer/src/worker/packet.rs +++ b/relayer/src/worker/packet.rs @@ -48,25 +48,7 @@ pub fn spawn_packet_worker( }; spawn_background_task(span, Some(Duration::from_millis(1000)), move || { - let relay_path = &mut link.lock().unwrap().a_to_b; - - relay_path - .refresh_schedule() - .map_err(handle_link_error_in_task)?; - - relay_path - .execute_schedule() - .map_err(handle_link_error_in_task)?; - - let summary = relay_path.process_pending_txs(resubmit); - - if !summary.is_empty() { - trace!("packet worker produced relay summary: {}", summary); - } - - telemetry!(packet_metrics(&path, &summary)); - let _path = &path; // avoid unused variable warning when telemetry is disabled - + handle_execute_schedule(&mut link.lock().unwrap(), &path, resubmit)?; Ok(Next::Continue) }) } @@ -173,7 +155,7 @@ fn handle_update_schedule( .update_schedule(batch) .map_err(handle_link_error_in_task)?; - handle_execute_schedule(link, clear_interval, path) + handle_execute_schedule(link, path, Resubmit::from_clear_interval(clear_interval)) } fn handle_clear_packet( @@ -186,13 +168,13 @@ fn handle_clear_packet( .schedule_packet_clearing(height) .map_err(handle_link_error_in_task)?; - handle_execute_schedule(link, clear_interval, path) + handle_execute_schedule(link, path, Resubmit::from_clear_interval(clear_interval)) } fn handle_execute_schedule( link: &mut Link, - clear_interval: u64, - path: &Packet, + _path: &Packet, + resubmit: Resubmit, ) -> Result<(), TaskError> { link.a_to_b .refresh_schedule() @@ -208,15 +190,13 @@ fn handle_execute_schedule( e })?; - let resubmit = Resubmit::from_clear_interval(clear_interval); - let summary = link.a_to_b.process_pending_txs(resubmit); if !summary.is_empty() { trace!("produced relay summary: {:?}", summary); } - telemetry!(packet_metrics(path, &summary)); + telemetry!(packet_metrics(_path, &summary)); Ok(()) } From f42c7b158c6ca0c4caf7699321645f2e6132c4ac Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 1 Jun 2022 11:05:08 +0200 Subject: [PATCH 042/113] Better handle packet cmd worker retry --- relayer/src/worker/packet.rs | 45 ++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/relayer/src/worker/packet.rs b/relayer/src/worker/packet.rs index c00f533611..2495012586 100644 --- a/relayer/src/worker/packet.rs +++ b/relayer/src/worker/packet.rs @@ -13,15 +13,15 @@ use crate::link::Resubmit; use crate::link::{error::LinkError, Link}; use crate::object::Packet; use crate::telemetry; -use crate::util::retry::{retry_with_index, RetryResult}; use crate::util::task::{spawn_background_task, Next, TaskError, TaskHandle}; -use crate::worker::retry_strategy; use super::error::RunError; use super::WorkerCmd; fn handle_link_error_in_task(e: LinkError) -> TaskError { if e.is_expired_or_frozen_error() { + // If the client is expired or frozen, terminate the packet worker + // as there is no point of relaying further packets. TaskError::Fatal(RunError::link(e)) } else { TaskError::Ignore(RunError::link(e)) @@ -71,27 +71,28 @@ pub fn spawn_packet_cmd_worker( dst_chain = %relay_path.dst_chain().id(), ) }; + + let mut current_command = None; + spawn_background_task(span, Some(Duration::from_millis(200)), move || { - if let Ok(cmd) = cmd_rx.try_recv() { - retry_with_index(retry_strategy::worker_stubborn_strategy(), |i| { - let result = handle_packet_cmd( - &mut link.lock().unwrap(), - &mut should_clear_on_start, - clear_interval, - &path, - cmd.clone(), - ); - - // Hack to use TaskError inside retry loop. Otherwise we - // will have to refactor all use of `retry_with_index` to - // make retry-able error handling more ergonomic. - match result { - Ok(()) => RetryResult::Ok(()), - Err(TaskError::Ignore(_)) => RetryResult::Retry(i), - Err(TaskError::Fatal(_)) => RetryResult::Err(i), - } - }) - .map_err(|e| TaskError::Fatal(RunError::retry(e)))?; + if current_command.is_none() { + // Only try to receive the next command if the + // previous command was processed successfully. + current_command = cmd_rx.try_recv().ok(); + } + + if let Some(cmd) = ¤t_command { + handle_packet_cmd( + &mut link.lock().unwrap(), + &mut should_clear_on_start, + clear_interval, + &path, + cmd.clone(), + )?; + + // Only reset current_command if handle_packet_cmd succeeds. + // Otherwise the same command will be retried in the next step. + current_command = None; } Ok(Next::Continue) From 6ca6066480094039c190c7c045d4a672c5ff5fa4 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 1 Jun 2022 11:14:52 +0200 Subject: [PATCH 043/113] Remove worker_subborn_strategy --- relayer/src/worker/retry_strategy.rs | 29 +--------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/relayer/src/worker/retry_strategy.rs b/relayer/src/worker/retry_strategy.rs index 5c5199b0fd..87122eb253 100644 --- a/relayer/src/worker/retry_strategy.rs +++ b/relayer/src/worker/retry_strategy.rs @@ -14,23 +14,11 @@ pub fn worker_default_strategy() -> impl Iterator { clamp_total(strategy, Duration::from_millis(500), Duration::from_secs(2)) } -/// A stubborn worker retry strategy. -/// -/// Initial retry backoff is hardcoded to 1s, and -/// this delay grows very slowly and steadily by -/// 10ms at every step. The strategy delay is -/// not capped, so it will retry indefinitely. -/// -/// See the `stubborn_strategy` test below. -pub fn worker_stubborn_strategy() -> impl Iterator { - ConstantGrowth::new(Duration::from_secs(1), Duration::from_millis(10)) -} - #[cfg(test)] mod tests { use std::time::Duration; - use crate::worker::retry_strategy::{worker_default_strategy, worker_stubborn_strategy}; + use crate::worker::retry_strategy::worker_default_strategy; #[test] fn default_strategy() { @@ -49,19 +37,4 @@ mod tests { ] ); } - - #[test] - fn stubborn_strategy() { - let strategy = worker_stubborn_strategy(); - // This strategy has an infinite amount of retry steps - // Assert that delays increment by 10ms - // Stop after 50 iterations - let mut delaysp = strategy.into_iter().take(50).peekable(); - let step = Duration::from_millis(10); - while let Some(first) = delaysp.next() { - if let Some(next) = delaysp.peek() { - assert_eq!(first + step, *next); - } - } - } } From f0b565874a1f2ffc8f7c8b3099a2f98ead140a12 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 1 Jun 2022 12:51:16 +0200 Subject: [PATCH 044/113] Add query counterparty address method --- Cargo.lock | 1 + tools/integration-test/src/tests/fee.rs | 22 ++++++++++++++ tools/test-framework/Cargo.toml | 1 + tools/test-framework/src/chain/ext/fee.rs | 21 ++++++++++++- tools/test-framework/src/relayer/fee.rs | 36 +++++++++++++++++++++++ tools/test-framework/src/types/wallet.rs | 4 +-- 6 files changed, 82 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3d5ed9150d..12bdd61488 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1684,6 +1684,7 @@ dependencies = [ "tendermint-rpc", "tokio", "toml", + "tonic", "tracing", "tracing-subscriber", ] diff --git a/tools/integration-test/src/tests/fee.rs b/tools/integration-test/src/tests/fee.rs index 7cbf5caff4..23c18d97bb 100644 --- a/tools/integration-test/src/tests/fee.rs +++ b/tools/integration-test/src/tests/fee.rs @@ -191,12 +191,34 @@ impl BinaryChannelTest for ForwardRelayerTest { chain_id_a ); + { + let counterparty_address = + chain_driver_b.query_counterparty_address(&channel_id_b, &relayer_b.address())?; + + assert_eq( + "counterparty address should be None before registering", + &counterparty_address, + &None, + )?; + } + chain_driver_b.register_counterparty_address( &relayer_b, &relayer_a.address(), &channel_id_b, )?; + { + let counterparty_address = + chain_driver_b.query_counterparty_address(&channel_id_b, &relayer_b.address())?; + + assert_eq( + "counterparty address should match registered address", + &counterparty_address, + &Some(relayer_a.address().cloned()), + )?; + } + let user_a = wallets_a.user1(); let user_b = wallets_b.user1(); diff --git a/tools/test-framework/Cargo.toml b/tools/test-framework/Cargo.toml index 2d17af82e6..77a95db4f6 100644 --- a/tools/test-framework/Cargo.toml +++ b/tools/test-framework/Cargo.toml @@ -42,3 +42,4 @@ crossbeam-channel = "0.5.4" semver = "1.0.7" flex-error = "0.4.4" prost = { version = "0.10" } +tonic = { version = "0.7", features = ["tls", "tls-roots"] } diff --git a/tools/test-framework/src/chain/ext/fee.rs b/tools/test-framework/src/chain/ext/fee.rs index f1600049a2..72cb4818c0 100644 --- a/tools/test-framework/src/chain/ext/fee.rs +++ b/tools/test-framework/src/chain/ext/fee.rs @@ -7,7 +7,8 @@ use crate::chain::tagged::TaggedChainDriverExt; use crate::error::Error; use crate::ibc::token::TaggedTokenRef; use crate::relayer::fee::{ - ibc_token_transfer_with_fee, pay_packet_fee, register_counterparty_address, + ibc_token_transfer_with_fee, pay_packet_fee, query_counterparty_address, + register_counterparty_address, }; use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef}; use crate::types::tagged::*; @@ -44,6 +45,12 @@ pub trait ChainFeeMethodsExt { counterparty_address: &MonoTagged, channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, ) -> Result<(), Error>; + + fn query_counterparty_address( + &self, + channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, + address: &MonoTagged, + ) -> Result>, Error>; } impl<'a, Chain: Send> ChainFeeMethodsExt for MonoTagged { @@ -108,4 +115,16 @@ impl<'a, Chain: Send> ChainFeeMethodsExt for MonoTagged( + &self, + channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, + address: &MonoTagged, + ) -> Result>, Error> { + self.value().runtime.block_on(query_counterparty_address( + &self.tx_config().value().grpc_address, + channel_id, + address, + )) + } } diff --git a/tools/test-framework/src/relayer/fee.rs b/tools/test-framework/src/relayer/fee.rs index 3a760e5d74..7686862add 100644 --- a/tools/test-framework/src/relayer/fee.rs +++ b/tools/test-framework/src/relayer/fee.rs @@ -1,14 +1,18 @@ use core::time::Duration; +use http::uri::Uri; use ibc::core::ics04_channel::packet::Sequence; use ibc::events::IbcEvent; use ibc_proto::cosmos::base::v1beta1::Coin; use ibc_proto::google::protobuf::Any; +use ibc_proto::ibc::applications::fee::v1::query_client::QueryClient; use ibc_proto::ibc::applications::fee::v1::{ Fee, MsgPayPacketFee, MsgPayPacketFeeAsync, MsgRegisterCounterpartyAddress, PacketFee, + QueryCounterpartyAddressRequest, }; use ibc_proto::ibc::core::channel::v1::PacketId; use ibc_relayer::chain::cosmos::types::config::TxConfig; use prost::{EncodeError, Message}; +use tonic::Code; use crate::error::{handle_generic_error, Error}; use crate::ibc::token::TaggedTokenRef; @@ -214,3 +218,35 @@ pub fn build_register_counterparty_address_message( Ok(MonoTagged::new(wrapped)) } + +pub async fn query_counterparty_address( + grpc_address: &Uri, + channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, + address: &MonoTagged, +) -> Result>, Error> { + let mut client = QueryClient::connect(grpc_address.clone()) + .await + .map_err(handle_generic_error)?; + + let request = QueryCounterpartyAddressRequest { + channel_id: channel_id.value().to_string(), + relayer_address: address.value().to_string(), + }; + + let result = client.counterparty_address(request).await; + + match result { + Ok(response) => { + let counterparty_address = WalletAddress(response.into_inner().counterparty_address); + + Ok(Some(MonoTagged::new(counterparty_address))) + } + Err(e) => { + if e.code() == Code::NotFound { + Ok(None) + } else { + Err(Error::generic(e.into())) + } + } + } +} diff --git a/tools/test-framework/src/types/wallet.rs b/tools/test-framework/src/types/wallet.rs index 2ec15d0e37..d7247fffe1 100644 --- a/tools/test-framework/src/types/wallet.rs +++ b/tools/test-framework/src/types/wallet.rs @@ -11,13 +11,13 @@ use crate::types::tagged::*; /** Newtype wrapper for a wallet ID as identified by the chain and relayer. */ -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct WalletId(pub String); /** Newtype wrapper for the address a wallet corresponds to. */ -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct WalletAddress(pub String); /** From f2aade85c1194b70e6c3c241357bf7a5f65b2d5d Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Thu, 2 Jun 2022 22:42:16 +0200 Subject: [PATCH 045/113] Add basic test and implementation for query incenvized packets --- tools/integration-test/src/tests/fee.rs | 30 ++++ tools/test-framework/src/chain/ext/fee.rs | 20 ++- tools/test-framework/src/ibc/denom.rs | 2 +- tools/test-framework/src/relayer/fee.rs | 163 ++++++++++++++++++++-- 4 files changed, 205 insertions(+), 10 deletions(-) diff --git a/tools/integration-test/src/tests/fee.rs b/tools/integration-test/src/tests/fee.rs index 23c18d97bb..8adb882dd8 100644 --- a/tools/integration-test/src/tests/fee.rs +++ b/tools/integration-test/src/tests/fee.rs @@ -460,6 +460,36 @@ impl BinaryChannelTest for PayPacketFeeAsyncTest { let sequence = send_packet_event.packet.sequence; + { + let packets = chain_driver_a.query_incentivized_packets(&channel_id_a, &port_a)?; + + info!("incenvitized packets: {:?}", packets); + + assert_eq!(packets.len(), 1); + + let packet = &packets[0]; + assert_eq!(packet.packet_id.sequence, sequence); + + assert_eq!(packet.packet_fees.len(), 1); + let packet_fee = &packet.packet_fees[0]; + + assert_eq!(packet_fee.recv_fee.len(), 1); + assert_eq!(packet_fee.ack_fee.len(), 1); + assert_eq!(packet_fee.timeout_fee.len(), 1); + + assert_eq!( + &packet_fee.recv_fee[0], + denom_a.with_amount(receive_fee).value() + ); + assert_eq!(&packet_fee.ack_fee[0], denom_a.with_amount(ack_fee).value()); + assert_eq!( + &packet_fee.timeout_fee[0], + denom_a.with_amount(timeout_fee).value() + ); + + assert_eq!(packet_fee.refund_address, user_a.value().address); + } + let receive_fee_2 = random_u128_range(300, 400); let ack_fee_2 = random_u128_range(200, 300); let timeout_fee_2 = random_u128_range(100, 200); diff --git a/tools/test-framework/src/chain/ext/fee.rs b/tools/test-framework/src/chain/ext/fee.rs index 72cb4818c0..cdec95a247 100644 --- a/tools/test-framework/src/chain/ext/fee.rs +++ b/tools/test-framework/src/chain/ext/fee.rs @@ -8,7 +8,7 @@ use crate::error::Error; use crate::ibc::token::TaggedTokenRef; use crate::relayer::fee::{ ibc_token_transfer_with_fee, pay_packet_fee, query_counterparty_address, - register_counterparty_address, + query_incentivized_packets, register_counterparty_address, IdentifiedPacketFees, }; use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef}; use crate::types::tagged::*; @@ -51,6 +51,12 @@ pub trait ChainFeeMethodsExt { channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, address: &MonoTagged, ) -> Result>, Error>; + + fn query_incentivized_packets( + &self, + channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, + port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, + ) -> Result, Error>; } impl<'a, Chain: Send> ChainFeeMethodsExt for MonoTagged { @@ -127,4 +133,16 @@ impl<'a, Chain: Send> ChainFeeMethodsExt for MonoTagged( + &self, + channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, + port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, + ) -> Result, Error> { + self.value().runtime.block_on(query_incentivized_packets( + &self.tx_config().value().grpc_address, + channel_id, + port_id, + )) + } } diff --git a/tools/test-framework/src/ibc/denom.rs b/tools/test-framework/src/ibc/denom.rs index 076651bf7c..121efa03d8 100644 --- a/tools/test-framework/src/ibc/denom.rs +++ b/tools/test-framework/src/ibc/denom.rs @@ -144,7 +144,7 @@ impl PartialEq for Denom { hashed: h2, }, ) => p1 == p2 && d1 == d2 && h1 == h2, - _ => false, + _ => self.as_str() == other.as_str(), } } } diff --git a/tools/test-framework/src/relayer/fee.rs b/tools/test-framework/src/relayer/fee.rs index 7686862add..6a8ecc4224 100644 --- a/tools/test-framework/src/relayer/fee.rs +++ b/tools/test-framework/src/relayer/fee.rs @@ -1,21 +1,27 @@ +use core::convert::TryFrom; +use core::str::FromStr; use core::time::Duration; +use eyre::eyre; use http::uri::Uri; use ibc::core::ics04_channel::packet::Sequence; +use ibc::core::ics24_host::identifier::{ChannelId, PortId}; use ibc::events::IbcEvent; use ibc_proto::cosmos::base::v1beta1::Coin; use ibc_proto::google::protobuf::Any; use ibc_proto::ibc::applications::fee::v1::query_client::QueryClient; use ibc_proto::ibc::applications::fee::v1::{ - Fee, MsgPayPacketFee, MsgPayPacketFeeAsync, MsgRegisterCounterpartyAddress, PacketFee, - QueryCounterpartyAddressRequest, + Fee as ProtoFee, IdentifiedPacketFees as ProtoIdentifiedPacketFees, MsgPayPacketFee, + MsgPayPacketFeeAsync, MsgRegisterCounterpartyAddress, PacketFee as ProtoPacketFee, + QueryCounterpartyAddressRequest, QueryIncentivizedPacketsForChannelRequest, }; -use ibc_proto::ibc::core::channel::v1::PacketId; +use ibc_proto::ibc::core::channel::v1::PacketId as ProtoPacketId; use ibc_relayer::chain::cosmos::types::config::TxConfig; use prost::{EncodeError, Message}; use tonic::Code; use crate::error::{handle_generic_error, Error}; -use crate::ibc::token::TaggedTokenRef; +use crate::ibc::denom::Denom; +use crate::ibc::token::{TaggedTokenRef, Token}; use crate::relayer::transfer::build_transfer_message; use crate::relayer::tx::simple_send_tx; use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef}; @@ -114,7 +120,7 @@ pub fn build_pay_packet_message( ) -> Result { const TYPE_URL: &str = "/ibc.applications.fee.v1.MsgPayPacketFee"; - let fee = Fee { + let fee = ProtoFee { recv_fee: vec![Coin { denom: receive_fee.value().denom.to_string(), amount: receive_fee.value().amount.to_string(), @@ -156,7 +162,7 @@ pub fn build_pay_packet_fee_async_message( ) -> Result { const TYPE_URL: &str = "/ibc.applications.fee.v1.MsgPayPacketFeeAsync"; - let fee = Fee { + let fee = ProtoFee { recv_fee: vec![Coin { denom: receive_fee.value().denom.to_string(), amount: receive_fee.value().amount.to_string(), @@ -171,13 +177,13 @@ pub fn build_pay_packet_fee_async_message( }], }; - let packet_fee = PacketFee { + let packet_fee = ProtoPacketFee { fee: Some(fee), refund_address: payer.value().0.clone(), relayers: Vec::new(), }; - let packet_id = PacketId { + let packet_id = ProtoPacketId { port_id: port_id.value().to_string(), channel_id: channel_id.value().to_string(), sequence: (*sequence.value()).into(), @@ -250,3 +256,144 @@ pub async fn query_counterparty_address( } } } + +#[derive(Debug, Clone)] +pub struct PacketId { + pub channel_id: ChannelId, + pub port_id: PortId, + pub sequence: Sequence, +} + +#[derive(Debug, Clone)] +pub struct PacketFee { + pub recv_fee: Vec, + pub ack_fee: Vec, + pub timeout_fee: Vec, + pub refund_address: WalletAddress, +} + +#[derive(Debug, Clone)] +pub struct IdentifiedPacketFees { + pub packet_id: PacketId, + pub packet_fees: Vec, +} + +impl TryFrom for PacketId { + type Error = Error; + + fn try_from(packet_id: ProtoPacketId) -> Result { + let channel_id = + ChannelId::from_str(&packet_id.channel_id).map_err(handle_generic_error)?; + + let port_id = PortId::from_str(&packet_id.port_id).map_err(handle_generic_error)?; + + let sequence = Sequence::from(packet_id.sequence); + + Ok(PacketId { + channel_id, + port_id, + sequence, + }) + } +} + +impl TryFrom for Token { + type Error = Error; + + fn try_from(fee: Coin) -> Result { + let denom = Denom::base(&fee.denom); + let amount = u128::from_str(&fee.amount).map_err(handle_generic_error)?; + + Ok(Token::new(denom, amount)) + } +} + +impl TryFrom for PacketFee { + type Error = Error; + + fn try_from(packet_fee: ProtoPacketFee) -> Result { + let fee = packet_fee + .fee + .ok_or_else(|| eyre!("expect fee field to be non-empty"))?; + + let recv_fee = fee + .recv_fee + .into_iter() + .map(Token::try_from) + .collect::>()?; + + let ack_fee = fee + .ack_fee + .into_iter() + .map(Token::try_from) + .collect::>()?; + + let timeout_fee = fee + .timeout_fee + .into_iter() + .map(Token::try_from) + .collect::>()?; + + let refund_address = WalletAddress(packet_fee.refund_address); + + Ok(PacketFee { + recv_fee, + ack_fee, + timeout_fee, + refund_address, + }) + } +} + +impl TryFrom for IdentifiedPacketFees { + type Error = Error; + + fn try_from(fees: ProtoIdentifiedPacketFees) -> Result { + let raw_packet_id = fees + .packet_id + .ok_or_else(|| eyre!("expect non-empty packet_id"))?; + + let packet_id = PacketId::try_from(raw_packet_id)?; + let packet_fees = fees + .packet_fees + .into_iter() + .map(PacketFee::try_from) + .collect::>()?; + + Ok(IdentifiedPacketFees { + packet_id, + packet_fees, + }) + } +} + +pub async fn query_incentivized_packets( + grpc_address: &Uri, + channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, + port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, +) -> Result, Error> { + let mut client = QueryClient::connect(grpc_address.clone()) + .await + .map_err(handle_generic_error)?; + + let request = QueryIncentivizedPacketsForChannelRequest { + channel_id: channel_id.value().to_string(), + port_id: port_id.value().to_string(), + pagination: None, + query_height: 0, + }; + + let response = client + .incentivized_packets_for_channel(request) + .await + .map_err(handle_generic_error)?; + + let raw_packets = response.into_inner().incentivized_packets; + + let packets = raw_packets + .into_iter() + .map(IdentifiedPacketFees::try_from) + .collect::>()?; + + Ok(packets) +} From bfbd0bf6fc7a6c5e5918ffb5f97eff955042ddff Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Sat, 4 Jun 2022 19:09:57 +0200 Subject: [PATCH 046/113] Copy fee implementations to ibc-relayer crate --- modules/src/applications/ics29_fee/error.rs | 28 +++++++ modules/src/applications/ics29_fee/mod.rs | 3 +- .../src/applications/ics29_fee/msgs/mod.rs | 3 - .../applications/ics29_fee/msgs/pay_packet.rs | 21 ----- .../src/applications/ics29_fee/packet_fee.rs | 57 ++++++++++++++ modules/src/core/ics04_channel/mod.rs | 1 + modules/src/core/ics04_channel/packet_id.rs | 32 ++++++++ relayer/src/chain/cosmos/query.rs | 1 + relayer/src/chain/cosmos/query/fee.rs | 77 +++++++++++++++++++ relayer/src/error.rs | 5 ++ 10 files changed, 203 insertions(+), 25 deletions(-) create mode 100644 modules/src/applications/ics29_fee/error.rs delete mode 100644 modules/src/applications/ics29_fee/msgs/mod.rs delete mode 100644 modules/src/applications/ics29_fee/msgs/pay_packet.rs create mode 100644 modules/src/applications/ics29_fee/packet_fee.rs create mode 100644 modules/src/core/ics04_channel/packet_id.rs create mode 100644 relayer/src/chain/cosmos/query/fee.rs diff --git a/modules/src/applications/ics29_fee/error.rs b/modules/src/applications/ics29_fee/error.rs new file mode 100644 index 0000000000..f12e52d503 --- /dev/null +++ b/modules/src/applications/ics29_fee/error.rs @@ -0,0 +1,28 @@ +use flex_error::define_error; + +use crate::applications::transfer::error::Error as TransferError; +use crate::core::ics04_channel::error::Error as ChannelError; +use crate::signer::SignerError; + +define_error! { + #[derive(Debug, PartialEq, Eq)] + Error { + Transfer + [ TransferError ] + | _ | { "transfer error" }, + + Channel + [ ChannelError ] + | _ | { "channel error" }, + + Signer + [ SignerError ] + | _ | { "failed to parse signer" }, + + EmptyFee + | _ | { "expect fee field to be non-empty" }, + + EmptyPacketId + | _ | { "expect packet_id field to be non-empty" }, + } +} diff --git a/modules/src/applications/ics29_fee/mod.rs b/modules/src/applications/ics29_fee/mod.rs index 159c4b7c03..befb2e6575 100644 --- a/modules/src/applications/ics29_fee/mod.rs +++ b/modules/src/applications/ics29_fee/mod.rs @@ -1 +1,2 @@ -mod msgs; +pub mod error; +pub mod packet_fee; diff --git a/modules/src/applications/ics29_fee/msgs/mod.rs b/modules/src/applications/ics29_fee/msgs/mod.rs deleted file mode 100644 index f1d22a0b71..0000000000 --- a/modules/src/applications/ics29_fee/msgs/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod pay_packet; - -pub use pay_packet::*; diff --git a/modules/src/applications/ics29_fee/msgs/pay_packet.rs b/modules/src/applications/ics29_fee/msgs/pay_packet.rs deleted file mode 100644 index 7c081dec75..0000000000 --- a/modules/src/applications/ics29_fee/msgs/pay_packet.rs +++ /dev/null @@ -1,21 +0,0 @@ -use ibc_proto::ibc::applications::fee::v1::MsgPayPacketFee; - -use crate::prelude::*; -use crate::tx_msg::Msg; - -pub const TYPE_URL: &str = "/ibc.applications.transfer.v1.MsgTransfer"; - -pub enum Error {} - -impl Msg for MsgPayPacketFee { - type ValidationError = Error; - type Raw = MsgPayPacketFee; - - fn route(&self) -> String { - crate::keys::ROUTER_KEY.to_string() - } - - fn type_url(&self) -> String { - TYPE_URL.to_string() - } -} diff --git a/modules/src/applications/ics29_fee/packet_fee.rs b/modules/src/applications/ics29_fee/packet_fee.rs new file mode 100644 index 0000000000..60d2aa423f --- /dev/null +++ b/modules/src/applications/ics29_fee/packet_fee.rs @@ -0,0 +1,57 @@ +use core::str::FromStr; +use ibc_proto::ibc::applications::fee::v1::Fee; +use ibc_proto::ibc::applications::fee::v1::{ + IdentifiedPacketFees as ProtoIdentifiedPacketFees, PacketFee as ProtoPacketFee, +}; + +use super::error::Error; +use crate::core::ics04_channel::packet_id::PacketId; +use crate::prelude::*; +use crate::signer::Signer; + +pub struct PacketFee { + pub fee: Fee, + pub refund_address: Signer, + // do not expose relayer field as it is currently a reserved field +} + +pub struct IdentifiedPacketFees { + pub packet_id: PacketId, + pub packet_fees: Vec, +} + +impl TryFrom for PacketFee { + type Error = Error; + + fn try_from(packet_fee: ProtoPacketFee) -> Result { + let fee = packet_fee.fee.ok_or_else(Error::empty_fee)?; + + let refund_address = Signer::from_str(&packet_fee.refund_address).map_err(Error::signer)?; + + Ok(PacketFee { + fee, + refund_address, + }) + } +} + +impl TryFrom for IdentifiedPacketFees { + type Error = Error; + + fn try_from(fees: ProtoIdentifiedPacketFees) -> Result { + let raw_packet_id = fees.packet_id.ok_or_else(Error::empty_packet_id)?; + + let packet_id = PacketId::try_from(raw_packet_id).map_err(Error::channel)?; + + let packet_fees = fees + .packet_fees + .into_iter() + .map(PacketFee::try_from) + .collect::>()?; + + Ok(IdentifiedPacketFees { + packet_id, + packet_fees, + }) + } +} diff --git a/modules/src/core/ics04_channel/mod.rs b/modules/src/core/ics04_channel/mod.rs index 35a8ef9e4c..ce59b5ed02 100644 --- a/modules/src/core/ics04_channel/mod.rs +++ b/modules/src/core/ics04_channel/mod.rs @@ -9,6 +9,7 @@ pub mod events; pub mod handler; pub mod msgs; pub mod packet; +pub mod packet_id; pub mod commitment; mod version; diff --git a/modules/src/core/ics04_channel/packet_id.rs b/modules/src/core/ics04_channel/packet_id.rs new file mode 100644 index 0000000000..9acf5b3cf8 --- /dev/null +++ b/modules/src/core/ics04_channel/packet_id.rs @@ -0,0 +1,32 @@ +use core::convert::TryFrom; +use core::str::FromStr; +use ibc_proto::ibc::core::channel::v1::PacketId as ProtoPacketId; + +use crate::core::ics04_channel::error::Error; +use crate::core::ics04_channel::packet::Sequence; +use crate::core::ics24_host::identifier::{ChannelId, PortId}; + +#[derive(Debug, Clone)] +pub struct PacketId { + pub channel_id: ChannelId, + pub port_id: PortId, + pub sequence: Sequence, +} + +impl TryFrom for PacketId { + type Error = Error; + + fn try_from(packet_id: ProtoPacketId) -> Result { + let channel_id = ChannelId::from_str(&packet_id.channel_id).map_err(Error::identifier)?; + + let port_id = PortId::from_str(&packet_id.port_id).map_err(Error::identifier)?; + + let sequence = Sequence::from(packet_id.sequence); + + Ok(PacketId { + channel_id, + port_id, + sequence, + }) + } +} diff --git a/relayer/src/chain/cosmos/query.rs b/relayer/src/chain/cosmos/query.rs index 3abd17b069..ed6ffcfae0 100644 --- a/relayer/src/chain/cosmos/query.rs +++ b/relayer/src/chain/cosmos/query.rs @@ -18,6 +18,7 @@ use crate::error::Error; pub mod account; pub mod balance; +pub mod fee; pub mod status; pub mod tx; diff --git a/relayer/src/chain/cosmos/query/fee.rs b/relayer/src/chain/cosmos/query/fee.rs new file mode 100644 index 0000000000..e84e9c7344 --- /dev/null +++ b/relayer/src/chain/cosmos/query/fee.rs @@ -0,0 +1,77 @@ +use core::str::FromStr; +use http::uri::Uri; +use ibc::applications::ics29_fee::packet_fee::IdentifiedPacketFees; +use ibc::core::ics24_host::identifier::{ChannelId, PortId}; +use ibc::signer::Signer; +use ibc_proto::ibc::applications::fee::v1::query_client::QueryClient; +use ibc_proto::ibc::applications::fee::v1::{ + QueryCounterpartyAddressRequest, QueryIncentivizedPacketsForChannelRequest, +}; +use tonic::Code; + +use crate::error::Error; + +pub async fn query_counterparty_address( + grpc_address: &Uri, + channel_id: &ChannelId, + address: &Signer, +) -> Result, Error> { + let mut client = QueryClient::connect(grpc_address.clone()) + .await + .map_err(Error::grpc_transport)?; + + let request = QueryCounterpartyAddressRequest { + channel_id: channel_id.to_string(), + relayer_address: address.to_string(), + }; + + let result = client.counterparty_address(request).await; + + match result { + Ok(response) => { + let counterparty_address = + Signer::from_str(&response.into_inner().counterparty_address).unwrap(); + + Ok(Some(counterparty_address)) + } + Err(e) => { + if e.code() == Code::NotFound { + Ok(None) + } else { + Err(Error::grpc_status(e)) + } + } + } +} + +pub async fn query_incentivized_packets( + grpc_address: &Uri, + channel_id: &ChannelId, + port_id: &PortId, +) -> Result, Error> { + let mut client = QueryClient::connect(grpc_address.clone()) + .await + .map_err(Error::grpc_transport)?; + + let request = QueryIncentivizedPacketsForChannelRequest { + channel_id: channel_id.to_string(), + port_id: port_id.to_string(), + pagination: None, + query_height: 0, + }; + + let response = client + .incentivized_packets_for_channel(request) + .await + .map_err(Error::grpc_status)?; + + let raw_packets = response.into_inner().incentivized_packets; + + let packets = raw_packets + .into_iter() + .map(IdentifiedPacketFees::try_from) + .collect::>() + .map_err(Error::ics29)?; + + Ok(packets) +} diff --git a/relayer/src/error.rs b/relayer/src/error.rs index 9e48a2d77d..781cb8b36c 100644 --- a/relayer/src/error.rs +++ b/relayer/src/error.rs @@ -22,6 +22,7 @@ use tonic::{ }; use ibc::{ + applications::ics29_fee::error::Error as FeeError, clients::ics07_tendermint::error as tendermint_error, core::{ ics02_client::{client_type::ClientType, error as client_error}, @@ -267,6 +268,10 @@ define_error! { [ commitment_error::Error ] |_| { "ICS 23 error" }, + Ics29 + [ FeeError ] + | _ | { "ICS 29 error" }, + InvalidUri { uri: String } [ TraceError ] From 70e277ff86a3be1b10f0ff44ea77f996f16c1aa4 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Sat, 4 Jun 2022 20:07:59 +0200 Subject: [PATCH 047/113] Copy proto message builders to ibc crate --- modules/src/applications/ics29_fee/error.rs | 7 ++- modules/src/applications/ics29_fee/mod.rs | 2 + .../src/applications/ics29_fee/msgs/mod.rs | 3 + .../applications/ics29_fee/msgs/pay_packet.rs | 41 ++++++++++++++ .../ics29_fee/msgs/pay_packet_async.rs | 55 +++++++++++++++++++ .../ics29_fee/msgs/register_counterparty.rs | 31 +++++++++++ modules/src/applications/ics29_fee/utils.rs | 9 +++ relayer/src/chain/cosmos.rs | 1 + relayer/src/chain/cosmos/fee.rs | 24 ++++++++ 9 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 modules/src/applications/ics29_fee/msgs/mod.rs create mode 100644 modules/src/applications/ics29_fee/msgs/pay_packet.rs create mode 100644 modules/src/applications/ics29_fee/msgs/pay_packet_async.rs create mode 100644 modules/src/applications/ics29_fee/msgs/register_counterparty.rs create mode 100644 modules/src/applications/ics29_fee/utils.rs create mode 100644 relayer/src/chain/cosmos/fee.rs diff --git a/modules/src/applications/ics29_fee/error.rs b/modules/src/applications/ics29_fee/error.rs index f12e52d503..9bdd076287 100644 --- a/modules/src/applications/ics29_fee/error.rs +++ b/modules/src/applications/ics29_fee/error.rs @@ -1,4 +1,5 @@ -use flex_error::define_error; +use flex_error::{define_error, TraceError}; +use prost::EncodeError; use crate::applications::transfer::error::Error as TransferError; use crate::core::ics04_channel::error::Error as ChannelError; @@ -24,5 +25,9 @@ define_error! { EmptyPacketId | _ | { "expect packet_id field to be non-empty" }, + + Encode + [ TraceError ] + | _ | { "protobuf encode error" } } } diff --git a/modules/src/applications/ics29_fee/mod.rs b/modules/src/applications/ics29_fee/mod.rs index befb2e6575..496ffc3fb7 100644 --- a/modules/src/applications/ics29_fee/mod.rs +++ b/modules/src/applications/ics29_fee/mod.rs @@ -1,2 +1,4 @@ pub mod error; +pub mod msgs; pub mod packet_fee; +pub(crate) mod utils; diff --git a/modules/src/applications/ics29_fee/msgs/mod.rs b/modules/src/applications/ics29_fee/msgs/mod.rs new file mode 100644 index 0000000000..5cac2afbab --- /dev/null +++ b/modules/src/applications/ics29_fee/msgs/mod.rs @@ -0,0 +1,3 @@ +pub mod pay_packet; +pub mod pay_packet_async; +pub mod register_counterparty; diff --git a/modules/src/applications/ics29_fee/msgs/pay_packet.rs b/modules/src/applications/ics29_fee/msgs/pay_packet.rs new file mode 100644 index 0000000000..f52b5b1120 --- /dev/null +++ b/modules/src/applications/ics29_fee/msgs/pay_packet.rs @@ -0,0 +1,41 @@ +use ibc_proto::cosmos::base::v1beta1::Coin; +use ibc_proto::google::protobuf::Any; +use ibc_proto::ibc::applications::fee::v1::{Fee as ProtoFee, MsgPayPacketFee}; + +use crate::applications::ics29_fee::error::Error; +use crate::applications::ics29_fee::utils::encode_message; +use crate::core::ics24_host::identifier::{ChannelId, PortId}; +use crate::prelude::*; +use crate::signer::Signer; + +const TYPE_URL: &str = "/ibc.applications.fee.v1.MsgPayPacketFee"; + +pub fn build_pay_packet_message( + port_id: &PortId, + channel_id: &ChannelId, + payer: &Signer, + recv_fee: Vec, + ack_fee: Vec, + timeout_fee: Vec, +) -> Result { + let fee = ProtoFee { + recv_fee, + ack_fee, + timeout_fee, + }; + + let message = MsgPayPacketFee { + fee: Some(fee), + source_port_id: port_id.to_string(), + source_channel_id: channel_id.to_string(), + signer: payer.to_string(), + relayers: Vec::new(), + }; + + let encoded = encode_message(&message).map_err(Error::encode)?; + + Ok(Any { + type_url: TYPE_URL.to_string(), + value: encoded, + }) +} diff --git a/modules/src/applications/ics29_fee/msgs/pay_packet_async.rs b/modules/src/applications/ics29_fee/msgs/pay_packet_async.rs new file mode 100644 index 0000000000..226b08ccac --- /dev/null +++ b/modules/src/applications/ics29_fee/msgs/pay_packet_async.rs @@ -0,0 +1,55 @@ +use ibc_proto::cosmos::base::v1beta1::Coin; +use ibc_proto::google::protobuf::Any; +use ibc_proto::ibc::applications::fee::v1::{ + Fee as ProtoFee, MsgPayPacketFeeAsync, PacketFee as ProtoPacketFee, +}; +use ibc_proto::ibc::core::channel::v1::PacketId as ProtoPacketId; + +use crate::applications::ics29_fee::error::Error; +use crate::applications::ics29_fee::utils::encode_message; +use crate::core::ics04_channel::packet::Sequence; +use crate::core::ics24_host::identifier::{ChannelId, PortId}; +use crate::prelude::*; +use crate::signer::Signer; + +const TYPE_URL: &str = "/ibc.applications.fee.v1.MsgPayPacketFeeAsync"; + +pub fn build_pay_packet_fee_async_message( + port_id: &PortId, + channel_id: &ChannelId, + sequence: Sequence, + payer: &Signer, + recv_fee: Vec, + ack_fee: Vec, + timeout_fee: Vec, +) -> Result { + let fee = ProtoFee { + recv_fee, + ack_fee, + timeout_fee, + }; + + let packet_fee = ProtoPacketFee { + fee: Some(fee), + refund_address: payer.to_string(), + relayers: Vec::new(), + }; + + let packet_id = ProtoPacketId { + port_id: port_id.to_string(), + channel_id: channel_id.to_string(), + sequence: sequence.into(), + }; + + let message = MsgPayPacketFeeAsync { + packet_fee: Some(packet_fee), + packet_id: Some(packet_id), + }; + + let encoded = encode_message(&message).map_err(Error::encode)?; + + Ok(Any { + type_url: TYPE_URL.to_string(), + value: encoded, + }) +} diff --git a/modules/src/applications/ics29_fee/msgs/register_counterparty.rs b/modules/src/applications/ics29_fee/msgs/register_counterparty.rs new file mode 100644 index 0000000000..6161e2ed5f --- /dev/null +++ b/modules/src/applications/ics29_fee/msgs/register_counterparty.rs @@ -0,0 +1,31 @@ +use ibc_proto::google::protobuf::Any; +use ibc_proto::ibc::applications::fee::v1::MsgRegisterCounterpartyAddress; + +use crate::applications::ics29_fee::error::Error; +use crate::applications::ics29_fee::utils::encode_message; +use crate::core::ics24_host::identifier::ChannelId; +use crate::prelude::*; +use crate::signer::Signer; + +const TYPE_URL: &str = "/ibc.applications.fee.v1.MsgRegisterCounterpartyAddress"; + +pub fn build_register_counterparty_address_message( + address: &Signer, + counterparty_address: &Signer, + channel_id: &ChannelId, +) -> Result { + let message = MsgRegisterCounterpartyAddress { + address: address.to_string(), + counterparty_address: counterparty_address.to_string(), + channel_id: channel_id.to_string(), + }; + + let encoded = encode_message(&message).map_err(Error::encode)?; + + let wrapped = Any { + type_url: TYPE_URL.to_string(), + value: encoded, + }; + + Ok(wrapped) +} diff --git a/modules/src/applications/ics29_fee/utils.rs b/modules/src/applications/ics29_fee/utils.rs new file mode 100644 index 0000000000..37d37f2fb8 --- /dev/null +++ b/modules/src/applications/ics29_fee/utils.rs @@ -0,0 +1,9 @@ +use prost::{EncodeError, Message}; + +use crate::prelude::*; + +pub fn encode_message(message: &M) -> Result, EncodeError> { + let mut buf = Vec::new(); + Message::encode(message, &mut buf)?; + Ok(buf) +} diff --git a/relayer/src/chain/cosmos.rs b/relayer/src/chain/cosmos.rs index 34b931dae7..e9ddb49a84 100644 --- a/relayer/src/chain/cosmos.rs +++ b/relayer/src/chain/cosmos.rs @@ -93,6 +93,7 @@ pub mod client; pub mod compatibility; pub mod encode; pub mod estimate; +pub mod fee; pub mod gas; pub mod query; pub mod retry; diff --git a/relayer/src/chain/cosmos/fee.rs b/relayer/src/chain/cosmos/fee.rs new file mode 100644 index 0000000000..644d8972b5 --- /dev/null +++ b/relayer/src/chain/cosmos/fee.rs @@ -0,0 +1,24 @@ +// pub async fn pay_packet_fee( +// tx_config: &MonoTagged, +// port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, +// channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, +// sequence: &DualTagged, +// payer: &MonoTagged, +// receive_fee: &TaggedTokenRef<'_, Chain>, +// ack_fee: &TaggedTokenRef<'_, Chain>, +// timeout_fee: &TaggedTokenRef<'_, Chain>, +// ) -> Result<(), Error> { +// let message = build_pay_packet_fee_async_message( +// port_id, +// channel_id, +// sequence, +// &payer.address(), +// receive_fee, +// ack_fee, +// timeout_fee, +// )?; + +// simple_send_tx(tx_config.value(), &payer.value().key, vec![message]).await?; + +// Ok(()) +// } From 026f81f2d05b5df97c1beada871951ffa7bd7015 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Sat, 4 Jun 2022 20:59:10 +0200 Subject: [PATCH 048/113] Remove fee implementation in test framework and import from ibc-relayer --- .../src/applications/ics29_fee/packet_fee.rs | 2 + relayer/src/chain/cosmos/fee.rs | 23 -- relayer/src/chain/cosmos/query/fee.rs | 2 +- tools/integration-test/src/tests/fee.rs | 25 +- tools/test-framework/src/chain/ext/fee.rs | 3 +- tools/test-framework/src/ibc/token.rs | 22 +- tools/test-framework/src/relayer/fee.rs | 377 +++--------------- 7 files changed, 103 insertions(+), 351 deletions(-) diff --git a/modules/src/applications/ics29_fee/packet_fee.rs b/modules/src/applications/ics29_fee/packet_fee.rs index 60d2aa423f..ce3a5b9185 100644 --- a/modules/src/applications/ics29_fee/packet_fee.rs +++ b/modules/src/applications/ics29_fee/packet_fee.rs @@ -9,12 +9,14 @@ use crate::core::ics04_channel::packet_id::PacketId; use crate::prelude::*; use crate::signer::Signer; +#[derive(Debug, Clone)] pub struct PacketFee { pub fee: Fee, pub refund_address: Signer, // do not expose relayer field as it is currently a reserved field } +#[derive(Debug, Clone)] pub struct IdentifiedPacketFees { pub packet_id: PacketId, pub packet_fees: Vec, diff --git a/relayer/src/chain/cosmos/fee.rs b/relayer/src/chain/cosmos/fee.rs index 644d8972b5..8b13789179 100644 --- a/relayer/src/chain/cosmos/fee.rs +++ b/relayer/src/chain/cosmos/fee.rs @@ -1,24 +1 @@ -// pub async fn pay_packet_fee( -// tx_config: &MonoTagged, -// port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, -// channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, -// sequence: &DualTagged, -// payer: &MonoTagged, -// receive_fee: &TaggedTokenRef<'_, Chain>, -// ack_fee: &TaggedTokenRef<'_, Chain>, -// timeout_fee: &TaggedTokenRef<'_, Chain>, -// ) -> Result<(), Error> { -// let message = build_pay_packet_fee_async_message( -// port_id, -// channel_id, -// sequence, -// &payer.address(), -// receive_fee, -// ack_fee, -// timeout_fee, -// )?; -// simple_send_tx(tx_config.value(), &payer.value().key, vec![message]).await?; - -// Ok(()) -// } diff --git a/relayer/src/chain/cosmos/query/fee.rs b/relayer/src/chain/cosmos/query/fee.rs index e84e9c7344..baf69426d8 100644 --- a/relayer/src/chain/cosmos/query/fee.rs +++ b/relayer/src/chain/cosmos/query/fee.rs @@ -44,7 +44,7 @@ pub async fn query_counterparty_address( } } -pub async fn query_incentivized_packets( +pub async fn query_incentivized_packets( grpc_address: &Uri, channel_id: &ChannelId, port_id: &PortId, diff --git a/tools/integration-test/src/tests/fee.rs b/tools/integration-test/src/tests/fee.rs index 8adb882dd8..fb9567e304 100644 --- a/tools/integration-test/src/tests/fee.rs +++ b/tools/integration-test/src/tests/fee.rs @@ -473,21 +473,28 @@ impl BinaryChannelTest for PayPacketFeeAsyncTest { assert_eq!(packet.packet_fees.len(), 1); let packet_fee = &packet.packet_fees[0]; - assert_eq!(packet_fee.recv_fee.len(), 1); - assert_eq!(packet_fee.ack_fee.len(), 1); - assert_eq!(packet_fee.timeout_fee.len(), 1); + assert_eq!(packet_fee.fee.recv_fee.len(), 1); + assert_eq!(packet_fee.fee.ack_fee.len(), 1); + assert_eq!(packet_fee.fee.timeout_fee.len(), 1); assert_eq!( - &packet_fee.recv_fee[0], - denom_a.with_amount(receive_fee).value() + &packet_fee.fee.recv_fee[0], + &denom_a.with_amount(receive_fee).value().as_coin(), ); - assert_eq!(&packet_fee.ack_fee[0], denom_a.with_amount(ack_fee).value()); assert_eq!( - &packet_fee.timeout_fee[0], - denom_a.with_amount(timeout_fee).value() + &packet_fee.fee.ack_fee[0], + &denom_a.with_amount(ack_fee).value().as_coin() ); - assert_eq!(packet_fee.refund_address, user_a.value().address); + assert_eq!( + &packet_fee.fee.timeout_fee[0], + &denom_a.with_amount(timeout_fee).value().as_coin(), + ); + + assert_eq!( + packet_fee.refund_address.as_ref(), + user_a.value().address.as_str(), + ); } let receive_fee_2 = random_u128_range(300, 400); diff --git a/tools/test-framework/src/chain/ext/fee.rs b/tools/test-framework/src/chain/ext/fee.rs index cdec95a247..1a788b282a 100644 --- a/tools/test-framework/src/chain/ext/fee.rs +++ b/tools/test-framework/src/chain/ext/fee.rs @@ -1,4 +1,5 @@ use core::time::Duration; +use ibc::applications::ics29_fee::packet_fee::IdentifiedPacketFees; use ibc::core::ics04_channel::packet::Sequence; use ibc::events::IbcEvent; @@ -8,7 +9,7 @@ use crate::error::Error; use crate::ibc::token::TaggedTokenRef; use crate::relayer::fee::{ ibc_token_transfer_with_fee, pay_packet_fee, query_counterparty_address, - query_incentivized_packets, register_counterparty_address, IdentifiedPacketFees, + query_incentivized_packets, register_counterparty_address, }; use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef}; use crate::types::tagged::*; diff --git a/tools/test-framework/src/ibc/token.rs b/tools/test-framework/src/ibc/token.rs index f889474e5d..d7e7e4bbc6 100644 --- a/tools/test-framework/src/ibc/token.rs +++ b/tools/test-framework/src/ibc/token.rs @@ -1,7 +1,9 @@ use core::fmt::{self, Display}; use core::ops::{Add, Sub}; +use core::str::FromStr; +use ibc_proto::cosmos::base::v1beta1::Coin; -use crate::error::Error; +use crate::error::{handle_generic_error, Error}; use crate::ibc::denom::{derive_ibc_denom, Denom, TaggedDenom, TaggedDenomRef}; use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef}; use crate::types::tagged::MonoTagged; @@ -35,6 +37,13 @@ impl Token { pub fn new(denom: Denom, amount: u128) -> Self { Self { denom, amount } } + + pub fn as_coin(&self) -> Coin { + Coin { + denom: self.denom.to_string(), + amount: self.amount.to_string(), + } + } } impl TaggedTokenExt for TaggedToken { @@ -138,3 +147,14 @@ impl Display for Token { write!(f, "{}{}", self.amount, self.denom) } } + +impl TryFrom for Token { + type Error = Error; + + fn try_from(fee: Coin) -> Result { + let denom = Denom::base(&fee.denom); + let amount = u128::from_str(&fee.amount).map_err(handle_generic_error)?; + + Ok(Token::new(denom, amount)) + } +} diff --git a/tools/test-framework/src/relayer/fee.rs b/tools/test-framework/src/relayer/fee.rs index 6a8ecc4224..c4b958c13e 100644 --- a/tools/test-framework/src/relayer/fee.rs +++ b/tools/test-framework/src/relayer/fee.rs @@ -1,32 +1,23 @@ -use core::convert::TryFrom; -use core::str::FromStr; use core::time::Duration; -use eyre::eyre; use http::uri::Uri; +use ibc::applications::ics29_fee::msgs::pay_packet::build_pay_packet_message; +use ibc::applications::ics29_fee::msgs::pay_packet_async::build_pay_packet_fee_async_message; +use ibc::applications::ics29_fee::msgs::register_counterparty::build_register_counterparty_address_message; +use ibc::applications::ics29_fee::packet_fee::IdentifiedPacketFees; use ibc::core::ics04_channel::packet::Sequence; -use ibc::core::ics24_host::identifier::{ChannelId, PortId}; use ibc::events::IbcEvent; -use ibc_proto::cosmos::base::v1beta1::Coin; -use ibc_proto::google::protobuf::Any; -use ibc_proto::ibc::applications::fee::v1::query_client::QueryClient; -use ibc_proto::ibc::applications::fee::v1::{ - Fee as ProtoFee, IdentifiedPacketFees as ProtoIdentifiedPacketFees, MsgPayPacketFee, - MsgPayPacketFeeAsync, MsgRegisterCounterpartyAddress, PacketFee as ProtoPacketFee, - QueryCounterpartyAddressRequest, QueryIncentivizedPacketsForChannelRequest, +use ibc_relayer::chain::cosmos::query::fee::{ + query_counterparty_address as raw_query_counterparty_address, + query_incentivized_packets as raw_query_incentivized_packets, }; -use ibc_proto::ibc::core::channel::v1::PacketId as ProtoPacketId; use ibc_relayer::chain::cosmos::types::config::TxConfig; -use prost::{EncodeError, Message}; -use tonic::Code; use crate::error::{handle_generic_error, Error}; -use crate::ibc::denom::Denom; -use crate::ibc::token::{TaggedTokenRef, Token}; +use crate::ibc::token::TaggedTokenRef; use crate::relayer::transfer::build_transfer_message; use crate::relayer::tx::simple_send_tx; use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef}; use crate::types::tagged::{DualTagged, MonoTagged}; -use crate::types::wallet::TaggedWallet; use crate::types::wallet::{Wallet, WalletAddress}; pub async fn ibc_token_transfer_with_fee( @@ -45,13 +36,19 @@ pub async fn ibc_token_transfer_with_fee( build_transfer_message(port_id, channel_id, sender, recipient, send_amount, timeout)?; let pay_message = build_pay_packet_message( - port_id, - channel_id, - &sender.address(), - receive_fee, - ack_fee, - timeout_fee, - )?; + port_id.value(), + channel_id.value(), + &sender + .value() + .address + .0 + .parse() + .map_err(handle_generic_error)?, + vec![receive_fee.value().as_coin()], + vec![ack_fee.value().as_coin()], + vec![timeout_fee.value().as_coin()], + ) + .map_err(handle_generic_error)?; let messages = vec![pay_message, transfer_message]; @@ -71,14 +68,20 @@ pub async fn pay_packet_fee( timeout_fee: &TaggedTokenRef<'_, Chain>, ) -> Result<(), Error> { let message = build_pay_packet_fee_async_message( - port_id, - channel_id, - sequence, - &payer.address(), - receive_fee, - ack_fee, - timeout_fee, - )?; + port_id.value(), + channel_id.value(), + *sequence.value(), + &payer + .value() + .address + .0 + .parse() + .map_err(handle_generic_error)?, + vec![receive_fee.value().as_coin()], + vec![ack_fee.value().as_coin()], + vec![timeout_fee.value().as_coin()], + ) + .map_err(handle_generic_error)?; simple_send_tx(tx_config.value(), &payer.value().key, vec![message]).await?; @@ -92,279 +95,42 @@ pub async fn register_counterparty_address( channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, ) -> Result<(), Error> { let message = build_register_counterparty_address_message( - &wallet.address(), - counterparty_address, - channel_id, - )?; - - let messages = vec![message.into_value()]; + &wallet + .value() + .address + .0 + .parse() + .map_err(handle_generic_error)?, + &counterparty_address + .value() + .0 + .parse() + .map_err(handle_generic_error)?, + channel_id.value(), + ) + .map_err(handle_generic_error)?; + + let messages = vec![message]; simple_send_tx(tx_config.value(), &wallet.value().key, messages).await?; Ok(()) } -fn encode_message(message: &M) -> Result, EncodeError> { - let mut buf = Vec::new(); - Message::encode(message, &mut buf)?; - Ok(buf) -} - -pub fn build_pay_packet_message( - port_id: &TaggedPortIdRef, - channel_id: &TaggedChannelIdRef, - payer: &MonoTagged, - receive_fee: &TaggedTokenRef<'_, Chain>, - ack_fee: &TaggedTokenRef<'_, Chain>, - timeout_fee: &TaggedTokenRef<'_, Chain>, -) -> Result { - const TYPE_URL: &str = "/ibc.applications.fee.v1.MsgPayPacketFee"; - - let fee = ProtoFee { - recv_fee: vec![Coin { - denom: receive_fee.value().denom.to_string(), - amount: receive_fee.value().amount.to_string(), - }], - ack_fee: vec![Coin { - denom: ack_fee.value().denom.to_string(), - amount: ack_fee.value().amount.to_string(), - }], - timeout_fee: vec![Coin { - denom: timeout_fee.value().denom.to_string(), - amount: timeout_fee.value().amount.to_string(), - }], - }; - - let message = MsgPayPacketFee { - fee: Some(fee), - source_port_id: port_id.value().to_string(), - source_channel_id: channel_id.value().to_string(), - signer: payer.value().0.clone(), - relayers: Vec::new(), - }; - - let encoded = encode_message(&message).map_err(handle_generic_error)?; - - Ok(Any { - type_url: TYPE_URL.to_string(), - value: encoded, - }) -} - -pub fn build_pay_packet_fee_async_message( - port_id: &TaggedPortIdRef, - channel_id: &TaggedChannelIdRef, - sequence: &DualTagged, - payer: &MonoTagged, - receive_fee: &TaggedTokenRef<'_, Chain>, - ack_fee: &TaggedTokenRef<'_, Chain>, - timeout_fee: &TaggedTokenRef<'_, Chain>, -) -> Result { - const TYPE_URL: &str = "/ibc.applications.fee.v1.MsgPayPacketFeeAsync"; - - let fee = ProtoFee { - recv_fee: vec![Coin { - denom: receive_fee.value().denom.to_string(), - amount: receive_fee.value().amount.to_string(), - }], - ack_fee: vec![Coin { - denom: ack_fee.value().denom.to_string(), - amount: ack_fee.value().amount.to_string(), - }], - timeout_fee: vec![Coin { - denom: timeout_fee.value().denom.to_string(), - amount: timeout_fee.value().amount.to_string(), - }], - }; - - let packet_fee = ProtoPacketFee { - fee: Some(fee), - refund_address: payer.value().0.clone(), - relayers: Vec::new(), - }; - - let packet_id = ProtoPacketId { - port_id: port_id.value().to_string(), - channel_id: channel_id.value().to_string(), - sequence: (*sequence.value()).into(), - }; - - let message = MsgPayPacketFeeAsync { - packet_fee: Some(packet_fee), - packet_id: Some(packet_id), - }; - - let encoded = encode_message(&message).map_err(handle_generic_error)?; - - Ok(Any { - type_url: TYPE_URL.to_string(), - value: encoded, - }) -} - -pub fn build_register_counterparty_address_message( - address: &MonoTagged, - counterparty_address: &MonoTagged, - channel_id: &TaggedChannelIdRef, -) -> Result, Error> { - const TYPE_URL: &str = "/ibc.applications.fee.v1.MsgRegisterCounterpartyAddress"; - - let message = MsgRegisterCounterpartyAddress { - address: address.value().0.clone(), - counterparty_address: counterparty_address.value().0.clone(), - channel_id: channel_id.value().to_string(), - }; - - let encoded = encode_message(&message).map_err(handle_generic_error)?; - - let wrapped = Any { - type_url: TYPE_URL.to_string(), - value: encoded, - }; - - Ok(MonoTagged::new(wrapped)) -} - pub async fn query_counterparty_address( grpc_address: &Uri, channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, address: &MonoTagged, ) -> Result>, Error> { - let mut client = QueryClient::connect(grpc_address.clone()) - .await - .map_err(handle_generic_error)?; - - let request = QueryCounterpartyAddressRequest { - channel_id: channel_id.value().to_string(), - relayer_address: address.value().to_string(), - }; - - let result = client.counterparty_address(request).await; - - match result { - Ok(response) => { - let counterparty_address = WalletAddress(response.into_inner().counterparty_address); + let counterparty_address = raw_query_counterparty_address( + grpc_address, + channel_id.value(), + &address.value().0.parse().map_err(handle_generic_error)?, + ) + .await + .map_err(handle_generic_error)?; - Ok(Some(MonoTagged::new(counterparty_address))) - } - Err(e) => { - if e.code() == Code::NotFound { - Ok(None) - } else { - Err(Error::generic(e.into())) - } - } - } -} - -#[derive(Debug, Clone)] -pub struct PacketId { - pub channel_id: ChannelId, - pub port_id: PortId, - pub sequence: Sequence, -} - -#[derive(Debug, Clone)] -pub struct PacketFee { - pub recv_fee: Vec, - pub ack_fee: Vec, - pub timeout_fee: Vec, - pub refund_address: WalletAddress, -} - -#[derive(Debug, Clone)] -pub struct IdentifiedPacketFees { - pub packet_id: PacketId, - pub packet_fees: Vec, -} - -impl TryFrom for PacketId { - type Error = Error; - - fn try_from(packet_id: ProtoPacketId) -> Result { - let channel_id = - ChannelId::from_str(&packet_id.channel_id).map_err(handle_generic_error)?; - - let port_id = PortId::from_str(&packet_id.port_id).map_err(handle_generic_error)?; - - let sequence = Sequence::from(packet_id.sequence); - - Ok(PacketId { - channel_id, - port_id, - sequence, - }) - } -} - -impl TryFrom for Token { - type Error = Error; - - fn try_from(fee: Coin) -> Result { - let denom = Denom::base(&fee.denom); - let amount = u128::from_str(&fee.amount).map_err(handle_generic_error)?; - - Ok(Token::new(denom, amount)) - } -} - -impl TryFrom for PacketFee { - type Error = Error; - - fn try_from(packet_fee: ProtoPacketFee) -> Result { - let fee = packet_fee - .fee - .ok_or_else(|| eyre!("expect fee field to be non-empty"))?; - - let recv_fee = fee - .recv_fee - .into_iter() - .map(Token::try_from) - .collect::>()?; - - let ack_fee = fee - .ack_fee - .into_iter() - .map(Token::try_from) - .collect::>()?; - - let timeout_fee = fee - .timeout_fee - .into_iter() - .map(Token::try_from) - .collect::>()?; - - let refund_address = WalletAddress(packet_fee.refund_address); - - Ok(PacketFee { - recv_fee, - ack_fee, - timeout_fee, - refund_address, - }) - } -} - -impl TryFrom for IdentifiedPacketFees { - type Error = Error; - - fn try_from(fees: ProtoIdentifiedPacketFees) -> Result { - let raw_packet_id = fees - .packet_id - .ok_or_else(|| eyre!("expect non-empty packet_id"))?; - - let packet_id = PacketId::try_from(raw_packet_id)?; - let packet_fees = fees - .packet_fees - .into_iter() - .map(PacketFee::try_from) - .collect::>()?; - - Ok(IdentifiedPacketFees { - packet_id, - packet_fees, - }) - } + Ok(counterparty_address.map(|address| MonoTagged::new(WalletAddress(address.to_string())))) } pub async fn query_incentivized_packets( @@ -372,28 +138,7 @@ pub async fn query_incentivized_packets( channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, ) -> Result, Error> { - let mut client = QueryClient::connect(grpc_address.clone()) - .await - .map_err(handle_generic_error)?; - - let request = QueryIncentivizedPacketsForChannelRequest { - channel_id: channel_id.value().to_string(), - port_id: port_id.value().to_string(), - pagination: None, - query_height: 0, - }; - - let response = client - .incentivized_packets_for_channel(request) + raw_query_incentivized_packets(grpc_address, channel_id.value(), port_id.value()) .await - .map_err(handle_generic_error)?; - - let raw_packets = response.into_inner().incentivized_packets; - - let packets = raw_packets - .into_iter() - .map(IdentifiedPacketFees::try_from) - .collect::>()?; - - Ok(packets) + .map_err(handle_generic_error) } From ce5c1110a8705c9cf06d49feea35e0ed9eb0d871 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Mon, 6 Jun 2022 10:59:46 +0200 Subject: [PATCH 049/113] Catch panics in hang_on_error --- tools/test-framework/src/util/suspend.rs | 53 ++++++++++++++++-------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/tools/test-framework/src/util/suspend.rs b/tools/test-framework/src/util/suspend.rs index d5d0001aa2..40272c7e26 100644 --- a/tools/test-framework/src/util/suspend.rs +++ b/tools/test-framework/src/util/suspend.rs @@ -2,11 +2,13 @@ Utilities for suspending the test. */ -use core::fmt::{Debug, Display}; use core::time::Duration; +use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe}; use std::thread::sleep; use tracing::{error, warn}; +use crate::error::Error; + /** Call this function in the middle of a test code of interest, so that we can suspend the test and still interact with the @@ -28,22 +30,39 @@ pub fn suspend() -> R { [`TestConfig`](crate::types::config::TestConfig), which in turns is set from the `HANG_ON_FAIL` environment variable. */ -pub fn hang_on_error( +pub fn hang_on_error( hang_on_fail: bool, - cont: impl FnOnce() -> Result, -) -> Result { - if hang_on_fail { - cont().map_err(|e| { - error!("test failure occured with HANG_ON_FAIL=1, suspending the test to allow debugging: {:?}", - e); - - suspend() - }) - } else { - cont().map_err(|e| { - error!("test failure occured. set HANG_ON_FAIL=1 to suspend the test on failure for debugging: {}", - e); - e - }) + cont: impl FnOnce() -> Result, +) -> Result { + let result = catch_unwind(AssertUnwindSafe(cont)); + + match result { + Err(e) => { + if hang_on_fail { + let message = e.downcast::<&str>().ok(); + error!("test panicked with HANG_ON_FAIL=1, suspending the test to allow debugging: {:?}", + message); + + suspend() + } else { + error!("test panicked. set HANG_ON_FAIL=1 to suspend the test on failure for debugging."); + + resume_unwind(e) + } + } + Ok(Err(e)) => { + if hang_on_fail { + error!("test failure occured with HANG_ON_FAIL=1, suspending the test to allow debugging: {:?}", + e); + + suspend() + } else { + error!("test failure occured. set HANG_ON_FAIL=1 to suspend the test on failure for debugging: {:?}", + e); + + Err(e) + } + } + Ok(Ok(res)) => Ok(res), } } From 1bf7ab1d768d609423a983aae77e946ec328864d Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Mon, 6 Jun 2022 11:09:00 +0200 Subject: [PATCH 050/113] Fix merge error --- .github/workflows/integration.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml index 53b06f9771..37bfa8090f 100644 --- a/.github/workflows/integration.yaml +++ b/.github/workflows/integration.yaml @@ -174,7 +174,6 @@ jobs: test -p ibc-integration-test --features ica --no-fail-fast -- \ --nocapture --test-threads=1 test_ica_filter -<<<<<<< HEAD ics29-fee-test: runs-on: ubuntu-latest steps: From 76e80a954181b73dfe1b1752fbfb207c58f19709 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Mon, 6 Jun 2022 12:43:13 +0200 Subject: [PATCH 051/113] Implement maybe_register_counterparty_address --- relayer/src/chain/cosmos/batch.rs | 6 +-- relayer/src/chain/cosmos/fee.rs | 59 +++++++++++++++++++++++++ relayer/src/chain/cosmos/query/fee.rs | 6 +-- relayer/src/chain/cosmos/retry.rs | 11 +---- tools/test-framework/src/relayer/fee.rs | 2 +- 5 files changed, 65 insertions(+), 19 deletions(-) diff --git a/relayer/src/chain/cosmos/batch.rs b/relayer/src/chain/cosmos/batch.rs index 1466aa777e..6825201b16 100644 --- a/relayer/src/chain/cosmos/batch.rs +++ b/relayer/src/chain/cosmos/batch.rs @@ -67,8 +67,7 @@ pub async fn send_batched_messages_and_wait_check_tx( for batch in batches { let response = - send_tx_with_account_sequence_retry(config, key_entry, account, tx_memo, batch, 0) - .await?; + send_tx_with_account_sequence_retry(config, key_entry, account, tx_memo, batch).await?; responses.push(response); } @@ -95,8 +94,7 @@ async fn send_messages_as_batches( for batch in batches { let response = - send_tx_with_account_sequence_retry(config, key_entry, account, tx_memo, batch, 0) - .await?; + send_tx_with_account_sequence_retry(config, key_entry, account, tx_memo, batch).await?; tx_hashes.push(response.hash); } diff --git a/relayer/src/chain/cosmos/fee.rs b/relayer/src/chain/cosmos/fee.rs index 8b13789179..9d3f78006d 100644 --- a/relayer/src/chain/cosmos/fee.rs +++ b/relayer/src/chain/cosmos/fee.rs @@ -1 +1,60 @@ +use ibc::applications::ics29_fee::msgs::register_counterparty::build_register_counterparty_address_message; +use ibc::core::ics24_host::identifier::ChannelId; +use ibc::signer::Signer; +use crate::chain::cosmos::query::fee::query_counterparty_address; +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::wait::wait_tx_succeed; +use crate::config::types::Memo; +use crate::error::Error; +use crate::keyring::KeyEntry; + +pub async fn maybe_register_counterparty_address( + tx_config: &TxConfig, + channel_id: &ChannelId, + key_entry: &KeyEntry, + account: &mut Account, + tx_memo: &Memo, + address: &Signer, + counterparty_address: &Signer, +) -> Result<(), Error> { + let current_counterparty_address = + query_counterparty_address(&tx_config.grpc_address, channel_id, address).await?; + + match ¤t_counterparty_address { + Some(current_counterparty_address) + if current_counterparty_address == counterparty_address.as_ref() => + { + Ok(()) + } + _ => { + let message = build_register_counterparty_address_message( + address, + counterparty_address, + channel_id, + ) + .map_err(Error::ics29)?; + + let response = send_tx_with_account_sequence_retry( + tx_config, + key_entry, + account, + tx_memo, + vec![message], + ) + .await?; + + wait_tx_succeed( + &tx_config.rpc_client, + &tx_config.rpc_address, + &tx_config.rpc_timeout, + &response.hash, + ) + .await?; + + Ok(()) + } + } +} diff --git a/relayer/src/chain/cosmos/query/fee.rs b/relayer/src/chain/cosmos/query/fee.rs index baf69426d8..3f1bf8cdc5 100644 --- a/relayer/src/chain/cosmos/query/fee.rs +++ b/relayer/src/chain/cosmos/query/fee.rs @@ -1,4 +1,3 @@ -use core::str::FromStr; use http::uri::Uri; use ibc::applications::ics29_fee::packet_fee::IdentifiedPacketFees; use ibc::core::ics24_host::identifier::{ChannelId, PortId}; @@ -15,7 +14,7 @@ pub async fn query_counterparty_address( grpc_address: &Uri, channel_id: &ChannelId, address: &Signer, -) -> Result, Error> { +) -> Result, Error> { let mut client = QueryClient::connect(grpc_address.clone()) .await .map_err(Error::grpc_transport)?; @@ -29,8 +28,7 @@ pub async fn query_counterparty_address( match result { Ok(response) => { - let counterparty_address = - Signer::from_str(&response.into_inner().counterparty_address).unwrap(); + let counterparty_address = response.into_inner().counterparty_address; Ok(Some(counterparty_address)) } diff --git a/relayer/src/chain/cosmos/retry.rs b/relayer/src/chain/cosmos/retry.rs index 61c10362db..480b9a1d18 100644 --- a/relayer/src/chain/cosmos/retry.rs +++ b/relayer/src/chain/cosmos/retry.rs @@ -51,7 +51,6 @@ pub async fn send_tx_with_account_sequence_retry( account: &mut Account, tx_memo: &Memo, messages: Vec, - retry_counter: u64, ) -> Result { crate::time!("send_tx_with_account_sequence_retry"); @@ -60,15 +59,7 @@ pub async fn send_tx_with_account_sequence_retry( telemetry!(msg_num, &config.chain_id, messages.len() as u64); - do_send_tx_with_account_sequence_retry( - config, - key_entry, - account, - tx_memo, - messages, - retry_counter, - ) - .await + do_send_tx_with_account_sequence_retry(config, key_entry, account, tx_memo, messages, 0).await } // We have to do explicit return of `Box` because Rust diff --git a/tools/test-framework/src/relayer/fee.rs b/tools/test-framework/src/relayer/fee.rs index c4b958c13e..7cf382e983 100644 --- a/tools/test-framework/src/relayer/fee.rs +++ b/tools/test-framework/src/relayer/fee.rs @@ -130,7 +130,7 @@ pub async fn query_counterparty_address( .await .map_err(handle_generic_error)?; - Ok(counterparty_address.map(|address| MonoTagged::new(WalletAddress(address.to_string())))) + Ok(counterparty_address.map(|address| MonoTagged::new(WalletAddress(address)))) } pub async fn query_incentivized_packets( From b7dbeb82eb0da756647f99bd6710d752ed920aac Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Tue, 7 Jun 2022 11:23:53 +0200 Subject: [PATCH 052/113] Add maybe_register_counterparty_address ChainHandle method --- relayer/src/chain/cosmos.rs | 22 +++++++++++++++++++++- relayer/src/chain/cosmos/fee.rs | 8 ++++++-- relayer/src/chain/endpoint.rs | 8 +++++++- relayer/src/chain/handle.rs | 12 ++++++++++++ relayer/src/chain/handle/base.rs | 12 ++++++++++++ relayer/src/chain/handle/cache.rs | 9 +++++++++ relayer/src/chain/handle/counting.rs | 9 +++++++++ relayer/src/chain/mock.rs | 10 +++++++++- relayer/src/chain/runtime.rs | 19 +++++++++++++++++++ tools/test-framework/src/relayer/chain.rs | 9 +++++++++ 10 files changed, 113 insertions(+), 5 deletions(-) diff --git a/relayer/src/chain/cosmos.rs b/relayer/src/chain/cosmos.rs index 17d9f6f486..c5edd48aa6 100644 --- a/relayer/src/chain/cosmos.rs +++ b/relayer/src/chain/cosmos.rs @@ -59,6 +59,7 @@ use crate::chain::cosmos::batch::{ send_batched_messages_and_wait_check_tx, send_batched_messages_and_wait_commit, }; use crate::chain::cosmos::encode::encode_to_bech32; +use crate::chain::cosmos::fee::maybe_register_counterparty_address; use crate::chain::cosmos::gas::{calculate_fee, mul_ceil}; use crate::chain::cosmos::query::account::get_or_fetch_account; use crate::chain::cosmos::query::balance::query_balance; @@ -593,7 +594,7 @@ impl ChainEndpoint for CosmosSdkChain { } /// Get the account for the signer - fn get_signer(&mut self) -> Result { + fn get_signer(&self) -> Result { crate::time!("get_signer"); // Get the key from key seed file @@ -1526,6 +1527,25 @@ impl ChainEndpoint for CosmosSdkChain { Ok((target, supporting)) } + + fn maybe_register_counterparty_address( + &mut self, + channel_id: &ChannelId, + counterparty_address: &Signer, + ) -> Result<(), Error> { + let address = self.get_signer()?; + let key_entry = self.key()?; + + self.rt.block_on(maybe_register_counterparty_address( + &self.tx_config, + &key_entry, + &mut self.account, + &self.config.memo_prefix, + channel_id, + &address, + counterparty_address, + )) + } } fn filter_matching_event( diff --git a/relayer/src/chain/cosmos/fee.rs b/relayer/src/chain/cosmos/fee.rs index 9d3f78006d..87886358ff 100644 --- a/relayer/src/chain/cosmos/fee.rs +++ b/relayer/src/chain/cosmos/fee.rs @@ -2,6 +2,7 @@ use ibc::applications::ics29_fee::msgs::register_counterparty::build_register_co use ibc::core::ics24_host::identifier::ChannelId; use ibc::signer::Signer; +use crate::chain::cosmos::query::account::get_or_fetch_account; use crate::chain::cosmos::query::fee::query_counterparty_address; use crate::chain::cosmos::retry::send_tx_with_account_sequence_retry; use crate::chain::cosmos::types::account::Account; @@ -13,13 +14,16 @@ use crate::keyring::KeyEntry; pub async fn maybe_register_counterparty_address( tx_config: &TxConfig, - channel_id: &ChannelId, key_entry: &KeyEntry, - account: &mut Account, + m_account: &mut Option, tx_memo: &Memo, + channel_id: &ChannelId, address: &Signer, counterparty_address: &Signer, ) -> Result<(), Error> { + let account = + get_or_fetch_account(&tx_config.grpc_address, &key_entry.account, m_account).await?; + let current_counterparty_address = query_counterparty_address(&tx_config.grpc_address, channel_id, address).await?; diff --git a/relayer/src/chain/endpoint.rs b/relayer/src/chain/endpoint.rs index 6b75fddc9c..39b846c0d3 100644 --- a/relayer/src/chain/endpoint.rs +++ b/relayer/src/chain/endpoint.rs @@ -116,7 +116,7 @@ pub trait ChainEndpoint: Sized { tracked_msgs: TrackedMsgs, ) -> Result, Error>; - fn get_signer(&mut self) -> Result; + fn get_signer(&self) -> Result; fn config(&self) -> ChainConfig; @@ -441,4 +441,10 @@ pub trait ChainEndpoint: Sized { Ok((bytes, proofs)) } + + fn maybe_register_counterparty_address( + &mut self, + channel_id: &ChannelId, + counterparty_address: &Signer, + ) -> Result<(), Error>; } diff --git a/relayer/src/chain/handle.rs b/relayer/src/chain/handle.rs index dfffb2c187..e2f143da2a 100644 --- a/relayer/src/chain/handle.rs +++ b/relayer/src/chain/handle.rs @@ -339,6 +339,12 @@ pub enum ChainRequest { request: QueryHostConsensusStateRequest, reply_to: ReplyTo, }, + + MaybeRegisterCounterpartyAddress { + channel_id: ChannelId, + counterparty_address: Signer, + reply_to: ReplyTo<()>, + }, } pub trait ChainHandle: Clone + Send + Sync + Serialize + Debug + 'static { @@ -561,4 +567,10 @@ pub trait ChainHandle: Clone + Send + Sync + Serialize + Debug + 'static { &self, request: QueryHostConsensusStateRequest, ) -> Result; + + fn maybe_register_counterparty_address( + &self, + channel_id: ChannelId, + counterparty_address: Signer, + ) -> Result<(), Error>; } diff --git a/relayer/src/chain/handle/base.rs b/relayer/src/chain/handle/base.rs index b086242eb6..fef18f274b 100644 --- a/relayer/src/chain/handle/base.rs +++ b/relayer/src/chain/handle/base.rs @@ -442,6 +442,18 @@ impl ChainHandle for BaseChainHandle { ) -> Result { self.send(|reply_to| ChainRequest::QueryHostConsensusState { request, reply_to }) } + + fn maybe_register_counterparty_address( + &self, + channel_id: ChannelId, + counterparty_address: Signer, + ) -> Result<(), Error> { + self.send(|reply_to| ChainRequest::MaybeRegisterCounterpartyAddress { + channel_id, + counterparty_address, + reply_to, + }) + } } impl Serialize for BaseChainHandle { diff --git a/relayer/src/chain/handle/cache.rs b/relayer/src/chain/handle/cache.rs index 31f7adfbdb..37dd57c1ce 100644 --- a/relayer/src/chain/handle/cache.rs +++ b/relayer/src/chain/handle/cache.rs @@ -446,4 +446,13 @@ impl ChainHandle for CachingChainHandle { ) -> Result { self.inner.query_host_consensus_state(request) } + + fn maybe_register_counterparty_address( + &self, + channel_id: ChannelId, + counterparty_address: Signer, + ) -> Result<(), Error> { + self.inner + .maybe_register_counterparty_address(channel_id, counterparty_address) + } } diff --git a/relayer/src/chain/handle/counting.rs b/relayer/src/chain/handle/counting.rs index b5dcac3b05..cef219dade 100644 --- a/relayer/src/chain/handle/counting.rs +++ b/relayer/src/chain/handle/counting.rs @@ -452,4 +452,13 @@ impl ChainHandle for CountingChainHandle { ) -> Result { self.inner.query_host_consensus_state(request) } + + fn maybe_register_counterparty_address( + &self, + channel_id: ChannelId, + counterparty_address: Signer, + ) -> Result<(), Error> { + self.inner + .maybe_register_counterparty_address(channel_id, counterparty_address) + } } diff --git a/relayer/src/chain/mock.rs b/relayer/src/chain/mock.rs index f61b334980..af34732ac2 100644 --- a/relayer/src/chain/mock.rs +++ b/relayer/src/chain/mock.rs @@ -144,7 +144,7 @@ impl ChainEndpoint for MockChain { todo!() } - fn get_signer(&mut self) -> Result { + fn get_signer(&self) -> Result { Ok(get_dummy_account_id()) } @@ -440,6 +440,14 @@ impl ChainEndpoint for MockChain { ) -> Result<(AnyConsensusState, MerkleProof), Error> { unimplemented!() } + + fn maybe_register_counterparty_address( + &mut self, + _channel_id: &ChannelId, + _counterparty_address: &Signer, + ) -> Result<(), Error> { + unimplemented!() + } } // For integration tests with the modules diff --git a/relayer/src/chain/runtime.rs b/relayer/src/chain/runtime.rs index 1202ec8859..ce8c51ae34 100644 --- a/relayer/src/chain/runtime.rs +++ b/relayer/src/chain/runtime.rs @@ -417,6 +417,10 @@ where self.query_host_consensus_state(request, reply_to)? }, + Ok(ChainRequest::MaybeRegisterCounterpartyAddress { channel_id, counterparty_address, reply_to }) => { + self.maybe_register_counterparty_address(&channel_id, &counterparty_address, reply_to)? + } + Err(e) => error!("received error via chain request channel: {}", e), } }, @@ -892,4 +896,19 @@ where Ok(()) } + + fn maybe_register_counterparty_address( + &mut self, + channel_id: &ChannelId, + counterparty_address: &Signer, + reply_to: ReplyTo<()>, + ) -> Result<(), Error> { + let result = self + .chain + .maybe_register_counterparty_address(channel_id, counterparty_address); + + reply_to.send(result).map_err(Error::send)?; + + Ok(()) + } } diff --git a/tools/test-framework/src/relayer/chain.rs b/tools/test-framework/src/relayer/chain.rs index 86cc962723..9c70487d0c 100644 --- a/tools/test-framework/src/relayer/chain.rs +++ b/tools/test-framework/src/relayer/chain.rs @@ -388,4 +388,13 @@ where fn query_balance(&self, key_name: Option) -> Result { self.value().query_balance(key_name) } + + fn maybe_register_counterparty_address( + &self, + channel_id: ChannelId, + counterparty_address: Signer, + ) -> Result<(), Error> { + self.value() + .maybe_register_counterparty_address(channel_id, counterparty_address) + } } From e4754c3322bf5ad0ebdf2a49550f24e577f32f0b Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Tue, 7 Jun 2022 14:25:38 +0200 Subject: [PATCH 053/113] Fix import error --- Cargo.lock | 11 ++++++----- relayer/src/chain/cosmos.rs | 2 +- relayer/src/chain/mock.rs | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f58d3ef607..11ba78f8c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3082,20 +3082,21 @@ dependencies = [ [[package]] name = "serial_test" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5bcc41d18f7a1d50525d080fd3e953be87c4f9f1a974f3c21798ca00d54ec15" +checksum = "d19dbfb999a147cedbfe82f042eb9555f5b0fa4ef95ee4570b74349103d9c9f4" dependencies = [ "lazy_static", - "parking_lot 0.11.2", + "log", + "parking_lot 0.12.0", "serial_test_derive", ] [[package]] name = "serial_test_derive" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2881bccd7d60fb32dfa3d7b3136385312f8ad75e2674aab2852867a09790cae8" +checksum = "cb9e2050b2be1d681f8f1c1a528bcfe4e00afa2d8995f713974f5333288659f2" dependencies = [ "proc-macro-error", "proc-macro2", diff --git a/relayer/src/chain/cosmos.rs b/relayer/src/chain/cosmos.rs index ed59b9723e..c430a95613 100644 --- a/relayer/src/chain/cosmos.rs +++ b/relayer/src/chain/cosmos.rs @@ -37,7 +37,7 @@ use ibc::core::ics04_channel::channel::{ use ibc::core::ics04_channel::events as ChannelEvents; use ibc::core::ics04_channel::packet::{Packet, Sequence}; use ibc::core::ics23_commitment::commitment::CommitmentPrefix; -use ibc::core::ics24_host::identifier::{ChainId, ClientId, ConnectionId}; +use ibc::core::ics24_host::identifier::{ChainId, ChannelId, ClientId, ConnectionId}; use ibc::core::ics24_host::path::{ AcksPath, ChannelEndsPath, ClientConsensusStatePath, ClientStatePath, CommitmentsPath, ConnectionsPath, ReceiptsPath, SeqRecvsPath, diff --git a/relayer/src/chain/mock.rs b/relayer/src/chain/mock.rs index 67f2644b70..1477adf1f5 100644 --- a/relayer/src/chain/mock.rs +++ b/relayer/src/chain/mock.rs @@ -19,7 +19,7 @@ use ibc::core::ics04_channel::channel::{ChannelEnd, IdentifiedChannelEnd}; use ibc::core::ics04_channel::context::ChannelReader; use ibc::core::ics04_channel::packet::Sequence; use ibc::core::ics23_commitment::{commitment::CommitmentPrefix, specs::ProofSpecs}; -use ibc::core::ics24_host::identifier::{ChainId, ConnectionId}; +use ibc::core::ics24_host::identifier::{ChainId, ChannelId, ConnectionId}; use ibc::events::IbcEvent; use ibc::mock::context::MockContext; use ibc::mock::host::HostType; From bb1922781d268e170f7e4cd6684ed37b4b6cadf1 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Tue, 7 Jun 2022 14:43:55 +0200 Subject: [PATCH 054/113] Add Link option for auto registering counterparty address --- relayer-cli/src/commands/clear.rs | 5 ++-- relayer-cli/src/commands/tx/packet.rs | 4 +-- relayer/src/config.rs | 8 ++++++ relayer/src/link.rs | 27 ++++++++++++++++--- relayer/src/worker.rs | 1 + tools/integration-test/src/mbt/transfer.rs | 1 + .../src/tests/client_expiration.rs | 1 + .../src/tests/execute_schedule.rs | 1 + .../src/tests/query_packet.rs | 3 ++- .../integration-test/src/tests/supervisor.rs | 1 + 10 files changed, 43 insertions(+), 9 deletions(-) diff --git a/relayer-cli/src/commands/clear.rs b/relayer-cli/src/commands/clear.rs index eff01641da..af1e5649fa 100644 --- a/relayer-cli/src/commands/clear.rs +++ b/relayer-cli/src/commands/clear.rs @@ -54,11 +54,12 @@ impl Runnable for ClearPacketsCmd { src_port_id: self.port_id.clone(), src_channel_id: self.channel_id, }; - let fwd_link = match Link::new_from_opts(chains.src.clone(), chains.dst, opts, false) { + let fwd_link = match Link::new_from_opts(chains.src.clone(), chains.dst, opts, false, false) + { Ok(link) => link, Err(e) => Output::error(format!("{}", e)).exit(), }; - let rev_link = match fwd_link.reverse(false) { + let rev_link = match fwd_link.reverse(false, false) { Ok(link) => link, Err(e) => Output::error(format!("{}", e)).exit(), }; diff --git a/relayer-cli/src/commands/tx/packet.rs b/relayer-cli/src/commands/tx/packet.rs index 607703b4f6..8f1b917594 100644 --- a/relayer-cli/src/commands/tx/packet.rs +++ b/relayer-cli/src/commands/tx/packet.rs @@ -38,7 +38,7 @@ impl Runnable for TxRawPacketRecvCmd { src_port_id: self.src_port_id.clone(), src_channel_id: self.src_channel_id, }; - let link = match Link::new_from_opts(chains.src, chains.dst, opts, false) { + let link = match Link::new_from_opts(chains.src, chains.dst, opts, false, false) { Ok(link) => link, Err(e) => Output::error(format!("{}", e)).exit(), }; @@ -82,7 +82,7 @@ impl Runnable for TxRawPacketAckCmd { src_port_id: self.src_port_id.clone(), src_channel_id: self.src_channel_id, }; - let link = match Link::new_from_opts(chains.src, chains.dst, opts, false) { + let link = match Link::new_from_opts(chains.src, chains.dst, opts, false, false) { Ok(link) => link, Err(e) => Output::error(format!("{}", e)).exit(), }; diff --git a/relayer/src/config.rs b/relayer/src/config.rs index 31d593dc9b..dc9eafdc67 100644 --- a/relayer/src/config.rs +++ b/relayer/src/config.rs @@ -73,6 +73,10 @@ pub mod default { pub fn connection_delay() -> Duration { ZERO_DURATION } + + pub fn auto_register_counterparty_address() -> bool { + false + } } #[derive(Clone, Debug, Default, Deserialize, Serialize)] @@ -156,6 +160,7 @@ impl Default for ModeConfig { clear_interval: default::clear_packets_interval(), clear_on_start: true, tx_confirmation: true, + auto_register_counterparty_address: default::auto_register_counterparty_address(), }, } } @@ -193,6 +198,8 @@ pub struct Packets { pub clear_on_start: bool, #[serde(default = "default::tx_confirmation")] pub tx_confirmation: bool, + #[serde(default = "default::auto_register_counterparty_address")] + pub auto_register_counterparty_address: bool, } impl Default for Packets { @@ -202,6 +209,7 @@ impl Default for Packets { clear_interval: default::clear_packets_interval(), clear_on_start: false, tx_confirmation: default::tx_confirmation(), + auto_register_counterparty_address: default::auto_register_counterparty_address(), } } } diff --git a/relayer/src/link.rs b/relayer/src/link.rs index f5854116f3..53be559edd 100644 --- a/relayer/src/link.rs +++ b/relayer/src/link.rs @@ -56,6 +56,7 @@ impl Link { b_chain: ChainB, opts: LinkParameters, with_tx_confirmation: bool, + auto_register_counterparty_address: bool, ) -> Result, LinkError> { // Check that the packet's channel on source chain is Open let a_channel_id = &opts.src_channel_id; @@ -124,7 +125,7 @@ impl Link { let channel = Channel { ordering: a_channel.ordering, a_side: ChannelSide::new( - a_chain, + a_chain.clone(), a_connection.client_id().clone(), a_connection_id, opts.src_port_id.clone(), @@ -132,7 +133,7 @@ impl Link { None, ), b_side: ChannelSide::new( - b_chain, + b_chain.clone(), a_connection.counterparty().client_id().clone(), a_connection.counterparty().connection_id().unwrap().clone(), a_channel.counterparty().port_id.clone(), @@ -142,12 +143,24 @@ impl Link { connection_delay: a_connection.delay_period(), }; + if auto_register_counterparty_address { + let address_a = a_chain.get_signer().map_err(LinkError::relayer)?; + + b_chain + .maybe_register_counterparty_address(b_channel_id, address_a) + .map_err(LinkError::relayer)?; + } + Link::new(channel, with_tx_confirmation) } /// Constructs a link around the channel that is reverse to the channel /// in this link. - pub fn reverse(&self, with_tx_confirmation: bool) -> Result, LinkError> { + pub fn reverse( + &self, + with_tx_confirmation: bool, + auto_register_counterparty_address: bool, + ) -> Result, LinkError> { let opts = LinkParameters { src_port_id: self.a_to_b.dst_port_id().clone(), src_channel_id: *self.a_to_b.dst_channel_id(), @@ -157,6 +170,12 @@ impl Link { // Some of the checks and initializations may be redundant; // going slowly, but reliably. - Link::new_from_opts(chain_b, chain_a, opts, with_tx_confirmation) + Link::new_from_opts( + chain_b, + chain_a, + opts, + with_tx_confirmation, + auto_register_counterparty_address, + ) } } diff --git a/relayer/src/worker.rs b/relayer/src/worker.rs index 8496761ef4..d10c90c234 100644 --- a/relayer/src/worker.rs +++ b/relayer/src/worker.rs @@ -118,6 +118,7 @@ pub fn spawn_worker_tasks( src_channel_id: path.src_channel_id, }, packets_config.tx_confirmation, + packets_config.auto_register_counterparty_address, ); match link_res { diff --git a/tools/integration-test/src/mbt/transfer.rs b/tools/integration-test/src/mbt/transfer.rs index 10b62fdee5..ff5e8d5678 100644 --- a/tools/integration-test/src/mbt/transfer.rs +++ b/tools/integration-test/src/mbt/transfer.rs @@ -157,6 +157,7 @@ impl TestOverrides for IbcTransferMBT { clear_interval: 10, clear_on_start: true, tx_confirmation: true, + ..Default::default() }, }; diff --git a/tools/integration-test/src/tests/client_expiration.rs b/tools/integration-test/src/tests/client_expiration.rs index 414cd774ab..bb36116736 100644 --- a/tools/integration-test/src/tests/client_expiration.rs +++ b/tools/integration-test/src/tests/client_expiration.rs @@ -115,6 +115,7 @@ impl TestOverrides for ExpirationTestOverrides { clear_interval: 10, clear_on_start: true, tx_confirmation: true, + ..Default::default() }, }; diff --git a/tools/integration-test/src/tests/execute_schedule.rs b/tools/integration-test/src/tests/execute_schedule.rs index 1040f12f85..fb6b87d299 100644 --- a/tools/integration-test/src/tests/execute_schedule.rs +++ b/tools/integration-test/src/tests/execute_schedule.rs @@ -53,6 +53,7 @@ impl BinaryChannelTest for ExecuteScheduleTest { chains.handle_b().clone(), chain_a_link_opts, true, + false, )?; let mut relay_path_a_to_b = chain_a_link.a_to_b; diff --git a/tools/integration-test/src/tests/query_packet.rs b/tools/integration-test/src/tests/query_packet.rs index 2717a305fa..79efcf5c63 100644 --- a/tools/integration-test/src/tests/query_packet.rs +++ b/tools/integration-test/src/tests/query_packet.rs @@ -65,6 +65,7 @@ impl BinaryChannelTest for QueryPacketPendingTest { chains.handle_b().clone(), opts, false, + false, )?; let channel_end = query_identified_channel_end( @@ -89,7 +90,7 @@ impl BinaryChannelTest for QueryPacketPendingTest { assert_eq!(summary.unreceived_acks, [1.into()]); // Acknowledge the packet on the source chain - let link = link.reverse(false)?; + let link = link.reverse(false, false)?; link.relay_ack_packet_messages()?; let summary = diff --git a/tools/integration-test/src/tests/supervisor.rs b/tools/integration-test/src/tests/supervisor.rs index 4bbe93c6c8..d9f5979584 100644 --- a/tools/integration-test/src/tests/supervisor.rs +++ b/tools/integration-test/src/tests/supervisor.rs @@ -29,6 +29,7 @@ impl TestOverrides for SupervisorTest { clear_interval: 10, clear_on_start: true, tx_confirmation: true, + ..Default::default() }, }; } From c975596277a666f5e713158cb4cf65b19c00a58d Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Tue, 7 Jun 2022 14:49:31 +0200 Subject: [PATCH 055/113] Add auto forward relayer test --- tools/integration-test/src/tests/fee.rs | 113 ++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/tools/integration-test/src/tests/fee.rs b/tools/integration-test/src/tests/fee.rs index fb9567e304..270949edca 100644 --- a/tools/integration-test/src/tests/fee.rs +++ b/tools/integration-test/src/tests/fee.rs @@ -14,6 +14,11 @@ fn test_forward_relayer() -> Result<(), Error> { run_binary_channel_test(&ForwardRelayerTest) } +#[test] +fn test_auto_forward_relayer() -> Result<(), Error> { + run_binary_channel_test(&AutoForwardRelayerTest) +} + #[test] fn test_timeout_fee() -> Result<(), Error> { run_binary_channel_test(&TimeoutFeeTest) @@ -25,6 +30,7 @@ fn test_pay_packet_fee_async() -> Result<(), Error> { } struct ForwardRelayerTest; +struct AutoForwardRelayerTest; struct NoForwardRelayerTest; struct TimeoutFeeTest; struct PayPacketFeeAsyncTest; @@ -35,7 +41,21 @@ impl TestOverrides for ForwardRelayerTest { } } +impl TestOverrides for AutoForwardRelayerTest { + fn modify_relayer_config(&self, config: &mut Config) { + config.mode.packets.auto_register_counterparty_address = true; + } + + fn channel_version(&self) -> Version { + Version::ics20_with_fee() + } +} + impl TestOverrides for NoForwardRelayerTest { + fn modify_relayer_config(&self, config: &mut Config) { + config.mode.packets.auto_register_counterparty_address = false; + } + fn channel_version(&self) -> Version { Version::ics20_with_fee() } @@ -291,6 +311,99 @@ impl BinaryChannelTest for ForwardRelayerTest { } } +impl BinaryChannelTest for AutoForwardRelayerTest { + fn run( + &self, + _config: &TestConfig, + _relayer: RelayerDriver, + chains: ConnectedChains, + channel: ConnectedChannel, + ) -> Result<(), Error> { + let chain_driver_a = chains.node_a.chain_driver(); + let chain_driver_b = chains.node_b.chain_driver(); + + let denom_a = chains.node_a.denom(); + + let port_a = channel.port_a.as_ref(); + let channel_id_a = channel.channel_id_a.as_ref(); + + let wallets_a = chains.node_a.wallets(); + let wallets_b = chains.node_b.wallets(); + + let relayer_a = wallets_a.relayer(); + + let user_a = wallets_a.user1(); + let user_b = wallets_b.user1(); + + let balance_a1 = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; + + let relayer_balance_a = chain_driver_a.query_balance(&relayer_a.address(), &denom_a)?; + + let send_amount = random_u128_range(1000, 2000); + let receive_fee = random_u128_range(300, 400); + let ack_fee = random_u128_range(200, 300); + let timeout_fee = random_u128_range(100, 200); + + let total_sent = send_amount + receive_fee + ack_fee + timeout_fee; + + let balance_a2 = balance_a1 - total_sent; + + chain_driver_a.ibc_token_transfer_with_fee( + &port_a, + &channel_id_a, + &user_a, + &user_b.address(), + &denom_a.with_amount(send_amount).as_ref(), + &denom_a.with_amount(receive_fee).as_ref(), + &denom_a.with_amount(ack_fee).as_ref(), + &denom_a.with_amount(timeout_fee).as_ref(), + Duration::from_secs(60), + )?; + + let denom_b = derive_ibc_denom( + &channel.port_b.as_ref(), + &channel.channel_id_b.as_ref(), + &denom_a, + )?; + + info!("Expect user A's balance after transfer: {}", balance_a2); + + chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a2.as_ref())?; + + chain_driver_b.assert_eventual_wallet_amount( + &user_b.address(), + &denom_b.with_amount(send_amount).as_ref(), + )?; + + info!( + "Expect user to be refunded receive timeout fee {} and go from {} to {}", + timeout_fee, + balance_a2, + balance_a2.amount() + timeout_fee + ); + + chain_driver_a.assert_eventual_wallet_amount( + &user_a.address(), + &(balance_a2 + timeout_fee).as_ref(), + )?; + + info!( + "Expect relayer to receive ack fee {} and receive fee {} and go from {} to {}", + ack_fee, + receive_fee, + relayer_balance_a, + relayer_balance_a.amount() + ack_fee + receive_fee, + ); + + chain_driver_a.assert_eventual_wallet_amount( + &relayer_a.address(), + &(relayer_balance_a + ack_fee + receive_fee).as_ref(), + )?; + + Ok(()) + } +} + impl BinaryChannelTest for TimeoutFeeTest { fn run( &self, From 6057dc431c40defed0242f88737d1896f1562350 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Mon, 13 Jun 2022 21:13:19 +0200 Subject: [PATCH 056/113] Add test for using fee feature with non-fee channels --- .github/workflows/integration.yaml | 2 +- flake.lock | 75 +++++++----------- modules/src/core/ics04_channel/version.rs | 24 +++++- relayer/src/link.rs | 2 +- tools/integration-test/src/tests/fee.rs | 95 +++++++++++++++++++++++ 5 files changed, 143 insertions(+), 55 deletions(-) diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml index 37bfa8090f..3cea66452d 100644 --- a/.github/workflows/integration.yaml +++ b/.github/workflows/integration.yaml @@ -202,7 +202,7 @@ jobs: NO_COLOR_LOG: 1 CHAIN_COMMAND_PATH: simd run: | - nix shell .#ibc-go-ics29-simapp -c cargo \ + nix shell .#ibc-go-main-simapp -c cargo \ test -p ibc-integration-test --features ics29-fee --no-fail-fast -- \ --nocapture --test-threads=1 test_channel_with_fee diff --git a/flake.lock b/flake.lock index 371d1acfbf..6f52bdc6f0 100644 --- a/flake.lock +++ b/flake.lock @@ -75,11 +75,11 @@ "wasmvm_1_beta7-src": "wasmvm_1_beta7-src" }, "locked": { - "lastModified": 1652265349, - "narHash": "sha256-B4LpqfgTQfj7CfHuxe6u+vqc/OdvSaMGrDLLHGX5Ee0=", + "lastModified": 1655147330, + "narHash": "sha256-PNy+y8hZ+ZY9ZNo3qOb6GcHU/Luc5o3otkoAVOVyOPA=", "owner": "informalsystems", "repo": "cosmos.nix", - "rev": "f00d2fc29d7149775f0ad0e47184d7adad4145b6", + "rev": "1500718c3e51ab66cf9694d73d596b64199f8635", "type": "github" }, "original": { @@ -156,21 +156,6 @@ } }, "flake-utils_2": { - "locked": { - "lastModified": 1649676176, - "narHash": "sha256-OWKJratjt2RW151VUlJPRALb7OU2S5s+f0vLj4o1bHM=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "a4b154ebbdc88c8498a5c7b01589addc9e9cb678", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "flake-utils_3": { "locked": { "lastModified": 1637014545, "narHash": "sha256-26IZAc5yzlD9FlDT54io1oqG/bBoyka+FJk5guaX4x4=", @@ -185,13 +170,13 @@ "type": "github" } }, - "flake-utils_4": { + "flake-utils_3": { "locked": { - "lastModified": 1649676176, - "narHash": "sha256-OWKJratjt2RW151VUlJPRALb7OU2S5s+f0vLj4o1bHM=", + "lastModified": 1653893745, + "narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=", "owner": "numtide", "repo": "flake-utils", - "rev": "a4b154ebbdc88c8498a5c7b01589addc9e9cb678", + "rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1", "type": "github" }, "original": { @@ -288,11 +273,11 @@ "ibc-go-main-src": { "flake": false, "locked": { - "lastModified": 1651571071, - "narHash": "sha256-AwTTN6p5/Q5tnoipuylv1qF8Gw4I7YHASLvIwtLxvLA=", + "lastModified": 1655117979, + "narHash": "sha256-9Ic4Rv2xco+5dzRDJ4wvq8AFnzIPfl5MAZaBWW9JjbE=", "owner": "cosmos", "repo": "ibc-go", - "rev": "bd086506f9256c4d5776bc38d2e930b523eb5125", + "rev": "11297aaa61e651c16e6d4147a15be24ce55ba7cc", "type": "github" }, "original": { @@ -436,20 +421,6 @@ } }, "nixpkgs_2": { - "locked": { - "lastModified": 1652133925, - "narHash": "sha256-kfATGChLe9/fQVZkXN9G71JAVMlhePv1qDbaRKklkQs=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "51d859cdab1ef58755bd342d45352fc607f5e59b", - "type": "github" - }, - "original": { - "id": "nixpkgs", - "type": "indirect" - } - }, - "nixpkgs_3": { "locked": { "lastModified": 1637453606, "narHash": "sha256-Gy6cwUswft9xqsjWxFYEnx/63/qzaFUwatcbV5GF/GQ=", @@ -465,13 +436,13 @@ "type": "github" } }, - "nixpkgs_4": { + "nixpkgs_3": { "locked": { - "lastModified": 1651804312, - "narHash": "sha256-DJxOGlxwQccuuwXUS0oRRkcNJbW5UP4fpsL5ga9ZwYw=", + "lastModified": 1655122334, + "narHash": "sha256-Rwwvo9TDCH0a4m/Jvoq5wZ3FLSLiVLBD1FFfN/3XawA=", "owner": "nixos", "repo": "nixpkgs", - "rev": "d59dd43e49f24b58fe8d5ded38cbdf00c3da4dc2", + "rev": "e1a1cfb56504d1b82a3953bfb0632b37a1ca8d30", "type": "github" }, "original": { @@ -500,8 +471,14 @@ }, "pre-commit-hooks": { "inputs": { - "flake-utils": "flake-utils_2", - "nixpkgs": "nixpkgs_2" + "flake-utils": [ + "cosmos-nix", + "flake-utils" + ], + "nixpkgs": [ + "cosmos-nix", + "nixpkgs" + ] }, "locked": { "lastModified": 1646153636, @@ -554,14 +531,14 @@ "root": { "inputs": { "cosmos-nix": "cosmos-nix", - "flake-utils": "flake-utils_4", - "nixpkgs": "nixpkgs_4" + "flake-utils": "flake-utils_3", + "nixpkgs": "nixpkgs_3" } }, "rust-overlay": { "inputs": { - "flake-utils": "flake-utils_3", - "nixpkgs": "nixpkgs_3" + "flake-utils": "flake-utils_2", + "nixpkgs": "nixpkgs_2" }, "locked": { "lastModified": 1645755566, diff --git a/modules/src/core/ics04_channel/version.rs b/modules/src/core/ics04_channel/version.rs index 8e680cb84b..ae88e562a7 100644 --- a/modules/src/core/ics04_channel/version.rs +++ b/modules/src/core/ics04_channel/version.rs @@ -6,6 +6,7 @@ use core::convert::Infallible; use core::fmt; use core::str::FromStr; use serde_derive::{Deserialize, Serialize}; +use serde_json as json; use crate::applications::transfer; use crate::prelude::*; @@ -28,15 +29,30 @@ impl Version { } pub fn ics20_with_fee() -> Self { - Self::new(format!( - "{{ \"feeVersion\": \"ics29-1\", \"appVersion\": \"{}\" }}", - transfer::VERSION - )) + let val = json::json!({ + "feeVersion": "ics29-1", + "appVersion": transfer::VERSION, + }); + + Self::new(val.to_string()) } pub fn empty() -> Self { Self::new("".to_string()) } + + pub fn supports_fee(&self) -> bool { + json::from_str::(&self.0) + .ok() + .and_then(|val| { + let _app_version = val.get("appVersion")?.as_str()?; + + let fee_version = val.get("feeVersion")?.as_str()?; + + Some(fee_version == "ics29-1") + }) + .unwrap_or(false) + } } impl From for Version { diff --git a/relayer/src/link.rs b/relayer/src/link.rs index 53be559edd..9e3f345b67 100644 --- a/relayer/src/link.rs +++ b/relayer/src/link.rs @@ -143,7 +143,7 @@ impl Link { connection_delay: a_connection.delay_period(), }; - if auto_register_counterparty_address { + if auto_register_counterparty_address && a_channel.version.supports_fee() { let address_a = a_chain.get_signer().map_err(LinkError::relayer)?; b_chain diff --git a/tools/integration-test/src/tests/fee.rs b/tools/integration-test/src/tests/fee.rs index 270949edca..b53d80d89f 100644 --- a/tools/integration-test/src/tests/fee.rs +++ b/tools/integration-test/src/tests/fee.rs @@ -29,11 +29,17 @@ fn test_pay_packet_fee_async() -> Result<(), Error> { run_binary_channel_test(&PayPacketFeeAsyncTest) } +#[test] +fn test_non_fee_channel() -> Result<(), Error> { + run_binary_channel_test(&NonFeeChannelTest) +} + struct ForwardRelayerTest; struct AutoForwardRelayerTest; struct NoForwardRelayerTest; struct TimeoutFeeTest; struct PayPacketFeeAsyncTest; +struct NonFeeChannelTest; impl TestOverrides for ForwardRelayerTest { fn channel_version(&self) -> Version { @@ -81,6 +87,12 @@ impl TestOverrides for PayPacketFeeAsyncTest { } } +impl TestOverrides for NonFeeChannelTest { + fn modify_relayer_config(&self, config: &mut Config) { + config.mode.packets.auto_register_counterparty_address = true; + } +} + impl BinaryChannelTest for NoForwardRelayerTest { fn run( &self, @@ -655,3 +667,86 @@ impl BinaryChannelTest for PayPacketFeeAsyncTest { }) } } + +impl BinaryChannelTest for NonFeeChannelTest { + fn run( + &self, + _config: &TestConfig, + _relayer: RelayerDriver, + chains: ConnectedChains, + channel: ConnectedChannel, + ) -> Result<(), Error> { + let chain_driver_a = chains.node_a.chain_driver(); + let chain_driver_b = chains.node_b.chain_driver(); + + let denom_a = chains.node_a.denom(); + + let port_a = channel.port_a.as_ref(); + let channel_id_a = channel.channel_id_a.as_ref(); + let channel_id_b = channel.channel_id_b.as_ref(); + + let wallets_a = chains.node_a.wallets(); + let wallets_b = chains.node_b.wallets(); + + let user_a = wallets_a.user1(); + let user_b = wallets_b.user1(); + + let relayer_a = wallets_a.relayer(); + let relayer_b = wallets_b.relayer(); + + let balance_a1 = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; + + let send_amount = random_u128_range(1000, 2000); + + { + let res = chain_driver_b.register_counterparty_address( + &relayer_b, + &relayer_a.address(), + &channel_id_b, + ); + + assert!(res.is_err()); + } + + { + let res = chain_driver_a.ibc_token_transfer_with_fee( + &port_a, + &channel_id_a, + &user_a, + &user_b.address(), + &denom_a.with_amount(send_amount).as_ref(), + &denom_a.with_amount(10).as_ref(), + &denom_a.with_amount(10).as_ref(), + &denom_a.with_amount(10).as_ref(), + Duration::from_secs(60), + ); + + assert!(res.is_err()); + } + + let balance_a2 = balance_a1 - send_amount; + + chain_driver_a.ibc_transfer_token( + &port_a, + &channel_id_a, + &user_a, + &user_b.address(), + &denom_a.with_amount(send_amount).as_ref(), + )?; + + let denom_b = derive_ibc_denom( + &channel.port_b.as_ref(), + &channel.channel_id_b.as_ref(), + &denom_a, + )?; + + chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a2.as_ref())?; + + chain_driver_b.assert_eventual_wallet_amount( + &user_b.address(), + &denom_b.with_amount(send_amount).as_ref(), + )?; + + Ok(()) + } +} From 099f51c8f78052d95c81f9c6e0b91a692ac5a2d3 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Tue, 14 Jun 2022 11:11:03 +0200 Subject: [PATCH 057/113] Update protobuf with new port_id field in MsgRegisterCounterpartyAddress --- .../ics29_fee/msgs/register_counterparty.rs | 4 +- .../clients/ics07_tendermint/client_state.rs | 2 + proto/src/IBC_GO_COMMIT | 2 +- proto/src/prost/cosmos.bank.v1beta1.rs | 117 +- proto/src/prost/cosmos.base.store.v1beta1.rs | 36 - proto/src/prost/cosmos.staking.v1beta1.rs | 102 +- proto/src/prost/cosmos.tx.v1beta1.rs | 47 + proto/src/prost/gogoproto.rs | 0 proto/src/prost/google.api.rs | 305 ++++ proto/src/prost/ibc.applications.fee.v1.rs | 1031 +++++++++++++- ...ibc.applications.interchain_accounts.v1.rs | 24 + .../src/prost/ibc.applications.transfer.v1.rs | 88 +- proto/src/prost/ibc.core.client.v1.rs | 98 ++ proto/src/prost/ibc.core.connection.v1.rs | 28 +- .../prost/ibc.lightclients.tendermint.v1.rs | 8 +- proto/src/prost/tendermint.abci.rs | 1225 +++++++++++++++++ proto/src/prost/tendermint.crypto.rs | 0 proto/src/prost/tendermint.p2p.rs | 0 proto/src/prost/tendermint.types.rs | 0 proto/src/prost/tendermint.version.rs | 0 relayer/src/chain/cosmos.rs | 4 +- relayer/src/chain/cosmos/fee.rs | 4 +- relayer/src/chain/endpoint.rs | 1 + relayer/src/chain/handle.rs | 2 + relayer/src/chain/handle/base.rs | 2 + relayer/src/chain/handle/cache.rs | 3 +- relayer/src/chain/handle/counting.rs | 3 +- relayer/src/chain/mock.rs | 3 +- relayer/src/chain/runtime.rs | 13 +- relayer/src/link.rs | 4 +- tools/integration-test/src/tests/fee.rs | 6 + tools/test-framework/src/chain/ext/fee.rs | 3 + tools/test-framework/src/relayer/chain.rs | 3 +- tools/test-framework/src/relayer/fee.rs | 2 + 34 files changed, 3006 insertions(+), 164 deletions(-) create mode 100644 proto/src/prost/gogoproto.rs create mode 100644 proto/src/prost/google.api.rs create mode 100644 proto/src/prost/tendermint.abci.rs create mode 100644 proto/src/prost/tendermint.crypto.rs create mode 100644 proto/src/prost/tendermint.p2p.rs create mode 100644 proto/src/prost/tendermint.types.rs create mode 100644 proto/src/prost/tendermint.version.rs diff --git a/modules/src/applications/ics29_fee/msgs/register_counterparty.rs b/modules/src/applications/ics29_fee/msgs/register_counterparty.rs index 6161e2ed5f..368e78b376 100644 --- a/modules/src/applications/ics29_fee/msgs/register_counterparty.rs +++ b/modules/src/applications/ics29_fee/msgs/register_counterparty.rs @@ -3,7 +3,7 @@ use ibc_proto::ibc::applications::fee::v1::MsgRegisterCounterpartyAddress; use crate::applications::ics29_fee::error::Error; use crate::applications::ics29_fee::utils::encode_message; -use crate::core::ics24_host::identifier::ChannelId; +use crate::core::ics24_host::identifier::{ChannelId, PortId}; use crate::prelude::*; use crate::signer::Signer; @@ -13,11 +13,13 @@ pub fn build_register_counterparty_address_message( address: &Signer, counterparty_address: &Signer, channel_id: &ChannelId, + port_id: &PortId, ) -> Result { let message = MsgRegisterCounterpartyAddress { address: address.to_string(), counterparty_address: counterparty_address.to_string(), channel_id: channel_id.to_string(), + port_id: port_id.to_string(), }; let encoded = encode_message(&message).map_err(Error::encode)?; diff --git a/modules/src/clients/ics07_tendermint/client_state.rs b/modules/src/clients/ics07_tendermint/client_state.rs index 5205b13687..fe41468950 100644 --- a/modules/src/clients/ics07_tendermint/client_state.rs +++ b/modules/src/clients/ics07_tendermint/client_state.rs @@ -273,6 +273,7 @@ impl TryFrom for ClientState { } }); + #[allow(deprecated)] Ok(Self { chain_id: ChainId::from_string(raw.chain_id.as_str()), trust_level: trust_level @@ -310,6 +311,7 @@ impl TryFrom for ClientState { impl From for RawClientState { fn from(value: ClientState) -> Self { + #[allow(deprecated)] RawClientState { chain_id: value.chain_id.to_string(), trust_level: Some(value.trust_level.into()), diff --git a/proto/src/IBC_GO_COMMIT b/proto/src/IBC_GO_COMMIT index 54b567fe07..470cf6102c 100644 --- a/proto/src/IBC_GO_COMMIT +++ b/proto/src/IBC_GO_COMMIT @@ -1 +1 @@ -dcd0681d8f07c624f53b9a9ffe9de2f122486207 +11297aaa61e651c16e6d4147a15be24ce55ba7cc diff --git a/proto/src/prost/cosmos.bank.v1beta1.rs b/proto/src/prost/cosmos.bank.v1beta1.rs index 8f8f7e7ff0..3804d28a37 100644 --- a/proto/src/prost/cosmos.bank.v1beta1.rs +++ b/proto/src/prost/cosmos.bank.v1beta1.rs @@ -408,6 +408,16 @@ pub mod msg_server { const NAME: &'static str = "cosmos.bank.v1beta1.Msg"; } } +/// SendAuthorization allows the grantee to spend up to spend_limit coins from +/// the granter's account. +/// +/// Since: cosmos-sdk 0.43 +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SendAuthorization { + #[prost(message, repeated, tag="1")] + pub spend_limit: ::prost::alloc::vec::Vec, +} /// QueryBalanceRequest is the request type for the Query/Balance RPC method. #[derive(::serde::Serialize, ::serde::Deserialize)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -450,6 +460,30 @@ pub struct QueryAllBalancesResponse { #[prost(message, optional, tag="2")] pub pagination: ::core::option::Option, } +/// QuerySpendableBalancesRequest defines the gRPC request structure for querying +/// an account's spendable balances. +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QuerySpendableBalancesRequest { + /// address is the address to query spendable balances for. + #[prost(string, tag="1")] + pub address: ::prost::alloc::string::String, + /// pagination defines an optional pagination for the request. + #[prost(message, optional, tag="2")] + pub pagination: ::core::option::Option, +} +/// QuerySpendableBalancesResponse defines the gRPC response structure for querying +/// an account's spendable balances. +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QuerySpendableBalancesResponse { + /// balances is the spendable balances of all the coins. + #[prost(message, repeated, tag="1")] + pub balances: ::prost::alloc::vec::Vec, + /// pagination defines the pagination in the response. + #[prost(message, optional, tag="2")] + pub pagination: ::core::option::Option, +} /// QueryTotalSupplyRequest is the request type for the Query/TotalSupply RPC /// method. #[derive(::serde::Serialize, ::serde::Deserialize)] @@ -646,6 +680,30 @@ pub mod query_client { ); self.inner.unary(request.into_request(), path, codec).await } + /// SpendableBalances queries the spenable balance of all coins for a single + /// account. + pub async fn spendable_balances( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/cosmos.bank.v1beta1.Query/SpendableBalances", + ); + self.inner.unary(request.into_request(), path, codec).await + } /// TotalSupply queries the total supply of all coins. pub async fn total_supply( &mut self, @@ -766,6 +824,15 @@ pub mod query_server { &self, request: tonic::Request, ) -> Result, tonic::Status>; + /// SpendableBalances queries the spenable balance of all coins for a single + /// account. + async fn spendable_balances( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; /// TotalSupply queries the total supply of all coins. async fn total_supply( &self, @@ -918,6 +985,46 @@ pub mod query_server { }; Box::pin(fut) } + "/cosmos.bank.v1beta1.Query/SpendableBalances" => { + #[allow(non_camel_case_types)] + struct SpendableBalancesSvc(pub Arc); + impl< + T: Query, + > tonic::server::UnaryService + for SpendableBalancesSvc { + type Response = super::QuerySpendableBalancesResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).spendable_balances(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = SpendableBalancesSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } "/cosmos.bank.v1beta1.Query/TotalSupply" => { #[allow(non_camel_case_types)] struct TotalSupplySvc(pub Arc); @@ -1151,16 +1258,6 @@ pub mod query_server { const NAME: &'static str = "cosmos.bank.v1beta1.Query"; } } -/// SendAuthorization allows the grantee to spend up to spend_limit coins from -/// the granter's account. -/// -/// Since: cosmos-sdk 0.43 -#[derive(::serde::Serialize, ::serde::Deserialize)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct SendAuthorization { - #[prost(message, repeated, tag="1")] - pub spend_limit: ::prost::alloc::vec::Vec, -} /// GenesisState defines the bank module's genesis state. #[derive(::serde::Serialize, ::serde::Deserialize)] #[derive(Clone, PartialEq, ::prost::Message)] diff --git a/proto/src/prost/cosmos.base.store.v1beta1.rs b/proto/src/prost/cosmos.base.store.v1beta1.rs index 7bc9739142..6600689491 100644 --- a/proto/src/prost/cosmos.base.store.v1beta1.rs +++ b/proto/src/prost/cosmos.base.store.v1beta1.rs @@ -25,42 +25,6 @@ pub struct CommitId { #[prost(bytes="vec", tag="2")] pub hash: ::prost::alloc::vec::Vec, } -/// SnapshotItem is an item contained in a rootmulti.Store snapshot. -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct SnapshotItem { - /// item is the specific type of snapshot item. - #[prost(oneof="snapshot_item::Item", tags="1, 2")] - pub item: ::core::option::Option, -} -/// Nested message and enum types in `SnapshotItem`. -pub mod snapshot_item { - /// item is the specific type of snapshot item. - #[derive(Clone, PartialEq, ::prost::Oneof)] - pub enum Item { - #[prost(message, tag="1")] - Store(super::SnapshotStoreItem), - #[prost(message, tag="2")] - Iavl(super::SnapshotIavlItem), - } -} -/// SnapshotStoreItem contains metadata about a snapshotted store. -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct SnapshotStoreItem { - #[prost(string, tag="1")] - pub name: ::prost::alloc::string::String, -} -/// SnapshotIAVLItem is an exported IAVL node. -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct SnapshotIavlItem { - #[prost(bytes="vec", tag="1")] - pub key: ::prost::alloc::vec::Vec, - #[prost(bytes="vec", tag="2")] - pub value: ::prost::alloc::vec::Vec, - #[prost(int64, tag="3")] - pub version: i64, - #[prost(int32, tag="4")] - pub height: i32, -} /// StoreKVPair is a KVStore KVPair used for listening to state changes (Sets and Deletes) /// It optionally includes the StoreKey for the originating KVStore and a Boolean flag to distinguish between Sets and /// Deletes diff --git a/proto/src/prost/cosmos.staking.v1beta1.rs b/proto/src/prost/cosmos.staking.v1beta1.rs index b73ed6c9a3..5876c4742d 100644 --- a/proto/src/prost/cosmos.staking.v1beta1.rs +++ b/proto/src/prost/cosmos.staking.v1beta1.rs @@ -863,6 +863,57 @@ pub mod msg_server { const NAME: &'static str = "cosmos.staking.v1beta1.Msg"; } } +/// StakeAuthorization defines authorization for delegate/undelegate/redelegate. +/// +/// Since: cosmos-sdk 0.43 +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StakeAuthorization { + /// max_tokens specifies the maximum amount of tokens can be delegate to a validator. If it is + /// empty, there is no spend limit and any amount of coins can be delegated. + #[prost(message, optional, tag="1")] + pub max_tokens: ::core::option::Option, + /// authorization_type defines one of AuthorizationType. + #[prost(enumeration="AuthorizationType", tag="4")] + pub authorization_type: i32, + /// validators is the oneof that represents either allow_list or deny_list + #[prost(oneof="stake_authorization::Validators", tags="2, 3")] + pub validators: ::core::option::Option, +} +/// Nested message and enum types in `StakeAuthorization`. +pub mod stake_authorization { + /// Validators defines list of validator addresses. + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct ValidatorsVec { + #[prost(string, repeated, tag="1")] + pub address: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, + } + /// validators is the oneof that represents either allow_list or deny_list + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Validators { + /// allow_list specifies list of validator addresses to whom grantee can delegate tokens on behalf of granter's + /// account. + #[prost(message, tag="2")] + AllowList(ValidatorsVec), + /// deny_list specifies list of validator addresses to whom grantee can not delegate tokens. + #[prost(message, tag="3")] + DenyList(ValidatorsVec), + } +} +/// AuthorizationType defines the type of staking module authorization type +/// +/// Since: cosmos-sdk 0.43 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum AuthorizationType { + /// AUTHORIZATION_TYPE_UNSPECIFIED specifies an unknown authorization type + Unspecified = 0, + /// AUTHORIZATION_TYPE_DELEGATE defines an authorization type for Msg/Delegate + Delegate = 1, + /// AUTHORIZATION_TYPE_UNDELEGATE defines an authorization type for Msg/Undelegate + Undelegate = 2, + /// AUTHORIZATION_TYPE_REDELEGATE defines an authorization type for Msg/BeginRedelegate + Redelegate = 3, +} /// QueryValidatorsRequest is request type for Query/Validators RPC method. #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryValidatorsRequest { @@ -2256,57 +2307,6 @@ pub mod query_server { const NAME: &'static str = "cosmos.staking.v1beta1.Query"; } } -/// StakeAuthorization defines authorization for delegate/undelegate/redelegate. -/// -/// Since: cosmos-sdk 0.43 -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct StakeAuthorization { - /// max_tokens specifies the maximum amount of tokens can be delegate to a validator. If it is - /// empty, there is no spend limit and any amount of coins can be delegated. - #[prost(message, optional, tag="1")] - pub max_tokens: ::core::option::Option, - /// authorization_type defines one of AuthorizationType. - #[prost(enumeration="AuthorizationType", tag="4")] - pub authorization_type: i32, - /// validators is the oneof that represents either allow_list or deny_list - #[prost(oneof="stake_authorization::Validators", tags="2, 3")] - pub validators: ::core::option::Option, -} -/// Nested message and enum types in `StakeAuthorization`. -pub mod stake_authorization { - /// Validators defines list of validator addresses. - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct ValidatorsVec { - #[prost(string, repeated, tag="1")] - pub address: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, - } - /// validators is the oneof that represents either allow_list or deny_list - #[derive(Clone, PartialEq, ::prost::Oneof)] - pub enum Validators { - /// allow_list specifies list of validator addresses to whom grantee can delegate tokens on behalf of granter's - /// account. - #[prost(message, tag="2")] - AllowList(ValidatorsVec), - /// deny_list specifies list of validator addresses to whom grantee can not delegate tokens. - #[prost(message, tag="3")] - DenyList(ValidatorsVec), - } -} -/// AuthorizationType defines the type of staking module authorization type -/// -/// Since: cosmos-sdk 0.43 -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum AuthorizationType { - /// AUTHORIZATION_TYPE_UNSPECIFIED specifies an unknown authorization type - Unspecified = 0, - /// AUTHORIZATION_TYPE_DELEGATE defines an authorization type for Msg/Delegate - Delegate = 1, - /// AUTHORIZATION_TYPE_UNDELEGATE defines an authorization type for Msg/Undelegate - Undelegate = 2, - /// AUTHORIZATION_TYPE_REDELEGATE defines an authorization type for Msg/BeginRedelegate - Redelegate = 3, -} /// GenesisState defines the staking module's genesis state. #[derive(Clone, PartialEq, ::prost::Message)] pub struct GenesisState { diff --git a/proto/src/prost/cosmos.tx.v1beta1.rs b/proto/src/prost/cosmos.tx.v1beta1.rs index 0ed156951d..7f2c669007 100644 --- a/proto/src/prost/cosmos.tx.v1beta1.rs +++ b/proto/src/prost/cosmos.tx.v1beta1.rs @@ -531,6 +531,13 @@ pub mod service_server { &self, request: tonic::Request, ) -> Result, tonic::Status>; + /// GetBlockWithTxs fetches a block with decoded txs. + /// + /// Since: cosmos-sdk 0.45.2 + async fn get_block_with_txs( + &self, + request: tonic::Request, + ) -> Result, tonic::Status>; } /// Service defines a gRPC service for interacting with transactions. #[derive(Debug)] @@ -732,6 +739,46 @@ pub mod service_server { }; Box::pin(fut) } + "/cosmos.tx.v1beta1.Service/GetBlockWithTxs" => { + #[allow(non_camel_case_types)] + struct GetBlockWithTxsSvc(pub Arc); + impl< + T: Service, + > tonic::server::UnaryService + for GetBlockWithTxsSvc { + type Response = super::GetBlockWithTxsResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).get_block_with_txs(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = GetBlockWithTxsSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } _ => { Box::pin(async move { Ok( diff --git a/proto/src/prost/gogoproto.rs b/proto/src/prost/gogoproto.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/proto/src/prost/google.api.rs b/proto/src/prost/google.api.rs new file mode 100644 index 0000000000..4d2d88d4c6 --- /dev/null +++ b/proto/src/prost/google.api.rs @@ -0,0 +1,305 @@ +/// Defines the HTTP configuration for an API service. It contains a list of +/// \[HttpRule][google.api.HttpRule\], each specifying the mapping of an RPC method +/// to one or more HTTP REST API methods. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Http { + /// A list of HTTP configuration rules that apply to individual API methods. + /// + /// **NOTE:** All service configuration rules follow "last one wins" order. + #[prost(message, repeated, tag="1")] + pub rules: ::prost::alloc::vec::Vec, + /// When set to true, URL path parmeters will be fully URI-decoded except in + /// cases of single segment matches in reserved expansion, where "%2F" will be + /// left encoded. + /// + /// The default behavior is to not decode RFC 6570 reserved characters in multi + /// segment matches. + #[prost(bool, tag="2")] + pub fully_decode_reserved_expansion: bool, +} +/// `HttpRule` defines the mapping of an RPC method to one or more HTTP +/// REST API methods. The mapping specifies how different portions of the RPC +/// request message are mapped to URL path, URL query parameters, and +/// HTTP request body. The mapping is typically specified as an +/// `google.api.http` annotation on the RPC method, +/// see "google/api/annotations.proto" for details. +/// +/// The mapping consists of a field specifying the path template and +/// method kind. The path template can refer to fields in the request +/// message, as in the example below which describes a REST GET +/// operation on a resource collection of messages: +/// +/// +/// service Messaging { +/// rpc GetMessage(GetMessageRequest) returns (Message) { +/// option (google.api.http).get = "/v1/messages/{message_id}/{sub.subfield}"; +/// } +/// } +/// message GetMessageRequest { +/// message SubMessage { +/// string subfield = 1; +/// } +/// string message_id = 1; // mapped to the URL +/// SubMessage sub = 2; // `sub.subfield` is url-mapped +/// } +/// message Message { +/// string text = 1; // content of the resource +/// } +/// +/// The same http annotation can alternatively be expressed inside the +/// `GRPC API Configuration` YAML file. +/// +/// http: +/// rules: +/// - selector: .Messaging.GetMessage +/// get: /v1/messages/{message_id}/{sub.subfield} +/// +/// This definition enables an automatic, bidrectional mapping of HTTP +/// JSON to RPC. Example: +/// +/// HTTP | RPC +/// -----|----- +/// `GET /v1/messages/123456/foo` | `GetMessage(message_id: "123456" sub: SubMessage(subfield: "foo"))` +/// +/// In general, not only fields but also field paths can be referenced +/// from a path pattern. Fields mapped to the path pattern cannot be +/// repeated and must have a primitive (non-message) type. +/// +/// Any fields in the request message which are not bound by the path +/// pattern automatically become (optional) HTTP query +/// parameters. Assume the following definition of the request message: +/// +/// +/// service Messaging { +/// rpc GetMessage(GetMessageRequest) returns (Message) { +/// option (google.api.http).get = "/v1/messages/{message_id}"; +/// } +/// } +/// message GetMessageRequest { +/// message SubMessage { +/// string subfield = 1; +/// } +/// string message_id = 1; // mapped to the URL +/// int64 revision = 2; // becomes a parameter +/// SubMessage sub = 3; // `sub.subfield` becomes a parameter +/// } +/// +/// +/// This enables a HTTP JSON to RPC mapping as below: +/// +/// HTTP | RPC +/// -----|----- +/// `GET /v1/messages/123456?revision=2&sub.subfield=foo` | `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: "foo"))` +/// +/// Note that fields which are mapped to HTTP parameters must have a +/// primitive type or a repeated primitive type. Message types are not +/// allowed. In the case of a repeated type, the parameter can be +/// repeated in the URL, as in `...?param=A¶m=B`. +/// +/// For HTTP method kinds which allow a request body, the `body` field +/// specifies the mapping. Consider a REST update method on the +/// message resource collection: +/// +/// +/// service Messaging { +/// rpc UpdateMessage(UpdateMessageRequest) returns (Message) { +/// option (google.api.http) = { +/// put: "/v1/messages/{message_id}" +/// body: "message" +/// }; +/// } +/// } +/// message UpdateMessageRequest { +/// string message_id = 1; // mapped to the URL +/// Message message = 2; // mapped to the body +/// } +/// +/// +/// The following HTTP JSON to RPC mapping is enabled, where the +/// representation of the JSON in the request body is determined by +/// protos JSON encoding: +/// +/// HTTP | RPC +/// -----|----- +/// `PUT /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: "123456" message { text: "Hi!" })` +/// +/// The special name `*` can be used in the body mapping to define that +/// every field not bound by the path template should be mapped to the +/// request body. This enables the following alternative definition of +/// the update method: +/// +/// service Messaging { +/// rpc UpdateMessage(Message) returns (Message) { +/// option (google.api.http) = { +/// put: "/v1/messages/{message_id}" +/// body: "*" +/// }; +/// } +/// } +/// message Message { +/// string message_id = 1; +/// string text = 2; +/// } +/// +/// +/// The following HTTP JSON to RPC mapping is enabled: +/// +/// HTTP | RPC +/// -----|----- +/// `PUT /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: "123456" text: "Hi!")` +/// +/// Note that when using `*` in the body mapping, it is not possible to +/// have HTTP parameters, as all fields not bound by the path end in +/// the body. This makes this option more rarely used in practice of +/// defining REST APIs. The common usage of `*` is in custom methods +/// which don't use the URL at all for transferring data. +/// +/// It is possible to define multiple HTTP methods for one RPC by using +/// the `additional_bindings` option. Example: +/// +/// service Messaging { +/// rpc GetMessage(GetMessageRequest) returns (Message) { +/// option (google.api.http) = { +/// get: "/v1/messages/{message_id}" +/// additional_bindings { +/// get: "/v1/users/{user_id}/messages/{message_id}" +/// } +/// }; +/// } +/// } +/// message GetMessageRequest { +/// string message_id = 1; +/// string user_id = 2; +/// } +/// +/// +/// This enables the following two alternative HTTP JSON to RPC +/// mappings: +/// +/// HTTP | RPC +/// -----|----- +/// `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` +/// `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: "123456")` +/// +/// # Rules for HTTP mapping +/// +/// The rules for mapping HTTP path, query parameters, and body fields +/// to the request message are as follows: +/// +/// 1. The `body` field specifies either `*` or a field path, or is +/// omitted. If omitted, it indicates there is no HTTP request body. +/// 2. Leaf fields (recursive expansion of nested messages in the +/// request) can be classified into three types: +/// (a) Matched in the URL template. +/// (b) Covered by body (if body is `*`, everything except (a) fields; +/// else everything under the body field) +/// (c) All other fields. +/// 3. URL query parameters found in the HTTP request are mapped to (c) fields. +/// 4. Any body sent with an HTTP request can contain only (b) fields. +/// +/// The syntax of the path template is as follows: +/// +/// Template = "/" Segments [ Verb ] ; +/// Segments = Segment { "/" Segment } ; +/// Segment = "*" | "**" | LITERAL | Variable ; +/// Variable = "{" FieldPath [ "=" Segments ] "}" ; +/// FieldPath = IDENT { "." IDENT } ; +/// Verb = ":" LITERAL ; +/// +/// The syntax `*` matches a single path segment. The syntax `**` matches zero +/// or more path segments, which must be the last part of the path except the +/// `Verb`. The syntax `LITERAL` matches literal text in the path. +/// +/// The syntax `Variable` matches part of the URL path as specified by its +/// template. A variable template must not contain other variables. If a variable +/// matches a single path segment, its template may be omitted, e.g. `{var}` +/// is equivalent to `{var=*}`. +/// +/// If a variable contains exactly one path segment, such as `"{var}"` or +/// `"{var=*}"`, when such a variable is expanded into a URL path, all characters +/// except `\[-_.~0-9a-zA-Z\]` are percent-encoded. Such variables show up in the +/// Discovery Document as `{var}`. +/// +/// If a variable contains one or more path segments, such as `"{var=foo/*}"` +/// or `"{var=**}"`, when such a variable is expanded into a URL path, all +/// characters except `\[-_.~/0-9a-zA-Z\]` are percent-encoded. Such variables +/// show up in the Discovery Document as `{+var}`. +/// +/// NOTE: While the single segment variable matches the semantics of +/// [RFC 6570]() Section 3.2.2 +/// Simple String Expansion, the multi segment variable **does not** match +/// RFC 6570 Reserved Expansion. The reason is that the Reserved Expansion +/// does not expand special characters like `?` and `#`, which would lead +/// to invalid URLs. +/// +/// NOTE: the field paths in variables and in the `body` must not refer to +/// repeated fields or map fields. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct HttpRule { + /// Selects methods to which this rule applies. + /// + /// Refer to \[selector][google.api.DocumentationRule.selector\] for syntax details. + #[prost(string, tag="1")] + pub selector: ::prost::alloc::string::String, + /// The name of the request field whose value is mapped to the HTTP body, or + /// `*` for mapping all fields not captured by the path pattern to the HTTP + /// body. NOTE: the referred field must not be a repeated field and must be + /// present at the top-level of request message type. + #[prost(string, tag="7")] + pub body: ::prost::alloc::string::String, + /// Optional. The name of the response field whose value is mapped to the HTTP + /// body of response. Other response fields are ignored. When + /// not set, the response message will be used as HTTP body of response. + #[prost(string, tag="12")] + pub response_body: ::prost::alloc::string::String, + /// Additional HTTP bindings for the selector. Nested bindings must + /// not contain an `additional_bindings` field themselves (that is, + /// the nesting may only be one level deep). + #[prost(message, repeated, tag="11")] + pub additional_bindings: ::prost::alloc::vec::Vec, + /// Determines the URL pattern is matched by this rules. This pattern can be + /// used with any of the {get|put|post|delete|patch} methods. A custom method + /// can be defined using the 'custom' field. + #[prost(oneof="http_rule::Pattern", tags="2, 3, 4, 5, 6, 8")] + pub pattern: ::core::option::Option, +} +/// Nested message and enum types in `HttpRule`. +pub mod http_rule { + /// Determines the URL pattern is matched by this rules. This pattern can be + /// used with any of the {get|put|post|delete|patch} methods. A custom method + /// can be defined using the 'custom' field. + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Pattern { + /// Used for listing and getting information about resources. + #[prost(string, tag="2")] + Get(::prost::alloc::string::String), + /// Used for updating a resource. + #[prost(string, tag="3")] + Put(::prost::alloc::string::String), + /// Used for creating a resource. + #[prost(string, tag="4")] + Post(::prost::alloc::string::String), + /// Used for deleting a resource. + #[prost(string, tag="5")] + Delete(::prost::alloc::string::String), + /// Used for updating a resource. + #[prost(string, tag="6")] + Patch(::prost::alloc::string::String), + /// The custom pattern is used for specifying an HTTP method that is not + /// included in the `pattern` field, such as HEAD, or "*" to leave the + /// HTTP method unspecified for this rule. The wild-card rule is useful + /// for services that provide content to Web (HTML) clients. + #[prost(message, tag="8")] + Custom(super::CustomHttpPattern), + } +} +/// A custom pattern is used for defining custom HTTP verb. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CustomHttpPattern { + /// The name of this custom HTTP verb. + #[prost(string, tag="1")] + pub kind: ::prost::alloc::string::String, + /// The path matched by this custom verb. + #[prost(string, tag="2")] + pub path: ::prost::alloc::string::String, +} diff --git a/proto/src/prost/ibc.applications.fee.v1.rs b/proto/src/prost/ibc.applications.fee.v1.rs index 038a8c6b00..2f81f47a52 100644 --- a/proto/src/prost/ibc.applications.fee.v1.rs +++ b/proto/src/prost/ibc.applications.fee.v1.rs @@ -52,6 +52,26 @@ pub struct IdentifiedPacketFees { #[prost(message, repeated, tag="2")] pub packet_fees: ::prost::alloc::vec::Vec, } +/// MsgRegisterPayee defines the request type for the RegisterPayee rpc +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgRegisterPayee { + /// unique port identifier + #[prost(string, tag="1")] + pub port_id: ::prost::alloc::string::String, + /// unique channel identifier + #[prost(string, tag="2")] + pub channel_id: ::prost::alloc::string::String, + /// the relayer address + #[prost(string, tag="3")] + pub relayer_address: ::prost::alloc::string::String, + /// the fee payee address + #[prost(string, tag="4")] + pub payee: ::prost::alloc::string::String, +} +/// MsgRegisterPayeeResponse defines the response type for the RegisterPayee rpc +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgRegisterPayeeResponse { +} /// MsgRegisterCounterpartyAddress defines the request type for the RegisterCounterpartyAddress rpc #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgRegisterCounterpartyAddress { @@ -61,8 +81,11 @@ pub struct MsgRegisterCounterpartyAddress { /// the counterparty relayer address #[prost(string, tag="2")] pub counterparty_address: ::prost::alloc::string::String, - /// unique channel identifier + /// unique port identifier #[prost(string, tag="3")] + pub port_id: ::prost::alloc::string::String, + /// unique channel identifier + #[prost(string, tag="4")] pub channel_id: ::prost::alloc::string::String, } /// MsgRegisterCounterpartyAddressResponse defines the response type for the RegisterCounterpartyAddress rpc @@ -134,7 +157,7 @@ pub mod msg_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Default + Body + Send + 'static, + T::ResponseBody: Body + Send + 'static, ::Error: Into + Send, { pub fn new(inner: T) -> Self { @@ -147,6 +170,7 @@ pub mod msg_client { ) -> MsgClient> where F: tonic::service::Interceptor, + T::ResponseBody: Default, T: tonic::codegen::Service< http::Request, Response = http::Response< @@ -174,18 +198,42 @@ pub mod msg_client { self.inner = self.inner.accept_gzip(); self } + /// RegisterPayee defines a rpc handler method for MsgRegisterPayee + /// RegisterPayee is called by the relayer on each channelEnd and allows them to set an optional + /// payee to which escrowed packet fees will be paid out. The payee should be registered on the source chain from which + /// packets originate as this is where fee distribution takes place. This function may be called more than once by a + /// relayer, in which case, the latest payee is always used. + pub async fn register_payee( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/ibc.applications.fee.v1.Msg/RegisterPayee", + ); + self.inner.unary(request.into_request(), path, codec).await + } /// RegisterCounterpartyAddress defines a rpc handler method for MsgRegisterCounterpartyAddress /// RegisterCounterpartyAddress is called by the relayer on each channelEnd and allows them to specify their /// counterparty address before relaying. This ensures they will be properly compensated for forward relaying since /// destination chain must send back relayer's source address (counterparty address) in acknowledgement. This function - /// may be called more than once by a relayer, in which case, latest counterparty address is always used. + /// may be called more than once by a relayer, in which case, the latest counterparty address is always used. pub async fn register_counterparty_address( &mut self, request: impl tonic::IntoRequest, ) -> Result< - tonic::Response, - tonic::Status, - > { + tonic::Response, + tonic::Status, + > { self.inner .ready() .await @@ -232,9 +280,9 @@ pub mod msg_client { &mut self, request: impl tonic::IntoRequest, ) -> Result< - tonic::Response, - tonic::Status, - > { + tonic::Response, + tonic::Status, + > { self.inner .ready() .await @@ -252,6 +300,295 @@ pub mod msg_client { } } } +/// Generated server implementations. +#[cfg(feature = "server")] +pub mod msg_server { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + ///Generated trait containing gRPC methods that should be implemented for use with MsgServer. + #[async_trait] + pub trait Msg: Send + Sync + 'static { + /// RegisterPayee defines a rpc handler method for MsgRegisterPayee + /// RegisterPayee is called by the relayer on each channelEnd and allows them to set an optional + /// payee to which escrowed packet fees will be paid out. The payee should be registered on the source chain from which + /// packets originate as this is where fee distribution takes place. This function may be called more than once by a + /// relayer, in which case, the latest payee is always used. + async fn register_payee( + &self, + request: tonic::Request, + ) -> Result, tonic::Status>; + /// RegisterCounterpartyAddress defines a rpc handler method for MsgRegisterCounterpartyAddress + /// RegisterCounterpartyAddress is called by the relayer on each channelEnd and allows them to specify their + /// counterparty address before relaying. This ensures they will be properly compensated for forward relaying since + /// destination chain must send back relayer's source address (counterparty address) in acknowledgement. This function + /// may be called more than once by a relayer, in which case, the latest counterparty address is always used. + async fn register_counterparty_address( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + /// PayPacketFee defines a rpc handler method for MsgPayPacketFee + /// PayPacketFee is an open callback that may be called by any module/user that wishes to escrow funds in order to + /// incentivize the relaying of the packet at the next sequence + /// NOTE: This method is intended to be used within a multi msg transaction, where the subsequent msg that follows + /// initiates the lifecycle of the incentivized packet + async fn pay_packet_fee( + &self, + request: tonic::Request, + ) -> Result, tonic::Status>; + /// PayPacketFeeAsync defines a rpc handler method for MsgPayPacketFeeAsync + /// PayPacketFeeAsync is an open callback that may be called by any module/user that wishes to escrow funds in order to + /// incentivize the relaying of a known packet (i.e. at a particular sequence) + async fn pay_packet_fee_async( + &self, + request: tonic::Request, + ) -> Result, tonic::Status>; + } + /// Msg defines the ICS29 Msg service. + #[derive(Debug)] + pub struct MsgServer { + inner: _Inner, + accept_compression_encodings: (), + send_compression_encodings: (), + } + struct _Inner(Arc); + impl MsgServer { + pub fn new(inner: T) -> Self { + Self::from_arc(Arc::new(inner)) + } + pub fn from_arc(inner: Arc) -> Self { + let inner = _Inner(inner); + Self { + inner, + accept_compression_encodings: Default::default(), + send_compression_encodings: Default::default(), + } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> InterceptedService + where + F: tonic::service::Interceptor, + { + InterceptedService::new(Self::new(inner), interceptor) + } + } + impl tonic::codegen::Service> for MsgServer + where + T: Msg, + B: Body + Send + 'static, + B::Error: Into + Send + 'static, + { + type Response = http::Response; + type Error = std::convert::Infallible; + type Future = BoxFuture; + fn poll_ready( + &mut self, + _cx: &mut Context<'_>, + ) -> Poll> { + Poll::Ready(Ok(())) + } + fn call(&mut self, req: http::Request) -> Self::Future { + let inner = self.inner.clone(); + match req.uri().path() { + "/ibc.applications.fee.v1.Msg/RegisterPayee" => { + #[allow(non_camel_case_types)] + struct RegisterPayeeSvc(pub Arc); + impl tonic::server::UnaryService + for RegisterPayeeSvc { + type Response = super::MsgRegisterPayeeResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).register_payee(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = RegisterPayeeSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/ibc.applications.fee.v1.Msg/RegisterCounterpartyAddress" => { + #[allow(non_camel_case_types)] + struct RegisterCounterpartyAddressSvc(pub Arc); + impl< + T: Msg, + > tonic::server::UnaryService + for RegisterCounterpartyAddressSvc { + type Response = super::MsgRegisterCounterpartyAddressResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + super::MsgRegisterCounterpartyAddress, + >, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).register_counterparty_address(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = RegisterCounterpartyAddressSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/ibc.applications.fee.v1.Msg/PayPacketFee" => { + #[allow(non_camel_case_types)] + struct PayPacketFeeSvc(pub Arc); + impl tonic::server::UnaryService + for PayPacketFeeSvc { + type Response = super::MsgPayPacketFeeResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).pay_packet_fee(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = PayPacketFeeSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/ibc.applications.fee.v1.Msg/PayPacketFeeAsync" => { + #[allow(non_camel_case_types)] + struct PayPacketFeeAsyncSvc(pub Arc); + impl tonic::server::UnaryService + for PayPacketFeeAsyncSvc { + type Response = super::MsgPayPacketFeeAsyncResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).pay_packet_fee_async(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = PayPacketFeeAsyncSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + _ => { + Box::pin(async move { + Ok( + http::Response::builder() + .status(200) + .header("grpc-status", "12") + .header("content-type", "application/grpc") + .body(empty_body()) + .unwrap(), + ) + }) + } + } + } + } + impl Clone for MsgServer { + fn clone(&self) -> Self { + let inner = self.inner.clone(); + Self { + inner, + accept_compression_encodings: self.accept_compression_encodings, + send_compression_encodings: self.send_compression_encodings, + } + } + } + impl Clone for _Inner { + fn clone(&self) -> Self { + Self(self.0.clone()) + } + } + impl std::fmt::Debug for _Inner { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.0) + } + } + impl tonic::transport::NamedService for MsgServer { + const NAME: &'static str = "ibc.applications.fee.v1.Msg"; + } +} /// GenesisState defines the ICS29 fee middleware genesis state #[derive(Clone, PartialEq, ::prost::Message)] pub struct GenesisState { @@ -261,11 +598,14 @@ pub struct GenesisState { /// list of fee enabled channels #[prost(message, repeated, tag="2")] pub fee_enabled_channels: ::prost::alloc::vec::Vec, - /// list of registered relayer addresses + /// list of registered payees #[prost(message, repeated, tag="3")] + pub registered_payees: ::prost::alloc::vec::Vec, + /// list of registered relayer addresses + #[prost(message, repeated, tag="4")] pub registered_relayers: ::prost::alloc::vec::Vec, /// list of forward relayer addresses - #[prost(message, repeated, tag="4")] + #[prost(message, repeated, tag="5")] pub forward_relayers: ::prost::alloc::vec::Vec, } /// FeeEnabledChannel contains the PortID & ChannelID for a fee enabled channel @@ -278,6 +618,19 @@ pub struct FeeEnabledChannel { #[prost(string, tag="2")] pub channel_id: ::prost::alloc::string::String, } +/// RegisteredPayee contains the relayer address and payee address for a specific channel +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RegisteredPayee { + /// the relayer address + #[prost(string, tag="1")] + pub relayer_address: ::prost::alloc::string::String, + /// the payee address + #[prost(string, tag="2")] + pub payee: ::prost::alloc::string::String, + /// unique channel identifier + #[prost(string, tag="3")] + pub channel_id: ::prost::alloc::string::String, +} /// RegisteredRelayerAddress contains the address and counterparty address for a specific relayer (for distributing fees) #[derive(Clone, PartialEq, ::prost::Message)] pub struct RegisteredRelayerAddress { @@ -399,6 +752,23 @@ pub struct QueryTotalTimeoutFeesResponse { #[prost(message, repeated, tag="1")] pub timeout_fees: ::prost::alloc::vec::Vec, } +/// QueryPayeeRequest defines the request type for the Payee rpc +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryPayeeRequest { + /// unique channel identifier + #[prost(string, tag="1")] + pub channel_id: ::prost::alloc::string::String, + /// the relayer address to which the distribution address is registered + #[prost(string, tag="2")] + pub relayer_address: ::prost::alloc::string::String, +} +/// QueryPayeeResponse defines the response type for the Payee rpc +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryPayeeResponse { + /// the payee address to which packet fees are paid out + #[prost(string, tag="1")] + pub payee_address: ::prost::alloc::string::String, +} /// QueryCounterpartyAddressRequest defines the request type for the CounterpartyAddress rpc #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryCounterpartyAddressRequest { @@ -475,7 +845,7 @@ pub mod query_client { where T: tonic::client::GrpcService, T::Error: Into, - T::ResponseBody: Default + Body + Send + 'static, + T::ResponseBody: Body + Send + 'static, ::Error: Into + Send, { pub fn new(inner: T) -> Self { @@ -488,6 +858,7 @@ pub mod query_client { ) -> QueryClient> where F: tonic::service::Interceptor, + T::ResponseBody: Default, T: tonic::codegen::Service< http::Request, Response = http::Response< @@ -520,9 +891,9 @@ pub mod query_client { &mut self, request: impl tonic::IntoRequest, ) -> Result< - tonic::Response, - tonic::Status, - > { + tonic::Response, + tonic::Status, + > { self.inner .ready() .await @@ -543,9 +914,9 @@ pub mod query_client { &mut self, request: impl tonic::IntoRequest, ) -> Result< - tonic::Response, - tonic::Status, - > { + tonic::Response, + tonic::Status, + > { self.inner .ready() .await @@ -568,9 +939,9 @@ pub mod query_client { super::QueryIncentivizedPacketsForChannelRequest, >, ) -> Result< - tonic::Response, - tonic::Status, - > { + tonic::Response, + tonic::Status, + > { self.inner .ready() .await @@ -631,9 +1002,9 @@ pub mod query_client { &mut self, request: impl tonic::IntoRequest, ) -> Result< - tonic::Response, - tonic::Status, - > { + tonic::Response, + tonic::Status, + > { self.inner .ready() .await @@ -649,14 +1020,34 @@ pub mod query_client { ); self.inner.unary(request.into_request(), path, codec).await } + /// Payee returns the registered payee address for a specific channel given the relayer address + pub async fn payee( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/ibc.applications.fee.v1.Query/Payee", + ); + self.inner.unary(request.into_request(), path, codec).await + } /// CounterpartyAddress returns the registered counterparty address for forward relaying pub async fn counterparty_address( &mut self, request: impl tonic::IntoRequest, ) -> Result< - tonic::Response, - tonic::Status, - > { + tonic::Response, + tonic::Status, + > { self.inner .ready() .await @@ -677,9 +1068,9 @@ pub mod query_client { &mut self, request: impl tonic::IntoRequest, ) -> Result< - tonic::Response, - tonic::Status, - > { + tonic::Response, + tonic::Status, + > { self.inner .ready() .await @@ -700,9 +1091,9 @@ pub mod query_client { &mut self, request: impl tonic::IntoRequest, ) -> Result< - tonic::Response, - tonic::Status, - > { + tonic::Response, + tonic::Status, + > { self.inner .ready() .await @@ -720,6 +1111,580 @@ pub mod query_client { } } } +/// Generated server implementations. +#[cfg(feature = "server")] +pub mod query_server { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + ///Generated trait containing gRPC methods that should be implemented for use with QueryServer. + #[async_trait] + pub trait Query: Send + Sync + 'static { + /// IncentivizedPackets returns all incentivized packets and their associated fees + async fn incentivized_packets( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + /// IncentivizedPacket returns all packet fees for a packet given its identifier + async fn incentivized_packet( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + /// Gets all incentivized packets for a specific channel + async fn incentivized_packets_for_channel( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + /// TotalRecvFees returns the total receive fees for a packet given its identifier + async fn total_recv_fees( + &self, + request: tonic::Request, + ) -> Result, tonic::Status>; + /// TotalAckFees returns the total acknowledgement fees for a packet given its identifier + async fn total_ack_fees( + &self, + request: tonic::Request, + ) -> Result, tonic::Status>; + /// TotalTimeoutFees returns the total timeout fees for a packet given its identifier + async fn total_timeout_fees( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + /// Payee returns the registered payee address for a specific channel given the relayer address + async fn payee( + &self, + request: tonic::Request, + ) -> Result, tonic::Status>; + /// CounterpartyAddress returns the registered counterparty address for forward relaying + async fn counterparty_address( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + /// FeeEnabledChannels returns a list of all fee enabled channels + async fn fee_enabled_channels( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + /// FeeEnabledChannel returns true if the provided port and channel identifiers belong to a fee enabled channel + async fn fee_enabled_channel( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + } + /// Query defines the ICS29 gRPC querier service. + #[derive(Debug)] + pub struct QueryServer { + inner: _Inner, + accept_compression_encodings: (), + send_compression_encodings: (), + } + struct _Inner(Arc); + impl QueryServer { + pub fn new(inner: T) -> Self { + Self::from_arc(Arc::new(inner)) + } + pub fn from_arc(inner: Arc) -> Self { + let inner = _Inner(inner); + Self { + inner, + accept_compression_encodings: Default::default(), + send_compression_encodings: Default::default(), + } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> InterceptedService + where + F: tonic::service::Interceptor, + { + InterceptedService::new(Self::new(inner), interceptor) + } + } + impl tonic::codegen::Service> for QueryServer + where + T: Query, + B: Body + Send + 'static, + B::Error: Into + Send + 'static, + { + type Response = http::Response; + type Error = std::convert::Infallible; + type Future = BoxFuture; + fn poll_ready( + &mut self, + _cx: &mut Context<'_>, + ) -> Poll> { + Poll::Ready(Ok(())) + } + fn call(&mut self, req: http::Request) -> Self::Future { + let inner = self.inner.clone(); + match req.uri().path() { + "/ibc.applications.fee.v1.Query/IncentivizedPackets" => { + #[allow(non_camel_case_types)] + struct IncentivizedPacketsSvc(pub Arc); + impl< + T: Query, + > tonic::server::UnaryService + for IncentivizedPacketsSvc { + type Response = super::QueryIncentivizedPacketsResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + super::QueryIncentivizedPacketsRequest, + >, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).incentivized_packets(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = IncentivizedPacketsSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/ibc.applications.fee.v1.Query/IncentivizedPacket" => { + #[allow(non_camel_case_types)] + struct IncentivizedPacketSvc(pub Arc); + impl< + T: Query, + > tonic::server::UnaryService + for IncentivizedPacketSvc { + type Response = super::QueryIncentivizedPacketResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + super::QueryIncentivizedPacketRequest, + >, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).incentivized_packet(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = IncentivizedPacketSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/ibc.applications.fee.v1.Query/IncentivizedPacketsForChannel" => { + #[allow(non_camel_case_types)] + struct IncentivizedPacketsForChannelSvc(pub Arc); + impl< + T: Query, + > tonic::server::UnaryService< + super::QueryIncentivizedPacketsForChannelRequest, + > for IncentivizedPacketsForChannelSvc { + type Response = super::QueryIncentivizedPacketsForChannelResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + super::QueryIncentivizedPacketsForChannelRequest, + >, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).incentivized_packets_for_channel(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = IncentivizedPacketsForChannelSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/ibc.applications.fee.v1.Query/TotalRecvFees" => { + #[allow(non_camel_case_types)] + struct TotalRecvFeesSvc(pub Arc); + impl< + T: Query, + > tonic::server::UnaryService + for TotalRecvFeesSvc { + type Response = super::QueryTotalRecvFeesResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).total_recv_fees(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = TotalRecvFeesSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/ibc.applications.fee.v1.Query/TotalAckFees" => { + #[allow(non_camel_case_types)] + struct TotalAckFeesSvc(pub Arc); + impl< + T: Query, + > tonic::server::UnaryService + for TotalAckFeesSvc { + type Response = super::QueryTotalAckFeesResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).total_ack_fees(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = TotalAckFeesSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/ibc.applications.fee.v1.Query/TotalTimeoutFees" => { + #[allow(non_camel_case_types)] + struct TotalTimeoutFeesSvc(pub Arc); + impl< + T: Query, + > tonic::server::UnaryService + for TotalTimeoutFeesSvc { + type Response = super::QueryTotalTimeoutFeesResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).total_timeout_fees(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = TotalTimeoutFeesSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/ibc.applications.fee.v1.Query/Payee" => { + #[allow(non_camel_case_types)] + struct PayeeSvc(pub Arc); + impl tonic::server::UnaryService + for PayeeSvc { + type Response = super::QueryPayeeResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { (*inner).payee(request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = PayeeSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/ibc.applications.fee.v1.Query/CounterpartyAddress" => { + #[allow(non_camel_case_types)] + struct CounterpartyAddressSvc(pub Arc); + impl< + T: Query, + > tonic::server::UnaryService + for CounterpartyAddressSvc { + type Response = super::QueryCounterpartyAddressResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + super::QueryCounterpartyAddressRequest, + >, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).counterparty_address(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = CounterpartyAddressSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/ibc.applications.fee.v1.Query/FeeEnabledChannels" => { + #[allow(non_camel_case_types)] + struct FeeEnabledChannelsSvc(pub Arc); + impl< + T: Query, + > tonic::server::UnaryService + for FeeEnabledChannelsSvc { + type Response = super::QueryFeeEnabledChannelsResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + super::QueryFeeEnabledChannelsRequest, + >, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).fee_enabled_channels(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = FeeEnabledChannelsSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/ibc.applications.fee.v1.Query/FeeEnabledChannel" => { + #[allow(non_camel_case_types)] + struct FeeEnabledChannelSvc(pub Arc); + impl< + T: Query, + > tonic::server::UnaryService + for FeeEnabledChannelSvc { + type Response = super::QueryFeeEnabledChannelResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).fee_enabled_channel(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = FeeEnabledChannelSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + _ => { + Box::pin(async move { + Ok( + http::Response::builder() + .status(200) + .header("grpc-status", "12") + .header("content-type", "application/grpc") + .body(empty_body()) + .unwrap(), + ) + }) + } + } + } + } + impl Clone for QueryServer { + fn clone(&self) -> Self { + let inner = self.inner.clone(); + Self { + inner, + accept_compression_encodings: self.accept_compression_encodings, + send_compression_encodings: self.send_compression_encodings, + } + } + } + impl Clone for _Inner { + fn clone(&self) -> Self { + Self(self.0.clone()) + } + } + impl std::fmt::Debug for _Inner { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.0) + } + } + impl tonic::transport::NamedService for QueryServer { + const NAME: &'static str = "ibc.applications.fee.v1.Query"; + } +} /// IncentivizedAcknowledgement is the acknowledgement format to be used by applications wrapped in the fee middleware #[derive(Clone, PartialEq, ::prost::Message)] pub struct IncentivizedAcknowledgement { diff --git a/proto/src/prost/ibc.applications.interchain_accounts.v1.rs b/proto/src/prost/ibc.applications.interchain_accounts.v1.rs index a4cb8d4495..35ed553094 100644 --- a/proto/src/prost/ibc.applications.interchain_accounts.v1.rs +++ b/proto/src/prost/ibc.applications.interchain_accounts.v1.rs @@ -1,3 +1,27 @@ +/// Metadata defines a set of protocol specific data encoded into the ICS27 channel version bytestring +/// See ICS004: +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Metadata { + /// version defines the ICS27 protocol version + #[prost(string, tag="1")] + pub version: ::prost::alloc::string::String, + /// controller_connection_id is the connection identifier associated with the controller chain + #[prost(string, tag="2")] + pub controller_connection_id: ::prost::alloc::string::String, + /// host_connection_id is the connection identifier associated with the host chain + #[prost(string, tag="3")] + pub host_connection_id: ::prost::alloc::string::String, + /// address defines the interchain account address to be fulfilled upon the OnChanOpenTry handshake step + /// NOTE: the address field is empty on the OnChanOpenInit handshake step + #[prost(string, tag="4")] + pub address: ::prost::alloc::string::String, + /// encoding defines the supported codec format + #[prost(string, tag="5")] + pub encoding: ::prost::alloc::string::String, + /// tx_type defines the type of transactions the interchain account can execute + #[prost(string, tag="6")] + pub tx_type: ::prost::alloc::string::String, +} /// An InterchainAccount is defined as a BaseAccount & the address of the account owner on the controller chain #[derive(Clone, PartialEq, ::prost::Message)] pub struct InterchainAccount { diff --git a/proto/src/prost/ibc.applications.transfer.v1.rs b/proto/src/prost/ibc.applications.transfer.v1.rs index 3f021b24ef..88037983e1 100644 --- a/proto/src/prost/ibc.applications.transfer.v1.rs +++ b/proto/src/prost/ibc.applications.transfer.v1.rs @@ -292,7 +292,7 @@ pub struct Params { #[derive(::serde::Serialize, ::serde::Deserialize)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryDenomTraceRequest { - /// hash (in hex format) of the denomination trace information. + /// hash (in hex format) or denom (full denom with ibc prefix) of the denomination trace information. #[prost(string, tag="1")] pub hash: ::prost::alloc::string::String, } @@ -344,7 +344,7 @@ pub struct QueryParamsResponse { #[derive(::serde::Serialize, ::serde::Deserialize)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryDenomHashRequest { - /// The denomination trace `([port_id]/[channel_id])+/[denom]` + /// The denomination trace (\[port_id]/[channel_id])+/[denom\] #[prost(string, tag="1")] pub trace: ::prost::alloc::string::String, } @@ -357,6 +357,25 @@ pub struct QueryDenomHashResponse { #[prost(string, tag="1")] pub hash: ::prost::alloc::string::String, } +/// QueryEscrowAddressRequest is the request type for the EscrowAddress RPC method. +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryEscrowAddressRequest { + /// unique port identifier + #[prost(string, tag="1")] + pub port_id: ::prost::alloc::string::String, + /// unique channel identifier + #[prost(string, tag="2")] + pub channel_id: ::prost::alloc::string::String, +} +/// QueryEscrowAddressResponse is the response type of the EscrowAddress RPC method. +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryEscrowAddressResponse { + /// the escrow account address + #[prost(string, tag="1")] + pub escrow_address: ::prost::alloc::string::String, +} /// Generated client implementations. #[cfg(feature = "client")] pub mod query_client { @@ -503,6 +522,26 @@ pub mod query_client { ); self.inner.unary(request.into_request(), path, codec).await } + /// EscrowAddress returns the escrow address for a particular port and channel id. + pub async fn escrow_address( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/ibc.applications.transfer.v1.Query/EscrowAddress", + ); + self.inner.unary(request.into_request(), path, codec).await + } } } /// Generated server implementations. @@ -533,6 +572,11 @@ pub mod query_server { &self, request: tonic::Request, ) -> Result, tonic::Status>; + /// EscrowAddress returns the escrow address for a particular port and channel id. + async fn escrow_address( + &self, + request: tonic::Request, + ) -> Result, tonic::Status>; } /// Query provides defines the gRPC querier service. #[derive(Debug)] @@ -734,6 +778,46 @@ pub mod query_server { }; Box::pin(fut) } + "/ibc.applications.transfer.v1.Query/EscrowAddress" => { + #[allow(non_camel_case_types)] + struct EscrowAddressSvc(pub Arc); + impl< + T: Query, + > tonic::server::UnaryService + for EscrowAddressSvc { + type Response = super::QueryEscrowAddressResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).escrow_address(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = EscrowAddressSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } _ => { Box::pin(async move { Ok( diff --git a/proto/src/prost/ibc.core.client.v1.rs b/proto/src/prost/ibc.core.client.v1.rs index 1e323c54a0..b501dfb31c 100644 --- a/proto/src/prost/ibc.core.client.v1.rs +++ b/proto/src/prost/ibc.core.client.v1.rs @@ -771,6 +771,30 @@ pub struct QueryConsensusStatesResponse { #[prost(message, optional, tag="2")] pub pagination: ::core::option::Option, } +/// QueryConsensusStateHeightsRequest is the request type for Query/ConsensusStateHeights +/// RPC method. +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryConsensusStateHeightsRequest { + /// client identifier + #[prost(string, tag="1")] + pub client_id: ::prost::alloc::string::String, + /// pagination request + #[prost(message, optional, tag="2")] + pub pagination: ::core::option::Option, +} +/// QueryConsensusStateHeightsResponse is the response type for the +/// Query/ConsensusStateHeights RPC method +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryConsensusStateHeightsResponse { + /// consensus state heights + #[prost(message, repeated, tag="1")] + pub consensus_state_heights: ::prost::alloc::vec::Vec, + /// pagination response + #[prost(message, optional, tag="2")] + pub pagination: ::core::option::Option, +} /// QueryClientStatusRequest is the request type for the Query/ClientStatus RPC /// method #[derive(::serde::Serialize, ::serde::Deserialize)] @@ -984,6 +1008,29 @@ pub mod query_client { ); self.inner.unary(request.into_request(), path, codec).await } + /// ConsensusStateHeights queries the height of every consensus states associated with a given client. + pub async fn consensus_state_heights( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/ibc.core.client.v1.Query/ConsensusStateHeights", + ); + self.inner.unary(request.into_request(), path, codec).await + } /// Status queries the status of an IBC client. pub async fn client_status( &mut self, @@ -1102,6 +1149,14 @@ pub mod query_server { &self, request: tonic::Request, ) -> Result, tonic::Status>; + /// ConsensusStateHeights queries the height of every consensus states associated with a given client. + async fn consensus_state_heights( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; /// Status queries the status of an IBC client. async fn client_status( &self, @@ -1337,6 +1392,49 @@ pub mod query_server { }; Box::pin(fut) } + "/ibc.core.client.v1.Query/ConsensusStateHeights" => { + #[allow(non_camel_case_types)] + struct ConsensusStateHeightsSvc(pub Arc); + impl< + T: Query, + > tonic::server::UnaryService< + super::QueryConsensusStateHeightsRequest, + > for ConsensusStateHeightsSvc { + type Response = super::QueryConsensusStateHeightsResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + super::QueryConsensusStateHeightsRequest, + >, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).consensus_state_heights(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = ConsensusStateHeightsSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } "/ibc.core.client.v1.Query/ClientStatus" => { #[allow(non_camel_case_types)] struct ClientStatusSvc(pub Arc); diff --git a/proto/src/prost/ibc.core.connection.v1.rs b/proto/src/prost/ibc.core.connection.v1.rs index 978ecd2ef9..7fca4cd510 100644 --- a/proto/src/prost/ibc.core.connection.v1.rs +++ b/proto/src/prost/ibc.core.connection.v1.rs @@ -994,20 +994,6 @@ pub mod query_client { } } } -/// GenesisState defines the ibc connection submodule's genesis state. -#[derive(::serde::Serialize, ::serde::Deserialize)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GenesisState { - #[prost(message, repeated, tag="1")] - pub connections: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag="2")] - pub client_connection_paths: ::prost::alloc::vec::Vec, - /// the sequence for the next generated connection identifier - #[prost(uint64, tag="3")] - pub next_connection_sequence: u64, - #[prost(message, optional, tag="4")] - pub params: ::core::option::Option, -} /// Generated server implementations. #[cfg(feature = "server")] pub mod query_server { @@ -1343,3 +1329,17 @@ pub mod query_server { const NAME: &'static str = "ibc.core.connection.v1.Query"; } } +/// GenesisState defines the ibc connection submodule's genesis state. +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GenesisState { + #[prost(message, repeated, tag="1")] + pub connections: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag="2")] + pub client_connection_paths: ::prost::alloc::vec::Vec, + /// the sequence for the next generated connection identifier + #[prost(uint64, tag="3")] + pub next_connection_sequence: u64, + #[prost(message, optional, tag="4")] + pub params: ::core::option::Option, +} diff --git a/proto/src/prost/ibc.lightclients.tendermint.v1.rs b/proto/src/prost/ibc.lightclients.tendermint.v1.rs index 23bd610879..3ce35376c8 100644 --- a/proto/src/prost/ibc.lightclients.tendermint.v1.rs +++ b/proto/src/prost/ibc.lightclients.tendermint.v1.rs @@ -34,12 +34,12 @@ pub struct ClientState { /// "upgradedIBCState"}` #[prost(string, repeated, tag="9")] pub upgrade_path: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, - /// This flag, when set to true, will allow governance to recover a client - /// which has expired + /// allow_update_after_expiry is deprecated + #[deprecated] #[prost(bool, tag="10")] pub allow_update_after_expiry: bool, - /// This flag, when set to true, will allow governance to unfreeze a client - /// whose chain has experienced a misbehaviour event + /// allow_update_after_misbehaviour is deprecated + #[deprecated] #[prost(bool, tag="11")] pub allow_update_after_misbehaviour: bool, } diff --git a/proto/src/prost/tendermint.abci.rs b/proto/src/prost/tendermint.abci.rs new file mode 100644 index 0000000000..630243c2ce --- /dev/null +++ b/proto/src/prost/tendermint.abci.rs @@ -0,0 +1,1225 @@ +/// Generated client implementations. +#[cfg(feature = "client")] +pub mod abci_application_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + #[derive(Debug, Clone)] + pub struct AbciApplicationClient { + inner: tonic::client::Grpc, + } + impl AbciApplicationClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: std::convert::TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl AbciApplicationClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> AbciApplicationClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + AbciApplicationClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with `gzip`. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_gzip(mut self) -> Self { + self.inner = self.inner.send_gzip(); + self + } + /// Enable decompressing responses with `gzip`. + #[must_use] + pub fn accept_gzip(mut self) -> Self { + self.inner = self.inner.accept_gzip(); + self + } + pub async fn echo( + &mut self, + request: impl tonic::IntoRequest<::tendermint_proto::abci::RequestEcho>, + ) -> Result< + tonic::Response<::tendermint_proto::abci::ResponseEcho>, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/tendermint.abci.ABCIApplication/Echo", + ); + self.inner.unary(request.into_request(), path, codec).await + } + pub async fn flush( + &mut self, + request: impl tonic::IntoRequest<::tendermint_proto::abci::RequestFlush>, + ) -> Result< + tonic::Response<::tendermint_proto::abci::ResponseFlush>, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/tendermint.abci.ABCIApplication/Flush", + ); + self.inner.unary(request.into_request(), path, codec).await + } + pub async fn info( + &mut self, + request: impl tonic::IntoRequest<::tendermint_proto::abci::RequestInfo>, + ) -> Result< + tonic::Response<::tendermint_proto::abci::ResponseInfo>, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/tendermint.abci.ABCIApplication/Info", + ); + self.inner.unary(request.into_request(), path, codec).await + } + pub async fn set_option( + &mut self, + request: impl tonic::IntoRequest<::tendermint_proto::abci::RequestSetOption>, + ) -> Result< + tonic::Response<::tendermint_proto::abci::ResponseSetOption>, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/tendermint.abci.ABCIApplication/SetOption", + ); + self.inner.unary(request.into_request(), path, codec).await + } + pub async fn deliver_tx( + &mut self, + request: impl tonic::IntoRequest<::tendermint_proto::abci::RequestDeliverTx>, + ) -> Result< + tonic::Response<::tendermint_proto::abci::ResponseDeliverTx>, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/tendermint.abci.ABCIApplication/DeliverTx", + ); + self.inner.unary(request.into_request(), path, codec).await + } + pub async fn check_tx( + &mut self, + request: impl tonic::IntoRequest<::tendermint_proto::abci::RequestCheckTx>, + ) -> Result< + tonic::Response<::tendermint_proto::abci::ResponseCheckTx>, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/tendermint.abci.ABCIApplication/CheckTx", + ); + self.inner.unary(request.into_request(), path, codec).await + } + pub async fn query( + &mut self, + request: impl tonic::IntoRequest<::tendermint_proto::abci::RequestQuery>, + ) -> Result< + tonic::Response<::tendermint_proto::abci::ResponseQuery>, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/tendermint.abci.ABCIApplication/Query", + ); + self.inner.unary(request.into_request(), path, codec).await + } + pub async fn commit( + &mut self, + request: impl tonic::IntoRequest<::tendermint_proto::abci::RequestCommit>, + ) -> Result< + tonic::Response<::tendermint_proto::abci::ResponseCommit>, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/tendermint.abci.ABCIApplication/Commit", + ); + self.inner.unary(request.into_request(), path, codec).await + } + pub async fn init_chain( + &mut self, + request: impl tonic::IntoRequest<::tendermint_proto::abci::RequestInitChain>, + ) -> Result< + tonic::Response<::tendermint_proto::abci::ResponseInitChain>, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/tendermint.abci.ABCIApplication/InitChain", + ); + self.inner.unary(request.into_request(), path, codec).await + } + pub async fn begin_block( + &mut self, + request: impl tonic::IntoRequest<::tendermint_proto::abci::RequestBeginBlock>, + ) -> Result< + tonic::Response<::tendermint_proto::abci::ResponseBeginBlock>, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/tendermint.abci.ABCIApplication/BeginBlock", + ); + self.inner.unary(request.into_request(), path, codec).await + } + pub async fn end_block( + &mut self, + request: impl tonic::IntoRequest<::tendermint_proto::abci::RequestEndBlock>, + ) -> Result< + tonic::Response<::tendermint_proto::abci::ResponseEndBlock>, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/tendermint.abci.ABCIApplication/EndBlock", + ); + self.inner.unary(request.into_request(), path, codec).await + } + pub async fn list_snapshots( + &mut self, + request: impl tonic::IntoRequest< + ::tendermint_proto::abci::RequestListSnapshots, + >, + ) -> Result< + tonic::Response<::tendermint_proto::abci::ResponseListSnapshots>, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/tendermint.abci.ABCIApplication/ListSnapshots", + ); + self.inner.unary(request.into_request(), path, codec).await + } + pub async fn offer_snapshot( + &mut self, + request: impl tonic::IntoRequest< + ::tendermint_proto::abci::RequestOfferSnapshot, + >, + ) -> Result< + tonic::Response<::tendermint_proto::abci::ResponseOfferSnapshot>, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/tendermint.abci.ABCIApplication/OfferSnapshot", + ); + self.inner.unary(request.into_request(), path, codec).await + } + pub async fn load_snapshot_chunk( + &mut self, + request: impl tonic::IntoRequest< + ::tendermint_proto::abci::RequestLoadSnapshotChunk, + >, + ) -> Result< + tonic::Response<::tendermint_proto::abci::ResponseLoadSnapshotChunk>, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/tendermint.abci.ABCIApplication/LoadSnapshotChunk", + ); + self.inner.unary(request.into_request(), path, codec).await + } + pub async fn apply_snapshot_chunk( + &mut self, + request: impl tonic::IntoRequest< + ::tendermint_proto::abci::RequestApplySnapshotChunk, + >, + ) -> Result< + tonic::Response<::tendermint_proto::abci::ResponseApplySnapshotChunk>, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/tendermint.abci.ABCIApplication/ApplySnapshotChunk", + ); + self.inner.unary(request.into_request(), path, codec).await + } + } +} +/// Generated server implementations. +#[cfg(feature = "server")] +pub mod abci_application_server { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + ///Generated trait containing gRPC methods that should be implemented for use with AbciApplicationServer. + #[async_trait] + pub trait AbciApplication: Send + Sync + 'static { + async fn echo( + &self, + request: tonic::Request<::tendermint_proto::abci::RequestEcho>, + ) -> Result< + tonic::Response<::tendermint_proto::abci::ResponseEcho>, + tonic::Status, + >; + async fn flush( + &self, + request: tonic::Request<::tendermint_proto::abci::RequestFlush>, + ) -> Result< + tonic::Response<::tendermint_proto::abci::ResponseFlush>, + tonic::Status, + >; + async fn info( + &self, + request: tonic::Request<::tendermint_proto::abci::RequestInfo>, + ) -> Result< + tonic::Response<::tendermint_proto::abci::ResponseInfo>, + tonic::Status, + >; + async fn set_option( + &self, + request: tonic::Request<::tendermint_proto::abci::RequestSetOption>, + ) -> Result< + tonic::Response<::tendermint_proto::abci::ResponseSetOption>, + tonic::Status, + >; + async fn deliver_tx( + &self, + request: tonic::Request<::tendermint_proto::abci::RequestDeliverTx>, + ) -> Result< + tonic::Response<::tendermint_proto::abci::ResponseDeliverTx>, + tonic::Status, + >; + async fn check_tx( + &self, + request: tonic::Request<::tendermint_proto::abci::RequestCheckTx>, + ) -> Result< + tonic::Response<::tendermint_proto::abci::ResponseCheckTx>, + tonic::Status, + >; + async fn query( + &self, + request: tonic::Request<::tendermint_proto::abci::RequestQuery>, + ) -> Result< + tonic::Response<::tendermint_proto::abci::ResponseQuery>, + tonic::Status, + >; + async fn commit( + &self, + request: tonic::Request<::tendermint_proto::abci::RequestCommit>, + ) -> Result< + tonic::Response<::tendermint_proto::abci::ResponseCommit>, + tonic::Status, + >; + async fn init_chain( + &self, + request: tonic::Request<::tendermint_proto::abci::RequestInitChain>, + ) -> Result< + tonic::Response<::tendermint_proto::abci::ResponseInitChain>, + tonic::Status, + >; + async fn begin_block( + &self, + request: tonic::Request<::tendermint_proto::abci::RequestBeginBlock>, + ) -> Result< + tonic::Response<::tendermint_proto::abci::ResponseBeginBlock>, + tonic::Status, + >; + async fn end_block( + &self, + request: tonic::Request<::tendermint_proto::abci::RequestEndBlock>, + ) -> Result< + tonic::Response<::tendermint_proto::abci::ResponseEndBlock>, + tonic::Status, + >; + async fn list_snapshots( + &self, + request: tonic::Request<::tendermint_proto::abci::RequestListSnapshots>, + ) -> Result< + tonic::Response<::tendermint_proto::abci::ResponseListSnapshots>, + tonic::Status, + >; + async fn offer_snapshot( + &self, + request: tonic::Request<::tendermint_proto::abci::RequestOfferSnapshot>, + ) -> Result< + tonic::Response<::tendermint_proto::abci::ResponseOfferSnapshot>, + tonic::Status, + >; + async fn load_snapshot_chunk( + &self, + request: tonic::Request<::tendermint_proto::abci::RequestLoadSnapshotChunk>, + ) -> Result< + tonic::Response<::tendermint_proto::abci::ResponseLoadSnapshotChunk>, + tonic::Status, + >; + async fn apply_snapshot_chunk( + &self, + request: tonic::Request<::tendermint_proto::abci::RequestApplySnapshotChunk>, + ) -> Result< + tonic::Response<::tendermint_proto::abci::ResponseApplySnapshotChunk>, + tonic::Status, + >; + } + #[derive(Debug)] + pub struct AbciApplicationServer { + inner: _Inner, + accept_compression_encodings: (), + send_compression_encodings: (), + } + struct _Inner(Arc); + impl AbciApplicationServer { + pub fn new(inner: T) -> Self { + Self::from_arc(Arc::new(inner)) + } + pub fn from_arc(inner: Arc) -> Self { + let inner = _Inner(inner); + Self { + inner, + accept_compression_encodings: Default::default(), + send_compression_encodings: Default::default(), + } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> InterceptedService + where + F: tonic::service::Interceptor, + { + InterceptedService::new(Self::new(inner), interceptor) + } + } + impl tonic::codegen::Service> for AbciApplicationServer + where + T: AbciApplication, + B: Body + Send + 'static, + B::Error: Into + Send + 'static, + { + type Response = http::Response; + type Error = std::convert::Infallible; + type Future = BoxFuture; + fn poll_ready( + &mut self, + _cx: &mut Context<'_>, + ) -> Poll> { + Poll::Ready(Ok(())) + } + fn call(&mut self, req: http::Request) -> Self::Future { + let inner = self.inner.clone(); + match req.uri().path() { + "/tendermint.abci.ABCIApplication/Echo" => { + #[allow(non_camel_case_types)] + struct EchoSvc(pub Arc); + impl< + T: AbciApplication, + > tonic::server::UnaryService<::tendermint_proto::abci::RequestEcho> + for EchoSvc { + type Response = ::tendermint_proto::abci::ResponseEcho; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + ::tendermint_proto::abci::RequestEcho, + >, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { (*inner).echo(request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = EchoSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/tendermint.abci.ABCIApplication/Flush" => { + #[allow(non_camel_case_types)] + struct FlushSvc(pub Arc); + impl< + T: AbciApplication, + > tonic::server::UnaryService<::tendermint_proto::abci::RequestFlush> + for FlushSvc { + type Response = ::tendermint_proto::abci::ResponseFlush; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + ::tendermint_proto::abci::RequestFlush, + >, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { (*inner).flush(request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = FlushSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/tendermint.abci.ABCIApplication/Info" => { + #[allow(non_camel_case_types)] + struct InfoSvc(pub Arc); + impl< + T: AbciApplication, + > tonic::server::UnaryService<::tendermint_proto::abci::RequestInfo> + for InfoSvc { + type Response = ::tendermint_proto::abci::ResponseInfo; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + ::tendermint_proto::abci::RequestInfo, + >, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { (*inner).info(request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = InfoSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/tendermint.abci.ABCIApplication/SetOption" => { + #[allow(non_camel_case_types)] + struct SetOptionSvc(pub Arc); + impl< + T: AbciApplication, + > tonic::server::UnaryService< + ::tendermint_proto::abci::RequestSetOption, + > for SetOptionSvc { + type Response = ::tendermint_proto::abci::ResponseSetOption; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + ::tendermint_proto::abci::RequestSetOption, + >, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { (*inner).set_option(request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = SetOptionSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/tendermint.abci.ABCIApplication/DeliverTx" => { + #[allow(non_camel_case_types)] + struct DeliverTxSvc(pub Arc); + impl< + T: AbciApplication, + > tonic::server::UnaryService< + ::tendermint_proto::abci::RequestDeliverTx, + > for DeliverTxSvc { + type Response = ::tendermint_proto::abci::ResponseDeliverTx; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + ::tendermint_proto::abci::RequestDeliverTx, + >, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { (*inner).deliver_tx(request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = DeliverTxSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/tendermint.abci.ABCIApplication/CheckTx" => { + #[allow(non_camel_case_types)] + struct CheckTxSvc(pub Arc); + impl< + T: AbciApplication, + > tonic::server::UnaryService< + ::tendermint_proto::abci::RequestCheckTx, + > for CheckTxSvc { + type Response = ::tendermint_proto::abci::ResponseCheckTx; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + ::tendermint_proto::abci::RequestCheckTx, + >, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { (*inner).check_tx(request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = CheckTxSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/tendermint.abci.ABCIApplication/Query" => { + #[allow(non_camel_case_types)] + struct QuerySvc(pub Arc); + impl< + T: AbciApplication, + > tonic::server::UnaryService<::tendermint_proto::abci::RequestQuery> + for QuerySvc { + type Response = ::tendermint_proto::abci::ResponseQuery; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + ::tendermint_proto::abci::RequestQuery, + >, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { (*inner).query(request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = QuerySvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/tendermint.abci.ABCIApplication/Commit" => { + #[allow(non_camel_case_types)] + struct CommitSvc(pub Arc); + impl< + T: AbciApplication, + > tonic::server::UnaryService< + ::tendermint_proto::abci::RequestCommit, + > for CommitSvc { + type Response = ::tendermint_proto::abci::ResponseCommit; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + ::tendermint_proto::abci::RequestCommit, + >, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { (*inner).commit(request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = CommitSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/tendermint.abci.ABCIApplication/InitChain" => { + #[allow(non_camel_case_types)] + struct InitChainSvc(pub Arc); + impl< + T: AbciApplication, + > tonic::server::UnaryService< + ::tendermint_proto::abci::RequestInitChain, + > for InitChainSvc { + type Response = ::tendermint_proto::abci::ResponseInitChain; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + ::tendermint_proto::abci::RequestInitChain, + >, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { (*inner).init_chain(request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = InitChainSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/tendermint.abci.ABCIApplication/BeginBlock" => { + #[allow(non_camel_case_types)] + struct BeginBlockSvc(pub Arc); + impl< + T: AbciApplication, + > tonic::server::UnaryService< + ::tendermint_proto::abci::RequestBeginBlock, + > for BeginBlockSvc { + type Response = ::tendermint_proto::abci::ResponseBeginBlock; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + ::tendermint_proto::abci::RequestBeginBlock, + >, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { (*inner).begin_block(request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = BeginBlockSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/tendermint.abci.ABCIApplication/EndBlock" => { + #[allow(non_camel_case_types)] + struct EndBlockSvc(pub Arc); + impl< + T: AbciApplication, + > tonic::server::UnaryService< + ::tendermint_proto::abci::RequestEndBlock, + > for EndBlockSvc { + type Response = ::tendermint_proto::abci::ResponseEndBlock; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + ::tendermint_proto::abci::RequestEndBlock, + >, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { (*inner).end_block(request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = EndBlockSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/tendermint.abci.ABCIApplication/ListSnapshots" => { + #[allow(non_camel_case_types)] + struct ListSnapshotsSvc(pub Arc); + impl< + T: AbciApplication, + > tonic::server::UnaryService< + ::tendermint_proto::abci::RequestListSnapshots, + > for ListSnapshotsSvc { + type Response = ::tendermint_proto::abci::ResponseListSnapshots; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + ::tendermint_proto::abci::RequestListSnapshots, + >, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).list_snapshots(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = ListSnapshotsSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/tendermint.abci.ABCIApplication/OfferSnapshot" => { + #[allow(non_camel_case_types)] + struct OfferSnapshotSvc(pub Arc); + impl< + T: AbciApplication, + > tonic::server::UnaryService< + ::tendermint_proto::abci::RequestOfferSnapshot, + > for OfferSnapshotSvc { + type Response = ::tendermint_proto::abci::ResponseOfferSnapshot; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + ::tendermint_proto::abci::RequestOfferSnapshot, + >, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).offer_snapshot(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = OfferSnapshotSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/tendermint.abci.ABCIApplication/LoadSnapshotChunk" => { + #[allow(non_camel_case_types)] + struct LoadSnapshotChunkSvc(pub Arc); + impl< + T: AbciApplication, + > tonic::server::UnaryService< + ::tendermint_proto::abci::RequestLoadSnapshotChunk, + > for LoadSnapshotChunkSvc { + type Response = ::tendermint_proto::abci::ResponseLoadSnapshotChunk; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + ::tendermint_proto::abci::RequestLoadSnapshotChunk, + >, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).load_snapshot_chunk(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = LoadSnapshotChunkSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/tendermint.abci.ABCIApplication/ApplySnapshotChunk" => { + #[allow(non_camel_case_types)] + struct ApplySnapshotChunkSvc(pub Arc); + impl< + T: AbciApplication, + > tonic::server::UnaryService< + ::tendermint_proto::abci::RequestApplySnapshotChunk, + > for ApplySnapshotChunkSvc { + type Response = ::tendermint_proto::abci::ResponseApplySnapshotChunk; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + ::tendermint_proto::abci::RequestApplySnapshotChunk, + >, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).apply_snapshot_chunk(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = ApplySnapshotChunkSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + _ => { + Box::pin(async move { + Ok( + http::Response::builder() + .status(200) + .header("grpc-status", "12") + .header("content-type", "application/grpc") + .body(empty_body()) + .unwrap(), + ) + }) + } + } + } + } + impl Clone for AbciApplicationServer { + fn clone(&self) -> Self { + let inner = self.inner.clone(); + Self { + inner, + accept_compression_encodings: self.accept_compression_encodings, + send_compression_encodings: self.send_compression_encodings, + } + } + } + impl Clone for _Inner { + fn clone(&self) -> Self { + Self(self.0.clone()) + } + } + impl std::fmt::Debug for _Inner { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.0) + } + } + impl tonic::transport::NamedService + for AbciApplicationServer { + const NAME: &'static str = "tendermint.abci.ABCIApplication"; + } +} diff --git a/proto/src/prost/tendermint.crypto.rs b/proto/src/prost/tendermint.crypto.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/proto/src/prost/tendermint.p2p.rs b/proto/src/prost/tendermint.p2p.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/proto/src/prost/tendermint.types.rs b/proto/src/prost/tendermint.types.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/proto/src/prost/tendermint.version.rs b/proto/src/prost/tendermint.version.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/relayer/src/chain/cosmos.rs b/relayer/src/chain/cosmos.rs index c430a95613..5cd2ff0dc7 100644 --- a/relayer/src/chain/cosmos.rs +++ b/relayer/src/chain/cosmos.rs @@ -37,7 +37,7 @@ use ibc::core::ics04_channel::channel::{ use ibc::core::ics04_channel::events as ChannelEvents; use ibc::core::ics04_channel::packet::{Packet, Sequence}; use ibc::core::ics23_commitment::commitment::CommitmentPrefix; -use ibc::core::ics24_host::identifier::{ChainId, ChannelId, ClientId, ConnectionId}; +use ibc::core::ics24_host::identifier::{ChainId, ChannelId, ClientId, ConnectionId, PortId}; use ibc::core::ics24_host::path::{ AcksPath, ChannelEndsPath, ClientConsensusStatePath, ClientStatePath, CommitmentsPath, ConnectionsPath, ReceiptsPath, SeqRecvsPath, @@ -1573,6 +1573,7 @@ impl ChainEndpoint for CosmosSdkChain { fn maybe_register_counterparty_address( &mut self, channel_id: &ChannelId, + port_id: &PortId, counterparty_address: &Signer, ) -> Result<(), Error> { let address = self.get_signer()?; @@ -1584,6 +1585,7 @@ impl ChainEndpoint for CosmosSdkChain { &mut self.account, &self.config.memo_prefix, channel_id, + port_id, &address, counterparty_address, )) diff --git a/relayer/src/chain/cosmos/fee.rs b/relayer/src/chain/cosmos/fee.rs index 87886358ff..2cf2e098d6 100644 --- a/relayer/src/chain/cosmos/fee.rs +++ b/relayer/src/chain/cosmos/fee.rs @@ -1,5 +1,5 @@ use ibc::applications::ics29_fee::msgs::register_counterparty::build_register_counterparty_address_message; -use ibc::core::ics24_host::identifier::ChannelId; +use ibc::core::ics24_host::identifier::{ChannelId, PortId}; use ibc::signer::Signer; use crate::chain::cosmos::query::account::get_or_fetch_account; @@ -18,6 +18,7 @@ pub async fn maybe_register_counterparty_address( m_account: &mut Option, tx_memo: &Memo, channel_id: &ChannelId, + port_id: &PortId, address: &Signer, counterparty_address: &Signer, ) -> Result<(), Error> { @@ -38,6 +39,7 @@ pub async fn maybe_register_counterparty_address( address, counterparty_address, channel_id, + port_id, ) .map_err(Error::ics29)?; diff --git a/relayer/src/chain/endpoint.rs b/relayer/src/chain/endpoint.rs index 9970635436..1378ef88c0 100644 --- a/relayer/src/chain/endpoint.rs +++ b/relayer/src/chain/endpoint.rs @@ -579,6 +579,7 @@ pub trait ChainEndpoint: Sized { fn maybe_register_counterparty_address( &mut self, channel_id: &ChannelId, + port_id: &PortId, counterparty_address: &Signer, ) -> Result<(), Error>; } diff --git a/relayer/src/chain/handle.rs b/relayer/src/chain/handle.rs index 78766e0c43..319ab03fde 100644 --- a/relayer/src/chain/handle.rs +++ b/relayer/src/chain/handle.rs @@ -348,6 +348,7 @@ pub enum ChainRequest { MaybeRegisterCounterpartyAddress { channel_id: ChannelId, + port_id: PortId, counterparty_address: Signer, reply_to: ReplyTo<()>, }, @@ -639,6 +640,7 @@ pub trait ChainHandle: Clone + Send + Sync + Serialize + Debug + 'static { fn maybe_register_counterparty_address( &self, channel_id: ChannelId, + port_id: PortId, counterparty_address: Signer, ) -> Result<(), Error>; } diff --git a/relayer/src/chain/handle/base.rs b/relayer/src/chain/handle/base.rs index d00b2e4f2d..85013d06a8 100644 --- a/relayer/src/chain/handle/base.rs +++ b/relayer/src/chain/handle/base.rs @@ -476,10 +476,12 @@ impl ChainHandle for BaseChainHandle { fn maybe_register_counterparty_address( &self, channel_id: ChannelId, + port_id: PortId, counterparty_address: Signer, ) -> Result<(), Error> { self.send(|reply_to| ChainRequest::MaybeRegisterCounterpartyAddress { channel_id, + port_id, counterparty_address, reply_to, }) diff --git a/relayer/src/chain/handle/cache.rs b/relayer/src/chain/handle/cache.rs index b0008a365f..0451b97228 100644 --- a/relayer/src/chain/handle/cache.rs +++ b/relayer/src/chain/handle/cache.rs @@ -485,9 +485,10 @@ impl ChainHandle for CachingChainHandle { fn maybe_register_counterparty_address( &self, channel_id: ChannelId, + port_id: PortId, counterparty_address: Signer, ) -> Result<(), Error> { self.inner - .maybe_register_counterparty_address(channel_id, counterparty_address) + .maybe_register_counterparty_address(channel_id, port_id, counterparty_address) } } diff --git a/relayer/src/chain/handle/counting.rs b/relayer/src/chain/handle/counting.rs index 043a1cfd79..50a3a846c0 100644 --- a/relayer/src/chain/handle/counting.rs +++ b/relayer/src/chain/handle/counting.rs @@ -469,9 +469,10 @@ impl ChainHandle for CountingChainHandle { fn maybe_register_counterparty_address( &self, channel_id: ChannelId, + port_id: PortId, counterparty_address: Signer, ) -> Result<(), Error> { self.inner - .maybe_register_counterparty_address(channel_id, counterparty_address) + .maybe_register_counterparty_address(channel_id, port_id, counterparty_address) } } diff --git a/relayer/src/chain/mock.rs b/relayer/src/chain/mock.rs index 1477adf1f5..7859d1e3a4 100644 --- a/relayer/src/chain/mock.rs +++ b/relayer/src/chain/mock.rs @@ -19,7 +19,7 @@ use ibc::core::ics04_channel::channel::{ChannelEnd, IdentifiedChannelEnd}; use ibc::core::ics04_channel::context::ChannelReader; use ibc::core::ics04_channel::packet::Sequence; use ibc::core::ics23_commitment::{commitment::CommitmentPrefix, specs::ProofSpecs}; -use ibc::core::ics24_host::identifier::{ChainId, ChannelId, ConnectionId}; +use ibc::core::ics24_host::identifier::{ChainId, ChannelId, ConnectionId, PortId}; use ibc::events::IbcEvent; use ibc::mock::context::MockContext; use ibc::mock::host::HostType; @@ -440,6 +440,7 @@ impl ChainEndpoint for MockChain { fn maybe_register_counterparty_address( &mut self, _channel_id: &ChannelId, + _port_id: &PortId, _counterparty_address: &Signer, ) -> Result<(), Error> { unimplemented!() diff --git a/relayer/src/chain/runtime.rs b/relayer/src/chain/runtime.rs index d0f5febd15..e4c02d8de9 100644 --- a/relayer/src/chain/runtime.rs +++ b/relayer/src/chain/runtime.rs @@ -419,8 +419,8 @@ where self.query_host_consensus_state(request, reply_to)? }, - Ok(ChainRequest::MaybeRegisterCounterpartyAddress { channel_id, counterparty_address, reply_to }) => { - self.maybe_register_counterparty_address(&channel_id, &counterparty_address, reply_to)? + Ok(ChainRequest::MaybeRegisterCounterpartyAddress { channel_id, port_id, counterparty_address, reply_to }) => { + self.maybe_register_counterparty_address(&channel_id, &port_id, &counterparty_address, reply_to)? } Err(e) => error!("received error via chain request channel: {}", e), @@ -902,12 +902,15 @@ where fn maybe_register_counterparty_address( &mut self, channel_id: &ChannelId, + port_id: &PortId, counterparty_address: &Signer, reply_to: ReplyTo<()>, ) -> Result<(), Error> { - let result = self - .chain - .maybe_register_counterparty_address(channel_id, counterparty_address); + let result = self.chain.maybe_register_counterparty_address( + channel_id, + port_id, + counterparty_address, + ); reply_to.send(result).map_err(Error::send)?; diff --git a/relayer/src/link.rs b/relayer/src/link.rs index 9e3f345b67..243240d0a6 100644 --- a/relayer/src/link.rs +++ b/relayer/src/link.rs @@ -88,6 +88,8 @@ impl Link { .channel_id .ok_or_else(|| LinkError::counterparty_channel_not_found(*a_channel_id))?; + let b_port_id = a_channel.counterparty().port_id.clone(); + if a_channel.connection_hops().is_empty() { return Err(LinkError::no_connection_hop(*a_channel_id, a_chain.id())); } @@ -147,7 +149,7 @@ impl Link { let address_a = a_chain.get_signer().map_err(LinkError::relayer)?; b_chain - .maybe_register_counterparty_address(b_channel_id, address_a) + .maybe_register_counterparty_address(b_channel_id, b_port_id, address_a) .map_err(LinkError::relayer)?; } diff --git a/tools/integration-test/src/tests/fee.rs b/tools/integration-test/src/tests/fee.rs index b53d80d89f..97b6934676 100644 --- a/tools/integration-test/src/tests/fee.rs +++ b/tools/integration-test/src/tests/fee.rs @@ -205,6 +205,7 @@ impl BinaryChannelTest for ForwardRelayerTest { let denom_a = chains.node_a.denom(); let port_a = channel.port_a.as_ref(); + let port_b = channel.port_b.as_ref(); let channel_id_a = channel.channel_id_a.as_ref(); let channel_id_b = channel.channel_id_b.as_ref(); @@ -238,6 +239,7 @@ impl BinaryChannelTest for ForwardRelayerTest { &relayer_b, &relayer_a.address(), &channel_id_b, + &port_b, )?; { @@ -520,6 +522,7 @@ impl BinaryChannelTest for PayPacketFeeAsyncTest { let denom_a = chains.node_a.denom(); let port_a = channel.port_a.as_ref(); + let port_b = channel.port_b.as_ref(); let channel_id_a = channel.channel_id_a.as_ref(); let channel_id_b = channel.channel_id_b.as_ref(); @@ -542,6 +545,7 @@ impl BinaryChannelTest for PayPacketFeeAsyncTest { &relayer_b, &relayer_a.address(), &channel_id_b, + &port_b, )?; let user_a = wallets_a.user1(); @@ -682,6 +686,7 @@ impl BinaryChannelTest for NonFeeChannelTest { let denom_a = chains.node_a.denom(); let port_a = channel.port_a.as_ref(); + let port_b = channel.port_b.as_ref(); let channel_id_a = channel.channel_id_a.as_ref(); let channel_id_b = channel.channel_id_b.as_ref(); @@ -703,6 +708,7 @@ impl BinaryChannelTest for NonFeeChannelTest { &relayer_b, &relayer_a.address(), &channel_id_b, + &port_b, ); assert!(res.is_err()); diff --git a/tools/test-framework/src/chain/ext/fee.rs b/tools/test-framework/src/chain/ext/fee.rs index 1a788b282a..14c449c23c 100644 --- a/tools/test-framework/src/chain/ext/fee.rs +++ b/tools/test-framework/src/chain/ext/fee.rs @@ -45,6 +45,7 @@ pub trait ChainFeeMethodsExt { wallet: &MonoTagged, counterparty_address: &MonoTagged, channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, + port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, ) -> Result<(), Error>; fn query_counterparty_address( @@ -114,12 +115,14 @@ impl<'a, Chain: Send> ChainFeeMethodsExt for MonoTagged, counterparty_address: &MonoTagged, channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, + port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, ) -> Result<(), Error> { self.value().runtime.block_on(register_counterparty_address( &self.tx_config(), wallet, counterparty_address, channel_id, + port_id, )) } diff --git a/tools/test-framework/src/relayer/chain.rs b/tools/test-framework/src/relayer/chain.rs index ec7ae7f3c5..8f50fef36d 100644 --- a/tools/test-framework/src/relayer/chain.rs +++ b/tools/test-framework/src/relayer/chain.rs @@ -405,9 +405,10 @@ where fn maybe_register_counterparty_address( &self, channel_id: ChannelId, + port_id: PortId, counterparty_address: Signer, ) -> Result<(), Error> { self.value() - .maybe_register_counterparty_address(channel_id, counterparty_address) + .maybe_register_counterparty_address(channel_id, port_id, counterparty_address) } } diff --git a/tools/test-framework/src/relayer/fee.rs b/tools/test-framework/src/relayer/fee.rs index 7cf382e983..6c74b3f4db 100644 --- a/tools/test-framework/src/relayer/fee.rs +++ b/tools/test-framework/src/relayer/fee.rs @@ -93,6 +93,7 @@ pub async fn register_counterparty_address( wallet: &MonoTagged, counterparty_address: &MonoTagged, channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, + port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, ) -> Result<(), Error> { let message = build_register_counterparty_address_message( &wallet @@ -107,6 +108,7 @@ pub async fn register_counterparty_address( .parse() .map_err(handle_generic_error)?, channel_id.value(), + port_id.value(), ) .map_err(handle_generic_error)?; From dfdf1597a409c29027b6c689fa857dcf24df2583 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Tue, 14 Jun 2022 11:33:15 +0200 Subject: [PATCH 058/113] Fix cargo doc --- proto/src/prost/ibc.applications.transfer.v1.rs | 2 +- tools/test-framework/src/ibc/denom.rs | 3 --- tools/test-framework/src/types/single/node.rs | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/proto/src/prost/ibc.applications.transfer.v1.rs b/proto/src/prost/ibc.applications.transfer.v1.rs index 88037983e1..d5975755c3 100644 --- a/proto/src/prost/ibc.applications.transfer.v1.rs +++ b/proto/src/prost/ibc.applications.transfer.v1.rs @@ -344,7 +344,7 @@ pub struct QueryParamsResponse { #[derive(::serde::Serialize, ::serde::Deserialize)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryDenomHashRequest { - /// The denomination trace (\[port_id]/[channel_id])+/[denom\] + /// The denomination trace `([port_id]/[channel_id])+/[denom]` #[prost(string, tag="1")] pub trace: ::prost::alloc::string::String, } diff --git a/tools/test-framework/src/ibc/denom.rs b/tools/test-framework/src/ibc/denom.rs index 121efa03d8..71ae02b638 100644 --- a/tools/test-framework/src/ibc/denom.rs +++ b/tools/test-framework/src/ibc/denom.rs @@ -35,9 +35,6 @@ pub type TaggedDenom = MonoTagged; pub type TaggedDenomRef<'a, Chain> = MonoTagged; /** - A tagged version of [`derive_ibc_denom`](token_transfer::derive_ibc_denom) - from the [`ibc`] module. - Derives the denom on `ChainB` based on a denom on `ChainA` that has been transferred to `ChainB` via IBC. diff --git a/tools/test-framework/src/types/single/node.rs b/tools/test-framework/src/types/single/node.rs index d3f6fb8b6b..a858d541b4 100644 --- a/tools/test-framework/src/types/single/node.rs +++ b/tools/test-framework/src/types/single/node.rs @@ -158,7 +158,7 @@ impl FullNode { Test writers can use this to kill the full node in the middle of tests, and then restart it using - [`ChainDriver::start`](crate::chain::driver::ChainDriver::start). + [`ChainDriver::start`](crate::chain::ext::bootstrap::ChainBootstrapMethodsExt::start). */ pub fn kill(&self) -> Result<(), Error> { self.process From 4fa92d9b6534d03acf0faafcaf6c6c2e3650b400 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Tue, 14 Jun 2022 13:09:24 +0200 Subject: [PATCH 059/113] Add RawCoin type with string as denom --- .../applications/ics29_fee/msgs/pay_packet.rs | 14 +++--- .../ics29_fee/msgs/pay_packet_async.rs | 14 +++--- .../src/applications/ics29_fee/packet_fee.rs | 44 +++++++++++++++++-- modules/src/applications/transfer/denom.rs | 16 ++++--- relayer-cli/src/lib.rs | 1 + tools/test-framework/src/ibc/token.rs | 17 +++---- 6 files changed, 74 insertions(+), 32 deletions(-) diff --git a/modules/src/applications/ics29_fee/msgs/pay_packet.rs b/modules/src/applications/ics29_fee/msgs/pay_packet.rs index f52b5b1120..8beb44ea4e 100644 --- a/modules/src/applications/ics29_fee/msgs/pay_packet.rs +++ b/modules/src/applications/ics29_fee/msgs/pay_packet.rs @@ -1,9 +1,9 @@ -use ibc_proto::cosmos::base::v1beta1::Coin; use ibc_proto::google::protobuf::Any; use ibc_proto::ibc::applications::fee::v1::{Fee as ProtoFee, MsgPayPacketFee}; use crate::applications::ics29_fee::error::Error; use crate::applications::ics29_fee::utils::encode_message; +use crate::applications::transfer::denom::RawCoin; use crate::core::ics24_host::identifier::{ChannelId, PortId}; use crate::prelude::*; use crate::signer::Signer; @@ -14,14 +14,14 @@ pub fn build_pay_packet_message( port_id: &PortId, channel_id: &ChannelId, payer: &Signer, - recv_fee: Vec, - ack_fee: Vec, - timeout_fee: Vec, + recv_fee: Vec, + ack_fee: Vec, + timeout_fee: Vec, ) -> Result { let fee = ProtoFee { - recv_fee, - ack_fee, - timeout_fee, + recv_fee: recv_fee.into_iter().map(Into::into).collect(), + ack_fee: ack_fee.into_iter().map(Into::into).collect(), + timeout_fee: timeout_fee.into_iter().map(Into::into).collect(), }; let message = MsgPayPacketFee { diff --git a/modules/src/applications/ics29_fee/msgs/pay_packet_async.rs b/modules/src/applications/ics29_fee/msgs/pay_packet_async.rs index 226b08ccac..afbed6f663 100644 --- a/modules/src/applications/ics29_fee/msgs/pay_packet_async.rs +++ b/modules/src/applications/ics29_fee/msgs/pay_packet_async.rs @@ -1,4 +1,3 @@ -use ibc_proto::cosmos::base::v1beta1::Coin; use ibc_proto::google::protobuf::Any; use ibc_proto::ibc::applications::fee::v1::{ Fee as ProtoFee, MsgPayPacketFeeAsync, PacketFee as ProtoPacketFee, @@ -7,6 +6,7 @@ use ibc_proto::ibc::core::channel::v1::PacketId as ProtoPacketId; use crate::applications::ics29_fee::error::Error; use crate::applications::ics29_fee::utils::encode_message; +use crate::applications::transfer::denom::RawCoin; use crate::core::ics04_channel::packet::Sequence; use crate::core::ics24_host::identifier::{ChannelId, PortId}; use crate::prelude::*; @@ -19,14 +19,14 @@ pub fn build_pay_packet_fee_async_message( channel_id: &ChannelId, sequence: Sequence, payer: &Signer, - recv_fee: Vec, - ack_fee: Vec, - timeout_fee: Vec, + recv_fee: Vec, + ack_fee: Vec, + timeout_fee: Vec, ) -> Result { let fee = ProtoFee { - recv_fee, - ack_fee, - timeout_fee, + recv_fee: recv_fee.into_iter().map(Into::into).collect(), + ack_fee: ack_fee.into_iter().map(Into::into).collect(), + timeout_fee: timeout_fee.into_iter().map(Into::into).collect(), }; let packet_fee = ProtoPacketFee { diff --git a/modules/src/applications/ics29_fee/packet_fee.rs b/modules/src/applications/ics29_fee/packet_fee.rs index ce3a5b9185..2d63ae53b5 100644 --- a/modules/src/applications/ics29_fee/packet_fee.rs +++ b/modules/src/applications/ics29_fee/packet_fee.rs @@ -1,14 +1,22 @@ use core::str::FromStr; -use ibc_proto::ibc::applications::fee::v1::Fee; +use ibc_proto::cosmos::base::v1beta1::Coin as ProtoCoin; use ibc_proto::ibc::applications::fee::v1::{ - IdentifiedPacketFees as ProtoIdentifiedPacketFees, PacketFee as ProtoPacketFee, + Fee as ProtoFee, IdentifiedPacketFees as ProtoIdentifiedPacketFees, PacketFee as ProtoPacketFee, }; use super::error::Error; +use crate::applications::transfer::denom::{Amount, RawCoin}; use crate::core::ics04_channel::packet_id::PacketId; use crate::prelude::*; use crate::signer::Signer; +#[derive(Debug, Clone)] +pub struct Fee { + pub recv_fee: Vec, + pub ack_fee: Vec, + pub timeout_fee: Vec, +} + #[derive(Debug, Clone)] pub struct PacketFee { pub fee: Fee, @@ -22,11 +30,41 @@ pub struct IdentifiedPacketFees { pub packet_fees: Vec, } +impl TryFrom for Fee { + type Error = Error; + + fn try_from(fee: ProtoFee) -> Result { + fn parse_coin_vec(coins: Vec) -> Result, Error> { + coins + .into_iter() + .map(|coin| { + Ok(RawCoin { + denom: coin.denom, + amount: Amount::from_str(&coin.amount).map_err(Error::transfer)?, + }) + }) + .collect() + } + + let recv_fee = parse_coin_vec(fee.recv_fee)?; + let ack_fee = parse_coin_vec(fee.ack_fee)?; + let timeout_fee = parse_coin_vec(fee.timeout_fee)?; + + Ok(Fee { + recv_fee, + ack_fee, + timeout_fee, + }) + } +} + impl TryFrom for PacketFee { type Error = Error; fn try_from(packet_fee: ProtoPacketFee) -> Result { - let fee = packet_fee.fee.ok_or_else(Error::empty_fee)?; + let proto_fee = packet_fee.fee.ok_or_else(Error::empty_fee)?; + + let fee = Fee::try_from(proto_fee)?; let refund_address = Signer::from_str(&packet_fee.refund_address).map_err(Error::signer)?; diff --git a/modules/src/applications/transfer/denom.rs b/modules/src/applications/transfer/denom.rs index e0ba26c5e6..fdeba80ef6 100644 --- a/modules/src/applications/transfer/denom.rs +++ b/modules/src/applications/transfer/denom.rs @@ -2,7 +2,7 @@ use core::fmt; use core::str::FromStr; use derive_more::{Display, From, Into}; -use ibc_proto::cosmos::base::v1beta1::Coin as RawCoin; +use ibc_proto::cosmos::base::v1beta1::Coin as ProtoCoin; use ibc_proto::ibc::applications::transfer::v1::DenomTrace as RawDenomTrace; use serde::{Deserialize, Serialize}; @@ -18,6 +18,8 @@ pub type PrefixedCoin = Coin; /// A `Coin` type with an unprefixed denomination. pub type BaseCoin = Coin; +pub type RawCoin = Coin; + /// Base denomination type #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize, Display)] #[serde(transparent)] @@ -281,7 +283,7 @@ impl fmt::Display for PrefixedDenom { #[derive( Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize, Display, From, Into, )] -pub struct Amount(U256); +pub struct Amount(pub U256); impl Amount { pub fn checked_add(self, rhs: Self) -> Option { @@ -324,22 +326,22 @@ pub struct Coin { pub amount: Amount, } -impl TryFrom for Coin +impl TryFrom for Coin where Error: From<::Err>, { type Error = Error; - fn try_from(proto: RawCoin) -> Result, Self::Error> { + fn try_from(proto: ProtoCoin) -> Result, Self::Error> { let denom = D::from_str(&proto.denom)?; let amount = Amount::from_str(&proto.amount)?; Ok(Self { denom, amount }) } } -impl From> for RawCoin { - fn from(coin: Coin) -> RawCoin { - RawCoin { +impl From> for ProtoCoin { + fn from(coin: Coin) -> ProtoCoin { + ProtoCoin { denom: coin.denom.to_string(), amount: coin.amount.to_string(), } diff --git a/relayer-cli/src/lib.rs b/relayer-cli/src/lib.rs index 9260d703bd..cab10648d9 100644 --- a/relayer-cli/src/lib.rs +++ b/relayer-cli/src/lib.rs @@ -19,6 +19,7 @@ unused_lifetimes, unused_qualifications )] +#![allow(deprecated)] extern crate alloc; diff --git a/tools/test-framework/src/ibc/token.rs b/tools/test-framework/src/ibc/token.rs index d7e7e4bbc6..8995b91179 100644 --- a/tools/test-framework/src/ibc/token.rs +++ b/tools/test-framework/src/ibc/token.rs @@ -1,7 +1,7 @@ use core::fmt::{self, Display}; use core::ops::{Add, Sub}; -use core::str::FromStr; -use ibc_proto::cosmos::base::v1beta1::Coin; +use eyre::eyre; +use ibc::applications::transfer::denom::RawCoin; use crate::error::{handle_generic_error, Error}; use crate::ibc::denom::{derive_ibc_denom, Denom, TaggedDenom, TaggedDenomRef}; @@ -38,10 +38,10 @@ impl Token { Self { denom, amount } } - pub fn as_coin(&self) -> Coin { - Coin { + pub fn as_coin(&self) -> RawCoin { + RawCoin { denom: self.denom.to_string(), - amount: self.amount.to_string(), + amount: self.amount.into(), } } } @@ -148,12 +148,13 @@ impl Display for Token { } } -impl TryFrom for Token { +impl TryFrom for Token { type Error = Error; - fn try_from(fee: Coin) -> Result { + fn try_from(fee: RawCoin) -> Result { let denom = Denom::base(&fee.denom); - let amount = u128::from_str(&fee.amount).map_err(handle_generic_error)?; + let amount = + u128::try_from(fee.amount.0).map_err(|e| handle_generic_error(eyre!("{}", e)))?; Ok(Token::new(denom, amount)) } From e061b03da9159b7e636b70f12de30409a9548eee Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Tue, 14 Jun 2022 20:55:11 +0200 Subject: [PATCH 060/113] Use Amount instead of u128 in Token --- modules/src/applications/transfer/denom.rs | 21 +++++-- .../src/tests/clear_packet.rs | 2 +- .../src/tests/client_expiration.rs | 4 +- tools/integration-test/src/tests/fee.rs | 59 +++---------------- tools/integration-test/src/tests/ica.rs | 4 +- .../integration-test/src/tests/supervisor.rs | 8 +-- .../src/tests/ternary_transfer.rs | 2 +- tools/test-framework/src/chain/cli/query.rs | 5 +- tools/test-framework/src/chain/driver.rs | 5 +- tools/test-framework/src/ibc/token.rs | 53 +++++++++-------- tools/test-framework/src/relayer/transfer.rs | 2 +- tools/test-framework/src/util/random.rs | 8 ++- 12 files changed, 75 insertions(+), 98 deletions(-) diff --git a/modules/src/applications/transfer/denom.rs b/modules/src/applications/transfer/denom.rs index fdeba80ef6..ac3c159be4 100644 --- a/modules/src/applications/transfer/denom.rs +++ b/modules/src/applications/transfer/denom.rs @@ -286,12 +286,12 @@ impl fmt::Display for PrefixedDenom { pub struct Amount(pub U256); impl Amount { - pub fn checked_add(self, rhs: Self) -> Option { - self.0.checked_add(rhs.0).map(Self) + pub fn checked_add(self, rhs: impl Into) -> Option { + self.0.checked_add(rhs.into().0).map(Self) } - pub fn checked_sub(self, rhs: Self) -> Option { - self.0.checked_sub(rhs.0).map(Self) + pub fn checked_sub(self, rhs: impl Into) -> Option { + self.0.checked_sub(rhs.into().0).map(Self) } } @@ -326,14 +326,23 @@ pub struct Coin { pub amount: Amount, } +impl Coin { + pub fn new(denom: D, amount: impl Into) -> Self { + Self { + denom, + amount: amount.into(), + } + } +} + impl TryFrom for Coin where - Error: From<::Err>, + D::Err: Into, { type Error = Error; fn try_from(proto: ProtoCoin) -> Result, Self::Error> { - let denom = D::from_str(&proto.denom)?; + let denom = D::from_str(&proto.denom).map_err(Into::into)?; let amount = Amount::from_str(&proto.amount)?; Ok(Self { denom, amount }) } diff --git a/tools/integration-test/src/tests/clear_packet.rs b/tools/integration-test/src/tests/clear_packet.rs index a765dcabfe..791218e5a7 100644 --- a/tools/integration-test/src/tests/clear_packet.rs +++ b/tools/integration-test/src/tests/clear_packet.rs @@ -139,7 +139,7 @@ impl BinaryChannelTest for ClearPacketRecoveryTest { chains.node_b.chain_driver().local_transfer_token( &relayer_wallet_b.as_ref(), &wallet_b.address(), - &denom_b1.with_amount(100).as_ref(), + &denom_b1.with_amount(100u64).as_ref(), )?; let amount1 = random_u128_range(1000, 5000); diff --git a/tools/integration-test/src/tests/client_expiration.rs b/tools/integration-test/src/tests/client_expiration.rs index bb36116736..a1a47db69a 100644 --- a/tools/integration-test/src/tests/client_expiration.rs +++ b/tools/integration-test/src/tests/client_expiration.rs @@ -293,7 +293,7 @@ impl BinaryChainTest for PacketExpirationTest { &channels.channel_id_a.as_ref(), &chains.node_a.wallets().user1(), &chains.node_b.wallets().user1().address(), - &chains.node_a.denom().with_amount(100).as_ref(), + &chains.node_a.denom().with_amount(100u64).as_ref(), )?; wait_for_client_expiry(); @@ -319,7 +319,7 @@ impl BinaryChainTest for PacketExpirationTest { assert_eq( "balance on wallet B should remain zero", &balance_b.amount(), - &0, + &0u64.into(), )?; Ok(()) diff --git a/tools/integration-test/src/tests/fee.rs b/tools/integration-test/src/tests/fee.rs index 97b6934676..0557c3044b 100644 --- a/tools/integration-test/src/tests/fee.rs +++ b/tools/integration-test/src/tests/fee.rs @@ -162,7 +162,10 @@ impl BinaryChannelTest for NoForwardRelayerTest { receive_fee, timeout_fee, balance_a2, - balance_a2.amount() + receive_fee + timeout_fee + balance_a2 + .amount() + .checked_add(receive_fee + timeout_fee) + .unwrap() ); // receive fee and timeout fee should be refunded, @@ -176,7 +179,7 @@ impl BinaryChannelTest for NoForwardRelayerTest { "Expect relayer to receive ack fee {} and go from {} to {}", ack_fee, relayer_balance_a, - relayer_balance_a.amount() + ack_fee, + relayer_balance_a.amount().checked_add(ack_fee).unwrap(), ); chain_driver_a.assert_eventual_wallet_amount( @@ -296,26 +299,11 @@ impl BinaryChannelTest for ForwardRelayerTest { &denom_b.with_amount(send_amount).as_ref(), )?; - info!( - "Expect user to be refunded receive timeout fee {} and go from {} to {}", - timeout_fee, - balance_a2, - balance_a2.amount() + timeout_fee - ); - chain_driver_a.assert_eventual_wallet_amount( &user_a.address(), &(balance_a2 + timeout_fee).as_ref(), )?; - info!( - "Expect relayer to receive ack fee {} and receive fee {} and go from {} to {}", - ack_fee, - receive_fee, - relayer_balance_a, - relayer_balance_a.amount() + ack_fee + receive_fee, - ); - chain_driver_a.assert_eventual_wallet_amount( &relayer_a.address(), &(relayer_balance_a + ack_fee + receive_fee).as_ref(), @@ -389,26 +377,11 @@ impl BinaryChannelTest for AutoForwardRelayerTest { &denom_b.with_amount(send_amount).as_ref(), )?; - info!( - "Expect user to be refunded receive timeout fee {} and go from {} to {}", - timeout_fee, - balance_a2, - balance_a2.amount() + timeout_fee - ); - chain_driver_a.assert_eventual_wallet_amount( &user_a.address(), &(balance_a2 + timeout_fee).as_ref(), )?; - info!( - "Expect relayer to receive ack fee {} and receive fee {} and go from {} to {}", - ack_fee, - receive_fee, - relayer_balance_a, - relayer_balance_a.amount() + ack_fee + receive_fee, - ); - chain_driver_a.assert_eventual_wallet_amount( &relayer_a.address(), &(relayer_balance_a + ack_fee + receive_fee).as_ref(), @@ -474,27 +447,11 @@ impl BinaryChannelTest for TimeoutFeeTest { thread::sleep(Duration::from_secs(6)); relayer.with_supervisor(|| { - info!( - "Expect user to be refunded send amount {}, receive fee {} and ack fee {} and go from {} to {}", - send_amount, - receive_fee, - ack_fee, - balance_a2, - balance_a2.amount() + send_amount + receive_fee + ack_fee - ); - chain_driver_a.assert_eventual_wallet_amount( &user_a.address(), &(balance_a2 + send_amount + receive_fee + ack_fee).as_ref(), )?; - info!( - "Expect relayer to receive timeout fee {} and go from {} to {}", - timeout_fee, - relayer_balance_a, - relayer_balance_a.amount() + timeout_fee, - ); - chain_driver_a.assert_eventual_wallet_amount( &relayer_a.address(), &(relayer_balance_a + timeout_fee).as_ref(), @@ -721,9 +678,9 @@ impl BinaryChannelTest for NonFeeChannelTest { &user_a, &user_b.address(), &denom_a.with_amount(send_amount).as_ref(), - &denom_a.with_amount(10).as_ref(), - &denom_a.with_amount(10).as_ref(), - &denom_a.with_amount(10).as_ref(), + &denom_a.with_amount(10u64).as_ref(), + &denom_a.with_amount(10u64).as_ref(), + &denom_a.with_amount(10u64).as_ref(), Duration::from_secs(60), ); diff --git a/tools/integration-test/src/tests/ica.rs b/tools/integration-test/src/tests/ica.rs index ea6d2fdee6..1985d34e59 100644 --- a/tools/integration-test/src/tests/ica.rs +++ b/tools/integration-test/src/tests/ica.rs @@ -114,11 +114,11 @@ impl BinaryConnectionTest for IcaFilterTestAllow { assert_eq( "balance of ICA account should be 0", &ica_balance.amount(), - &0, + &0u64.into(), )?; // Send funds to the interchain account. - let ica_fund = 42000; + let ica_fund = 42000u64; chains.node_b.chain_driver().local_transfer_token( &chains.node_b.wallets().user1(), diff --git a/tools/integration-test/src/tests/supervisor.rs b/tools/integration-test/src/tests/supervisor.rs index d9f5979584..1eddc03edb 100644 --- a/tools/integration-test/src/tests/supervisor.rs +++ b/tools/integration-test/src/tests/supervisor.rs @@ -85,7 +85,7 @@ impl BinaryChainTest for SupervisorTest { let wallet_a = chains.node_a.wallets().user1().cloned(); let wallet_b = chains.node_b.wallets().user1().cloned(); - let transfer_amount = 1000; + let transfer_amount = 1000u64; let balance_a = chains .node_a @@ -98,13 +98,13 @@ impl BinaryChainTest for SupervisorTest { chains.node_a.chain_driver().local_transfer_token( &chains.node_a.wallets().relayer(), &chains.node_a.wallets().user2().address(), - &denom_a.with_amount(1000).as_ref(), + &denom_a.with_amount(1000u64).as_ref(), )?; chains.node_b.chain_driver().local_transfer_token( &chains.node_b.wallets().relayer(), &chains.node_b.wallets().user2().address(), - &chains.node_b.denom().with_amount(1000).as_ref(), + &chains.node_b.denom().with_amount(1000u64).as_ref(), )?; info!( @@ -120,7 +120,7 @@ impl BinaryChainTest for SupervisorTest { &channel_id_a.as_ref(), &wallet_a.as_ref(), &wallet_b.address(), - &denom_a.with_amount(transfer_amount).as_ref(), + &denom_a.with_amount(1000u64).as_ref(), )?; // 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 6fc5184c9e..d49d28bfa8 100644 --- a/tools/integration-test/src/tests/ternary_transfer.rs +++ b/tools/integration-test/src/tests/ternary_transfer.rs @@ -45,7 +45,7 @@ impl NaryChannelTest<3> for TernaryIbcTransferTest { .chain_driver() .query_balance(&wallet_a1.address(), &denom_a)?; - let a_to_b_amount = 5000; + let a_to_b_amount = 5000u64; let channel_a_to_b = channels.channel_at::<0, 1>()?; diff --git a/tools/test-framework/src/chain/cli/query.rs b/tools/test-framework/src/chain/cli/query.rs index 7cf556d576..54d7e93dc9 100644 --- a/tools/test-framework/src/chain/cli/query.rs +++ b/tools/test-framework/src/chain/cli/query.rs @@ -1,5 +1,6 @@ use core::str::FromStr; use eyre::eyre; +use ibc::applications::transfer::denom::Amount; use serde_json as json; use serde_yaml as yaml; @@ -12,7 +13,7 @@ pub fn query_balance( rpc_listen_address: &str, wallet_id: &str, denom: &str, -) -> Result { +) -> Result { let res = simple_exec( chain_id, command_path, @@ -39,7 +40,7 @@ pub fn query_balance( .ok_or_else(|| eyre!("expected string field"))? .to_string(); - let amount = u128::from_str(&amount_str).map_err(handle_generic_error)?; + let amount = Amount::from_str(&amount_str).map_err(handle_generic_error)?; Ok(amount) } diff --git a/tools/test-framework/src/chain/driver.rs b/tools/test-framework/src/chain/driver.rs index 251bd964e6..bf8899d90f 100644 --- a/tools/test-framework/src/chain/driver.rs +++ b/tools/test-framework/src/chain/driver.rs @@ -8,6 +8,7 @@ use alloc::sync::Arc; use eyre::eyre; use tokio::runtime::Runtime; +use ibc::applications::transfer::denom::Amount; use ibc::core::ics24_host::identifier::ChainId; use ibc_relayer::chain::cosmos::types::config::TxConfig; @@ -171,7 +172,7 @@ impl ChainDriver { /** Query for the balances for a given wallet address and denomination */ - pub fn query_balance(&self, wallet_id: &WalletAddress, denom: &Denom) -> Result { + pub fn query_balance(&self, wallet_id: &WalletAddress, denom: &Denom) -> Result { query_balance( self.chain_id.as_str(), &self.command_path, @@ -195,7 +196,7 @@ impl ChainDriver { WAIT_WALLET_AMOUNT_ATTEMPTS, Duration::from_secs(1), || { - let amount = self.query_balance(wallet, &token.denom)?; + let amount: Amount = self.query_balance(wallet, &token.denom)?; if amount == token.amount { Ok(()) diff --git a/tools/test-framework/src/ibc/token.rs b/tools/test-framework/src/ibc/token.rs index 8995b91179..a0ef665784 100644 --- a/tools/test-framework/src/ibc/token.rs +++ b/tools/test-framework/src/ibc/token.rs @@ -1,7 +1,7 @@ use core::fmt::{self, Display}; use core::ops::{Add, Sub}; use eyre::eyre; -use ibc::applications::transfer::denom::RawCoin; +use ibc::applications::transfer::denom::{Amount, RawCoin}; use crate::error::{handle_generic_error, Error}; use crate::ibc::denom::{derive_ibc_denom, Denom, TaggedDenom, TaggedDenomRef}; @@ -11,7 +11,7 @@ use crate::types::tagged::MonoTagged; #[derive(Debug, Clone, Eq, PartialEq)] pub struct Token { pub denom: Denom, - pub amount: u128, + pub amount: Amount, } pub type TaggedToken = MonoTagged; @@ -20,7 +20,7 @@ pub type TaggedTokenRef<'a, Chain> = MonoTagged; pub trait TaggedTokenExt { fn denom(&self) -> TaggedDenomRef; - fn amount(&self) -> u128; + fn amount(&self) -> Amount; fn transfer( &self, @@ -30,18 +30,21 @@ pub trait TaggedTokenExt { } pub trait TaggedDenomExt { - fn with_amount(&self, amount: u128) -> TaggedToken; + fn with_amount(&self, amount: impl Into) -> TaggedToken; } impl Token { - pub fn new(denom: Denom, amount: u128) -> Self { - Self { denom, amount } + pub fn new(denom: Denom, amount: impl Into) -> Self { + Self { + denom, + amount: amount.into(), + } } pub fn as_coin(&self) -> RawCoin { RawCoin { denom: self.denom.to_string(), - amount: self.amount.into(), + amount: self.amount, } } } @@ -51,7 +54,7 @@ impl TaggedTokenExt for TaggedToken { self.map_ref(|t| &t.denom) } - fn amount(&self) -> u128 { + fn amount(&self) -> Amount { self.value().amount } @@ -71,7 +74,7 @@ impl<'a, Chain> TaggedTokenExt for TaggedTokenRef<'a, Chain> { self.map_ref(|t| &t.denom) } - fn amount(&self) -> u128 { + fn amount(&self) -> Amount { self.value().amount } @@ -87,58 +90,58 @@ impl<'a, Chain> TaggedTokenExt for TaggedTokenRef<'a, Chain> { } impl TaggedDenomExt for TaggedDenom { - fn with_amount(&self, amount: u128) -> TaggedToken { + fn with_amount(&self, amount: impl Into) -> TaggedToken { self.map(|denom| Token { denom: denom.clone(), - amount, + amount: amount.into(), }) } } impl<'a, Chain> TaggedDenomExt for TaggedDenomRef<'a, Chain> { - fn with_amount(&self, amount: u128) -> TaggedToken { + fn with_amount(&self, amount: impl Into) -> TaggedToken { self.map(|denom| Token { denom: (*denom).clone(), - amount, + amount: amount.into(), }) } } -impl Add for Token { +impl> Add for Token { type Output = Self; - fn add(self, amount: u128) -> Self { + fn add(self, amount: I) -> Self { Self { denom: self.denom, - amount: self.amount + amount, + amount: self.amount.checked_add(amount).unwrap(), } } } -impl Sub for Token { +impl> Sub for Token { type Output = Self; - fn sub(self, amount: u128) -> Self { + fn sub(self, amount: I) -> Self { Self { denom: self.denom, - amount: self.amount - amount, + amount: self.amount.checked_sub(amount).unwrap(), } } } -impl Add for MonoTagged { +impl> Add for MonoTagged { type Output = Self; - fn add(self, amount: u128) -> Self { - self.map_into(|t| t + amount) + fn add(self, amount: I) -> Self { + self.map_into(|t| t + amount.into()) } } -impl Sub for MonoTagged { +impl> Sub for MonoTagged { type Output = Self; - fn sub(self, amount: u128) -> Self { - self.map_into(|t| t - amount) + fn sub(self, amount: I) -> Self { + self.map_into(|t| t - amount.into()) } } diff --git a/tools/test-framework/src/relayer/transfer.rs b/tools/test-framework/src/relayer/transfer.rs index 40965d31fa..86bc392ee7 100644 --- a/tools/test-framework/src/relayer/transfer.rs +++ b/tools/test-framework/src/relayer/transfer.rs @@ -49,7 +49,7 @@ pub fn build_transfer_message( Ok(raw_build_transfer_message( (*port_id.value()).clone(), **channel_id.value(), - token.value().amount.into(), + token.value().amount, token.value().denom.to_string(), sender, receiver, diff --git a/tools/test-framework/src/util/random.rs b/tools/test-framework/src/util/random.rs index 01bda39c1b..672e64c3b5 100644 --- a/tools/test-framework/src/util/random.rs +++ b/tools/test-framework/src/util/random.rs @@ -2,6 +2,7 @@ Utilities for random value generation. */ +use ibc::applications::transfer::denom::Amount; use rand::Rng; use std::net::{Ipv4Addr, SocketAddrV4, TcpListener}; @@ -28,12 +29,17 @@ pub fn random_u64_range(min: u64, max: u64) -> u64 { rng.gen_range(min..max) } -/// Generates a random `u64` value between the given min and max. +/// Generates a random `u128` value between the given min and max. pub fn random_u128_range(min: u128, max: u128) -> u128 { let mut rng = rand::thread_rng(); rng.gen_range(min..max) } +pub fn random_amount_range(min: u128, max: u128) -> Amount { + let mut rng = rand::thread_rng(); + rng.gen_range(min..max).into() +} + /// Generates a random string value, in the form of `u64` hex for simplicity. pub fn random_string() -> String { format!("{:x}", random_u64()) From 16498012540032a3606404c6f0283b79e61c5d69 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 15 Jun 2022 10:33:20 +0200 Subject: [PATCH 061/113] Turn Token into type alias for Coin --- modules/src/applications/transfer/denom.rs | 20 +++-- tools/integration-test/src/tests/fee.rs | 6 +- tools/test-framework/src/ibc/token.rs | 86 +++++----------------- tools/test-framework/src/relayer/fee.rs | 14 ++-- 4 files changed, 44 insertions(+), 82 deletions(-) diff --git a/modules/src/applications/transfer/denom.rs b/modules/src/applications/transfer/denom.rs index ac3c159be4..02ea1e7e63 100644 --- a/modules/src/applications/transfer/denom.rs +++ b/modules/src/applications/transfer/denom.rs @@ -1,4 +1,4 @@ -use core::fmt; +use core::fmt::{self, Display}; use core::str::FromStr; use derive_more::{Display, From, Into}; @@ -52,7 +52,7 @@ impl TracePrefix { } } -impl fmt::Display for TracePrefix { +impl Display for TracePrefix { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}/{}", self.port_id, self.channel_id) } @@ -130,7 +130,7 @@ impl FromStr for TracePath { } } -impl fmt::Display for TracePath { +impl Display for TracePath { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let path = self .0 @@ -269,7 +269,7 @@ impl From for PrefixedDenom { } } -impl fmt::Display for PrefixedDenom { +impl Display for PrefixedDenom { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if self.trace_path.0.is_empty() { write!(f, "{}", self.base_denom) @@ -333,6 +333,16 @@ impl Coin { amount: amount.into(), } } + + pub fn checked_add(self, rhs: impl Into) -> Option { + let amount = self.amount.checked_add(rhs)?; + Some(Self::new(self.denom, amount)) + } + + pub fn checked_sub(self, rhs: impl Into) -> Option { + let amount = self.amount.checked_sub(rhs)?; + Some(Self::new(self.denom, amount)) + } } impl TryFrom for Coin @@ -366,7 +376,7 @@ impl From for PrefixedCoin { } } -impl fmt::Display for PrefixedCoin { +impl Display for Coin { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}-{}", self.amount, self.denom) } diff --git a/tools/integration-test/src/tests/fee.rs b/tools/integration-test/src/tests/fee.rs index 0557c3044b..f810fef06f 100644 --- a/tools/integration-test/src/tests/fee.rs +++ b/tools/integration-test/src/tests/fee.rs @@ -565,16 +565,16 @@ impl BinaryChannelTest for PayPacketFeeAsyncTest { assert_eq!( &packet_fee.fee.recv_fee[0], - &denom_a.with_amount(receive_fee).value().as_coin(), + &denom_a.with_amount(receive_fee).as_coin(), ); assert_eq!( &packet_fee.fee.ack_fee[0], - &denom_a.with_amount(ack_fee).value().as_coin() + &denom_a.with_amount(ack_fee).as_coin() ); assert_eq!( &packet_fee.fee.timeout_fee[0], - &denom_a.with_amount(timeout_fee).value().as_coin(), + &denom_a.with_amount(timeout_fee).as_coin(), ); assert_eq!( diff --git a/tools/test-framework/src/ibc/token.rs b/tools/test-framework/src/ibc/token.rs index a0ef665784..2ba63895c5 100644 --- a/tools/test-framework/src/ibc/token.rs +++ b/tools/test-framework/src/ibc/token.rs @@ -1,18 +1,12 @@ -use core::fmt::{self, Display}; use core::ops::{Add, Sub}; -use eyre::eyre; -use ibc::applications::transfer::denom::{Amount, RawCoin}; +use ibc::applications::transfer::denom::{Amount, Coin, RawCoin}; -use crate::error::{handle_generic_error, Error}; +use crate::error::Error; use crate::ibc::denom::{derive_ibc_denom, Denom, TaggedDenom, TaggedDenomRef}; use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef}; use crate::types::tagged::MonoTagged; -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct Token { - pub denom: Denom, - pub amount: Amount, -} +pub type Token = Coin; pub type TaggedToken = MonoTagged; pub type TaggedTokenRef<'a, Chain> = MonoTagged; @@ -22,6 +16,8 @@ pub trait TaggedTokenExt { fn amount(&self) -> Amount; + fn as_coin(&self) -> RawCoin; + fn transfer( &self, port_id: &TaggedPortIdRef, @@ -33,22 +29,6 @@ pub trait TaggedDenomExt { fn with_amount(&self, amount: impl Into) -> TaggedToken; } -impl Token { - pub fn new(denom: Denom, amount: impl Into) -> Self { - Self { - denom, - amount: amount.into(), - } - } - - pub fn as_coin(&self) -> RawCoin { - RawCoin { - denom: self.denom.to_string(), - amount: self.amount, - } - } -} - impl TaggedTokenExt for TaggedToken { fn denom(&self) -> TaggedDenomRef { self.map_ref(|t| &t.denom) @@ -58,6 +38,10 @@ impl TaggedTokenExt for TaggedToken { self.value().amount } + fn as_coin(&self) -> RawCoin { + RawCoin::new(self.value().denom.to_string(), self.value().amount) + } + fn transfer( &self, port_id: &TaggedPortIdRef, @@ -78,6 +62,10 @@ impl<'a, Chain> TaggedTokenExt for TaggedTokenRef<'a, Chain> { self.value().amount } + fn as_coin(&self) -> RawCoin { + RawCoin::new(self.value().denom.to_string(), self.value().amount) + } + fn transfer( &self, port_id: &TaggedPortIdRef, @@ -107,33 +95,13 @@ impl<'a, Chain> TaggedDenomExt for TaggedDenomRef<'a, Chain> { } } -impl> Add for Token { - type Output = Self; - - fn add(self, amount: I) -> Self { - Self { - denom: self.denom, - amount: self.amount.checked_add(amount).unwrap(), - } - } -} - -impl> Sub for Token { - type Output = Self; - - fn sub(self, amount: I) -> Self { - Self { - denom: self.denom, - amount: self.amount.checked_sub(amount).unwrap(), - } - } -} - impl> Add for MonoTagged { type Output = Self; fn add(self, amount: I) -> Self { - self.map_into(|t| t + amount.into()) + self.map_into(|t| t.checked_add(amount)) + .transpose() + .unwrap() } } @@ -141,24 +109,8 @@ impl> Sub for MonoTagged { type Output = Self; fn sub(self, amount: I) -> Self { - self.map_into(|t| t - amount.into()) - } -} - -impl Display for Token { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}{}", self.amount, self.denom) - } -} - -impl TryFrom for Token { - type Error = Error; - - fn try_from(fee: RawCoin) -> Result { - let denom = Denom::base(&fee.denom); - let amount = - u128::try_from(fee.amount.0).map_err(|e| handle_generic_error(eyre!("{}", e)))?; - - Ok(Token::new(denom, amount)) + self.map_into(|t| t.checked_sub(amount)) + .transpose() + .unwrap() } } diff --git a/tools/test-framework/src/relayer/fee.rs b/tools/test-framework/src/relayer/fee.rs index 6c74b3f4db..f397f478e8 100644 --- a/tools/test-framework/src/relayer/fee.rs +++ b/tools/test-framework/src/relayer/fee.rs @@ -13,7 +13,7 @@ use ibc_relayer::chain::cosmos::query::fee::{ use ibc_relayer::chain::cosmos::types::config::TxConfig; use crate::error::{handle_generic_error, Error}; -use crate::ibc::token::TaggedTokenRef; +use crate::ibc::token::{TaggedTokenExt, TaggedTokenRef}; use crate::relayer::transfer::build_transfer_message; use crate::relayer::tx::simple_send_tx; use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef}; @@ -44,9 +44,9 @@ pub async fn ibc_token_transfer_with_fee( .0 .parse() .map_err(handle_generic_error)?, - vec![receive_fee.value().as_coin()], - vec![ack_fee.value().as_coin()], - vec![timeout_fee.value().as_coin()], + vec![receive_fee.as_coin()], + vec![ack_fee.as_coin()], + vec![timeout_fee.as_coin()], ) .map_err(handle_generic_error)?; @@ -77,9 +77,9 @@ pub async fn pay_packet_fee( .0 .parse() .map_err(handle_generic_error)?, - vec![receive_fee.value().as_coin()], - vec![ack_fee.value().as_coin()], - vec![timeout_fee.value().as_coin()], + vec![receive_fee.as_coin()], + vec![ack_fee.as_coin()], + vec![timeout_fee.as_coin()], ) .map_err(handle_generic_error)?; From f4f0e33c41319b50ce96f591e73d3e4d55f073e5 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 15 Jun 2022 10:48:43 +0200 Subject: [PATCH 062/113] Refactor use of encode_message --- modules/src/applications/ics29_fee/mod.rs | 1 - .../applications/ics29_fee/msgs/pay_packet.rs | 2 +- .../ics29_fee/msgs/pay_packet_async.rs | 2 +- .../ics29_fee/msgs/register_counterparty.rs | 2 +- modules/src/applications/ics29_fee/utils.rs | 9 -------- modules/src/applications/transfer/denom.rs | 2 +- .../src/core/ics23_commitment/commitment.rs | 7 +++--- modules/src/proofs.rs | 8 ++++++- modules/src/tx_msg.rs | 22 ++++++++++++------- 9 files changed, 29 insertions(+), 26 deletions(-) delete mode 100644 modules/src/applications/ics29_fee/utils.rs diff --git a/modules/src/applications/ics29_fee/mod.rs b/modules/src/applications/ics29_fee/mod.rs index 496ffc3fb7..de5f5710a7 100644 --- a/modules/src/applications/ics29_fee/mod.rs +++ b/modules/src/applications/ics29_fee/mod.rs @@ -1,4 +1,3 @@ pub mod error; pub mod msgs; pub mod packet_fee; -pub(crate) mod utils; diff --git a/modules/src/applications/ics29_fee/msgs/pay_packet.rs b/modules/src/applications/ics29_fee/msgs/pay_packet.rs index 8beb44ea4e..a1f85360dd 100644 --- a/modules/src/applications/ics29_fee/msgs/pay_packet.rs +++ b/modules/src/applications/ics29_fee/msgs/pay_packet.rs @@ -2,11 +2,11 @@ use ibc_proto::google::protobuf::Any; use ibc_proto::ibc::applications::fee::v1::{Fee as ProtoFee, MsgPayPacketFee}; use crate::applications::ics29_fee::error::Error; -use crate::applications::ics29_fee::utils::encode_message; use crate::applications::transfer::denom::RawCoin; use crate::core::ics24_host::identifier::{ChannelId, PortId}; use crate::prelude::*; use crate::signer::Signer; +use crate::tx_msg::encode_message; const TYPE_URL: &str = "/ibc.applications.fee.v1.MsgPayPacketFee"; diff --git a/modules/src/applications/ics29_fee/msgs/pay_packet_async.rs b/modules/src/applications/ics29_fee/msgs/pay_packet_async.rs index afbed6f663..d2ad124466 100644 --- a/modules/src/applications/ics29_fee/msgs/pay_packet_async.rs +++ b/modules/src/applications/ics29_fee/msgs/pay_packet_async.rs @@ -5,12 +5,12 @@ use ibc_proto::ibc::applications::fee::v1::{ use ibc_proto::ibc::core::channel::v1::PacketId as ProtoPacketId; use crate::applications::ics29_fee::error::Error; -use crate::applications::ics29_fee::utils::encode_message; use crate::applications::transfer::denom::RawCoin; use crate::core::ics04_channel::packet::Sequence; use crate::core::ics24_host::identifier::{ChannelId, PortId}; use crate::prelude::*; use crate::signer::Signer; +use crate::tx_msg::encode_message; const TYPE_URL: &str = "/ibc.applications.fee.v1.MsgPayPacketFeeAsync"; diff --git a/modules/src/applications/ics29_fee/msgs/register_counterparty.rs b/modules/src/applications/ics29_fee/msgs/register_counterparty.rs index 368e78b376..afcf082f92 100644 --- a/modules/src/applications/ics29_fee/msgs/register_counterparty.rs +++ b/modules/src/applications/ics29_fee/msgs/register_counterparty.rs @@ -2,10 +2,10 @@ use ibc_proto::google::protobuf::Any; use ibc_proto::ibc::applications::fee::v1::MsgRegisterCounterpartyAddress; use crate::applications::ics29_fee::error::Error; -use crate::applications::ics29_fee::utils::encode_message; use crate::core::ics24_host::identifier::{ChannelId, PortId}; use crate::prelude::*; use crate::signer::Signer; +use crate::tx_msg::encode_message; const TYPE_URL: &str = "/ibc.applications.fee.v1.MsgRegisterCounterpartyAddress"; diff --git a/modules/src/applications/ics29_fee/utils.rs b/modules/src/applications/ics29_fee/utils.rs deleted file mode 100644 index 37d37f2fb8..0000000000 --- a/modules/src/applications/ics29_fee/utils.rs +++ /dev/null @@ -1,9 +0,0 @@ -use prost::{EncodeError, Message}; - -use crate::prelude::*; - -pub fn encode_message(message: &M) -> Result, EncodeError> { - let mut buf = Vec::new(); - Message::encode(message, &mut buf)?; - Ok(buf) -} diff --git a/modules/src/applications/transfer/denom.rs b/modules/src/applications/transfer/denom.rs index 02ea1e7e63..bfc1761bc5 100644 --- a/modules/src/applications/transfer/denom.rs +++ b/modules/src/applications/transfer/denom.rs @@ -378,7 +378,7 @@ impl From for PrefixedCoin { impl Display for Coin { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}-{}", self.amount, self.denom) + write!(f, "{}{}", self.amount, self.denom) } } diff --git a/modules/src/core/ics23_commitment/commitment.rs b/modules/src/core/ics23_commitment/commitment.rs index fe77cb854e..b39507a08b 100644 --- a/modules/src/core/ics23_commitment/commitment.rs +++ b/modules/src/core/ics23_commitment/commitment.rs @@ -1,6 +1,7 @@ use crate::core::ics23_commitment::error::Error; use crate::prelude::*; use crate::proofs::ProofError; +use crate::tx_msg::encode_message; use core::{convert::TryFrom, fmt}; use ibc_proto::ibc::core::commitment::v1::MerkleProof as RawMerkleProof; @@ -84,9 +85,9 @@ impl TryFrom for CommitmentProofBytes { type Error = ProofError; fn try_from(proof: RawMerkleProof) -> Result { - let mut buf = Vec::new(); - prost::Message::encode(&proof, &mut buf).unwrap(); - buf.try_into() + encode_message(&proof) + .map_err(ProofError::encode)? + .try_into() } } diff --git a/modules/src/proofs.rs b/modules/src/proofs.rs index 30e84aa726..a34423c99a 100644 --- a/modules/src/proofs.rs +++ b/modules/src/proofs.rs @@ -1,16 +1,22 @@ +use flex_error::{define_error, TraceError}; +use prost::EncodeError; use serde::Serialize; use crate::core::ics23_commitment::commitment::CommitmentProofBytes; use crate::Height; -use flex_error::define_error; define_error! { #[derive(Debug, PartialEq, Eq)] ProofError { ZeroHeight | _ | { format_args!("proof height cannot be zero") }, + EmptyProof | _ | { format_args!("proof cannot be empty") }, + + Encode + [ TraceError ] + | _ | { "protobuf encode error" } } } diff --git a/modules/src/tx_msg.rs b/modules/src/tx_msg.rs index 5de9ba8780..c3ac9eea28 100644 --- a/modules/src/tx_msg.rs +++ b/modules/src/tx_msg.rs @@ -1,10 +1,12 @@ +use ibc_proto::google::protobuf::Any; +use prost::{EncodeError, Message}; + use crate::core::ics24_host::error::ValidationError; use crate::prelude::*; -use ibc_proto::google::protobuf::Any; pub trait Msg: Clone { type ValidationError; - type Raw: From + prost::Message; + type Raw: From + Message; // TODO: Clarify what is this function supposed to do & its connection to ICS26 routing mod. fn route(&self) -> String; @@ -21,19 +23,23 @@ pub trait Msg: Clone { } fn get_sign_bytes(self) -> Vec { - let mut buf = Vec::new(); let raw_msg: Self::Raw = self.into(); - match prost::Message::encode(&raw_msg, &mut buf) { - Ok(()) => buf, + encode_message(&raw_msg).unwrap_or_else(|e| { // Severe error that cannot be recovered. - Err(e) => panic!( + panic!( "Cannot encode the proto message {:?} into a buffer due to underlying error: {}", raw_msg, e - ), - } + ) + }) } fn validate_basic(&self) -> Result<(), ValidationError> { Ok(()) } } + +pub fn encode_message(message: &M) -> Result, EncodeError> { + let mut buf = Vec::new(); + Message::encode(message, &mut buf)?; + Ok(buf) +} From 44c33208f519a9484893460628c7438fa14697eb Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 15 Jun 2022 11:03:53 +0200 Subject: [PATCH 063/113] Refactor Coin and Amount definitions into separate modules --- .../applications/ics29_fee/msgs/pay_packet.rs | 2 +- .../ics29_fee/msgs/pay_packet_async.rs | 2 +- .../src/applications/ics29_fee/packet_fee.rs | 3 +- modules/src/applications/transfer/amount.rs | 44 +++++++ modules/src/applications/transfer/coin.rs | 84 +++++++++++++ modules/src/applications/transfer/denom.rs | 115 +----------------- modules/src/applications/transfer/mod.rs | 4 + tools/test-framework/src/chain/cli/query.rs | 2 +- tools/test-framework/src/chain/driver.rs | 2 +- tools/test-framework/src/ibc/token.rs | 3 +- tools/test-framework/src/util/random.rs | 2 +- 11 files changed, 142 insertions(+), 121 deletions(-) create mode 100644 modules/src/applications/transfer/amount.rs create mode 100644 modules/src/applications/transfer/coin.rs diff --git a/modules/src/applications/ics29_fee/msgs/pay_packet.rs b/modules/src/applications/ics29_fee/msgs/pay_packet.rs index a1f85360dd..6047d7d412 100644 --- a/modules/src/applications/ics29_fee/msgs/pay_packet.rs +++ b/modules/src/applications/ics29_fee/msgs/pay_packet.rs @@ -2,7 +2,7 @@ use ibc_proto::google::protobuf::Any; use ibc_proto::ibc::applications::fee::v1::{Fee as ProtoFee, MsgPayPacketFee}; use crate::applications::ics29_fee::error::Error; -use crate::applications::transfer::denom::RawCoin; +use crate::applications::transfer::coin::RawCoin; use crate::core::ics24_host::identifier::{ChannelId, PortId}; use crate::prelude::*; use crate::signer::Signer; diff --git a/modules/src/applications/ics29_fee/msgs/pay_packet_async.rs b/modules/src/applications/ics29_fee/msgs/pay_packet_async.rs index d2ad124466..436060f23a 100644 --- a/modules/src/applications/ics29_fee/msgs/pay_packet_async.rs +++ b/modules/src/applications/ics29_fee/msgs/pay_packet_async.rs @@ -5,7 +5,7 @@ use ibc_proto::ibc::applications::fee::v1::{ use ibc_proto::ibc::core::channel::v1::PacketId as ProtoPacketId; use crate::applications::ics29_fee::error::Error; -use crate::applications::transfer::denom::RawCoin; +use crate::applications::transfer::coin::RawCoin; use crate::core::ics04_channel::packet::Sequence; use crate::core::ics24_host::identifier::{ChannelId, PortId}; use crate::prelude::*; diff --git a/modules/src/applications/ics29_fee/packet_fee.rs b/modules/src/applications/ics29_fee/packet_fee.rs index 2d63ae53b5..12c4325ea7 100644 --- a/modules/src/applications/ics29_fee/packet_fee.rs +++ b/modules/src/applications/ics29_fee/packet_fee.rs @@ -5,7 +5,8 @@ use ibc_proto::ibc::applications::fee::v1::{ }; use super::error::Error; -use crate::applications::transfer::denom::{Amount, RawCoin}; +use crate::applications::transfer::amount::Amount; +use crate::applications::transfer::coin::RawCoin; use crate::core::ics04_channel::packet_id::PacketId; use crate::prelude::*; use crate::signer::Signer; diff --git a/modules/src/applications/transfer/amount.rs b/modules/src/applications/transfer/amount.rs new file mode 100644 index 0000000000..095cfb55aa --- /dev/null +++ b/modules/src/applications/transfer/amount.rs @@ -0,0 +1,44 @@ +use core::str::FromStr; +use derive_more::{Display, From, Into}; +use serde::{Deserialize, Serialize}; + +use super::error::Error; +use crate::bigint::U256; +use crate::prelude::*; + +/// A type for representing token transfer amounts. +#[derive( + Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize, Display, From, Into, +)] +pub struct Amount(pub U256); + +impl Amount { + pub fn checked_add(self, rhs: impl Into) -> Option { + self.0.checked_add(rhs.into().0).map(Self) + } + + pub fn checked_sub(self, rhs: impl Into) -> Option { + self.0.checked_sub(rhs.into().0).map(Self) + } +} + +impl FromStr for Amount { + type Err = Error; + + fn from_str(s: &str) -> Result { + let amount = U256::from_str_radix(s, 10).map_err(Error::invalid_amount)?; + Ok(Self(amount)) + } +} + +impl From for Amount { + fn from(v: u64) -> Self { + Self(v.into()) + } +} + +impl From for Amount { + fn from(amount: u128) -> Self { + Self(amount.into()) + } +} diff --git a/modules/src/applications/transfer/coin.rs b/modules/src/applications/transfer/coin.rs new file mode 100644 index 0000000000..5d272a612e --- /dev/null +++ b/modules/src/applications/transfer/coin.rs @@ -0,0 +1,84 @@ +use core::fmt::{self, Display}; +use core::str::FromStr; +use ibc_proto::cosmos::base::v1beta1::Coin as ProtoCoin; +use serde::{Deserialize, Serialize}; + +use super::amount::Amount; +use super::denom::{BaseDenom, PrefixedDenom}; +use super::error::Error; +use crate::prelude::*; +use crate::serializers::serde_string; + +/// A `Coin` type with fully qualified `PrefixedDenom`. +pub type PrefixedCoin = Coin; + +/// A `Coin` type with an unprefixed denomination. +pub type BaseCoin = Coin; + +pub type RawCoin = Coin; + +/// Coin defines a token with a denomination and an amount. +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] +pub struct Coin { + /// Denomination + pub denom: D, + /// Amount + #[serde(with = "serde_string")] + pub amount: Amount, +} + +impl Coin { + pub fn new(denom: D, amount: impl Into) -> Self { + Self { + denom, + amount: amount.into(), + } + } + + pub fn checked_add(self, rhs: impl Into) -> Option { + let amount = self.amount.checked_add(rhs)?; + Some(Self::new(self.denom, amount)) + } + + pub fn checked_sub(self, rhs: impl Into) -> Option { + let amount = self.amount.checked_sub(rhs)?; + Some(Self::new(self.denom, amount)) + } +} + +impl TryFrom for Coin +where + D::Err: Into, +{ + type Error = Error; + + fn try_from(proto: ProtoCoin) -> Result, Self::Error> { + let denom = D::from_str(&proto.denom).map_err(Into::into)?; + let amount = Amount::from_str(&proto.amount)?; + Ok(Self { denom, amount }) + } +} + +impl From> for ProtoCoin { + fn from(coin: Coin) -> ProtoCoin { + ProtoCoin { + denom: coin.denom.to_string(), + amount: coin.amount.to_string(), + } + } +} + +impl From for PrefixedCoin { + fn from(coin: BaseCoin) -> PrefixedCoin { + PrefixedCoin { + denom: coin.denom.into(), + amount: coin.amount, + } + } +} + +impl Display for Coin { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}{}", self.amount, self.denom) + } +} diff --git a/modules/src/applications/transfer/denom.rs b/modules/src/applications/transfer/denom.rs index bfc1761bc5..8d881acf21 100644 --- a/modules/src/applications/transfer/denom.rs +++ b/modules/src/applications/transfer/denom.rs @@ -1,25 +1,15 @@ use core::fmt::{self, Display}; use core::str::FromStr; -use derive_more::{Display, From, Into}; -use ibc_proto::cosmos::base::v1beta1::Coin as ProtoCoin; +use derive_more::{Display, From}; use ibc_proto::ibc::applications::transfer::v1::DenomTrace as RawDenomTrace; use serde::{Deserialize, Serialize}; use super::error::Error; -use crate::bigint::U256; use crate::core::ics24_host::identifier::{ChannelId, PortId}; use crate::prelude::*; use crate::serializers::serde_string; -/// A `Coin` type with fully qualified `PrefixedDenom`. -pub type PrefixedCoin = Coin; - -/// A `Coin` type with an unprefixed denomination. -pub type BaseCoin = Coin; - -pub type RawCoin = Coin; - /// Base denomination type #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize, Display)] #[serde(transparent)] @@ -279,109 +269,6 @@ impl Display for PrefixedDenom { } } -/// A type for representing token transfer amounts. -#[derive( - Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize, Display, From, Into, -)] -pub struct Amount(pub U256); - -impl Amount { - pub fn checked_add(self, rhs: impl Into) -> Option { - self.0.checked_add(rhs.into().0).map(Self) - } - - pub fn checked_sub(self, rhs: impl Into) -> Option { - self.0.checked_sub(rhs.into().0).map(Self) - } -} - -impl FromStr for Amount { - type Err = Error; - - fn from_str(s: &str) -> Result { - let amount = U256::from_str_radix(s, 10).map_err(Error::invalid_amount)?; - Ok(Self(amount)) - } -} - -impl From for Amount { - fn from(v: u64) -> Self { - Self(v.into()) - } -} - -impl From for Amount { - fn from(amount: u128) -> Self { - Self(amount.into()) - } -} - -/// Coin defines a token with a denomination and an amount. -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct Coin { - /// Denomination - pub denom: D, - /// Amount - #[serde(with = "serde_string")] - pub amount: Amount, -} - -impl Coin { - pub fn new(denom: D, amount: impl Into) -> Self { - Self { - denom, - amount: amount.into(), - } - } - - pub fn checked_add(self, rhs: impl Into) -> Option { - let amount = self.amount.checked_add(rhs)?; - Some(Self::new(self.denom, amount)) - } - - pub fn checked_sub(self, rhs: impl Into) -> Option { - let amount = self.amount.checked_sub(rhs)?; - Some(Self::new(self.denom, amount)) - } -} - -impl TryFrom for Coin -where - D::Err: Into, -{ - type Error = Error; - - fn try_from(proto: ProtoCoin) -> Result, Self::Error> { - let denom = D::from_str(&proto.denom).map_err(Into::into)?; - let amount = Amount::from_str(&proto.amount)?; - Ok(Self { denom, amount }) - } -} - -impl From> for ProtoCoin { - fn from(coin: Coin) -> ProtoCoin { - ProtoCoin { - denom: coin.denom.to_string(), - amount: coin.amount.to_string(), - } - } -} - -impl From for PrefixedCoin { - fn from(coin: BaseCoin) -> PrefixedCoin { - PrefixedCoin { - denom: coin.denom.into(), - amount: coin.amount, - } - } -} - -impl Display for Coin { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}{}", self.amount, self.denom) - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/modules/src/applications/transfer/mod.rs b/modules/src/applications/transfer/mod.rs index 1a8a87a89a..36479d8936 100644 --- a/modules/src/applications/transfer/mod.rs +++ b/modules/src/applications/transfer/mod.rs @@ -2,6 +2,8 @@ //! constitutes a "fungible token transfer bridge module" between the IBC routing module and an //! asset tracking module. pub mod acknowledgement; +pub mod amount; +pub mod coin; pub mod context; pub mod denom; pub mod error; @@ -10,6 +12,8 @@ pub mod msgs; pub mod packet; pub mod relay; +pub use amount::*; +pub use coin::*; pub use denom::*; /// Module identifier for the ICS20 application. diff --git a/tools/test-framework/src/chain/cli/query.rs b/tools/test-framework/src/chain/cli/query.rs index 54d7e93dc9..210a335cb5 100644 --- a/tools/test-framework/src/chain/cli/query.rs +++ b/tools/test-framework/src/chain/cli/query.rs @@ -1,6 +1,6 @@ use core::str::FromStr; use eyre::eyre; -use ibc::applications::transfer::denom::Amount; +use ibc::applications::transfer::amount::Amount; use serde_json as json; use serde_yaml as yaml; diff --git a/tools/test-framework/src/chain/driver.rs b/tools/test-framework/src/chain/driver.rs index bf8899d90f..4396a8af16 100644 --- a/tools/test-framework/src/chain/driver.rs +++ b/tools/test-framework/src/chain/driver.rs @@ -8,7 +8,7 @@ use alloc::sync::Arc; use eyre::eyre; use tokio::runtime::Runtime; -use ibc::applications::transfer::denom::Amount; +use ibc::applications::transfer::amount::Amount; use ibc::core::ics24_host::identifier::ChainId; use ibc_relayer::chain::cosmos::types::config::TxConfig; diff --git a/tools/test-framework/src/ibc/token.rs b/tools/test-framework/src/ibc/token.rs index 2ba63895c5..4af154600c 100644 --- a/tools/test-framework/src/ibc/token.rs +++ b/tools/test-framework/src/ibc/token.rs @@ -1,5 +1,6 @@ use core::ops::{Add, Sub}; -use ibc::applications::transfer::denom::{Amount, Coin, RawCoin}; +use ibc::applications::transfer::amount::Amount; +use ibc::applications::transfer::coin::{Coin, RawCoin}; use crate::error::Error; use crate::ibc::denom::{derive_ibc_denom, Denom, TaggedDenom, TaggedDenomRef}; diff --git a/tools/test-framework/src/util/random.rs b/tools/test-framework/src/util/random.rs index 672e64c3b5..298402bc0a 100644 --- a/tools/test-framework/src/util/random.rs +++ b/tools/test-framework/src/util/random.rs @@ -2,7 +2,7 @@ Utilities for random value generation. */ -use ibc::applications::transfer::denom::Amount; +use ibc::applications::transfer::amount::Amount; use rand::Rng; use std::net::{Ipv4Addr, SocketAddrV4, TcpListener}; From 7cec777d11842524dc2b24b14ac9c7e72ab97a02 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 15 Jun 2022 21:45:12 +0200 Subject: [PATCH 064/113] Add parsing logic for incentivized packet event --- modules/src/applications/ics29_fee/error.rs | 12 +++- modules/src/applications/ics29_fee/events.rs | 65 ++++++++++++++++++++ modules/src/applications/ics29_fee/mod.rs | 1 + modules/src/applications/transfer/coin.rs | 36 +++++++++++ modules/src/applications/transfer/error.rs | 17 ++++- modules/src/events.rs | 4 ++ modules/src/proofs.rs | 2 +- 7 files changed, 134 insertions(+), 3 deletions(-) create mode 100644 modules/src/applications/ics29_fee/events.rs diff --git a/modules/src/applications/ics29_fee/error.rs b/modules/src/applications/ics29_fee/error.rs index 9bdd076287..59962a2828 100644 --- a/modules/src/applications/ics29_fee/error.rs +++ b/modules/src/applications/ics29_fee/error.rs @@ -3,6 +3,8 @@ use prost::EncodeError; use crate::applications::transfer::error::Error as TransferError; use crate::core::ics04_channel::error::Error as ChannelError; +use crate::core::ics24_host::error::ValidationError; +use crate::prelude::*; use crate::signer::SignerError; define_error! { @@ -20,6 +22,10 @@ define_error! { [ SignerError ] | _ | { "failed to parse signer" }, + Ics24 + [ ValidationError ] + | _ | { "ics24 error" }, + EmptyFee | _ | { "expect fee field to be non-empty" }, @@ -28,6 +34,10 @@ define_error! { Encode [ TraceError ] - | _ | { "protobuf encode error" } + | _ | { "protobuf encode error" }, + + EventAttributeNotFound + { key: String } + | e | { format_args!("IBC event attribute not found for key: {}", e.key) }, } } diff --git a/modules/src/applications/ics29_fee/events.rs b/modules/src/applications/ics29_fee/events.rs new file mode 100644 index 0000000000..b0a59874cf --- /dev/null +++ b/modules/src/applications/ics29_fee/events.rs @@ -0,0 +1,65 @@ +use core::str::FromStr; +use tendermint::abci::tag::Tag; + +use super::error::Error; +use crate::applications::transfer::coin::RawCoin; +use crate::core::ics04_channel::packet::Sequence; +use crate::core::ics24_host::identifier::{ChannelId, PortId}; +use crate::prelude::*; + +pub struct IncentivizedPacketEvent { + pub port_id: PortId, + pub channel_id: ChannelId, + pub sequence: Sequence, + pub total_recv_fee: Vec, + pub total_ack_fee: Vec, + pub total_timeout_fee: Vec, +} + +fn find_value(key: &str, entries: &[Tag]) -> Result { + entries + .iter() + .find_map(|entry| { + if entry.key.as_ref() == key { + Some(entry.value.to_string()) + } else { + None + } + }) + .ok_or_else(|| Error::event_attribute_not_found(key.to_string())) +} + +impl TryFrom> for IncentivizedPacketEvent { + type Error = Error; + + fn try_from(entries: Vec) -> Result { + let port_id_str = find_value("port_id", &entries)?; + let channel_id_str = find_value("channel_id", &entries)?; + let sequence_str = find_value("packet_sequence", &entries)?; + let recv_fee_str = find_value("recv_fee", &entries)?; + let ack_fee_str = find_value("ack_fee", &entries)?; + let timeout_fee_str = find_value("timeout_fee", &entries)?; + + let port_id = PortId::from_str(&port_id_str).map_err(Error::ics24)?; + + let channel_id = ChannelId::from_str(&channel_id_str).map_err(Error::ics24)?; + + let sequence = Sequence::from_str(&sequence_str).map_err(Error::channel)?; + + let total_recv_fee = RawCoin::from_string_list(&recv_fee_str).map_err(Error::transfer)?; + + let total_ack_fee = RawCoin::from_string_list(&ack_fee_str).map_err(Error::transfer)?; + + let total_timeout_fee = + RawCoin::from_string_list(&timeout_fee_str).map_err(Error::transfer)?; + + Ok(IncentivizedPacketEvent { + port_id, + channel_id, + sequence, + total_recv_fee, + total_ack_fee, + total_timeout_fee, + }) + } +} diff --git a/modules/src/applications/ics29_fee/mod.rs b/modules/src/applications/ics29_fee/mod.rs index de5f5710a7..40c2c44bf3 100644 --- a/modules/src/applications/ics29_fee/mod.rs +++ b/modules/src/applications/ics29_fee/mod.rs @@ -1,3 +1,4 @@ pub mod error; +pub mod events; pub mod msgs; pub mod packet_fee; diff --git a/modules/src/applications/transfer/coin.rs b/modules/src/applications/transfer/coin.rs index 5d272a612e..9e42eef5ad 100644 --- a/modules/src/applications/transfer/coin.rs +++ b/modules/src/applications/transfer/coin.rs @@ -1,6 +1,8 @@ use core::fmt::{self, Display}; +use core::str::from_utf8; use core::str::FromStr; use ibc_proto::cosmos::base::v1beta1::Coin as ProtoCoin; +use safe_regex::regex; use serde::{Deserialize, Serialize}; use super::amount::Amount; @@ -46,6 +48,40 @@ impl Coin { } } +impl FromStr for Coin +where + D::Err: Into, +{ + type Err = Error; + + #[allow(clippy::assign_op_pattern)] + fn from_str(coin_str: &str) -> Result { + let matcher = regex!(br"(\\d+)([a-zA-Z].+)"); + + let (m1, m2) = matcher + .match_slices(coin_str.as_bytes()) + .ok_or_else(|| Error::invalid_coin(coin_str.to_string()))?; + + let amount = from_utf8(m1).map_err(Error::utf8_decode)?.parse()?; + + let denom = from_utf8(m2) + .map_err(Error::utf8_decode)? + .parse() + .map_err(Into::into)?; + + Ok(Coin { amount, denom }) + } +} + +impl Coin +where + D::Err: Into, +{ + pub fn from_string_list(coin_str: &str) -> Result, Error> { + coin_str.split(',').map(FromStr::from_str).collect() + } +} + impl TryFrom for Coin where D::Err: Into, diff --git a/modules/src/applications/transfer/error.rs b/modules/src/applications/transfer/error.rs index c9f71fdc33..4d1674e903 100644 --- a/modules/src/applications/transfer/error.rs +++ b/modules/src/applications/transfer/error.rs @@ -1,5 +1,6 @@ use alloc::string::FromUtf8Error; - +use core::convert::Infallible; +use core::str::Utf8Error; use flex_error::{define_error, DisplayOnly, TraceError}; use subtle_encoding::Error as EncodingError; use tendermint_proto::Error as TendermintProtoError; @@ -136,5 +137,19 @@ define_error! { UnknownMsgType { msg_type: String } | e | { format_args!("unknown msg type: {0}", e.msg_type) }, + + InvalidCoin + { coin: String } + | e | { format_args!("invalid coin string: {}", e.coin) }, + + Utf8Decode + [ TraceError ] + | _ | { "error decoding raw bytes as UTF8 string" }, + } +} + +impl From for Error { + fn from(e: Infallible) -> Self { + match e {} } } diff --git a/modules/src/events.rs b/modules/src/events.rs index 58e6d54e2b..18ce2c3c33 100644 --- a/modules/src/events.rs +++ b/modules/src/events.rs @@ -120,6 +120,7 @@ const WRITE_ACK_EVENT: &str = "write_acknowledgement"; const ACK_PACKET_EVENT: &str = "acknowledge_packet"; const TIMEOUT_EVENT: &str = "timeout_packet"; const TIMEOUT_ON_CLOSE_EVENT: &str = "timeout_packet_on_close"; +const INCENTIVIZED_PACKET_EVENT: &str = "incentivized_ibc_packet"; /// Events types #[derive(Debug, Clone, Deserialize, Serialize)] @@ -145,6 +146,7 @@ pub enum IbcEventType { AckPacket, Timeout, TimeoutOnClose, + IncentivizedPacket, AppModule, Empty, ChainError, @@ -174,6 +176,7 @@ impl IbcEventType { IbcEventType::AckPacket => ACK_PACKET_EVENT, IbcEventType::Timeout => TIMEOUT_EVENT, IbcEventType::TimeoutOnClose => TIMEOUT_ON_CLOSE_EVENT, + IbcEventType::IncentivizedPacket => INCENTIVIZED_PACKET_EVENT, IbcEventType::AppModule => APP_MODULE_EVENT, IbcEventType::Empty => EMPTY_EVENT, IbcEventType::ChainError => CHAIN_ERROR_EVENT, @@ -207,6 +210,7 @@ impl FromStr for IbcEventType { ACK_PACKET_EVENT => Ok(IbcEventType::AckPacket), TIMEOUT_EVENT => Ok(IbcEventType::Timeout), TIMEOUT_ON_CLOSE_EVENT => Ok(IbcEventType::TimeoutOnClose), + INCENTIVIZED_PACKET_EVENT => Ok(IbcEventType::IncentivizedPacket), EMPTY_EVENT => Ok(IbcEventType::Empty), CHAIN_ERROR_EVENT => Ok(IbcEventType::ChainError), // from_str() for `APP_MODULE_EVENT` MUST fail because a `ModuleEvent`'s type isn't constant diff --git a/modules/src/proofs.rs b/modules/src/proofs.rs index a34423c99a..66f2ba9135 100644 --- a/modules/src/proofs.rs +++ b/modules/src/proofs.rs @@ -16,7 +16,7 @@ define_error! { Encode [ TraceError ] - | _ | { "protobuf encode error" } + | _ | { "protobuf encode error" }, } } From 8c30d80b27787fba0be6c1ab8779b51d622cbd4b Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Thu, 16 Jun 2022 10:24:30 +0200 Subject: [PATCH 065/113] Update protobuf --- proto/src/COSMOS_SDK_COMMIT | 2 +- proto/src/IBC_GO_COMMIT | 2 +- proto/src/prost/cosmos.tx.signing.v1beta1.rs | 2 +- proto/src/prost/ibc.applications.fee.v1.rs | 177 +++++++++---------- 4 files changed, 90 insertions(+), 93 deletions(-) diff --git a/proto/src/COSMOS_SDK_COMMIT b/proto/src/COSMOS_SDK_COMMIT index 0a695d7e1b..022a319118 100644 --- a/proto/src/COSMOS_SDK_COMMIT +++ b/proto/src/COSMOS_SDK_COMMIT @@ -1 +1 @@ -ad9e5620fb3445c716e9de45cfcdb56e8f1745bf +a2761bdc6f23500a2b38d398ee2a423f2a5311c0 diff --git a/proto/src/IBC_GO_COMMIT b/proto/src/IBC_GO_COMMIT index 470cf6102c..5bde5e6287 100644 --- a/proto/src/IBC_GO_COMMIT +++ b/proto/src/IBC_GO_COMMIT @@ -1 +1 @@ -11297aaa61e651c16e6d4147a15be24ce55ba7cc +681a558e3d2da314313c0edde93b29d59b3b18be diff --git a/proto/src/prost/cosmos.tx.signing.v1beta1.rs b/proto/src/prost/cosmos.tx.signing.v1beta1.rs index 670f7dbde9..3dae83ec6f 100644 --- a/proto/src/prost/cosmos.tx.signing.v1beta1.rs +++ b/proto/src/prost/cosmos.tx.signing.v1beta1.rs @@ -84,7 +84,7 @@ pub enum SignMode { LegacyAminoJson = 127, /// SIGN_MODE_EIP_191 specifies the sign mode for EIP 191 signing on the Cosmos /// SDK. Ref: - /// + /// /// Currently, SIGN_MODE_EIP_191 is registered as a SignMode enum variant, /// but is not implemented on the SDK by default. To enable EIP-191, you need /// to pass a custom `TxConfig` that has an implementation of diff --git a/proto/src/prost/ibc.applications.fee.v1.rs b/proto/src/prost/ibc.applications.fee.v1.rs index 2f81f47a52..f468c5db0e 100644 --- a/proto/src/prost/ibc.applications.fee.v1.rs +++ b/proto/src/prost/ibc.applications.fee.v1.rs @@ -63,8 +63,8 @@ pub struct MsgRegisterPayee { pub channel_id: ::prost::alloc::string::String, /// the relayer address #[prost(string, tag="3")] - pub relayer_address: ::prost::alloc::string::String, - /// the fee payee address + pub relayer: ::prost::alloc::string::String, + /// the payee address #[prost(string, tag="4")] pub payee: ::prost::alloc::string::String, } @@ -72,25 +72,25 @@ pub struct MsgRegisterPayee { #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgRegisterPayeeResponse { } -/// MsgRegisterCounterpartyAddress defines the request type for the RegisterCounterpartyAddress rpc +/// MsgRegisterCounterpartyPayee defines the request type for the RegisterCounterpartyPayee rpc #[derive(Clone, PartialEq, ::prost::Message)] -pub struct MsgRegisterCounterpartyAddress { - /// the relayer address - #[prost(string, tag="1")] - pub address: ::prost::alloc::string::String, - /// the counterparty relayer address - #[prost(string, tag="2")] - pub counterparty_address: ::prost::alloc::string::String, +pub struct MsgRegisterCounterpartyPayee { /// unique port identifier - #[prost(string, tag="3")] + #[prost(string, tag="1")] pub port_id: ::prost::alloc::string::String, /// unique channel identifier - #[prost(string, tag="4")] + #[prost(string, tag="2")] pub channel_id: ::prost::alloc::string::String, + /// the relayer address + #[prost(string, tag="3")] + pub relayer: ::prost::alloc::string::String, + /// the counterparty payee address + #[prost(string, tag="4")] + pub counterparty_payee: ::prost::alloc::string::String, } -/// MsgRegisterCounterpartyAddressResponse defines the response type for the RegisterCounterpartyAddress rpc +/// MsgRegisterCounterpartyPayeeResponse defines the response type for the RegisterCounterpartyPayee rpc #[derive(Clone, PartialEq, ::prost::Message)] -pub struct MsgRegisterCounterpartyAddressResponse { +pub struct MsgRegisterCounterpartyPayeeResponse { } /// MsgPayPacketFee defines the request type for the PayPacketFee rpc /// This Msg can be used to pay for a packet at the next sequence send & should be combined with the Msg that will be @@ -200,9 +200,9 @@ pub mod msg_client { } /// RegisterPayee defines a rpc handler method for MsgRegisterPayee /// RegisterPayee is called by the relayer on each channelEnd and allows them to set an optional - /// payee to which escrowed packet fees will be paid out. The payee should be registered on the source chain from which - /// packets originate as this is where fee distribution takes place. This function may be called more than once by a - /// relayer, in which case, the latest payee is always used. + /// payee to which reverse and timeout relayer packet fees will be paid out. The payee should be registered on + /// the source chain from which packets originate as this is where fee distribution takes place. This function may be + /// called more than once by a relayer, in which case, the latest payee is always used. pub async fn register_payee( &mut self, request: impl tonic::IntoRequest, @@ -222,16 +222,16 @@ pub mod msg_client { ); self.inner.unary(request.into_request(), path, codec).await } - /// RegisterCounterpartyAddress defines a rpc handler method for MsgRegisterCounterpartyAddress - /// RegisterCounterpartyAddress is called by the relayer on each channelEnd and allows them to specify their - /// counterparty address before relaying. This ensures they will be properly compensated for forward relaying since - /// destination chain must send back relayer's source address (counterparty address) in acknowledgement. This function - /// may be called more than once by a relayer, in which case, the latest counterparty address is always used. - pub async fn register_counterparty_address( + /// RegisterCounterpartyPayee defines a rpc handler method for MsgRegisterCounterpartyPayee + /// RegisterCounterpartyPayee is called by the relayer on each channelEnd and allows them to specify the counterparty + /// payee address before relaying. This ensures they will be properly compensated for forward relaying since + /// the destination chain must include the registered counterparty payee address in the acknowledgement. This function + /// may be called more than once by a relayer, in which case, the latest counterparty payee address is always used. + pub async fn register_counterparty_payee( &mut self, - request: impl tonic::IntoRequest, + request: impl tonic::IntoRequest, ) -> Result< - tonic::Response, + tonic::Response, tonic::Status, > { self.inner @@ -245,7 +245,7 @@ pub mod msg_client { })?; let codec = tonic::codec::ProstCodec::default(); let path = http::uri::PathAndQuery::from_static( - "/ibc.applications.fee.v1.Msg/RegisterCounterpartyAddress", + "/ibc.applications.fee.v1.Msg/RegisterCounterpartyPayee", ); self.inner.unary(request.into_request(), path, codec).await } @@ -310,23 +310,23 @@ pub mod msg_server { pub trait Msg: Send + Sync + 'static { /// RegisterPayee defines a rpc handler method for MsgRegisterPayee /// RegisterPayee is called by the relayer on each channelEnd and allows them to set an optional - /// payee to which escrowed packet fees will be paid out. The payee should be registered on the source chain from which - /// packets originate as this is where fee distribution takes place. This function may be called more than once by a - /// relayer, in which case, the latest payee is always used. + /// payee to which reverse and timeout relayer packet fees will be paid out. The payee should be registered on + /// the source chain from which packets originate as this is where fee distribution takes place. This function may be + /// called more than once by a relayer, in which case, the latest payee is always used. async fn register_payee( &self, request: tonic::Request, ) -> Result, tonic::Status>; - /// RegisterCounterpartyAddress defines a rpc handler method for MsgRegisterCounterpartyAddress - /// RegisterCounterpartyAddress is called by the relayer on each channelEnd and allows them to specify their - /// counterparty address before relaying. This ensures they will be properly compensated for forward relaying since - /// destination chain must send back relayer's source address (counterparty address) in acknowledgement. This function - /// may be called more than once by a relayer, in which case, the latest counterparty address is always used. - async fn register_counterparty_address( + /// RegisterCounterpartyPayee defines a rpc handler method for MsgRegisterCounterpartyPayee + /// RegisterCounterpartyPayee is called by the relayer on each channelEnd and allows them to specify the counterparty + /// payee address before relaying. This ensures they will be properly compensated for forward relaying since + /// the destination chain must include the registered counterparty payee address in the acknowledgement. This function + /// may be called more than once by a relayer, in which case, the latest counterparty payee address is always used. + async fn register_counterparty_payee( &self, - request: tonic::Request, + request: tonic::Request, ) -> Result< - tonic::Response, + tonic::Response, tonic::Status, >; /// PayPacketFee defines a rpc handler method for MsgPayPacketFee @@ -432,27 +432,25 @@ pub mod msg_server { }; Box::pin(fut) } - "/ibc.applications.fee.v1.Msg/RegisterCounterpartyAddress" => { + "/ibc.applications.fee.v1.Msg/RegisterCounterpartyPayee" => { #[allow(non_camel_case_types)] - struct RegisterCounterpartyAddressSvc(pub Arc); + struct RegisterCounterpartyPayeeSvc(pub Arc); impl< T: Msg, - > tonic::server::UnaryService - for RegisterCounterpartyAddressSvc { - type Response = super::MsgRegisterCounterpartyAddressResponse; + > tonic::server::UnaryService + for RegisterCounterpartyPayeeSvc { + type Response = super::MsgRegisterCounterpartyPayeeResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request< - super::MsgRegisterCounterpartyAddress, - >, + request: tonic::Request, ) -> Self::Future { let inner = self.0.clone(); let fut = async move { - (*inner).register_counterparty_address(request).await + (*inner).register_counterparty_payee(request).await }; Box::pin(fut) } @@ -462,7 +460,7 @@ pub mod msg_server { let inner = self.inner.clone(); let fut = async move { let inner = inner.0; - let method = RegisterCounterpartyAddressSvc(inner); + let method = RegisterCounterpartyPayeeSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -601,9 +599,9 @@ pub struct GenesisState { /// list of registered payees #[prost(message, repeated, tag="3")] pub registered_payees: ::prost::alloc::vec::Vec, - /// list of registered relayer addresses + /// list of registered counterparty payees #[prost(message, repeated, tag="4")] - pub registered_relayers: ::prost::alloc::vec::Vec, + pub registered_counterparty_payees: ::prost::alloc::vec::Vec, /// list of forward relayer addresses #[prost(message, repeated, tag="5")] pub forward_relayers: ::prost::alloc::vec::Vec, @@ -621,28 +619,29 @@ pub struct FeeEnabledChannel { /// RegisteredPayee contains the relayer address and payee address for a specific channel #[derive(Clone, PartialEq, ::prost::Message)] pub struct RegisteredPayee { - /// the relayer address + /// unique channel identifier #[prost(string, tag="1")] - pub relayer_address: ::prost::alloc::string::String, - /// the payee address + pub channel_id: ::prost::alloc::string::String, + /// the relayer address #[prost(string, tag="2")] - pub payee: ::prost::alloc::string::String, - /// unique channel identifier + pub relayer: ::prost::alloc::string::String, + /// the payee address #[prost(string, tag="3")] - pub channel_id: ::prost::alloc::string::String, + pub payee: ::prost::alloc::string::String, } -/// RegisteredRelayerAddress contains the address and counterparty address for a specific relayer (for distributing fees) +/// RegisteredCounterpartyPayee contains the relayer address and counterparty payee address for a specific channel (used +/// for recv fee distribution) #[derive(Clone, PartialEq, ::prost::Message)] -pub struct RegisteredRelayerAddress { - /// the relayer address +pub struct RegisteredCounterpartyPayee { + /// unique channel identifier #[prost(string, tag="1")] - pub address: ::prost::alloc::string::String, - /// the counterparty relayer address + pub channel_id: ::prost::alloc::string::String, + /// the relayer address #[prost(string, tag="2")] - pub counterparty_address: ::prost::alloc::string::String, - /// unique channel identifier + pub relayer: ::prost::alloc::string::String, + /// the counterparty payee address #[prost(string, tag="3")] - pub channel_id: ::prost::alloc::string::String, + pub counterparty_payee: ::prost::alloc::string::String, } /// ForwardRelayerAddress contains the forward relayer address and PacketId used for async acknowledgements #[derive(Clone, PartialEq, ::prost::Message)] @@ -760,7 +759,7 @@ pub struct QueryPayeeRequest { pub channel_id: ::prost::alloc::string::String, /// the relayer address to which the distribution address is registered #[prost(string, tag="2")] - pub relayer_address: ::prost::alloc::string::String, + pub relayer: ::prost::alloc::string::String, } /// QueryPayeeResponse defines the response type for the Payee rpc #[derive(Clone, PartialEq, ::prost::Message)] @@ -769,22 +768,22 @@ pub struct QueryPayeeResponse { #[prost(string, tag="1")] pub payee_address: ::prost::alloc::string::String, } -/// QueryCounterpartyAddressRequest defines the request type for the CounterpartyAddress rpc +/// QueryCounterpartyPayeeRequest defines the request type for the CounterpartyPayee rpc #[derive(Clone, PartialEq, ::prost::Message)] -pub struct QueryCounterpartyAddressRequest { +pub struct QueryCounterpartyPayeeRequest { /// unique channel identifier #[prost(string, tag="1")] pub channel_id: ::prost::alloc::string::String, /// the relayer address to which the counterparty is registered #[prost(string, tag="2")] - pub relayer_address: ::prost::alloc::string::String, + pub relayer: ::prost::alloc::string::String, } -/// QueryCounterpartyAddressResponse defines the response type for the CounterpartyAddress rpc +/// QueryCounterpartyPayeeResponse defines the response type for the CounterpartyPayee rpc #[derive(Clone, PartialEq, ::prost::Message)] -pub struct QueryCounterpartyAddressResponse { - /// the counterparty address used to compensate forward relaying +pub struct QueryCounterpartyPayeeResponse { + /// the counterparty payee address used to compensate forward relaying #[prost(string, tag="1")] - pub counterparty_address: ::prost::alloc::string::String, + pub counterparty_payee: ::prost::alloc::string::String, } /// QueryFeeEnabledChannelsRequest defines the request type for the FeeEnabledChannels rpc #[derive(Clone, PartialEq, ::prost::Message)] @@ -1040,12 +1039,12 @@ pub mod query_client { ); self.inner.unary(request.into_request(), path, codec).await } - /// CounterpartyAddress returns the registered counterparty address for forward relaying - pub async fn counterparty_address( + /// CounterpartyPayee returns the registered counterparty payee for forward relaying + pub async fn counterparty_payee( &mut self, - request: impl tonic::IntoRequest, + request: impl tonic::IntoRequest, ) -> Result< - tonic::Response, + tonic::Response, tonic::Status, > { self.inner @@ -1059,7 +1058,7 @@ pub mod query_client { })?; let codec = tonic::codec::ProstCodec::default(); let path = http::uri::PathAndQuery::from_static( - "/ibc.applications.fee.v1.Query/CounterpartyAddress", + "/ibc.applications.fee.v1.Query/CounterpartyPayee", ); self.inner.unary(request.into_request(), path, codec).await } @@ -1166,12 +1165,12 @@ pub mod query_server { &self, request: tonic::Request, ) -> Result, tonic::Status>; - /// CounterpartyAddress returns the registered counterparty address for forward relaying - async fn counterparty_address( + /// CounterpartyPayee returns the registered counterparty payee for forward relaying + async fn counterparty_payee( &self, - request: tonic::Request, + request: tonic::Request, ) -> Result< - tonic::Response, + tonic::Response, tonic::Status, >; /// FeeEnabledChannels returns a list of all fee enabled channels @@ -1522,27 +1521,25 @@ pub mod query_server { }; Box::pin(fut) } - "/ibc.applications.fee.v1.Query/CounterpartyAddress" => { + "/ibc.applications.fee.v1.Query/CounterpartyPayee" => { #[allow(non_camel_case_types)] - struct CounterpartyAddressSvc(pub Arc); + struct CounterpartyPayeeSvc(pub Arc); impl< T: Query, - > tonic::server::UnaryService - for CounterpartyAddressSvc { - type Response = super::QueryCounterpartyAddressResponse; + > tonic::server::UnaryService + for CounterpartyPayeeSvc { + type Response = super::QueryCounterpartyPayeeResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request< - super::QueryCounterpartyAddressRequest, - >, + request: tonic::Request, ) -> Self::Future { let inner = self.0.clone(); let fut = async move { - (*inner).counterparty_address(request).await + (*inner).counterparty_payee(request).await }; Box::pin(fut) } @@ -1552,7 +1549,7 @@ pub mod query_server { let inner = self.inner.clone(); let fut = async move { let inner = inner.0; - let method = CounterpartyAddressSvc(inner); + let method = CounterpartyPayeeSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( From 14095c4096f36f3b6c6b14382cec8b456a1d6fa8 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Thu, 16 Jun 2022 10:36:47 +0200 Subject: [PATCH 066/113] Update CounterpartyAddress to CounterpartyPayee --- flake.lock | 18 +++++++------- .../ics29_fee/msgs/register_counterparty.rs | 14 +++++------ relayer/src/chain/cosmos.rs | 10 ++++---- relayer/src/chain/cosmos/fee.rs | 22 ++++++++--------- relayer/src/chain/cosmos/query/fee.rs | 14 +++++------ relayer/src/chain/endpoint.rs | 4 ++-- relayer/src/chain/handle.rs | 8 +++---- relayer/src/chain/handle/base.rs | 8 +++---- relayer/src/chain/handle/cache.rs | 6 ++--- relayer/src/chain/handle/counting.rs | 6 ++--- relayer/src/chain/mock.rs | 4 ++-- relayer/src/chain/runtime.rs | 16 ++++++------- relayer/src/config.rs | 10 ++++---- relayer/src/link.rs | 10 ++++---- relayer/src/worker.rs | 2 +- tools/integration-test/src/tests/fee.rs | 24 +++++++++---------- tools/test-framework/src/chain/ext/fee.rs | 22 ++++++++--------- tools/test-framework/src/relayer/chain.rs | 6 ++--- tools/test-framework/src/relayer/fee.rs | 18 +++++++------- 19 files changed, 110 insertions(+), 112 deletions(-) diff --git a/flake.lock b/flake.lock index 6f52bdc6f0..3f0d2a4821 100644 --- a/flake.lock +++ b/flake.lock @@ -75,11 +75,11 @@ "wasmvm_1_beta7-src": "wasmvm_1_beta7-src" }, "locked": { - "lastModified": 1655147330, - "narHash": "sha256-PNy+y8hZ+ZY9ZNo3qOb6GcHU/Luc5o3otkoAVOVyOPA=", + "lastModified": 1655296674, + "narHash": "sha256-yUROp+8agaaf6N5p0NB5dyDt3v3clp8maU1yQA16Hc4=", "owner": "informalsystems", "repo": "cosmos.nix", - "rev": "1500718c3e51ab66cf9694d73d596b64199f8635", + "rev": "da3a0758136fe7152203c689a3cea91547b070c9", "type": "github" }, "original": { @@ -273,11 +273,11 @@ "ibc-go-main-src": { "flake": false, "locked": { - "lastModified": 1655117979, - "narHash": "sha256-9Ic4Rv2xco+5dzRDJ4wvq8AFnzIPfl5MAZaBWW9JjbE=", + "lastModified": 1655287744, + "narHash": "sha256-7HuNg2h2I2mYO/dql1P4aHfuFn/WlqhlA3kQ4upqKrw=", "owner": "cosmos", "repo": "ibc-go", - "rev": "11297aaa61e651c16e6d4147a15be24ce55ba7cc", + "rev": "a71fc1029ad1fc6d377d642781d02ad3cbfa0910", "type": "github" }, "original": { @@ -438,11 +438,11 @@ }, "nixpkgs_3": { "locked": { - "lastModified": 1655122334, - "narHash": "sha256-Rwwvo9TDCH0a4m/Jvoq5wZ3FLSLiVLBD1FFfN/3XawA=", + "lastModified": 1655332021, + "narHash": "sha256-LZcCR0/4oQUrmmyBBGdGcMYz0fJA0pdhb4PLaPvjrq0=", "owner": "nixos", "repo": "nixpkgs", - "rev": "e1a1cfb56504d1b82a3953bfb0632b37a1ca8d30", + "rev": "f649383c5a34f3599f1142f0756535dceed2eb31", "type": "github" }, "original": { diff --git a/modules/src/applications/ics29_fee/msgs/register_counterparty.rs b/modules/src/applications/ics29_fee/msgs/register_counterparty.rs index afcf082f92..fba9d6dda2 100644 --- a/modules/src/applications/ics29_fee/msgs/register_counterparty.rs +++ b/modules/src/applications/ics29_fee/msgs/register_counterparty.rs @@ -1,5 +1,5 @@ use ibc_proto::google::protobuf::Any; -use ibc_proto::ibc::applications::fee::v1::MsgRegisterCounterpartyAddress; +use ibc_proto::ibc::applications::fee::v1::MsgRegisterCounterpartyPayee; use crate::applications::ics29_fee::error::Error; use crate::core::ics24_host::identifier::{ChannelId, PortId}; @@ -7,17 +7,17 @@ use crate::prelude::*; use crate::signer::Signer; use crate::tx_msg::encode_message; -const TYPE_URL: &str = "/ibc.applications.fee.v1.MsgRegisterCounterpartyAddress"; +const TYPE_URL: &str = "/ibc.applications.fee.v1.MsgRegisterCounterpartyPayee"; -pub fn build_register_counterparty_address_message( +pub fn build_register_counterparty_payee_message( address: &Signer, - counterparty_address: &Signer, + counterparty_payee: &Signer, channel_id: &ChannelId, port_id: &PortId, ) -> Result { - let message = MsgRegisterCounterpartyAddress { - address: address.to_string(), - counterparty_address: counterparty_address.to_string(), + let message = MsgRegisterCounterpartyPayee { + relayer: address.to_string(), + counterparty_payee: counterparty_payee.to_string(), channel_id: channel_id.to_string(), port_id: port_id.to_string(), }; diff --git a/relayer/src/chain/cosmos.rs b/relayer/src/chain/cosmos.rs index 5cd2ff0dc7..e6e085b79a 100644 --- a/relayer/src/chain/cosmos.rs +++ b/relayer/src/chain/cosmos.rs @@ -60,7 +60,7 @@ use crate::chain::cosmos::batch::{ send_batched_messages_and_wait_check_tx, send_batched_messages_and_wait_commit, }; use crate::chain::cosmos::encode::encode_to_bech32; -use crate::chain::cosmos::fee::maybe_register_counterparty_address; +use crate::chain::cosmos::fee::maybe_register_counterparty_payee; use crate::chain::cosmos::gas::{calculate_fee, mul_ceil}; use crate::chain::cosmos::query::account::get_or_fetch_account; use crate::chain::cosmos::query::balance::query_balance; @@ -1570,16 +1570,16 @@ impl ChainEndpoint for CosmosSdkChain { Ok((target, supporting)) } - fn maybe_register_counterparty_address( + fn maybe_register_counterparty_payee( &mut self, channel_id: &ChannelId, port_id: &PortId, - counterparty_address: &Signer, + counterparty_payee: &Signer, ) -> Result<(), Error> { let address = self.get_signer()?; let key_entry = self.key()?; - self.rt.block_on(maybe_register_counterparty_address( + self.rt.block_on(maybe_register_counterparty_payee( &self.tx_config, &key_entry, &mut self.account, @@ -1587,7 +1587,7 @@ impl ChainEndpoint for CosmosSdkChain { channel_id, port_id, &address, - counterparty_address, + counterparty_payee, )) } } diff --git a/relayer/src/chain/cosmos/fee.rs b/relayer/src/chain/cosmos/fee.rs index 2cf2e098d6..6647d0761f 100644 --- a/relayer/src/chain/cosmos/fee.rs +++ b/relayer/src/chain/cosmos/fee.rs @@ -1,9 +1,9 @@ -use ibc::applications::ics29_fee::msgs::register_counterparty::build_register_counterparty_address_message; +use ibc::applications::ics29_fee::msgs::register_counterparty::build_register_counterparty_payee_message; use ibc::core::ics24_host::identifier::{ChannelId, PortId}; use ibc::signer::Signer; use crate::chain::cosmos::query::account::get_or_fetch_account; -use crate::chain::cosmos::query::fee::query_counterparty_address; +use crate::chain::cosmos::query::fee::query_counterparty_payee; 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; @@ -12,7 +12,7 @@ use crate::config::types::Memo; use crate::error::Error; use crate::keyring::KeyEntry; -pub async fn maybe_register_counterparty_address( +pub async fn maybe_register_counterparty_payee( tx_config: &TxConfig, key_entry: &KeyEntry, m_account: &mut Option, @@ -20,24 +20,24 @@ pub async fn maybe_register_counterparty_address( channel_id: &ChannelId, port_id: &PortId, address: &Signer, - counterparty_address: &Signer, + counterparty_payee: &Signer, ) -> Result<(), Error> { let account = get_or_fetch_account(&tx_config.grpc_address, &key_entry.account, m_account).await?; - let current_counterparty_address = - query_counterparty_address(&tx_config.grpc_address, channel_id, address).await?; + let current_counterparty_payee = + query_counterparty_payee(&tx_config.grpc_address, channel_id, address).await?; - match ¤t_counterparty_address { - Some(current_counterparty_address) - if current_counterparty_address == counterparty_address.as_ref() => + match ¤t_counterparty_payee { + Some(current_counterparty_payee) + if current_counterparty_payee == counterparty_payee.as_ref() => { Ok(()) } _ => { - let message = build_register_counterparty_address_message( + let message = build_register_counterparty_payee_message( address, - counterparty_address, + counterparty_payee, channel_id, port_id, ) diff --git a/relayer/src/chain/cosmos/query/fee.rs b/relayer/src/chain/cosmos/query/fee.rs index 3f1bf8cdc5..75855fc9a4 100644 --- a/relayer/src/chain/cosmos/query/fee.rs +++ b/relayer/src/chain/cosmos/query/fee.rs @@ -4,13 +4,13 @@ use ibc::core::ics24_host::identifier::{ChannelId, PortId}; use ibc::signer::Signer; use ibc_proto::ibc::applications::fee::v1::query_client::QueryClient; use ibc_proto::ibc::applications::fee::v1::{ - QueryCounterpartyAddressRequest, QueryIncentivizedPacketsForChannelRequest, + QueryCounterpartyPayeeRequest, QueryIncentivizedPacketsForChannelRequest, }; use tonic::Code; use crate::error::Error; -pub async fn query_counterparty_address( +pub async fn query_counterparty_payee( grpc_address: &Uri, channel_id: &ChannelId, address: &Signer, @@ -19,18 +19,18 @@ pub async fn query_counterparty_address( .await .map_err(Error::grpc_transport)?; - let request = QueryCounterpartyAddressRequest { + let request = QueryCounterpartyPayeeRequest { channel_id: channel_id.to_string(), - relayer_address: address.to_string(), + relayer: address.to_string(), }; - let result = client.counterparty_address(request).await; + let result = client.counterparty_payee(request).await; match result { Ok(response) => { - let counterparty_address = response.into_inner().counterparty_address; + let counterparty_payee = response.into_inner().counterparty_payee; - Ok(Some(counterparty_address)) + Ok(Some(counterparty_payee)) } Err(e) => { if e.code() == Code::NotFound { diff --git a/relayer/src/chain/endpoint.rs b/relayer/src/chain/endpoint.rs index 1378ef88c0..0728667021 100644 --- a/relayer/src/chain/endpoint.rs +++ b/relayer/src/chain/endpoint.rs @@ -576,10 +576,10 @@ pub trait ChainEndpoint: Sized { Ok(proofs) } - fn maybe_register_counterparty_address( + fn maybe_register_counterparty_payee( &mut self, channel_id: &ChannelId, port_id: &PortId, - counterparty_address: &Signer, + counterparty_payee: &Signer, ) -> Result<(), Error>; } diff --git a/relayer/src/chain/handle.rs b/relayer/src/chain/handle.rs index 319ab03fde..54ab89d0a8 100644 --- a/relayer/src/chain/handle.rs +++ b/relayer/src/chain/handle.rs @@ -346,10 +346,10 @@ pub enum ChainRequest { reply_to: ReplyTo, }, - MaybeRegisterCounterpartyAddress { + MaybeRegisterCounterpartyPayee { channel_id: ChannelId, port_id: PortId, - counterparty_address: Signer, + counterparty_payee: Signer, reply_to: ReplyTo<()>, }, } @@ -637,10 +637,10 @@ pub trait ChainHandle: Clone + Send + Sync + Serialize + Debug + 'static { request: QueryHostConsensusStateRequest, ) -> Result; - fn maybe_register_counterparty_address( + fn maybe_register_counterparty_payee( &self, channel_id: ChannelId, port_id: PortId, - counterparty_address: Signer, + counterparty_payee: Signer, ) -> Result<(), Error>; } diff --git a/relayer/src/chain/handle/base.rs b/relayer/src/chain/handle/base.rs index 85013d06a8..e5136286e5 100644 --- a/relayer/src/chain/handle/base.rs +++ b/relayer/src/chain/handle/base.rs @@ -473,16 +473,16 @@ impl ChainHandle for BaseChainHandle { self.send(|reply_to| ChainRequest::QueryHostConsensusState { request, reply_to }) } - fn maybe_register_counterparty_address( + fn maybe_register_counterparty_payee( &self, channel_id: ChannelId, port_id: PortId, - counterparty_address: Signer, + counterparty_payee: Signer, ) -> Result<(), Error> { - self.send(|reply_to| ChainRequest::MaybeRegisterCounterpartyAddress { + self.send(|reply_to| ChainRequest::MaybeRegisterCounterpartyPayee { channel_id, port_id, - counterparty_address, + counterparty_payee, reply_to, }) } diff --git a/relayer/src/chain/handle/cache.rs b/relayer/src/chain/handle/cache.rs index 0451b97228..f0ce0dab53 100644 --- a/relayer/src/chain/handle/cache.rs +++ b/relayer/src/chain/handle/cache.rs @@ -482,13 +482,13 @@ impl ChainHandle for CachingChainHandle { self.inner.query_host_consensus_state(request) } - fn maybe_register_counterparty_address( + fn maybe_register_counterparty_payee( &self, channel_id: ChannelId, port_id: PortId, - counterparty_address: Signer, + counterparty_payee: Signer, ) -> Result<(), Error> { self.inner - .maybe_register_counterparty_address(channel_id, port_id, counterparty_address) + .maybe_register_counterparty_payee(channel_id, port_id, counterparty_payee) } } diff --git a/relayer/src/chain/handle/counting.rs b/relayer/src/chain/handle/counting.rs index 50a3a846c0..daa6da9b4a 100644 --- a/relayer/src/chain/handle/counting.rs +++ b/relayer/src/chain/handle/counting.rs @@ -466,13 +466,13 @@ impl ChainHandle for CountingChainHandle { self.inner.query_host_consensus_state(request) } - fn maybe_register_counterparty_address( + fn maybe_register_counterparty_payee( &self, channel_id: ChannelId, port_id: PortId, - counterparty_address: Signer, + counterparty_payee: Signer, ) -> Result<(), Error> { self.inner - .maybe_register_counterparty_address(channel_id, port_id, counterparty_address) + .maybe_register_counterparty_payee(channel_id, port_id, counterparty_payee) } } diff --git a/relayer/src/chain/mock.rs b/relayer/src/chain/mock.rs index 7859d1e3a4..224f156d66 100644 --- a/relayer/src/chain/mock.rs +++ b/relayer/src/chain/mock.rs @@ -437,11 +437,11 @@ impl ChainEndpoint for MockChain { unimplemented!() } - fn maybe_register_counterparty_address( + fn maybe_register_counterparty_payee( &mut self, _channel_id: &ChannelId, _port_id: &PortId, - _counterparty_address: &Signer, + _counterparty_payee: &Signer, ) -> Result<(), Error> { unimplemented!() } diff --git a/relayer/src/chain/runtime.rs b/relayer/src/chain/runtime.rs index e4c02d8de9..d57ab39eb6 100644 --- a/relayer/src/chain/runtime.rs +++ b/relayer/src/chain/runtime.rs @@ -419,8 +419,8 @@ where self.query_host_consensus_state(request, reply_to)? }, - Ok(ChainRequest::MaybeRegisterCounterpartyAddress { channel_id, port_id, counterparty_address, reply_to }) => { - self.maybe_register_counterparty_address(&channel_id, &port_id, &counterparty_address, reply_to)? + Ok(ChainRequest::MaybeRegisterCounterpartyPayee { channel_id, port_id, counterparty_payee, reply_to }) => { + self.maybe_register_counterparty_payee(&channel_id, &port_id, &counterparty_payee, reply_to)? } Err(e) => error!("received error via chain request channel: {}", e), @@ -899,18 +899,16 @@ where Ok(()) } - fn maybe_register_counterparty_address( + fn maybe_register_counterparty_payee( &mut self, channel_id: &ChannelId, port_id: &PortId, - counterparty_address: &Signer, + counterparty_payee: &Signer, reply_to: ReplyTo<()>, ) -> Result<(), Error> { - let result = self.chain.maybe_register_counterparty_address( - channel_id, - port_id, - counterparty_address, - ); + let result = + self.chain + .maybe_register_counterparty_payee(channel_id, port_id, counterparty_payee); reply_to.send(result).map_err(Error::send)?; diff --git a/relayer/src/config.rs b/relayer/src/config.rs index dc9eafdc67..1c75a41feb 100644 --- a/relayer/src/config.rs +++ b/relayer/src/config.rs @@ -74,7 +74,7 @@ pub mod default { ZERO_DURATION } - pub fn auto_register_counterparty_address() -> bool { + pub fn auto_register_counterparty_payee() -> bool { false } } @@ -160,7 +160,7 @@ impl Default for ModeConfig { clear_interval: default::clear_packets_interval(), clear_on_start: true, tx_confirmation: true, - auto_register_counterparty_address: default::auto_register_counterparty_address(), + auto_register_counterparty_payee: default::auto_register_counterparty_payee(), }, } } @@ -198,8 +198,8 @@ pub struct Packets { pub clear_on_start: bool, #[serde(default = "default::tx_confirmation")] pub tx_confirmation: bool, - #[serde(default = "default::auto_register_counterparty_address")] - pub auto_register_counterparty_address: bool, + #[serde(default = "default::auto_register_counterparty_payee")] + pub auto_register_counterparty_payee: bool, } impl Default for Packets { @@ -209,7 +209,7 @@ impl Default for Packets { clear_interval: default::clear_packets_interval(), clear_on_start: false, tx_confirmation: default::tx_confirmation(), - auto_register_counterparty_address: default::auto_register_counterparty_address(), + auto_register_counterparty_payee: default::auto_register_counterparty_payee(), } } } diff --git a/relayer/src/link.rs b/relayer/src/link.rs index 243240d0a6..71ed619c70 100644 --- a/relayer/src/link.rs +++ b/relayer/src/link.rs @@ -56,7 +56,7 @@ impl Link { b_chain: ChainB, opts: LinkParameters, with_tx_confirmation: bool, - auto_register_counterparty_address: bool, + auto_register_counterparty_payee: bool, ) -> Result, LinkError> { // Check that the packet's channel on source chain is Open let a_channel_id = &opts.src_channel_id; @@ -145,11 +145,11 @@ impl Link { connection_delay: a_connection.delay_period(), }; - if auto_register_counterparty_address && a_channel.version.supports_fee() { + if auto_register_counterparty_payee && a_channel.version.supports_fee() { let address_a = a_chain.get_signer().map_err(LinkError::relayer)?; b_chain - .maybe_register_counterparty_address(b_channel_id, b_port_id, address_a) + .maybe_register_counterparty_payee(b_channel_id, b_port_id, address_a) .map_err(LinkError::relayer)?; } @@ -161,7 +161,7 @@ impl Link { pub fn reverse( &self, with_tx_confirmation: bool, - auto_register_counterparty_address: bool, + auto_register_counterparty_payee: bool, ) -> Result, LinkError> { let opts = LinkParameters { src_port_id: self.a_to_b.dst_port_id().clone(), @@ -177,7 +177,7 @@ impl Link { chain_a, opts, with_tx_confirmation, - auto_register_counterparty_address, + auto_register_counterparty_payee, ) } } diff --git a/relayer/src/worker.rs b/relayer/src/worker.rs index d10c90c234..00dd504933 100644 --- a/relayer/src/worker.rs +++ b/relayer/src/worker.rs @@ -118,7 +118,7 @@ pub fn spawn_worker_tasks( src_channel_id: path.src_channel_id, }, packets_config.tx_confirmation, - packets_config.auto_register_counterparty_address, + packets_config.auto_register_counterparty_payee, ); match link_res { diff --git a/tools/integration-test/src/tests/fee.rs b/tools/integration-test/src/tests/fee.rs index f810fef06f..d4d89ce0f7 100644 --- a/tools/integration-test/src/tests/fee.rs +++ b/tools/integration-test/src/tests/fee.rs @@ -49,7 +49,7 @@ impl TestOverrides for ForwardRelayerTest { impl TestOverrides for AutoForwardRelayerTest { fn modify_relayer_config(&self, config: &mut Config) { - config.mode.packets.auto_register_counterparty_address = true; + config.mode.packets.auto_register_counterparty_payee = true; } fn channel_version(&self) -> Version { @@ -59,7 +59,7 @@ impl TestOverrides for AutoForwardRelayerTest { impl TestOverrides for NoForwardRelayerTest { fn modify_relayer_config(&self, config: &mut Config) { - config.mode.packets.auto_register_counterparty_address = false; + config.mode.packets.auto_register_counterparty_payee = false; } fn channel_version(&self) -> Version { @@ -89,7 +89,7 @@ impl TestOverrides for PayPacketFeeAsyncTest { impl TestOverrides for NonFeeChannelTest { fn modify_relayer_config(&self, config: &mut Config) { - config.mode.packets.auto_register_counterparty_address = true; + config.mode.packets.auto_register_counterparty_payee = true; } } @@ -228,17 +228,17 @@ impl BinaryChannelTest for ForwardRelayerTest { ); { - let counterparty_address = - chain_driver_b.query_counterparty_address(&channel_id_b, &relayer_b.address())?; + let counterparty_payee = + chain_driver_b.query_counterparty_payee(&channel_id_b, &relayer_b.address())?; assert_eq( "counterparty address should be None before registering", - &counterparty_address, + &counterparty_payee, &None, )?; } - chain_driver_b.register_counterparty_address( + chain_driver_b.register_counterparty_payee( &relayer_b, &relayer_a.address(), &channel_id_b, @@ -246,12 +246,12 @@ impl BinaryChannelTest for ForwardRelayerTest { )?; { - let counterparty_address = - chain_driver_b.query_counterparty_address(&channel_id_b, &relayer_b.address())?; + let counterparty_payee = + chain_driver_b.query_counterparty_payee(&channel_id_b, &relayer_b.address())?; assert_eq( "counterparty address should match registered address", - &counterparty_address, + &counterparty_payee, &Some(relayer_a.address().cloned()), )?; } @@ -498,7 +498,7 @@ impl BinaryChannelTest for PayPacketFeeAsyncTest { chain_id_a ); - chain_driver_b.register_counterparty_address( + chain_driver_b.register_counterparty_payee( &relayer_b, &relayer_a.address(), &channel_id_b, @@ -661,7 +661,7 @@ impl BinaryChannelTest for NonFeeChannelTest { let send_amount = random_u128_range(1000, 2000); { - let res = chain_driver_b.register_counterparty_address( + let res = chain_driver_b.register_counterparty_payee( &relayer_b, &relayer_a.address(), &channel_id_b, diff --git a/tools/test-framework/src/chain/ext/fee.rs b/tools/test-framework/src/chain/ext/fee.rs index 14c449c23c..02c3fb5d86 100644 --- a/tools/test-framework/src/chain/ext/fee.rs +++ b/tools/test-framework/src/chain/ext/fee.rs @@ -8,8 +8,8 @@ use crate::chain::tagged::TaggedChainDriverExt; use crate::error::Error; use crate::ibc::token::TaggedTokenRef; use crate::relayer::fee::{ - ibc_token_transfer_with_fee, pay_packet_fee, query_counterparty_address, - query_incentivized_packets, register_counterparty_address, + ibc_token_transfer_with_fee, pay_packet_fee, query_counterparty_payee, + query_incentivized_packets, register_counterparty_payee, }; use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef}; use crate::types::tagged::*; @@ -40,15 +40,15 @@ pub trait ChainFeeMethodsExt { timeout_fee: &TaggedTokenRef<'_, Chain>, ) -> Result<(), Error>; - fn register_counterparty_address( + fn register_counterparty_payee( &self, wallet: &MonoTagged, - counterparty_address: &MonoTagged, + counterparty_payee: &MonoTagged, channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, ) -> Result<(), Error>; - fn query_counterparty_address( + fn query_counterparty_payee( &self, channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, address: &MonoTagged, @@ -110,28 +110,28 @@ impl<'a, Chain: Send> ChainFeeMethodsExt for MonoTagged( + fn register_counterparty_payee( &self, wallet: &MonoTagged, - counterparty_address: &MonoTagged, + counterparty_payee: &MonoTagged, channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, ) -> Result<(), Error> { - self.value().runtime.block_on(register_counterparty_address( + self.value().runtime.block_on(register_counterparty_payee( &self.tx_config(), wallet, - counterparty_address, + counterparty_payee, channel_id, port_id, )) } - fn query_counterparty_address( + fn query_counterparty_payee( &self, channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, address: &MonoTagged, ) -> Result>, Error> { - self.value().runtime.block_on(query_counterparty_address( + self.value().runtime.block_on(query_counterparty_payee( &self.tx_config().value().grpc_address, channel_id, address, diff --git a/tools/test-framework/src/relayer/chain.rs b/tools/test-framework/src/relayer/chain.rs index 8f50fef36d..5f9a817d80 100644 --- a/tools/test-framework/src/relayer/chain.rs +++ b/tools/test-framework/src/relayer/chain.rs @@ -402,13 +402,13 @@ where self.value().query_balance(key_name) } - fn maybe_register_counterparty_address( + fn maybe_register_counterparty_payee( &self, channel_id: ChannelId, port_id: PortId, - counterparty_address: Signer, + counterparty_payee: Signer, ) -> Result<(), Error> { self.value() - .maybe_register_counterparty_address(channel_id, port_id, counterparty_address) + .maybe_register_counterparty_payee(channel_id, port_id, counterparty_payee) } } diff --git a/tools/test-framework/src/relayer/fee.rs b/tools/test-framework/src/relayer/fee.rs index f397f478e8..873693c834 100644 --- a/tools/test-framework/src/relayer/fee.rs +++ b/tools/test-framework/src/relayer/fee.rs @@ -2,12 +2,12 @@ use core::time::Duration; use http::uri::Uri; use ibc::applications::ics29_fee::msgs::pay_packet::build_pay_packet_message; use ibc::applications::ics29_fee::msgs::pay_packet_async::build_pay_packet_fee_async_message; -use ibc::applications::ics29_fee::msgs::register_counterparty::build_register_counterparty_address_message; +use ibc::applications::ics29_fee::msgs::register_counterparty::build_register_counterparty_payee_message; use ibc::applications::ics29_fee::packet_fee::IdentifiedPacketFees; use ibc::core::ics04_channel::packet::Sequence; use ibc::events::IbcEvent; use ibc_relayer::chain::cosmos::query::fee::{ - query_counterparty_address as raw_query_counterparty_address, + query_counterparty_payee as raw_query_counterparty_payee, query_incentivized_packets as raw_query_incentivized_packets, }; use ibc_relayer::chain::cosmos::types::config::TxConfig; @@ -88,21 +88,21 @@ pub async fn pay_packet_fee( Ok(()) } -pub async fn register_counterparty_address( +pub async fn register_counterparty_payee( tx_config: &MonoTagged, wallet: &MonoTagged, - counterparty_address: &MonoTagged, + counterparty_payee: &MonoTagged, channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, ) -> Result<(), Error> { - let message = build_register_counterparty_address_message( + let message = build_register_counterparty_payee_message( &wallet .value() .address .0 .parse() .map_err(handle_generic_error)?, - &counterparty_address + &counterparty_payee .value() .0 .parse() @@ -119,12 +119,12 @@ pub async fn register_counterparty_address( Ok(()) } -pub async fn query_counterparty_address( +pub async fn query_counterparty_payee( grpc_address: &Uri, channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, address: &MonoTagged, ) -> Result>, Error> { - let counterparty_address = raw_query_counterparty_address( + let counterparty_payee = raw_query_counterparty_payee( grpc_address, channel_id.value(), &address.value().0.parse().map_err(handle_generic_error)?, @@ -132,7 +132,7 @@ pub async fn query_counterparty_address( .await .map_err(handle_generic_error)?; - Ok(counterparty_address.map(|address| MonoTagged::new(WalletAddress(address)))) + Ok(counterparty_payee.map(|address| MonoTagged::new(WalletAddress(address)))) } pub async fn query_incentivized_packets( From e54e0ec5680d76c909427e43633ab275cfd6372d Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Thu, 16 Jun 2022 12:16:41 +0200 Subject: [PATCH 067/113] Add IncentivizedPacket event to IbcEvent --- Cargo.lock | 1 + modules/Cargo.toml | 1 + modules/src/applications/ics29_fee/events.rs | 65 +++++++++++++++++--- modules/src/events.rs | 7 +++ 4 files changed, 64 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 811f7fb1bc..a4c857a229 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1478,6 +1478,7 @@ dependencies = [ "flex-error", "ibc-proto", "ics23", + "itertools", "modelator 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits", "primitive-types", diff --git a/modules/Cargo.toml b/modules/Cargo.toml index 8f79a8538f..bd12a2c2e4 100644 --- a/modules/Cargo.toml +++ b/modules/Cargo.toml @@ -45,6 +45,7 @@ num-traits = { version = "0.2.15", default-features = false } derive_more = { version = "0.99.17", default-features = false, features = ["from", "into", "display"] } uint = { version = "0.9", default-features = false } primitive-types = { version = "0.11.1", default-features = false, features = ["serde_no_std"] } +itertools = { version = "0.10.3", default-features = false } [dependencies.tendermint] version = "=0.23.7" diff --git a/modules/src/applications/ics29_fee/events.rs b/modules/src/applications/ics29_fee/events.rs index b0a59874cf..dbb9a61d7c 100644 --- a/modules/src/applications/ics29_fee/events.rs +++ b/modules/src/applications/ics29_fee/events.rs @@ -1,13 +1,18 @@ use core::str::FromStr; +use itertools::Itertools; +use serde_derive::{Deserialize, Serialize}; use tendermint::abci::tag::Tag; +use tendermint::abci::Event as AbciEvent; use super::error::Error; use crate::applications::transfer::coin::RawCoin; use crate::core::ics04_channel::packet::Sequence; use crate::core::ics24_host::identifier::{ChannelId, PortId}; +use crate::events::{IbcEvent, IbcEventType}; use crate::prelude::*; -pub struct IncentivizedPacketEvent { +#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] +pub struct IncentivizedPacket { pub port_id: PortId, pub channel_id: ChannelId, pub sequence: Sequence, @@ -16,6 +21,21 @@ pub struct IncentivizedPacketEvent { pub total_timeout_fee: Vec, } +pub fn try_from_tx(event: &AbciEvent) -> Option { + event + .type_str + .parse::() + .ok() + .and_then(|event_type| { + if let IbcEventType::IncentivizedPacket = event_type { + let event = IncentivizedPacket::try_from(&event.attributes).ok()?; + Some(IbcEvent::IncentivizedPacket(event)) + } else { + None + } + }) +} + fn find_value(key: &str, entries: &[Tag]) -> Result { entries .iter() @@ -29,16 +49,41 @@ fn find_value(key: &str, entries: &[Tag]) -> Result { .ok_or_else(|| Error::event_attribute_not_found(key.to_string())) } -impl TryFrom> for IncentivizedPacketEvent { +fn new_tag(key: &str, value: &str) -> Tag { + Tag { + key: key.parse().unwrap(), + value: value.parse().unwrap(), + } +} + +impl From for AbciEvent { + fn from(event: IncentivizedPacket) -> AbciEvent { + let attributes: Vec = vec![ + new_tag("port_id", event.port_id.as_str()), + new_tag("channel_id", &event.channel_id.to_string()), + new_tag("packet_sequence", &event.sequence.to_string()), + new_tag("recv_fee", &event.total_recv_fee.iter().join(",")), + new_tag("ack_fee", &event.total_ack_fee.iter().join(",")), + new_tag("timeout_fee", &event.total_timeout_fee.iter().join(",")), + ]; + + AbciEvent { + type_str: IbcEventType::IncentivizedPacket.as_str().to_string(), + attributes, + } + } +} + +impl<'a> TryFrom<&'a Vec> for IncentivizedPacket { type Error = Error; - fn try_from(entries: Vec) -> Result { - let port_id_str = find_value("port_id", &entries)?; - let channel_id_str = find_value("channel_id", &entries)?; - let sequence_str = find_value("packet_sequence", &entries)?; - let recv_fee_str = find_value("recv_fee", &entries)?; - let ack_fee_str = find_value("ack_fee", &entries)?; - let timeout_fee_str = find_value("timeout_fee", &entries)?; + fn try_from(entries: &'a Vec) -> Result { + let port_id_str = find_value("port_id", entries)?; + let channel_id_str = find_value("channel_id", entries)?; + let sequence_str = find_value("packet_sequence", entries)?; + let recv_fee_str = find_value("recv_fee", entries)?; + let ack_fee_str = find_value("ack_fee", entries)?; + let timeout_fee_str = find_value("timeout_fee", entries)?; let port_id = PortId::from_str(&port_id_str).map_err(Error::ics24)?; @@ -53,7 +98,7 @@ impl TryFrom> for IncentivizedPacketEvent { let total_timeout_fee = RawCoin::from_string_list(&timeout_fee_str).map_err(Error::transfer)?; - Ok(IncentivizedPacketEvent { + Ok(IncentivizedPacket { port_id, channel_id, sequence, diff --git a/modules/src/events.rs b/modules/src/events.rs index 18ce2c3c33..f9206686da 100644 --- a/modules/src/events.rs +++ b/modules/src/events.rs @@ -9,6 +9,7 @@ use serde_derive::{Deserialize, Serialize}; use tendermint::abci::tag::Tag; use tendermint::abci::Event as AbciEvent; +use crate::applications::ics29_fee::events::IncentivizedPacket; use crate::core::ics02_client::error as client_error; use crate::core::ics02_client::events as ClientEvents; use crate::core::ics02_client::events::NewBlock; @@ -248,6 +249,8 @@ pub enum IbcEvent { TimeoutPacket(ChannelEvents::TimeoutPacket), TimeoutOnClosePacket(ChannelEvents::TimeoutOnClosePacket), + IncentivizedPacket(IncentivizedPacket), + AppModule(ModuleEvent), Empty(String), // Special event, signifying empty response @@ -301,6 +304,8 @@ impl fmt::Display for IbcEvent { IbcEvent::TimeoutPacket(ev) => write!(f, "TimeoutPacketEv({})", ev), IbcEvent::TimeoutOnClosePacket(ev) => write!(f, "TimeoutOnClosePacketEv({})", ev), + IbcEvent::IncentivizedPacket(ev) => write!(f, "IncenvitizedPacket({:?}", ev), + IbcEvent::AppModule(ev) => write!(f, "AppModuleEv({:?})", ev), IbcEvent::Empty(ev) => write!(f, "EmptyEv({})", ev), @@ -334,6 +339,7 @@ impl TryFrom for AbciEvent { IbcEvent::AcknowledgePacket(event) => event.try_into().map_err(Error::channel)?, IbcEvent::TimeoutPacket(event) => event.try_into().map_err(Error::channel)?, IbcEvent::TimeoutOnClosePacket(event) => event.try_into().map_err(Error::channel)?, + IbcEvent::IncentivizedPacket(event) => event.into(), IbcEvent::AppModule(event) => event.try_into()?, IbcEvent::NewBlock(_) | IbcEvent::Empty(_) | IbcEvent::ChainError(_) => { return Err(Error::incorrect_event_type(event.to_string())) @@ -443,6 +449,7 @@ impl IbcEvent { IbcEvent::AcknowledgePacket(_) => IbcEventType::AckPacket, IbcEvent::TimeoutPacket(_) => IbcEventType::Timeout, IbcEvent::TimeoutOnClosePacket(_) => IbcEventType::TimeoutOnClose, + IbcEvent::IncentivizedPacket(_) => IbcEventType::IncentivizedPacket, IbcEvent::AppModule(_) => IbcEventType::AppModule, IbcEvent::Empty(_) => IbcEventType::Empty, IbcEvent::ChainError(_) => IbcEventType::ChainError, From 53fb68bbf5e37d8a4f30eeefb0fccd318f39b2cf Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Thu, 16 Jun 2022 21:16:50 +0200 Subject: [PATCH 068/113] Fix itertools dependency --- modules/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/Cargo.toml b/modules/Cargo.toml index bd12a2c2e4..411f3ecb44 100644 --- a/modules/Cargo.toml +++ b/modules/Cargo.toml @@ -45,7 +45,7 @@ num-traits = { version = "0.2.15", default-features = false } derive_more = { version = "0.99.17", default-features = false, features = ["from", "into", "display"] } uint = { version = "0.9", default-features = false } primitive-types = { version = "0.11.1", default-features = false, features = ["serde_no_std"] } -itertools = { version = "0.10.3", default-features = false } +itertools = { version = "0.10.3", default-features = false, features = ["use_alloc"] } [dependencies.tendermint] version = "=0.23.7" From 88a25b5690c2c381e49cbeff93ae87473f4ac4cc Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Thu, 16 Jun 2022 22:54:04 +0200 Subject: [PATCH 069/113] Testing of incentivized packet event is working --- modules/src/applications/transfer/coin.rs | 59 ++++++++++++++++++++++- modules/src/events.rs | 5 +- tools/integration-test/src/tests/fee.rs | 56 ++++++++++++++++----- 3 files changed, 107 insertions(+), 13 deletions(-) diff --git a/modules/src/applications/transfer/coin.rs b/modules/src/applications/transfer/coin.rs index 9e42eef5ad..5c125046fe 100644 --- a/modules/src/applications/transfer/coin.rs +++ b/modules/src/applications/transfer/coin.rs @@ -56,7 +56,11 @@ where #[allow(clippy::assign_op_pattern)] fn from_str(coin_str: &str) -> Result { - let matcher = regex!(br"(\\d+)([a-zA-Z].+)"); + // Denominations can be 3 ~ 128 characters long and support letters, followed by either + // a letter, a number or a separator ('/', ':', '.', '_' or '-'). + // Loosely copy the regex from here: + // https://github.com/cosmos/cosmos-sdk/blob/v0.45.5/types/coin.go#L760-L762 + let matcher = regex!(br"([0-9]+)([a-zA-Z0-9/:\\._\x2d]+)"); let (m1, m2) = matcher .match_slices(coin_str.as_bytes()) @@ -118,3 +122,56 @@ impl Display for Coin { write!(f, "{}{}", self.amount, self.denom) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parse_raw_coin() -> Result<(), Error> { + { + let coin = RawCoin::from_str("123stake")?; + assert_eq!(coin.denom, "stake"); + assert_eq!(coin.amount, 123u64.into()); + } + + { + let coin = RawCoin::from_str("1a1")?; + assert_eq!(coin.denom, "a1"); + assert_eq!(coin.amount, 1u64.into()); + } + + { + let coin = RawCoin::from_str("0x1/:.\\_-")?; + assert_eq!(coin.denom, "x1/:.\\_-"); + assert_eq!(coin.amount, 0u64.into()); + } + + { + // `!` is not allowed + let res = RawCoin::from_str("0x!"); + assert!(res.is_err()); + } + + Ok(()) + } + + #[test] + fn test_parse_raw_coin_list() -> Result<(), Error> { + { + let coins = RawCoin::from_string_list("123stake,1a1,999den0m")?; + assert_eq!(coins.len(), 3); + + assert_eq!(coins[0].denom, "stake"); + assert_eq!(coins[0].amount, 123u64.into()); + + assert_eq!(coins[1].denom, "a1"); + assert_eq!(coins[1].amount, 1u64.into()); + + assert_eq!(coins[2].denom, "den0m"); + assert_eq!(coins[2].amount, 999u64.into()); + } + + Ok(()) + } +} diff --git a/modules/src/events.rs b/modules/src/events.rs index f9206686da..41c41e06a1 100644 --- a/modules/src/events.rs +++ b/modules/src/events.rs @@ -9,7 +9,7 @@ use serde_derive::{Deserialize, Serialize}; use tendermint::abci::tag::Tag; use tendermint::abci::Event as AbciEvent; -use crate::applications::ics29_fee::events::IncentivizedPacket; +use crate::applications::ics29_fee::events::{self as FeeEvents, IncentivizedPacket}; use crate::core::ics02_client::error as client_error; use crate::core::ics02_client::events as ClientEvents; use crate::core::ics02_client::events::NewBlock; @@ -360,6 +360,8 @@ pub fn from_tx_response_event(height: Height, event: &tendermint::abci::Event) - } else if let Some(mut chan_res) = ChannelEvents::try_from_tx(event) { chan_res.set_height(height); Some(chan_res) + } else if let Some(event) = FeeEvents::try_from_tx(event) { + Some(event) } else { None } @@ -422,6 +424,7 @@ impl IbcEvent { IbcEvent::WriteAcknowledgement(ev) => ev.set_height(height), IbcEvent::AcknowledgePacket(ev) => ev.set_height(height), IbcEvent::TimeoutPacket(ev) => ev.set_height(height), + IbcEvent::IncentivizedPacket(_) => {} _ => unimplemented!(), } } diff --git a/tools/integration-test/src/tests/fee.rs b/tools/integration-test/src/tests/fee.rs index d4d89ce0f7..632983157b 100644 --- a/tools/integration-test/src/tests/fee.rs +++ b/tools/integration-test/src/tests/fee.rs @@ -532,24 +532,58 @@ impl BinaryChannelTest for PayPacketFeeAsyncTest { let total_sent = send_amount + receive_fee + ack_fee + timeout_fee; let balance_a2 = balance_a1 - total_sent; - info!("Expect user A's balance after transfer: {}", balance_a2); chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a2.as_ref())?; - let send_packet_event = events - .into_iter() - .find_map(|event| match event { - IbcEvent::SendPacket(e) => Some(e), - _ => None, - }) - .ok_or_else(|| eyre!("expect send packet event"))?; + let sequence = { + let send_packet_event = events + .iter() + .find_map(|event| match event { + IbcEvent::SendPacket(e) => Some(e), + _ => None, + }) + .ok_or_else(|| eyre!("expect send packet event"))?; - let sequence = send_packet_event.packet.sequence; + send_packet_event.packet.sequence + }; { - let packets = chain_driver_a.query_incentivized_packets(&channel_id_a, &port_a)?; + let event = events + .iter() + .find_map(|ev| { + if let IbcEvent::IncentivizedPacket(ev) = ev { + Some(ev) + } else { + None + } + }) + .unwrap(); + + info!("incentivized packet event: {:?}", event); + + assert_eq!(event.sequence, sequence); + + assert_eq!(event.total_recv_fee.len(), 1); + assert_eq!(event.total_ack_fee.len(), 1); + assert_eq!(event.total_timeout_fee.len(), 1); - info!("incenvitized packets: {:?}", packets); + assert_eq!( + &event.total_recv_fee[0], + &denom_a.with_amount(receive_fee).as_coin(), + ); + assert_eq!( + &event.total_ack_fee[0], + &denom_a.with_amount(ack_fee).as_coin() + ); + + assert_eq!( + &event.total_timeout_fee[0], + &denom_a.with_amount(timeout_fee).as_coin(), + ); + } + + { + let packets = chain_driver_a.query_incentivized_packets(&channel_id_a, &port_a)?; assert_eq!(packets.len(), 1); From 849347388d377739652f0617e90c28138272e3e1 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Fri, 17 Jun 2022 11:06:30 +0200 Subject: [PATCH 070/113] Fix merge error --- tools/integration-test/src/tests/denom_trace.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tools/integration-test/src/tests/denom_trace.rs b/tools/integration-test/src/tests/denom_trace.rs index 608ccb617d..5c53a22f1a 100644 --- a/tools/integration-test/src/tests/denom_trace.rs +++ b/tools/integration-test/src/tests/denom_trace.rs @@ -37,8 +37,7 @@ impl BinaryChannelTest for IbcDenomTraceTest { &channel.channel_id_a.as_ref(), &wallet_a.as_ref(), &wallet_b.address(), - &denom_a, - a_to_b_amount, + &denom_a.with_amount(a_to_b_amount).as_ref(), )?; let denom_b = derive_ibc_denom( @@ -54,14 +53,12 @@ impl BinaryChannelTest for IbcDenomTraceTest { chains.node_a.chain_driver().assert_eventual_wallet_amount( &wallet_a.address(), - balance_a - a_to_b_amount, - &denom_a, + &(balance_a - a_to_b_amount).as_ref(), )?; chains.node_b.chain_driver().assert_eventual_wallet_amount( &wallet_b.address(), - a_to_b_amount, - &denom_b.as_ref(), + &denom_b.with_amount(a_to_b_amount).as_ref(), )?; info!( From b09b9f91374f4f17b12b7185b3100151e176d96b Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Fri, 17 Jun 2022 14:08:08 +0200 Subject: [PATCH 071/113] Split fee tests into separate files --- tools/integration-test/src/tests/fee.rs | 749 ------------------ .../src/tests/fee/auto_forward_relayer.rs | 96 +++ .../src/tests/fee/forward_relayer.rs | 136 ++++ tools/integration-test/src/tests/fee/mod.rs | 11 + .../src/tests/fee/no_forward_relayer.rs | 98 +++ .../src/tests/fee/non_fee_channel.rs | 100 +++ .../src/tests/fee/pay_fee_async.rs | 222 ++++++ .../src/tests/fee/timeout_fee.rs | 92 +++ 8 files changed, 755 insertions(+), 749 deletions(-) delete mode 100644 tools/integration-test/src/tests/fee.rs create mode 100644 tools/integration-test/src/tests/fee/auto_forward_relayer.rs create mode 100644 tools/integration-test/src/tests/fee/forward_relayer.rs create mode 100644 tools/integration-test/src/tests/fee/mod.rs create mode 100644 tools/integration-test/src/tests/fee/no_forward_relayer.rs create mode 100644 tools/integration-test/src/tests/fee/non_fee_channel.rs create mode 100644 tools/integration-test/src/tests/fee/pay_fee_async.rs create mode 100644 tools/integration-test/src/tests/fee/timeout_fee.rs diff --git a/tools/integration-test/src/tests/fee.rs b/tools/integration-test/src/tests/fee.rs deleted file mode 100644 index 632983157b..0000000000 --- a/tools/integration-test/src/tests/fee.rs +++ /dev/null @@ -1,749 +0,0 @@ -use ibc::core::ics04_channel::Version; -use ibc::events::IbcEvent; -use ibc_test_framework::prelude::*; -use ibc_test_framework::util::random::random_u128_range; -use std::thread; - -#[test] -fn test_no_forward_relayer() -> Result<(), Error> { - run_binary_channel_test(&NoForwardRelayerTest) -} - -#[test] -fn test_forward_relayer() -> Result<(), Error> { - run_binary_channel_test(&ForwardRelayerTest) -} - -#[test] -fn test_auto_forward_relayer() -> Result<(), Error> { - run_binary_channel_test(&AutoForwardRelayerTest) -} - -#[test] -fn test_timeout_fee() -> Result<(), Error> { - run_binary_channel_test(&TimeoutFeeTest) -} - -#[test] -fn test_pay_packet_fee_async() -> Result<(), Error> { - run_binary_channel_test(&PayPacketFeeAsyncTest) -} - -#[test] -fn test_non_fee_channel() -> Result<(), Error> { - run_binary_channel_test(&NonFeeChannelTest) -} - -struct ForwardRelayerTest; -struct AutoForwardRelayerTest; -struct NoForwardRelayerTest; -struct TimeoutFeeTest; -struct PayPacketFeeAsyncTest; -struct NonFeeChannelTest; - -impl TestOverrides for ForwardRelayerTest { - fn channel_version(&self) -> Version { - Version::ics20_with_fee() - } -} - -impl TestOverrides for AutoForwardRelayerTest { - fn modify_relayer_config(&self, config: &mut Config) { - config.mode.packets.auto_register_counterparty_payee = true; - } - - fn channel_version(&self) -> Version { - Version::ics20_with_fee() - } -} - -impl TestOverrides for NoForwardRelayerTest { - fn modify_relayer_config(&self, config: &mut Config) { - config.mode.packets.auto_register_counterparty_payee = false; - } - - fn channel_version(&self) -> Version { - Version::ics20_with_fee() - } -} - -impl TestOverrides for TimeoutFeeTest { - fn should_spawn_supervisor(&self) -> bool { - false - } - - fn channel_version(&self) -> Version { - Version::ics20_with_fee() - } -} - -impl TestOverrides for PayPacketFeeAsyncTest { - fn should_spawn_supervisor(&self) -> bool { - false - } - - fn channel_version(&self) -> Version { - Version::ics20_with_fee() - } -} - -impl TestOverrides for NonFeeChannelTest { - fn modify_relayer_config(&self, config: &mut Config) { - config.mode.packets.auto_register_counterparty_payee = true; - } -} - -impl BinaryChannelTest for NoForwardRelayerTest { - fn run( - &self, - _config: &TestConfig, - _relayer: RelayerDriver, - chains: ConnectedChains, - channel: ConnectedChannel, - ) -> Result<(), Error> { - let chain_driver_a = chains.node_a.chain_driver(); - let chain_driver_b = chains.node_b.chain_driver(); - - let denom_a = chains.node_a.denom(); - - let port_a = channel.port_a.as_ref(); - let channel_id_a = channel.channel_id_a.as_ref(); - - let wallets_a = chains.node_a.wallets(); - let wallets_b = chains.node_b.wallets(); - - let relayer_a = wallets_a.relayer(); - - let user_a = wallets_a.user1(); - let user_b = wallets_b.user1(); - - let balance_a1 = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; - - let relayer_balance_a = chain_driver_a.query_balance(&relayer_a.address(), &denom_a)?; - - let send_amount = random_u128_range(1000, 2000); - let receive_fee = random_u128_range(300, 400); - let ack_fee = random_u128_range(200, 300); - let timeout_fee = random_u128_range(100, 200); - - let total_sent = send_amount + receive_fee + ack_fee + timeout_fee; - - let balance_a2 = balance_a1 - total_sent; - - chain_driver_a.ibc_token_transfer_with_fee( - &port_a, - &channel_id_a, - &user_a, - &user_b.address(), - &denom_a.with_amount(send_amount).as_ref(), - &denom_a.with_amount(receive_fee).as_ref(), - &denom_a.with_amount(ack_fee).as_ref(), - &denom_a.with_amount(timeout_fee).as_ref(), - Duration::from_secs(60), - )?; - - let denom_b = derive_ibc_denom( - &channel.port_b.as_ref(), - &channel.channel_id_b.as_ref(), - &denom_a, - )?; - - info!("Expect user A's balance after transfer: {}", balance_a2); - - chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a2.as_ref())?; - - chain_driver_b.assert_eventual_wallet_amount( - &user_b.address(), - &denom_b.with_amount(send_amount).as_ref(), - )?; - - info!( - "Expect user to be refunded receive fee {} and timeout fee {} and go from {} to {}", - receive_fee, - timeout_fee, - balance_a2, - balance_a2 - .amount() - .checked_add(receive_fee + timeout_fee) - .unwrap() - ); - - // receive fee and timeout fee should be refunded, - // as there is no counterparty address registered. - chain_driver_a.assert_eventual_wallet_amount( - &user_a.address(), - &(balance_a2 + receive_fee + timeout_fee).as_ref(), - )?; - - info!( - "Expect relayer to receive ack fee {} and go from {} to {}", - ack_fee, - relayer_balance_a, - relayer_balance_a.amount().checked_add(ack_fee).unwrap(), - ); - - chain_driver_a.assert_eventual_wallet_amount( - &relayer_a.address(), - &(relayer_balance_a + ack_fee).as_ref(), - )?; - - Ok(()) - } -} - -impl BinaryChannelTest for ForwardRelayerTest { - fn run( - &self, - _config: &TestConfig, - _relayer: RelayerDriver, - chains: ConnectedChains, - channel: ConnectedChannel, - ) -> Result<(), Error> { - let chain_driver_a = chains.node_a.chain_driver(); - let chain_driver_b = chains.node_b.chain_driver(); - - let chain_id_a = chain_driver_a.chain_id(); - let chain_id_b = chain_driver_b.chain_id(); - - let denom_a = chains.node_a.denom(); - - let port_a = channel.port_a.as_ref(); - let port_b = channel.port_b.as_ref(); - let channel_id_a = channel.channel_id_a.as_ref(); - - let channel_id_b = channel.channel_id_b.as_ref(); - - let wallets_a = chains.node_a.wallets(); - let wallets_b = chains.node_b.wallets(); - - let relayer_a = wallets_a.relayer(); - let relayer_b = wallets_b.relayer(); - - info!( - "registering counterparty address of relayer {} on chain {} to be {} on chain {}", - relayer_b.address(), - chain_id_b, - relayer_a.address(), - chain_id_a - ); - - { - let counterparty_payee = - chain_driver_b.query_counterparty_payee(&channel_id_b, &relayer_b.address())?; - - assert_eq( - "counterparty address should be None before registering", - &counterparty_payee, - &None, - )?; - } - - chain_driver_b.register_counterparty_payee( - &relayer_b, - &relayer_a.address(), - &channel_id_b, - &port_b, - )?; - - { - let counterparty_payee = - chain_driver_b.query_counterparty_payee(&channel_id_b, &relayer_b.address())?; - - assert_eq( - "counterparty address should match registered address", - &counterparty_payee, - &Some(relayer_a.address().cloned()), - )?; - } - - let user_a = wallets_a.user1(); - let user_b = wallets_b.user1(); - - let balance_a1 = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; - - let relayer_balance_a = chain_driver_a.query_balance(&relayer_a.address(), &denom_a)?; - - let send_amount = random_u128_range(1000, 2000); - let receive_fee = random_u128_range(300, 400); - let ack_fee = random_u128_range(200, 300); - let timeout_fee = random_u128_range(100, 200); - - let total_sent = send_amount + receive_fee + ack_fee + timeout_fee; - - let balance_a2 = balance_a1 - total_sent; - - chain_driver_a.ibc_token_transfer_with_fee( - &port_a, - &channel_id_a, - &user_a, - &user_b.address(), - &denom_a.with_amount(send_amount).as_ref(), - &denom_a.with_amount(receive_fee).as_ref(), - &denom_a.with_amount(ack_fee).as_ref(), - &denom_a.with_amount(timeout_fee).as_ref(), - Duration::from_secs(60), - )?; - - let denom_b = derive_ibc_denom( - &channel.port_b.as_ref(), - &channel.channel_id_b.as_ref(), - &denom_a, - )?; - - info!("Expect user A's balance after transfer: {}", balance_a2); - - chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a2.as_ref())?; - - chain_driver_b.assert_eventual_wallet_amount( - &user_b.address(), - &denom_b.with_amount(send_amount).as_ref(), - )?; - - chain_driver_a.assert_eventual_wallet_amount( - &user_a.address(), - &(balance_a2 + timeout_fee).as_ref(), - )?; - - chain_driver_a.assert_eventual_wallet_amount( - &relayer_a.address(), - &(relayer_balance_a + ack_fee + receive_fee).as_ref(), - )?; - - Ok(()) - } -} - -impl BinaryChannelTest for AutoForwardRelayerTest { - fn run( - &self, - _config: &TestConfig, - _relayer: RelayerDriver, - chains: ConnectedChains, - channel: ConnectedChannel, - ) -> Result<(), Error> { - let chain_driver_a = chains.node_a.chain_driver(); - let chain_driver_b = chains.node_b.chain_driver(); - - let denom_a = chains.node_a.denom(); - - let port_a = channel.port_a.as_ref(); - let channel_id_a = channel.channel_id_a.as_ref(); - - let wallets_a = chains.node_a.wallets(); - let wallets_b = chains.node_b.wallets(); - - let relayer_a = wallets_a.relayer(); - - let user_a = wallets_a.user1(); - let user_b = wallets_b.user1(); - - let balance_a1 = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; - - let relayer_balance_a = chain_driver_a.query_balance(&relayer_a.address(), &denom_a)?; - - let send_amount = random_u128_range(1000, 2000); - let receive_fee = random_u128_range(300, 400); - let ack_fee = random_u128_range(200, 300); - let timeout_fee = random_u128_range(100, 200); - - let total_sent = send_amount + receive_fee + ack_fee + timeout_fee; - - let balance_a2 = balance_a1 - total_sent; - - chain_driver_a.ibc_token_transfer_with_fee( - &port_a, - &channel_id_a, - &user_a, - &user_b.address(), - &denom_a.with_amount(send_amount).as_ref(), - &denom_a.with_amount(receive_fee).as_ref(), - &denom_a.with_amount(ack_fee).as_ref(), - &denom_a.with_amount(timeout_fee).as_ref(), - Duration::from_secs(60), - )?; - - let denom_b = derive_ibc_denom( - &channel.port_b.as_ref(), - &channel.channel_id_b.as_ref(), - &denom_a, - )?; - - info!("Expect user A's balance after transfer: {}", balance_a2); - - chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a2.as_ref())?; - - chain_driver_b.assert_eventual_wallet_amount( - &user_b.address(), - &denom_b.with_amount(send_amount).as_ref(), - )?; - - chain_driver_a.assert_eventual_wallet_amount( - &user_a.address(), - &(balance_a2 + timeout_fee).as_ref(), - )?; - - chain_driver_a.assert_eventual_wallet_amount( - &relayer_a.address(), - &(relayer_balance_a + ack_fee + receive_fee).as_ref(), - )?; - - Ok(()) - } -} - -impl BinaryChannelTest for TimeoutFeeTest { - fn run( - &self, - _config: &TestConfig, - relayer: RelayerDriver, - chains: ConnectedChains, - channel: ConnectedChannel, - ) -> Result<(), Error> { - let chain_driver_a = chains.node_a.chain_driver(); - - let denom_a = chains.node_a.denom(); - - let port_a = channel.port_a.as_ref(); - let channel_id_a = channel.channel_id_a.as_ref(); - - let wallets_a = chains.node_a.wallets(); - let wallets_b = chains.node_b.wallets(); - - let relayer_a = wallets_a.relayer(); - - let user_a = wallets_a.user1(); - let user_b = wallets_b.user1(); - - let balance_a1 = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; - - let relayer_balance_a = chain_driver_a.query_balance(&relayer_a.address(), &denom_a)?; - - let send_amount = random_u128_range(1000, 2000); - let receive_fee = random_u128_range(300, 400); - let ack_fee = random_u128_range(200, 300); - let timeout_fee = random_u128_range(100, 200); - - let total_sent = send_amount + receive_fee + ack_fee + timeout_fee; - - let balance_a2 = balance_a1 - total_sent; - - chain_driver_a.ibc_token_transfer_with_fee( - &port_a, - &channel_id_a, - &user_a, - &user_b.address(), - &denom_a.with_amount(send_amount).as_ref(), - &denom_a.with_amount(receive_fee).as_ref(), - &denom_a.with_amount(ack_fee).as_ref(), - &denom_a.with_amount(timeout_fee).as_ref(), - Duration::from_secs(5), - )?; - - info!("Expect user A's balance after transfer: {}", balance_a2); - - chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a2.as_ref())?; - - // Sleep to wait for IBC packet to timeout before start relaying - thread::sleep(Duration::from_secs(6)); - - relayer.with_supervisor(|| { - chain_driver_a.assert_eventual_wallet_amount( - &user_a.address(), - &(balance_a2 + send_amount + receive_fee + ack_fee).as_ref(), - )?; - - chain_driver_a.assert_eventual_wallet_amount( - &relayer_a.address(), - &(relayer_balance_a + timeout_fee).as_ref(), - )?; - - Ok(()) - }) - } -} - -impl BinaryChannelTest for PayPacketFeeAsyncTest { - fn run( - &self, - _config: &TestConfig, - relayer: RelayerDriver, - chains: ConnectedChains, - channel: ConnectedChannel, - ) -> Result<(), Error> { - let chain_driver_a = chains.node_a.chain_driver(); - let chain_driver_b = chains.node_b.chain_driver(); - - let chain_id_a = chain_driver_a.chain_id(); - let chain_id_b = chain_driver_b.chain_id(); - - let denom_a = chains.node_a.denom(); - - let port_a = channel.port_a.as_ref(); - let port_b = channel.port_b.as_ref(); - let channel_id_a = channel.channel_id_a.as_ref(); - - let channel_id_b = channel.channel_id_b.as_ref(); - - let wallets_a = chains.node_a.wallets(); - let wallets_b = chains.node_b.wallets(); - - let relayer_a = wallets_a.relayer(); - let relayer_b = wallets_b.relayer(); - - info!( - "registering counterparty address of relayer {} on chain {} to be {} on chain {}", - relayer_b.address(), - chain_id_b, - relayer_a.address(), - chain_id_a - ); - - chain_driver_b.register_counterparty_payee( - &relayer_b, - &relayer_a.address(), - &channel_id_b, - &port_b, - )?; - - let user_a = wallets_a.user1(); - - let user_b = wallets_b.user1(); - - let balance_a1 = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; - - let relayer_balance_a = chain_driver_a.query_balance(&relayer_a.address(), &denom_a)?; - - let send_amount = random_u128_range(1000, 2000); - let receive_fee = random_u128_range(300, 400); - let ack_fee = random_u128_range(200, 300); - let timeout_fee = random_u128_range(100, 200); - - let events = chain_driver_a.ibc_token_transfer_with_fee( - &port_a, - &channel_id_a, - &user_a, - &user_b.address(), - &denom_a.with_amount(send_amount).as_ref(), - &denom_a.with_amount(receive_fee).as_ref(), - &denom_a.with_amount(ack_fee).as_ref(), - &denom_a.with_amount(timeout_fee).as_ref(), - Duration::from_secs(60), - )?; - - let total_sent = send_amount + receive_fee + ack_fee + timeout_fee; - let balance_a2 = balance_a1 - total_sent; - - chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a2.as_ref())?; - - let sequence = { - let send_packet_event = events - .iter() - .find_map(|event| match event { - IbcEvent::SendPacket(e) => Some(e), - _ => None, - }) - .ok_or_else(|| eyre!("expect send packet event"))?; - - send_packet_event.packet.sequence - }; - - { - let event = events - .iter() - .find_map(|ev| { - if let IbcEvent::IncentivizedPacket(ev) = ev { - Some(ev) - } else { - None - } - }) - .unwrap(); - - info!("incentivized packet event: {:?}", event); - - assert_eq!(event.sequence, sequence); - - assert_eq!(event.total_recv_fee.len(), 1); - assert_eq!(event.total_ack_fee.len(), 1); - assert_eq!(event.total_timeout_fee.len(), 1); - - assert_eq!( - &event.total_recv_fee[0], - &denom_a.with_amount(receive_fee).as_coin(), - ); - assert_eq!( - &event.total_ack_fee[0], - &denom_a.with_amount(ack_fee).as_coin() - ); - - assert_eq!( - &event.total_timeout_fee[0], - &denom_a.with_amount(timeout_fee).as_coin(), - ); - } - - { - let packets = chain_driver_a.query_incentivized_packets(&channel_id_a, &port_a)?; - - assert_eq!(packets.len(), 1); - - let packet = &packets[0]; - assert_eq!(packet.packet_id.sequence, sequence); - - assert_eq!(packet.packet_fees.len(), 1); - let packet_fee = &packet.packet_fees[0]; - - assert_eq!(packet_fee.fee.recv_fee.len(), 1); - assert_eq!(packet_fee.fee.ack_fee.len(), 1); - assert_eq!(packet_fee.fee.timeout_fee.len(), 1); - - assert_eq!( - &packet_fee.fee.recv_fee[0], - &denom_a.with_amount(receive_fee).as_coin(), - ); - assert_eq!( - &packet_fee.fee.ack_fee[0], - &denom_a.with_amount(ack_fee).as_coin() - ); - - assert_eq!( - &packet_fee.fee.timeout_fee[0], - &denom_a.with_amount(timeout_fee).as_coin(), - ); - - assert_eq!( - packet_fee.refund_address.as_ref(), - user_a.value().address.as_str(), - ); - } - - let receive_fee_2 = random_u128_range(300, 400); - let ack_fee_2 = random_u128_range(200, 300); - let timeout_fee_2 = random_u128_range(100, 200); - - chain_driver_a.pay_packet_fee( - &port_a, - &channel_id_a, - &DualTagged::new(sequence), - &user_a, - &denom_a.with_amount(receive_fee_2).as_ref(), - &denom_a.with_amount(ack_fee_2).as_ref(), - &denom_a.with_amount(timeout_fee_2).as_ref(), - )?; - - let total_sent_2 = receive_fee_2 + ack_fee_2 + timeout_fee_2; - let balance_a3 = balance_a2 - total_sent_2; - - chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a3.as_ref())?; - - let denom_b = derive_ibc_denom( - &channel.port_b.as_ref(), - &channel.channel_id_b.as_ref(), - &denom_a, - )?; - - relayer.with_supervisor(|| { - chain_driver_b.assert_eventual_wallet_amount( - &user_b.address(), - &denom_b.with_amount(send_amount).as_ref(), - )?; - - chain_driver_a.assert_eventual_wallet_amount( - &user_a.address(), - &(balance_a3 + timeout_fee + timeout_fee_2).as_ref(), - )?; - - chain_driver_a.assert_eventual_wallet_amount( - &relayer_a.address(), - &(relayer_balance_a + ack_fee + receive_fee + ack_fee_2 + receive_fee_2).as_ref(), - )?; - - Ok(()) - }) - } -} - -impl BinaryChannelTest for NonFeeChannelTest { - fn run( - &self, - _config: &TestConfig, - _relayer: RelayerDriver, - chains: ConnectedChains, - channel: ConnectedChannel, - ) -> Result<(), Error> { - let chain_driver_a = chains.node_a.chain_driver(); - let chain_driver_b = chains.node_b.chain_driver(); - - let denom_a = chains.node_a.denom(); - - let port_a = channel.port_a.as_ref(); - let port_b = channel.port_b.as_ref(); - let channel_id_a = channel.channel_id_a.as_ref(); - let channel_id_b = channel.channel_id_b.as_ref(); - - let wallets_a = chains.node_a.wallets(); - let wallets_b = chains.node_b.wallets(); - - let user_a = wallets_a.user1(); - let user_b = wallets_b.user1(); - - let relayer_a = wallets_a.relayer(); - let relayer_b = wallets_b.relayer(); - - let balance_a1 = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; - - let send_amount = random_u128_range(1000, 2000); - - { - let res = chain_driver_b.register_counterparty_payee( - &relayer_b, - &relayer_a.address(), - &channel_id_b, - &port_b, - ); - - assert!(res.is_err()); - } - - { - let res = chain_driver_a.ibc_token_transfer_with_fee( - &port_a, - &channel_id_a, - &user_a, - &user_b.address(), - &denom_a.with_amount(send_amount).as_ref(), - &denom_a.with_amount(10u64).as_ref(), - &denom_a.with_amount(10u64).as_ref(), - &denom_a.with_amount(10u64).as_ref(), - Duration::from_secs(60), - ); - - assert!(res.is_err()); - } - - let balance_a2 = balance_a1 - send_amount; - - chain_driver_a.ibc_transfer_token( - &port_a, - &channel_id_a, - &user_a, - &user_b.address(), - &denom_a.with_amount(send_amount).as_ref(), - )?; - - let denom_b = derive_ibc_denom( - &channel.port_b.as_ref(), - &channel.channel_id_b.as_ref(), - &denom_a, - )?; - - chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a2.as_ref())?; - - chain_driver_b.assert_eventual_wallet_amount( - &user_b.address(), - &denom_b.with_amount(send_amount).as_ref(), - )?; - - Ok(()) - } -} diff --git a/tools/integration-test/src/tests/fee/auto_forward_relayer.rs b/tools/integration-test/src/tests/fee/auto_forward_relayer.rs new file mode 100644 index 0000000000..43ba51f9f5 --- /dev/null +++ b/tools/integration-test/src/tests/fee/auto_forward_relayer.rs @@ -0,0 +1,96 @@ +use ibc::core::ics04_channel::Version; +use ibc_test_framework::prelude::*; +use ibc_test_framework::util::random::random_u128_range; + +#[test] +fn test_auto_forward_relayer() -> Result<(), Error> { + run_binary_channel_test(&AutoForwardRelayerTest) +} + +struct AutoForwardRelayerTest; + +impl TestOverrides for AutoForwardRelayerTest { + fn modify_relayer_config(&self, config: &mut Config) { + config.mode.packets.auto_register_counterparty_payee = true; + } + + fn channel_version(&self) -> Version { + Version::ics20_with_fee() + } +} + +impl BinaryChannelTest for AutoForwardRelayerTest { + fn run( + &self, + _config: &TestConfig, + _relayer: RelayerDriver, + chains: ConnectedChains, + channel: ConnectedChannel, + ) -> Result<(), Error> { + let chain_driver_a = chains.node_a.chain_driver(); + let chain_driver_b = chains.node_b.chain_driver(); + + let denom_a = chains.node_a.denom(); + + let port_a = channel.port_a.as_ref(); + let channel_id_a = channel.channel_id_a.as_ref(); + + let wallets_a = chains.node_a.wallets(); + let wallets_b = chains.node_b.wallets(); + + let relayer_a = wallets_a.relayer(); + + let user_a = wallets_a.user1(); + let user_b = wallets_b.user1(); + + let balance_a1 = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; + + let relayer_balance_a = chain_driver_a.query_balance(&relayer_a.address(), &denom_a)?; + + let send_amount = random_u128_range(1000, 2000); + let receive_fee = random_u128_range(300, 400); + let ack_fee = random_u128_range(200, 300); + let timeout_fee = random_u128_range(100, 200); + + let total_sent = send_amount + receive_fee + ack_fee + timeout_fee; + + let balance_a2 = balance_a1 - total_sent; + + chain_driver_a.ibc_token_transfer_with_fee( + &port_a, + &channel_id_a, + &user_a, + &user_b.address(), + &denom_a.with_amount(send_amount).as_ref(), + &denom_a.with_amount(receive_fee).as_ref(), + &denom_a.with_amount(ack_fee).as_ref(), + &denom_a.with_amount(timeout_fee).as_ref(), + Duration::from_secs(60), + )?; + + let denom_b = derive_ibc_denom( + &channel.port_b.as_ref(), + &channel.channel_id_b.as_ref(), + &denom_a, + )?; + + chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a2.as_ref())?; + + chain_driver_b.assert_eventual_wallet_amount( + &user_b.address(), + &denom_b.with_amount(send_amount).as_ref(), + )?; + + chain_driver_a.assert_eventual_wallet_amount( + &user_a.address(), + &(balance_a2 + timeout_fee).as_ref(), + )?; + + chain_driver_a.assert_eventual_wallet_amount( + &relayer_a.address(), + &(relayer_balance_a + ack_fee + receive_fee).as_ref(), + )?; + + Ok(()) + } +} diff --git a/tools/integration-test/src/tests/fee/forward_relayer.rs b/tools/integration-test/src/tests/fee/forward_relayer.rs new file mode 100644 index 0000000000..2acb5c16ef --- /dev/null +++ b/tools/integration-test/src/tests/fee/forward_relayer.rs @@ -0,0 +1,136 @@ +use ibc::core::ics04_channel::Version; +use ibc_test_framework::prelude::*; +use ibc_test_framework::util::random::random_u128_range; + +#[test] +fn test_forward_relayer() -> Result<(), Error> { + run_binary_channel_test(&ForwardRelayerTest) +} + +struct ForwardRelayerTest; + +impl TestOverrides for ForwardRelayerTest { + fn channel_version(&self) -> Version { + Version::ics20_with_fee() + } +} + +impl BinaryChannelTest for ForwardRelayerTest { + fn run( + &self, + _config: &TestConfig, + _relayer: RelayerDriver, + chains: ConnectedChains, + channel: ConnectedChannel, + ) -> Result<(), Error> { + let chain_driver_a = chains.node_a.chain_driver(); + let chain_driver_b = chains.node_b.chain_driver(); + + let chain_id_a = chain_driver_a.chain_id(); + let chain_id_b = chain_driver_b.chain_id(); + + let denom_a = chains.node_a.denom(); + + let port_a = channel.port_a.as_ref(); + let port_b = channel.port_b.as_ref(); + let channel_id_a = channel.channel_id_a.as_ref(); + + let channel_id_b = channel.channel_id_b.as_ref(); + + let wallets_a = chains.node_a.wallets(); + let wallets_b = chains.node_b.wallets(); + + let relayer_a = wallets_a.relayer(); + let relayer_b = wallets_b.relayer(); + + info!( + "registering counterparty address of relayer {} on chain {} to be {} on chain {}", + relayer_b.address(), + chain_id_b, + relayer_a.address(), + chain_id_a + ); + + { + let counterparty_payee = + chain_driver_b.query_counterparty_payee(&channel_id_b, &relayer_b.address())?; + + assert_eq( + "counterparty address should be None before registering", + &counterparty_payee, + &None, + )?; + } + + chain_driver_b.register_counterparty_payee( + &relayer_b, + &relayer_a.address(), + &channel_id_b, + &port_b, + )?; + + { + let counterparty_payee = + chain_driver_b.query_counterparty_payee(&channel_id_b, &relayer_b.address())?; + + assert_eq( + "counterparty address should match registered address", + &counterparty_payee, + &Some(relayer_a.address().cloned()), + )?; + } + + let user_a = wallets_a.user1(); + let user_b = wallets_b.user1(); + + let balance_a1 = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; + + let relayer_balance_a = chain_driver_a.query_balance(&relayer_a.address(), &denom_a)?; + + let send_amount = random_u128_range(1000, 2000); + let receive_fee = random_u128_range(300, 400); + let ack_fee = random_u128_range(200, 300); + let timeout_fee = random_u128_range(100, 200); + + let total_sent = send_amount + receive_fee + ack_fee + timeout_fee; + + let balance_a2 = balance_a1 - total_sent; + + chain_driver_a.ibc_token_transfer_with_fee( + &port_a, + &channel_id_a, + &user_a, + &user_b.address(), + &denom_a.with_amount(send_amount).as_ref(), + &denom_a.with_amount(receive_fee).as_ref(), + &denom_a.with_amount(ack_fee).as_ref(), + &denom_a.with_amount(timeout_fee).as_ref(), + Duration::from_secs(60), + )?; + + let denom_b = derive_ibc_denom( + &channel.port_b.as_ref(), + &channel.channel_id_b.as_ref(), + &denom_a, + )?; + + chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a2.as_ref())?; + + chain_driver_b.assert_eventual_wallet_amount( + &user_b.address(), + &denom_b.with_amount(send_amount).as_ref(), + )?; + + chain_driver_a.assert_eventual_wallet_amount( + &user_a.address(), + &(balance_a2 + timeout_fee).as_ref(), + )?; + + chain_driver_a.assert_eventual_wallet_amount( + &relayer_a.address(), + &(relayer_balance_a + ack_fee + receive_fee).as_ref(), + )?; + + Ok(()) + } +} diff --git a/tools/integration-test/src/tests/fee/mod.rs b/tools/integration-test/src/tests/fee/mod.rs new file mode 100644 index 0000000000..1d01d3bb92 --- /dev/null +++ b/tools/integration-test/src/tests/fee/mod.rs @@ -0,0 +1,11 @@ +pub mod forward_relayer; + +pub mod no_forward_relayer; + +pub mod auto_forward_relayer; + +pub mod timeout_fee; + +pub mod pay_fee_async; + +pub mod non_fee_channel; diff --git a/tools/integration-test/src/tests/fee/no_forward_relayer.rs b/tools/integration-test/src/tests/fee/no_forward_relayer.rs new file mode 100644 index 0000000000..5e4d247d0e --- /dev/null +++ b/tools/integration-test/src/tests/fee/no_forward_relayer.rs @@ -0,0 +1,98 @@ +use ibc::core::ics04_channel::Version; +use ibc_test_framework::prelude::*; +use ibc_test_framework::util::random::random_u128_range; + +#[test] +fn test_no_forward_relayer() -> Result<(), Error> { + run_binary_channel_test(&NoForwardRelayerTest) +} + +struct NoForwardRelayerTest; + +impl TestOverrides for NoForwardRelayerTest { + fn modify_relayer_config(&self, config: &mut Config) { + config.mode.packets.auto_register_counterparty_payee = false; + } + + fn channel_version(&self) -> Version { + Version::ics20_with_fee() + } +} + +impl BinaryChannelTest for NoForwardRelayerTest { + fn run( + &self, + _config: &TestConfig, + _relayer: RelayerDriver, + chains: ConnectedChains, + channel: ConnectedChannel, + ) -> Result<(), Error> { + let chain_driver_a = chains.node_a.chain_driver(); + let chain_driver_b = chains.node_b.chain_driver(); + + let denom_a = chains.node_a.denom(); + + let port_a = channel.port_a.as_ref(); + let channel_id_a = channel.channel_id_a.as_ref(); + + let wallets_a = chains.node_a.wallets(); + let wallets_b = chains.node_b.wallets(); + + let relayer_a = wallets_a.relayer(); + + let user_a = wallets_a.user1(); + let user_b = wallets_b.user1(); + + let balance_a1 = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; + + let relayer_balance_a = chain_driver_a.query_balance(&relayer_a.address(), &denom_a)?; + + let send_amount = random_u128_range(1000, 2000); + let receive_fee = random_u128_range(300, 400); + let ack_fee = random_u128_range(200, 300); + let timeout_fee = random_u128_range(100, 200); + + let total_sent = send_amount + receive_fee + ack_fee + timeout_fee; + + let balance_a2 = balance_a1 - total_sent; + + chain_driver_a.ibc_token_transfer_with_fee( + &port_a, + &channel_id_a, + &user_a, + &user_b.address(), + &denom_a.with_amount(send_amount).as_ref(), + &denom_a.with_amount(receive_fee).as_ref(), + &denom_a.with_amount(ack_fee).as_ref(), + &denom_a.with_amount(timeout_fee).as_ref(), + Duration::from_secs(60), + )?; + + let denom_b = derive_ibc_denom( + &channel.port_b.as_ref(), + &channel.channel_id_b.as_ref(), + &denom_a, + )?; + + chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a2.as_ref())?; + + chain_driver_b.assert_eventual_wallet_amount( + &user_b.address(), + &denom_b.with_amount(send_amount).as_ref(), + )?; + + // receive fee and timeout fee should be refunded, + // as there is no counterparty address registered. + chain_driver_a.assert_eventual_wallet_amount( + &user_a.address(), + &(balance_a2 + receive_fee + timeout_fee).as_ref(), + )?; + + chain_driver_a.assert_eventual_wallet_amount( + &relayer_a.address(), + &(relayer_balance_a + ack_fee).as_ref(), + )?; + + Ok(()) + } +} diff --git a/tools/integration-test/src/tests/fee/non_fee_channel.rs b/tools/integration-test/src/tests/fee/non_fee_channel.rs new file mode 100644 index 0000000000..c3a1978861 --- /dev/null +++ b/tools/integration-test/src/tests/fee/non_fee_channel.rs @@ -0,0 +1,100 @@ +use ibc_test_framework::prelude::*; +use ibc_test_framework::util::random::random_u128_range; + +#[test] +fn test_non_fee_channel() -> Result<(), Error> { + run_binary_channel_test(&NonFeeChannelTest) +} + +struct NonFeeChannelTest; + +impl TestOverrides for NonFeeChannelTest { + fn modify_relayer_config(&self, config: &mut Config) { + config.mode.packets.auto_register_counterparty_payee = true; + } +} + +impl BinaryChannelTest for NonFeeChannelTest { + fn run( + &self, + _config: &TestConfig, + _relayer: RelayerDriver, + chains: ConnectedChains, + channel: ConnectedChannel, + ) -> Result<(), Error> { + let chain_driver_a = chains.node_a.chain_driver(); + let chain_driver_b = chains.node_b.chain_driver(); + + let denom_a = chains.node_a.denom(); + + let port_a = channel.port_a.as_ref(); + let port_b = channel.port_b.as_ref(); + let channel_id_a = channel.channel_id_a.as_ref(); + let channel_id_b = channel.channel_id_b.as_ref(); + + let wallets_a = chains.node_a.wallets(); + let wallets_b = chains.node_b.wallets(); + + let user_a = wallets_a.user1(); + let user_b = wallets_b.user1(); + + let relayer_a = wallets_a.relayer(); + let relayer_b = wallets_b.relayer(); + + let balance_a1 = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; + + let send_amount = random_u128_range(1000, 2000); + + { + let res = chain_driver_b.register_counterparty_payee( + &relayer_b, + &relayer_a.address(), + &channel_id_b, + &port_b, + ); + + assert!(res.is_err()); + } + + { + let res = chain_driver_a.ibc_token_transfer_with_fee( + &port_a, + &channel_id_a, + &user_a, + &user_b.address(), + &denom_a.with_amount(send_amount).as_ref(), + &denom_a.with_amount(10u64).as_ref(), + &denom_a.with_amount(10u64).as_ref(), + &denom_a.with_amount(10u64).as_ref(), + Duration::from_secs(60), + ); + + assert!(res.is_err()); + } + + let balance_a2 = balance_a1 - send_amount; + + chain_driver_a.ibc_transfer_token( + &port_a, + &channel_id_a, + &user_a, + &user_b.address(), + &denom_a.with_amount(send_amount).as_ref(), + )?; + + let denom_b = derive_ibc_denom( + &channel.port_b.as_ref(), + &channel.channel_id_b.as_ref(), + &denom_a, + )?; + + chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a2.as_ref())?; + + chain_driver_b.assert_eventual_wallet_amount( + &user_b.address(), + &denom_b.with_amount(send_amount).as_ref(), + )?; + + Ok(()) + } +} diff --git a/tools/integration-test/src/tests/fee/pay_fee_async.rs b/tools/integration-test/src/tests/fee/pay_fee_async.rs new file mode 100644 index 0000000000..fb895f05e6 --- /dev/null +++ b/tools/integration-test/src/tests/fee/pay_fee_async.rs @@ -0,0 +1,222 @@ +use ibc::core::ics04_channel::Version; +use ibc::events::IbcEvent; +use ibc_test_framework::prelude::*; +use ibc_test_framework::util::random::random_u128_range; + +#[test] +fn test_pay_packet_fee_async() -> Result<(), Error> { + run_binary_channel_test(&PayPacketFeeAsyncTest) +} + +struct PayPacketFeeAsyncTest; + +impl TestOverrides for PayPacketFeeAsyncTest { + fn should_spawn_supervisor(&self) -> bool { + false + } + + fn channel_version(&self) -> Version { + Version::ics20_with_fee() + } +} + +impl BinaryChannelTest for PayPacketFeeAsyncTest { + fn run( + &self, + _config: &TestConfig, + relayer: RelayerDriver, + chains: ConnectedChains, + channel: ConnectedChannel, + ) -> Result<(), Error> { + let chain_driver_a = chains.node_a.chain_driver(); + let chain_driver_b = chains.node_b.chain_driver(); + + let chain_id_a = chain_driver_a.chain_id(); + let chain_id_b = chain_driver_b.chain_id(); + + let denom_a = chains.node_a.denom(); + + let port_a = channel.port_a.as_ref(); + let port_b = channel.port_b.as_ref(); + let channel_id_a = channel.channel_id_a.as_ref(); + + let channel_id_b = channel.channel_id_b.as_ref(); + + let wallets_a = chains.node_a.wallets(); + let wallets_b = chains.node_b.wallets(); + + let relayer_a = wallets_a.relayer(); + let relayer_b = wallets_b.relayer(); + + info!( + "registering counterparty address of relayer {} on chain {} to be {} on chain {}", + relayer_b.address(), + chain_id_b, + relayer_a.address(), + chain_id_a + ); + + chain_driver_b.register_counterparty_payee( + &relayer_b, + &relayer_a.address(), + &channel_id_b, + &port_b, + )?; + + let user_a = wallets_a.user1(); + + let user_b = wallets_b.user1(); + + let balance_a1 = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; + + let relayer_balance_a = chain_driver_a.query_balance(&relayer_a.address(), &denom_a)?; + + let send_amount = random_u128_range(1000, 2000); + let receive_fee = random_u128_range(300, 400); + let ack_fee = random_u128_range(200, 300); + let timeout_fee = random_u128_range(100, 200); + + let events = chain_driver_a.ibc_token_transfer_with_fee( + &port_a, + &channel_id_a, + &user_a, + &user_b.address(), + &denom_a.with_amount(send_amount).as_ref(), + &denom_a.with_amount(receive_fee).as_ref(), + &denom_a.with_amount(ack_fee).as_ref(), + &denom_a.with_amount(timeout_fee).as_ref(), + Duration::from_secs(60), + )?; + + let total_sent = send_amount + receive_fee + ack_fee + timeout_fee; + let balance_a2 = balance_a1 - total_sent; + + chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a2.as_ref())?; + + let sequence = { + let send_packet_event = events + .iter() + .find_map(|event| match event { + IbcEvent::SendPacket(e) => Some(e), + _ => None, + }) + .ok_or_else(|| eyre!("expect send packet event"))?; + + send_packet_event.packet.sequence + }; + + { + let event = events + .iter() + .find_map(|ev| { + if let IbcEvent::IncentivizedPacket(ev) = ev { + Some(ev) + } else { + None + } + }) + .unwrap(); + + info!("incentivized packet event: {:?}", event); + + assert_eq!(event.sequence, sequence); + + assert_eq!(event.total_recv_fee.len(), 1); + assert_eq!(event.total_ack_fee.len(), 1); + assert_eq!(event.total_timeout_fee.len(), 1); + + assert_eq!( + &event.total_recv_fee[0], + &denom_a.with_amount(receive_fee).as_coin(), + ); + assert_eq!( + &event.total_ack_fee[0], + &denom_a.with_amount(ack_fee).as_coin() + ); + + assert_eq!( + &event.total_timeout_fee[0], + &denom_a.with_amount(timeout_fee).as_coin(), + ); + } + + { + let packets = chain_driver_a.query_incentivized_packets(&channel_id_a, &port_a)?; + + assert_eq!(packets.len(), 1); + + let packet = &packets[0]; + assert_eq!(packet.packet_id.sequence, sequence); + + assert_eq!(packet.packet_fees.len(), 1); + let packet_fee = &packet.packet_fees[0]; + + assert_eq!(packet_fee.fee.recv_fee.len(), 1); + assert_eq!(packet_fee.fee.ack_fee.len(), 1); + assert_eq!(packet_fee.fee.timeout_fee.len(), 1); + + assert_eq!( + &packet_fee.fee.recv_fee[0], + &denom_a.with_amount(receive_fee).as_coin(), + ); + assert_eq!( + &packet_fee.fee.ack_fee[0], + &denom_a.with_amount(ack_fee).as_coin() + ); + + assert_eq!( + &packet_fee.fee.timeout_fee[0], + &denom_a.with_amount(timeout_fee).as_coin(), + ); + + assert_eq!( + packet_fee.refund_address.as_ref(), + user_a.value().address.as_str(), + ); + } + + let receive_fee_2 = random_u128_range(300, 400); + let ack_fee_2 = random_u128_range(200, 300); + let timeout_fee_2 = random_u128_range(100, 200); + + chain_driver_a.pay_packet_fee( + &port_a, + &channel_id_a, + &DualTagged::new(sequence), + &user_a, + &denom_a.with_amount(receive_fee_2).as_ref(), + &denom_a.with_amount(ack_fee_2).as_ref(), + &denom_a.with_amount(timeout_fee_2).as_ref(), + )?; + + let total_sent_2 = receive_fee_2 + ack_fee_2 + timeout_fee_2; + let balance_a3 = balance_a2 - total_sent_2; + + chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a3.as_ref())?; + + let denom_b = derive_ibc_denom( + &channel.port_b.as_ref(), + &channel.channel_id_b.as_ref(), + &denom_a, + )?; + + relayer.with_supervisor(|| { + chain_driver_b.assert_eventual_wallet_amount( + &user_b.address(), + &denom_b.with_amount(send_amount).as_ref(), + )?; + + chain_driver_a.assert_eventual_wallet_amount( + &user_a.address(), + &(balance_a3 + timeout_fee + timeout_fee_2).as_ref(), + )?; + + chain_driver_a.assert_eventual_wallet_amount( + &relayer_a.address(), + &(relayer_balance_a + ack_fee + receive_fee + ack_fee_2 + receive_fee_2).as_ref(), + )?; + + Ok(()) + }) + } +} diff --git a/tools/integration-test/src/tests/fee/timeout_fee.rs b/tools/integration-test/src/tests/fee/timeout_fee.rs new file mode 100644 index 0000000000..f6b4938f28 --- /dev/null +++ b/tools/integration-test/src/tests/fee/timeout_fee.rs @@ -0,0 +1,92 @@ +use ibc::core::ics04_channel::Version; +use ibc_test_framework::prelude::*; +use ibc_test_framework::util::random::random_u128_range; +use std::thread; + +#[test] +fn test_timeout_fee() -> Result<(), Error> { + run_binary_channel_test(&TimeoutFeeTest) +} + +struct TimeoutFeeTest; + +impl TestOverrides for TimeoutFeeTest { + fn should_spawn_supervisor(&self) -> bool { + false + } + + fn channel_version(&self) -> Version { + Version::ics20_with_fee() + } +} + +impl BinaryChannelTest for TimeoutFeeTest { + fn run( + &self, + _config: &TestConfig, + relayer: RelayerDriver, + chains: ConnectedChains, + channel: ConnectedChannel, + ) -> Result<(), Error> { + let chain_driver_a = chains.node_a.chain_driver(); + + let denom_a = chains.node_a.denom(); + + let port_a = channel.port_a.as_ref(); + let channel_id_a = channel.channel_id_a.as_ref(); + + let wallets_a = chains.node_a.wallets(); + let wallets_b = chains.node_b.wallets(); + + let relayer_a = wallets_a.relayer(); + + let user_a = wallets_a.user1(); + let user_b = wallets_b.user1(); + + let balance_a1 = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; + + let relayer_balance_a = chain_driver_a.query_balance(&relayer_a.address(), &denom_a)?; + + let send_amount = random_u128_range(1000, 2000); + let receive_fee = random_u128_range(300, 400); + let ack_fee = random_u128_range(200, 300); + let timeout_fee = random_u128_range(100, 200); + + let total_sent = send_amount + receive_fee + ack_fee + timeout_fee; + + let balance_a2 = balance_a1 - total_sent; + + chain_driver_a.ibc_token_transfer_with_fee( + &port_a, + &channel_id_a, + &user_a, + &user_b.address(), + &denom_a.with_amount(send_amount).as_ref(), + &denom_a.with_amount(receive_fee).as_ref(), + &denom_a.with_amount(ack_fee).as_ref(), + &denom_a.with_amount(timeout_fee).as_ref(), + Duration::from_secs(5), + )?; + + info!("Expect user A's balance after transfer: {}", balance_a2); + + chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a2.as_ref())?; + + // Sleep to wait for IBC packet to timeout before start relaying + thread::sleep(Duration::from_secs(6)); + + relayer.with_supervisor(|| { + chain_driver_a.assert_eventual_wallet_amount( + &user_a.address(), + &(balance_a2 + send_amount + receive_fee + ack_fee).as_ref(), + )?; + + chain_driver_a.assert_eventual_wallet_amount( + &relayer_a.address(), + &(relayer_balance_a + timeout_fee).as_ref(), + )?; + + Ok(()) + }) + } +} From 73b4588b75953742fb0652b46101906194beff2f Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Fri, 17 Jun 2022 17:12:42 +0200 Subject: [PATCH 072/113] Fix fee tests not running on CI, and fix test_auto_forward_relayer --- .github/workflows/integration.yaml | 4 ++-- modules/src/core/ics04_channel/version.rs | 28 +++++++++++++++++++---- relayer/src/link.rs | 8 +++++++ tools/test-framework/src/chain/driver.rs | 2 +- 4 files changed, 34 insertions(+), 8 deletions(-) diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml index 3cea66452d..484d7e1015 100644 --- a/.github/workflows/integration.yaml +++ b/.github/workflows/integration.yaml @@ -195,7 +195,7 @@ jobs: - uses: actions-rs/cargo@v1 with: command: test - args: -p ibc-integration-test --no-fail-fast --no-run + args: -p ibc-integration-test --features ics29-fee --no-fail-fast --no-run - env: RUST_LOG: info RUST_BACKTRACE: 1 @@ -204,7 +204,7 @@ jobs: run: | nix shell .#ibc-go-main-simapp -c cargo \ test -p ibc-integration-test --features ics29-fee --no-fail-fast -- \ - --nocapture --test-threads=1 test_channel_with_fee + --nocapture --test-threads=1 fee:: model-based-test: runs-on: ubuntu-latest diff --git a/modules/src/core/ics04_channel/version.rs b/modules/src/core/ics04_channel/version.rs index ae88e562a7..2852631367 100644 --- a/modules/src/core/ics04_channel/version.rs +++ b/modules/src/core/ics04_channel/version.rs @@ -17,7 +17,7 @@ use crate::prelude::*; /// No explicit validation is necessary, and the /// spec (v1) currently allows empty strings. #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] -pub struct Version(String); +pub struct Version(pub String); impl Version { pub fn new(v: String) -> Self { @@ -30,8 +30,8 @@ impl Version { pub fn ics20_with_fee() -> Self { let val = json::json!({ - "feeVersion": "ics29-1", - "appVersion": transfer::VERSION, + "fee_version": "ics29-1", + "app_version": transfer::VERSION, }); Self::new(val.to_string()) @@ -45,9 +45,9 @@ impl Version { json::from_str::(&self.0) .ok() .and_then(|val| { - let _app_version = val.get("appVersion")?.as_str()?; + let _app_version = val.get("app_version")?.as_str()?; - let fee_version = val.get("feeVersion")?.as_str()?; + let fee_version = val.get("fee_version")?.as_str()?; Some(fee_version == "ics29-1") }) @@ -81,3 +81,21 @@ impl fmt::Display for Version { write!(f, "{}", self.0) } } + +#[cfg(test)] +mod test { + use super::Version; + + #[test] + fn test_ics29_version() { + { + let version = Version::ics20(); + assert!(!version.supports_fee()); + } + + { + let version = Version::ics20_with_fee(); + assert!(version.supports_fee()); + } + } +} diff --git a/relayer/src/link.rs b/relayer/src/link.rs index 71ed619c70..1a8603dcb7 100644 --- a/relayer/src/link.rs +++ b/relayer/src/link.rs @@ -6,6 +6,7 @@ use ibc::{ }, Height, }; +use tracing::info; use crate::chain::requests::QueryChannelRequest; use crate::chain::{counterparty::check_channel_counterparty, requests::QueryConnectionRequest}; @@ -148,6 +149,13 @@ impl Link { if auto_register_counterparty_payee && a_channel.version.supports_fee() { let address_a = a_chain.get_signer().map_err(LinkError::relayer)?; + info!( + "auto registering counterparty payee on chain {} as {} on chain {}", + b_chain.id(), + address_a, + a_chain.id() + ); + b_chain .maybe_register_counterparty_payee(b_channel_id, b_port_id, address_a) .map_err(LinkError::relayer)?; diff --git a/tools/test-framework/src/chain/driver.rs b/tools/test-framework/src/chain/driver.rs index 4396a8af16..f78b1c3841 100644 --- a/tools/test-framework/src/chain/driver.rs +++ b/tools/test-framework/src/chain/driver.rs @@ -32,7 +32,7 @@ use crate::util::retry::assert_eventually_succeed; test is taking much longer to reach eventual consistency, it might be indication of some underlying performance issues. */ -const WAIT_WALLET_AMOUNT_ATTEMPTS: u16 = 180; +const WAIT_WALLET_AMOUNT_ATTEMPTS: u16 = 90; /** A driver for interacting with a chain full nodes through command line. From bcf88117eb9b967f3e393bba816fc3e89fe59791 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Mon, 20 Jun 2022 13:25:01 +0200 Subject: [PATCH 073/113] Test incentivized packet event after pay packet fee async --- .../src/tests/fee/pay_fee_async.rs | 39 +++++++++++++++++-- tools/test-framework/src/chain/ext/fee.rs | 4 +- tools/test-framework/src/relayer/fee.rs | 6 +-- 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/tools/integration-test/src/tests/fee/pay_fee_async.rs b/tools/integration-test/src/tests/fee/pay_fee_async.rs index fb895f05e6..325b04b247 100644 --- a/tools/integration-test/src/tests/fee/pay_fee_async.rs +++ b/tools/integration-test/src/tests/fee/pay_fee_async.rs @@ -115,9 +115,7 @@ impl BinaryChannelTest for PayPacketFeeAsyncTest { None } }) - .unwrap(); - - info!("incentivized packet event: {:?}", event); + .ok_or_else(|| eyre!("expect incentivized packet event"))?; assert_eq!(event.sequence, sequence); @@ -179,7 +177,7 @@ impl BinaryChannelTest for PayPacketFeeAsyncTest { let ack_fee_2 = random_u128_range(200, 300); let timeout_fee_2 = random_u128_range(100, 200); - chain_driver_a.pay_packet_fee( + let events2 = chain_driver_a.pay_packet_fee( &port_a, &channel_id_a, &DualTagged::new(sequence), @@ -194,6 +192,39 @@ impl BinaryChannelTest for PayPacketFeeAsyncTest { chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a3.as_ref())?; + { + let event = events2 + .iter() + .find_map(|ev| { + if let IbcEvent::IncentivizedPacket(ev) = ev { + Some(ev) + } else { + None + } + }) + .ok_or_else(|| eyre!("expect incentivized packet event"))?; + + assert_eq!(event.sequence, sequence); + + assert_eq!(event.total_recv_fee.len(), 1); + assert_eq!(event.total_ack_fee.len(), 1); + assert_eq!(event.total_timeout_fee.len(), 1); + + assert_eq!( + &event.total_recv_fee[0], + &denom_a.with_amount(receive_fee + receive_fee_2).as_coin(), + ); + assert_eq!( + &event.total_ack_fee[0], + &denom_a.with_amount(ack_fee + ack_fee_2).as_coin() + ); + + assert_eq!( + &event.total_timeout_fee[0], + &denom_a.with_amount(timeout_fee + timeout_fee_2).as_coin(), + ); + } + let denom_b = derive_ibc_denom( &channel.port_b.as_ref(), &channel.channel_id_b.as_ref(), diff --git a/tools/test-framework/src/chain/ext/fee.rs b/tools/test-framework/src/chain/ext/fee.rs index 02c3fb5d86..411a89ecbb 100644 --- a/tools/test-framework/src/chain/ext/fee.rs +++ b/tools/test-framework/src/chain/ext/fee.rs @@ -38,7 +38,7 @@ pub trait ChainFeeMethodsExt { receive_fee: &TaggedTokenRef<'_, Chain>, ack_fee: &TaggedTokenRef<'_, Chain>, timeout_fee: &TaggedTokenRef<'_, Chain>, - ) -> Result<(), Error>; + ) -> Result, Error>; fn register_counterparty_payee( &self, @@ -97,7 +97,7 @@ impl<'a, Chain: Send> ChainFeeMethodsExt for MonoTagged, ack_fee: &TaggedTokenRef<'_, Chain>, timeout_fee: &TaggedTokenRef<'_, Chain>, - ) -> Result<(), Error> { + ) -> Result, Error> { self.value().runtime.block_on(pay_packet_fee( &self.tx_config(), port_id, diff --git a/tools/test-framework/src/relayer/fee.rs b/tools/test-framework/src/relayer/fee.rs index 873693c834..d59bfb04fc 100644 --- a/tools/test-framework/src/relayer/fee.rs +++ b/tools/test-framework/src/relayer/fee.rs @@ -66,7 +66,7 @@ pub async fn pay_packet_fee( receive_fee: &TaggedTokenRef<'_, Chain>, ack_fee: &TaggedTokenRef<'_, Chain>, timeout_fee: &TaggedTokenRef<'_, Chain>, -) -> Result<(), Error> { +) -> Result, Error> { let message = build_pay_packet_fee_async_message( port_id.value(), channel_id.value(), @@ -83,9 +83,7 @@ pub async fn pay_packet_fee( ) .map_err(handle_generic_error)?; - simple_send_tx(tx_config.value(), &payer.value().key, vec![message]).await?; - - Ok(()) + simple_send_tx(tx_config.value(), &payer.value().key, vec![message]).await } pub async fn register_counterparty_payee( From f3a6cea851db9557688e8c0f46e6c96c1ca7e71a Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Fri, 24 Jun 2022 11:57:52 +0200 Subject: [PATCH 074/113] Fix merge error --- relayer/src/chain/cosmos/query/tx.rs | 3 +-- relayer/src/chain/cosmos/wait.rs | 4 ---- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/relayer/src/chain/cosmos/query/tx.rs b/relayer/src/chain/cosmos/query/tx.rs index 98d227c1a5..5c70be025a 100644 --- a/relayer/src/chain/cosmos/query/tx.rs +++ b/relayer/src/chain/cosmos/query/tx.rs @@ -3,7 +3,6 @@ use ibc::core::ics04_channel::events as ChannelEvents; use ibc::core::ics04_channel::packet::{Packet, Sequence}; use ibc::core::ics24_host::identifier::ChainId; use ibc::events::{from_tx_response_event, IbcEvent}; -use ibc::query::{QueryTxHash, QueryTxRequest}; use ibc::Height as ICSHeight; use tendermint::abci::transaction::Hash as TxHash; use tendermint::abci::Event; @@ -14,7 +13,7 @@ use tracing::trace; use crate::chain::cosmos::query::{header_query, packet_query, tx_hash_query}; use crate::chain::requests::{ - QueryClientEventRequest, QueryHeight, QueryPacketEventDataRequest, QueryTxRequest, + QueryClientEventRequest, QueryHeight, QueryPacketEventDataRequest, QueryTxHash, QueryTxRequest, }; use crate::error::Error; diff --git a/relayer/src/chain/cosmos/wait.rs b/relayer/src/chain/cosmos/wait.rs index 785c246327..f9cf1d0473 100644 --- a/relayer/src/chain/cosmos/wait.rs +++ b/relayer/src/chain/cosmos/wait.rs @@ -2,8 +2,6 @@ use core::time::Duration; use futures::stream::{FuturesOrdered, StreamExt}; use ibc::core::ics24_host::identifier::ChainId; use ibc::events::IbcEvent; -use itertools::Itertools; -use std::thread; use std::time::Instant; use tendermint::abci::transaction::Hash as TxHash; use tendermint_rpc::endpoint::tx::Response as TxResponse; @@ -13,8 +11,6 @@ use tokio::time::sleep; use tracing::info; use crate::chain::cosmos::query::tx::{all_ibc_events_from_tx_search_response, query_tx_response}; -use crate::chain::cosmos::types::tx::TxSyncResult; -use crate::chain::requests::{QueryTxHash, QueryTxRequest}; use crate::error::Error; const WAIT_BACKOFF: Duration = Duration::from_millis(300); From 5021049a19e5326901d833bf1d3957ed074d0f1f Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Fri, 24 Jun 2022 11:57:59 +0200 Subject: [PATCH 075/113] Update ibc-go --- flake.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/flake.lock b/flake.lock index 3f0d2a4821..4ecb5a1982 100644 --- a/flake.lock +++ b/flake.lock @@ -75,11 +75,11 @@ "wasmvm_1_beta7-src": "wasmvm_1_beta7-src" }, "locked": { - "lastModified": 1655296674, - "narHash": "sha256-yUROp+8agaaf6N5p0NB5dyDt3v3clp8maU1yQA16Hc4=", + "lastModified": 1656064272, + "narHash": "sha256-/Ny22b7Nxt0q0vNU9q5eIlyf8e1FJKWMO9WUmpMSUKA=", "owner": "informalsystems", "repo": "cosmos.nix", - "rev": "da3a0758136fe7152203c689a3cea91547b070c9", + "rev": "85d5dd413bf77ea7aefe93be8fb374743993616b", "type": "github" }, "original": { @@ -273,11 +273,11 @@ "ibc-go-main-src": { "flake": false, "locked": { - "lastModified": 1655287744, - "narHash": "sha256-7HuNg2h2I2mYO/dql1P4aHfuFn/WlqhlA3kQ4upqKrw=", + "lastModified": 1656015845, + "narHash": "sha256-5y+7CrbXW7Gy6IzLavd/b1jWWQemrjXxcpAnSc2JLzI=", "owner": "cosmos", "repo": "ibc-go", - "rev": "a71fc1029ad1fc6d377d642781d02ad3cbfa0910", + "rev": "20ffa6f1aca8adddccdcd714488eead2256a420d", "type": "github" }, "original": { @@ -438,11 +438,11 @@ }, "nixpkgs_3": { "locked": { - "lastModified": 1655332021, - "narHash": "sha256-LZcCR0/4oQUrmmyBBGdGcMYz0fJA0pdhb4PLaPvjrq0=", + "lastModified": 1655567057, + "narHash": "sha256-Cc5hQSMsTzOHmZnYm8OSJ5RNUp22bd5NADWLHorULWQ=", "owner": "nixos", "repo": "nixpkgs", - "rev": "f649383c5a34f3599f1142f0756535dceed2eb31", + "rev": "e0a42267f73ea52adc061a64650fddc59906fc99", "type": "github" }, "original": { From 2b4f25a239c2ad86016fae9f6af6c641f1597225 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 6 Jul 2022 12:38:05 +0200 Subject: [PATCH 076/113] Update Cosmos.nix and ibc-go version --- .github/workflows/integration.yaml | 2 +- flake.lock | 64 +++++++++++++++++++----------- flake.nix | 1 + 3 files changed, 43 insertions(+), 24 deletions(-) diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml index 484d7e1015..ae6a685780 100644 --- a/.github/workflows/integration.yaml +++ b/.github/workflows/integration.yaml @@ -202,7 +202,7 @@ jobs: NO_COLOR_LOG: 1 CHAIN_COMMAND_PATH: simd run: | - nix shell .#ibc-go-main-simapp -c cargo \ + nix shell .#ibc-go-v4-simapp -c cargo \ test -p ibc-integration-test --features ics29-fee --no-fail-fast -- \ --nocapture --test-threads=1 fee:: diff --git a/flake.lock b/flake.lock index 4ecb5a1982..b75db9e3d7 100644 --- a/flake.lock +++ b/flake.lock @@ -50,6 +50,7 @@ "ibc-go-main-src": "ibc-go-main-src", "ibc-go-v2-src": "ibc-go-v2-src", "ibc-go-v3-src": "ibc-go-v3-src", + "ibc-go-v4-src": "ibc-go-v4-src", "ibc-rs-src": "ibc-rs-src", "ica-src": "ica-src", "iris-src": "iris-src", @@ -75,11 +76,11 @@ "wasmvm_1_beta7-src": "wasmvm_1_beta7-src" }, "locked": { - "lastModified": 1656064272, - "narHash": "sha256-/Ny22b7Nxt0q0vNU9q5eIlyf8e1FJKWMO9WUmpMSUKA=", + "lastModified": 1657102239, + "narHash": "sha256-zrCFXOwH6HOwpxsn5SODC3j/yE6JZO7etmUemQ5yXdk=", "owner": "informalsystems", "repo": "cosmos.nix", - "rev": "85d5dd413bf77ea7aefe93be8fb374743993616b", + "rev": "48f3e042da77530a08fba6adb59406fe2c0d85ec", "type": "github" }, "original": { @@ -172,11 +173,11 @@ }, "flake-utils_3": { "locked": { - "lastModified": 1653893745, - "narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=", + "lastModified": 1656928814, + "narHash": "sha256-RIFfgBuKz6Hp89yRr7+NR5tzIAbn52h8vT6vXkYjZoM=", "owner": "numtide", "repo": "flake-utils", - "rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1", + "rev": "7e2a3b3dfd9af950a856d66b0a7d01e3c18aa249", "type": "github" }, "original": { @@ -256,16 +257,16 @@ "ibc-go-ics29-src": { "flake": false, "locked": { - "lastModified": 1652196479, - "narHash": "sha256-kdSJwSIA2MvPFLguvCPe6TnzMkmQI3pIVJNhN/B7gwU=", + "lastModified": 1655712472, + "narHash": "sha256-1KoCoWezR+A+rwy2U77kZrmckcwtOc2brfpiksUHmOk=", "owner": "cosmos", "repo": "ibc-go", - "rev": "dcd0681d8f07c624f53b9a9ffe9de2f122486207", + "rev": "6c034bc085e1701a7cbaa26476eb33e958b3a57c", "type": "github" }, "original": { "owner": "cosmos", - "ref": "ics29-beta2", + "ref": "ics29-beta3", "repo": "ibc-go", "type": "github" } @@ -273,11 +274,11 @@ "ibc-go-main-src": { "flake": false, "locked": { - "lastModified": 1656015845, - "narHash": "sha256-5y+7CrbXW7Gy6IzLavd/b1jWWQemrjXxcpAnSc2JLzI=", + "lastModified": 1657010958, + "narHash": "sha256-N+f1EeX6qJVBJXpJISlpqgerNJuapYG7MaDJqZt5tCM=", "owner": "cosmos", "repo": "ibc-go", - "rev": "20ffa6f1aca8adddccdcd714488eead2256a420d", + "rev": "7d181821314d4bc6d0f8a5b885f293f5b975aed0", "type": "github" }, "original": { @@ -306,16 +307,33 @@ "ibc-go-v3-src": { "flake": false, "locked": { - "lastModified": 1647356202, - "narHash": "sha256-wX3kUzK5dkPeNgmBGP0mE8QeNR4LRo1obVGasZSLSpE=", + "lastModified": 1655212180, + "narHash": "sha256-68YXAToz6p5cmiFEkdfMmcAsOb8EnLYLls5695V94CY=", "owner": "cosmos", "repo": "ibc-go", - "rev": "46e020640e66f9043c14c53a4d215a5b457d6703", + "rev": "bf062ad92329a659b3b20122b7c3bc5823c040e1", "type": "github" }, "original": { "owner": "cosmos", - "ref": "v3.0.0", + "ref": "v3.1.0", + "repo": "ibc-go", + "type": "github" + } + }, + "ibc-go-v4-src": { + "flake": false, + "locked": { + "lastModified": 1656924495, + "narHash": "sha256-WeIpJOgLO3hNbSfkrnzRcXE3NrBago9nhdtT2XDDXKA=", + "owner": "cosmos", + "repo": "ibc-go", + "rev": "efda07d984a65ad4099fc6d9c82f71a28d66a411", + "type": "github" + }, + "original": { + "owner": "cosmos", + "ref": "v4.0.0-rc0", "repo": "ibc-go", "type": "github" } @@ -406,11 +424,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1648219316, - "narHash": "sha256-Ctij+dOi0ZZIfX5eMhgwugfvB+WZSrvVNAyAuANOsnQ=", + "lastModified": 1657056915, + "narHash": "sha256-pzpuGI0+UHNlWae91QYeAlK0rY0FGZJAhHfRArHNwKY=", "owner": "nixos", "repo": "nixpkgs", - "rev": "30d3d79b7d3607d56546dd2a6b49e156ba0ec634", + "rev": "c9ad20e7ebbe27a29d12353d15cdc853f896291b", "type": "github" }, "original": { @@ -438,11 +456,11 @@ }, "nixpkgs_3": { "locked": { - "lastModified": 1655567057, - "narHash": "sha256-Cc5hQSMsTzOHmZnYm8OSJ5RNUp22bd5NADWLHorULWQ=", + "lastModified": 1657056915, + "narHash": "sha256-pzpuGI0+UHNlWae91QYeAlK0rY0FGZJAhHfRArHNwKY=", "owner": "nixos", "repo": "nixpkgs", - "rev": "e0a42267f73ea52adc061a64650fddc59906fc99", + "rev": "c9ad20e7ebbe27a29d12353d15cdc853f896291b", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 4f8c0ed3c4..b389502cf4 100644 --- a/flake.nix +++ b/flake.nix @@ -36,6 +36,7 @@ gaia6-ordered ibc-go-v2-simapp ibc-go-v3-simapp + ibc-go-v4-simapp ibc-go-main-simapp ibc-go-ics29-simapp wasmd From d5ee5f57a08d055144d6627236cea2e829d3080c Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 6 Jul 2022 19:19:14 +0200 Subject: [PATCH 077/113] Update Cosmos.nix --- flake.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index b75db9e3d7..8b8f387244 100644 --- a/flake.lock +++ b/flake.lock @@ -76,11 +76,11 @@ "wasmvm_1_beta7-src": "wasmvm_1_beta7-src" }, "locked": { - "lastModified": 1657102239, - "narHash": "sha256-zrCFXOwH6HOwpxsn5SODC3j/yE6JZO7etmUemQ5yXdk=", + "lastModified": 1657103197, + "narHash": "sha256-37Og2DnucAcZSGDeAn/HXfVl7a/THLN9sNSCC/WUv/E=", "owner": "informalsystems", "repo": "cosmos.nix", - "rev": "48f3e042da77530a08fba6adb59406fe2c0d85ec", + "rev": "27201c38a38e1901f7eb2e2d7b53a6fdd99a5845", "type": "github" }, "original": { @@ -456,11 +456,11 @@ }, "nixpkgs_3": { "locked": { - "lastModified": 1657056915, - "narHash": "sha256-pzpuGI0+UHNlWae91QYeAlK0rY0FGZJAhHfRArHNwKY=", + "lastModified": 1657086189, + "narHash": "sha256-wSiZ7wBqke9qCDOyYhAU68HT63iZQWrsxG6NlTfBzto=", "owner": "nixos", "repo": "nixpkgs", - "rev": "c9ad20e7ebbe27a29d12353d15cdc853f896291b", + "rev": "e120ef6a5a7d835e19082d037f6a079e836ce8ca", "type": "github" }, "original": { From cee8e3e3de627360365a202c390cd8a24cb9f697 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Mon, 18 Jul 2022 12:26:11 +0200 Subject: [PATCH 078/113] Fix merge error --- proto/src/lib.rs | 5 +++++ relayer-cli/src/commands/tx/transfer.rs | 16 ++++++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/proto/src/lib.rs b/proto/src/lib.rs index 982562f05a..abf163e681 100644 --- a/proto/src/lib.rs +++ b/proto/src/lib.rs @@ -137,6 +137,11 @@ pub mod ibc { include_proto!("ibc.applications.transfer.v2.rs"); } } + pub mod fee { + pub mod v1 { + include_proto!("ibc.applications.fee.v1.rs"); + } + } pub mod interchain_accounts { pub mod v1 { include_proto!("ibc.applications.interchain_accounts.v1.rs"); diff --git a/relayer-cli/src/commands/tx/transfer.rs b/relayer-cli/src/commands/tx/transfer.rs index 3555f69850..c752063d65 100644 --- a/relayer-cli/src/commands/tx/transfer.rs +++ b/relayer-cli/src/commands/tx/transfer.rs @@ -297,7 +297,7 @@ mod tests { src_chain_id: ChainId::from_string("chain_sender"), src_port_id: PortId::from_str("port_sender").unwrap(), src_channel_id: ChannelId::from_str("channel_sender").unwrap(), - amount: Amount::from(42), + amount: Amount::from(42u64), timeout_height_offset: 0, timeout_seconds: 0, receiver: None, @@ -329,7 +329,7 @@ mod tests { src_chain_id: ChainId::from_string("chain_sender"), src_port_id: PortId::from_str("port_sender").unwrap(), src_channel_id: ChannelId::from_str("channel_sender").unwrap(), - amount: Amount::from(42), + amount: Amount::from(42u64), timeout_height_offset: 0, timeout_seconds: 0, receiver: None, @@ -361,7 +361,7 @@ mod tests { src_chain_id: ChainId::from_string("chain_sender"), src_port_id: PortId::from_str("port_sender").unwrap(), src_channel_id: ChannelId::from_str("channel_sender").unwrap(), - amount: Amount::from(42), + amount: Amount::from(42u64), timeout_height_offset: 0, timeout_seconds: 0, receiver: None, @@ -395,7 +395,7 @@ mod tests { src_chain_id: ChainId::from_string("chain_sender"), src_port_id: PortId::from_str("port_sender").unwrap(), src_channel_id: ChannelId::from_str("channel_sender").unwrap(), - amount: Amount::from(42), + amount: Amount::from(42u64), timeout_height_offset: 0, timeout_seconds: 0, receiver: None, @@ -429,7 +429,7 @@ mod tests { src_chain_id: ChainId::from_string("chain_sender"), src_port_id: PortId::from_str("port_sender").unwrap(), src_channel_id: ChannelId::from_str("channel_sender").unwrap(), - amount: Amount::from(42), + amount: Amount::from(42u64), timeout_height_offset: 0, timeout_seconds: 0, receiver: None, @@ -463,7 +463,7 @@ mod tests { src_chain_id: ChainId::from_string("chain_sender"), src_port_id: PortId::from_str("port_sender").unwrap(), src_channel_id: ChannelId::from_str("channel_sender").unwrap(), - amount: Amount::from(42), + amount: Amount::from(42u64), timeout_height_offset: 0, timeout_seconds: 0, receiver: Some("receiver_addr".to_owned()), @@ -497,7 +497,7 @@ mod tests { src_chain_id: ChainId::from_string("chain_sender"), src_port_id: PortId::from_str("port_sender").unwrap(), src_channel_id: ChannelId::from_str("channel_sender").unwrap(), - amount: Amount::from(42), + amount: Amount::from(42u64), timeout_height_offset: 21, timeout_seconds: 0, receiver: None, @@ -531,7 +531,7 @@ mod tests { src_chain_id: ChainId::from_string("chain_sender"), src_port_id: PortId::from_str("port_sender").unwrap(), src_channel_id: ChannelId::from_str("channel_sender").unwrap(), - amount: Amount::from(42), + amount: Amount::from(42u64), timeout_height_offset: 0, timeout_seconds: 21, receiver: None, From 6f79ebb2cebde8da3a320746fdb33c3e9c1796bf Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Mon, 18 Jul 2022 13:00:43 +0200 Subject: [PATCH 079/113] Use back Cosmos.nix master --- flake.lock | 51 ++++++++++++++-------------- flake.nix | 3 +- relayer/src/chain/cosmos/query/tx.rs | 3 -- 3 files changed, 26 insertions(+), 31 deletions(-) diff --git a/flake.lock b/flake.lock index 8b8f387244..e55f226f16 100644 --- a/flake.lock +++ b/flake.lock @@ -46,7 +46,6 @@ "gaia6-ordered-src": "gaia6-ordered-src", "gaia6-src": "gaia6-src", "gaia7-src": "gaia7-src", - "ibc-go-ics29-src": "ibc-go-ics29-src", "ibc-go-main-src": "ibc-go-main-src", "ibc-go-v2-src": "ibc-go-v2-src", "ibc-go-v3-src": "ibc-go-v3-src", @@ -73,19 +72,19 @@ "umee-src": "umee-src", "wasmd-src": "wasmd-src", "wasmvm_0_16_3-src": "wasmvm_0_16_3-src", + "wasmvm_1-src": "wasmvm_1-src", "wasmvm_1_beta7-src": "wasmvm_1_beta7-src" }, "locked": { - "lastModified": 1657103197, - "narHash": "sha256-37Og2DnucAcZSGDeAn/HXfVl7a/THLN9sNSCC/WUv/E=", + "lastModified": 1658141978, + "narHash": "sha256-3VtU3PVwsUtIU1NN5dmJjZ4RDTlnxRNZRox1J7F877M=", "owner": "informalsystems", "repo": "cosmos.nix", - "rev": "27201c38a38e1901f7eb2e2d7b53a6fdd99a5845", + "rev": "74e7257cd4305697857fa17e9b8a931ae4d553a7", "type": "github" }, "original": { "owner": "informalsystems", - "ref": "ibc-go-ics29-simapp", "repo": "cosmos.nix", "type": "github" } @@ -254,23 +253,6 @@ "type": "github" } }, - "ibc-go-ics29-src": { - "flake": false, - "locked": { - "lastModified": 1655712472, - "narHash": "sha256-1KoCoWezR+A+rwy2U77kZrmckcwtOc2brfpiksUHmOk=", - "owner": "cosmos", - "repo": "ibc-go", - "rev": "6c034bc085e1701a7cbaa26476eb33e958b3a57c", - "type": "github" - }, - "original": { - "owner": "cosmos", - "ref": "ics29-beta3", - "repo": "ibc-go", - "type": "github" - } - }, "ibc-go-main-src": { "flake": false, "locked": { @@ -724,16 +706,16 @@ "wasmd-src": { "flake": false, "locked": { - "lastModified": 1646852618, - "narHash": "sha256-3ifvKZhdv50E6yA8jDiVnartZZ34Ji09VJbtkkW7Lig=", + "lastModified": 1652950226, + "narHash": "sha256-hN7XJDoZ8El2tvwJnW67abhwg37e1ckFyreytN2AwZ0=", "owner": "CosmWasm", "repo": "wasmd", - "rev": "3bc0bdeab3fa2b3f7de745622226ff36c2ec6d6a", + "rev": "d63bea442bedf5b3055f3821472c7e6cafc3d813", "type": "github" }, "original": { "owner": "CosmWasm", - "ref": "v0.24.0", + "ref": "v0.27.0", "repo": "wasmd", "type": "github" } @@ -755,6 +737,23 @@ "type": "github" } }, + "wasmvm_1-src": { + "flake": false, + "locked": { + "lastModified": 1652698028, + "narHash": "sha256-4m64mPwFLz7aZEKVxM2lJQtX98BkhdKTZb3evpDOk/4=", + "owner": "CosmWasm", + "repo": "wasmvm", + "rev": "bc49a2f4842d023c0038798f343b56f3f0530646", + "type": "github" + }, + "original": { + "owner": "CosmWasm", + "ref": "v1.0.0", + "repo": "wasmvm", + "type": "github" + } + }, "wasmvm_1_beta7-src": { "flake": false, "locked": { diff --git a/flake.nix b/flake.nix index b389502cf4..a9d0d336ae 100644 --- a/flake.nix +++ b/flake.nix @@ -4,7 +4,7 @@ inputs = { nixpkgs.url = github:nixos/nixpkgs/nixpkgs-unstable; flake-utils.url = github:numtide/flake-utils; - cosmos-nix.url = github:informalsystems/cosmos.nix/ibc-go-ics29-simapp; + cosmos-nix.url = github:informalsystems/cosmos.nix; }; outputs = inputs: @@ -38,7 +38,6 @@ ibc-go-v3-simapp ibc-go-v4-simapp ibc-go-main-simapp - ibc-go-ics29-simapp wasmd apalache ; diff --git a/relayer/src/chain/cosmos/query/tx.rs b/relayer/src/chain/cosmos/query/tx.rs index ecb9730a29..136668322b 100644 --- a/relayer/src/chain/cosmos/query/tx.rs +++ b/relayer/src/chain/cosmos/query/tx.rs @@ -8,7 +8,6 @@ use tendermint::abci::transaction::Hash as TxHash; use tendermint::abci::Event; use tendermint_rpc::endpoint::tx::Response as TxResponse; use tendermint_rpc::{Client, HttpClient, Order, Url}; -use tracing::trace; use crate::chain::cosmos::query::{header_query, packet_query, tx_hash_query}; use crate::chain::requests::{ @@ -124,8 +123,6 @@ pub async fn query_txs( .await .map_err(|e| Error::rpc(rpc_address.clone(), e))?; - trace!("response from tx_hash_query for {:?}: {:?}", tx, response); - if response.txs.is_empty() { Ok(vec![]) } else { From cee2262c253ec9b3e59461de4ef81ecd040e41ee Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Mon, 18 Jul 2022 13:11:36 +0200 Subject: [PATCH 080/113] Enable general CI test for ibc-go-v4-simapp --- .github/workflows/integration.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml index ae6a685780..d94fb86e48 100644 --- a/.github/workflows/integration.yaml +++ b/.github/workflows/integration.yaml @@ -83,6 +83,7 @@ jobs: simapp: - ibc-go-v2-simapp - ibc-go-v3-simapp + - ibc-go-v4-simapp steps: - uses: actions/checkout@v2 - uses: cachix/install-nix-action@v15 From 6d85debdc141debdb1293f017fb2efbeca2bbdf7 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Mon, 18 Jul 2022 16:14:34 +0200 Subject: [PATCH 081/113] Add register payee test --- .../src/applications/ics29_fee/msgs/mod.rs | 2 +- ...ster_counterparty.rs => register_payee.rs} | 31 +++- relayer/src/chain/cosmos/fee.rs | 2 +- tools/integration-test/src/tests/fee/mod.rs | 12 +- .../src/tests/fee/register_payee.rs | 153 ++++++++++++++++++ tools/test-framework/src/chain/ext/fee.rs | 26 ++- tools/test-framework/src/relayer/fee.rs | 31 +++- 7 files changed, 242 insertions(+), 15 deletions(-) rename modules/src/applications/ics29_fee/msgs/{register_counterparty.rs => register_payee.rs} (51%) create mode 100644 tools/integration-test/src/tests/fee/register_payee.rs diff --git a/modules/src/applications/ics29_fee/msgs/mod.rs b/modules/src/applications/ics29_fee/msgs/mod.rs index 5cac2afbab..07fb9ae248 100644 --- a/modules/src/applications/ics29_fee/msgs/mod.rs +++ b/modules/src/applications/ics29_fee/msgs/mod.rs @@ -1,3 +1,3 @@ pub mod pay_packet; pub mod pay_packet_async; -pub mod register_counterparty; +pub mod register_payee; diff --git a/modules/src/applications/ics29_fee/msgs/register_counterparty.rs b/modules/src/applications/ics29_fee/msgs/register_payee.rs similarity index 51% rename from modules/src/applications/ics29_fee/msgs/register_counterparty.rs rename to modules/src/applications/ics29_fee/msgs/register_payee.rs index fba9d6dda2..0126643811 100644 --- a/modules/src/applications/ics29_fee/msgs/register_counterparty.rs +++ b/modules/src/applications/ics29_fee/msgs/register_payee.rs @@ -1,5 +1,5 @@ use ibc_proto::google::protobuf::Any; -use ibc_proto::ibc::applications::fee::v1::MsgRegisterCounterpartyPayee; +use ibc_proto::ibc::applications::fee::v1::{MsgRegisterCounterpartyPayee, MsgRegisterPayee}; use crate::applications::ics29_fee::error::Error; use crate::core::ics24_host::identifier::{ChannelId, PortId}; @@ -7,14 +7,14 @@ use crate::prelude::*; use crate::signer::Signer; use crate::tx_msg::encode_message; -const TYPE_URL: &str = "/ibc.applications.fee.v1.MsgRegisterCounterpartyPayee"; - pub fn build_register_counterparty_payee_message( address: &Signer, counterparty_payee: &Signer, channel_id: &ChannelId, port_id: &PortId, ) -> Result { + const TYPE_URL: &str = "/ibc.applications.fee.v1.MsgRegisterCounterpartyPayee"; + let message = MsgRegisterCounterpartyPayee { relayer: address.to_string(), counterparty_payee: counterparty_payee.to_string(), @@ -31,3 +31,28 @@ pub fn build_register_counterparty_payee_message( Ok(wrapped) } + +pub fn build_register_payee_message( + address: &Signer, + payee: &Signer, + channel_id: &ChannelId, + port_id: &PortId, +) -> Result { + const TYPE_URL: &str = "/ibc.applications.fee.v1.MsgRegisterPayee"; + + let message = MsgRegisterPayee { + relayer: address.to_string(), + payee: payee.to_string(), + channel_id: channel_id.to_string(), + port_id: port_id.to_string(), + }; + + let encoded = encode_message(&message).map_err(Error::encode)?; + + let wrapped = Any { + type_url: TYPE_URL.to_string(), + value: encoded, + }; + + Ok(wrapped) +} diff --git a/relayer/src/chain/cosmos/fee.rs b/relayer/src/chain/cosmos/fee.rs index 6647d0761f..f6253f04fa 100644 --- a/relayer/src/chain/cosmos/fee.rs +++ b/relayer/src/chain/cosmos/fee.rs @@ -1,4 +1,4 @@ -use ibc::applications::ics29_fee::msgs::register_counterparty::build_register_counterparty_payee_message; +use ibc::applications::ics29_fee::msgs::register_payee::build_register_counterparty_payee_message; use ibc::core::ics24_host::identifier::{ChannelId, PortId}; use ibc::signer::Signer; diff --git a/tools/integration-test/src/tests/fee/mod.rs b/tools/integration-test/src/tests/fee/mod.rs index 1d01d3bb92..72ecc2add2 100644 --- a/tools/integration-test/src/tests/fee/mod.rs +++ b/tools/integration-test/src/tests/fee/mod.rs @@ -1,11 +1,7 @@ +pub mod auto_forward_relayer; pub mod forward_relayer; - pub mod no_forward_relayer; - -pub mod auto_forward_relayer; - -pub mod timeout_fee; - -pub mod pay_fee_async; - pub mod non_fee_channel; +pub mod pay_fee_async; +pub mod register_payee; +pub mod timeout_fee; diff --git a/tools/integration-test/src/tests/fee/register_payee.rs b/tools/integration-test/src/tests/fee/register_payee.rs new file mode 100644 index 0000000000..1d2de7ce4d --- /dev/null +++ b/tools/integration-test/src/tests/fee/register_payee.rs @@ -0,0 +1,153 @@ +use ibc::core::ics04_channel::Version; +use ibc_test_framework::prelude::*; +use ibc_test_framework::util::random::random_u128_range; + +#[test] +fn test_register_payee() -> Result<(), Error> { + run_binary_channel_test(&ForwardRelayerTest) +} + +struct ForwardRelayerTest; + +impl TestOverrides for ForwardRelayerTest { + fn channel_version(&self) -> Version { + Version::ics20_with_fee() + } +} + +impl BinaryChannelTest for ForwardRelayerTest { + fn run( + &self, + _config: &TestConfig, + _relayer: RelayerDriver, + chains: ConnectedChains, + channel: ConnectedChannel, + ) -> Result<(), Error> { + let chain_driver_a = chains.node_a.chain_driver(); + let chain_driver_b = chains.node_b.chain_driver(); + + let chain_id_a = chain_driver_a.chain_id(); + let chain_id_b = chain_driver_b.chain_id(); + + let denom_a = chains.node_a.denom(); + + let port_a = channel.port_a.as_ref(); + let port_b = channel.port_b.as_ref(); + let channel_id_a = channel.channel_id_a.as_ref(); + + let channel_id_b = channel.channel_id_b.as_ref(); + + let wallets_a = chains.node_a.wallets(); + let wallets_b = chains.node_b.wallets(); + + let relayer_a = wallets_a.relayer(); + let relayer_b = wallets_b.relayer(); + + let payee_a = wallets_a.user2(); + + info!( + "registering payee address of relayer {} on chain {} to be {}", + relayer_a.address(), + chain_id_a, + payee_a.address(), + ); + + chain_driver_a.register_payee(&relayer_a, &payee_a.address(), &channel_id_a, &port_a)?; + + { + let counterparty_payee = + chain_driver_b.query_counterparty_payee(&channel_id_b, &relayer_b.address())?; + + assert_eq( + "counterparty address should be None before registering", + &counterparty_payee, + &None, + )?; + } + + info!( + "registering counterparty address of relayer {} on chain {} to be {} on chain {}", + relayer_b.address(), + chain_id_b, + relayer_a.address(), + chain_id_a + ); + + chain_driver_b.register_counterparty_payee( + &relayer_b, + &relayer_a.address(), + &channel_id_b, + &port_b, + )?; + + { + let counterparty_payee = + chain_driver_b.query_counterparty_payee(&channel_id_b, &relayer_b.address())?; + + assert_eq( + "counterparty address should match registered address", + &counterparty_payee, + &Some(relayer_a.address().cloned()), + )?; + } + + let user_a = wallets_a.user1(); + let user_b = wallets_b.user1(); + + let balance_a1 = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; + + let relayer_balance_a = chain_driver_a.query_balance(&relayer_a.address(), &denom_a)?; + let payee_balance_a = chain_driver_a.query_balance(&payee_a.address(), &denom_a)?; + + let send_amount = random_u128_range(1000, 2000); + let receive_fee = random_u128_range(300, 400); + let ack_fee = random_u128_range(200, 300); + let timeout_fee = random_u128_range(100, 200); + + let total_sent = send_amount + receive_fee + ack_fee + timeout_fee; + + let balance_a2 = balance_a1 - total_sent; + + chain_driver_a.ibc_token_transfer_with_fee( + &port_a, + &channel_id_a, + &user_a, + &user_b.address(), + &denom_a.with_amount(send_amount).as_ref(), + &denom_a.with_amount(receive_fee).as_ref(), + &denom_a.with_amount(ack_fee).as_ref(), + &denom_a.with_amount(timeout_fee).as_ref(), + Duration::from_secs(60), + )?; + + let denom_b = derive_ibc_denom( + &channel.port_b.as_ref(), + &channel.channel_id_b.as_ref(), + &denom_a, + )?; + + chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a2.as_ref())?; + + chain_driver_b.assert_eventual_wallet_amount( + &user_b.address(), + &denom_b.with_amount(send_amount).as_ref(), + )?; + + chain_driver_a.assert_eventual_wallet_amount( + &user_a.address(), + &(balance_a2 + timeout_fee).as_ref(), + )?; + + chain_driver_a.assert_eventual_wallet_amount( + &payee_a.address(), + &(payee_balance_a + ack_fee).as_ref(), + )?; + + chain_driver_a.assert_eventual_wallet_amount( + &relayer_a.address(), + &(relayer_balance_a + receive_fee).as_ref(), + )?; + + Ok(()) + } +} diff --git a/tools/test-framework/src/chain/ext/fee.rs b/tools/test-framework/src/chain/ext/fee.rs index 411a89ecbb..297d0d62ed 100644 --- a/tools/test-framework/src/chain/ext/fee.rs +++ b/tools/test-framework/src/chain/ext/fee.rs @@ -9,7 +9,7 @@ use crate::error::Error; use crate::ibc::token::TaggedTokenRef; use crate::relayer::fee::{ ibc_token_transfer_with_fee, pay_packet_fee, query_counterparty_payee, - query_incentivized_packets, register_counterparty_payee, + query_incentivized_packets, register_counterparty_payee, register_payee, }; use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef}; use crate::types::tagged::*; @@ -48,6 +48,14 @@ pub trait ChainFeeMethodsExt { port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, ) -> Result<(), Error>; + fn register_payee( + &self, + wallet: &MonoTagged, + payee: &MonoTagged, + channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, + port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, + ) -> Result<(), Error>; + fn query_counterparty_payee( &self, channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, @@ -126,6 +134,22 @@ impl<'a, Chain: Send> ChainFeeMethodsExt for MonoTagged( + &self, + wallet: &MonoTagged, + payee: &MonoTagged, + channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, + port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, + ) -> Result<(), Error> { + self.value().runtime.block_on(register_payee( + &self.tx_config(), + wallet, + payee, + channel_id, + port_id, + )) + } + fn query_counterparty_payee( &self, channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, diff --git a/tools/test-framework/src/relayer/fee.rs b/tools/test-framework/src/relayer/fee.rs index d59bfb04fc..85141dbf9f 100644 --- a/tools/test-framework/src/relayer/fee.rs +++ b/tools/test-framework/src/relayer/fee.rs @@ -2,7 +2,9 @@ use core::time::Duration; use http::uri::Uri; use ibc::applications::ics29_fee::msgs::pay_packet::build_pay_packet_message; use ibc::applications::ics29_fee::msgs::pay_packet_async::build_pay_packet_fee_async_message; -use ibc::applications::ics29_fee::msgs::register_counterparty::build_register_counterparty_payee_message; +use ibc::applications::ics29_fee::msgs::register_payee::{ + build_register_counterparty_payee_message, build_register_payee_message, +}; use ibc::applications::ics29_fee::packet_fee::IdentifiedPacketFees; use ibc::core::ics04_channel::packet::Sequence; use ibc::events::IbcEvent; @@ -117,6 +119,33 @@ pub async fn register_counterparty_payee( Ok(()) } +pub async fn register_payee( + tx_config: &MonoTagged, + wallet: &MonoTagged, + payee: &MonoTagged, + channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, + port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, +) -> Result<(), Error> { + let message = build_register_payee_message( + &wallet + .value() + .address + .0 + .parse() + .map_err(handle_generic_error)?, + &payee.value().0.parse().map_err(handle_generic_error)?, + channel_id.value(), + port_id.value(), + ) + .map_err(handle_generic_error)?; + + let messages = vec![message]; + + simple_send_tx(tx_config.value(), &wallet.value().key, messages).await?; + + Ok(()) +} + pub async fn query_counterparty_payee( grpc_address: &Uri, channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, From 2a58252861c93e90d42a84c268b1a1c18f48cd9b Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 20 Jul 2022 19:13:16 +0000 Subject: [PATCH 082/113] Initial draft implementation for register-payee CLI --- modules/src/signer.rs | 4 +- relayer-cli/src/commands.rs | 10 +- relayer-cli/src/commands/fee/command.rs | 10 ++ relayer-cli/src/commands/fee/mod.rs | 2 + .../src/commands/fee/register_payee.rs | 108 ++++++++++++++++++ relayer-cli/src/error.rs | 19 ++- relayer/src/chain/cosmos.rs | 15 +-- relayer/src/chain/cosmos/encode.rs | 12 ++ relayer/src/chain/cosmos/tx.rs | 46 ++++++++ relayer/src/error.rs | 6 +- relayer/src/keyring.rs | 5 +- relayer/src/spawn.rs | 2 +- tools/test-framework/src/chain/tagged.rs | 15 ++- tools/test-framework/src/relayer/fee.rs | 8 +- tools/test-framework/src/relayer/transfer.rs | 2 +- tools/test-framework/src/relayer/tx.rs | 50 -------- 16 files changed, 233 insertions(+), 81 deletions(-) create mode 100644 relayer-cli/src/commands/fee/command.rs create mode 100644 relayer-cli/src/commands/fee/mod.rs create mode 100644 relayer-cli/src/commands/fee/register_payee.rs diff --git a/modules/src/signer.rs b/modules/src/signer.rs index 21c62bf116..35088b2725 100644 --- a/modules/src/signer.rs +++ b/modules/src/signer.rs @@ -1,11 +1,11 @@ use core::str::FromStr; -use crate::prelude::*; - use derive_more::Display; use flex_error::define_error; use serde::{Deserialize, Serialize}; +use crate::prelude::*; + define_error! { #[derive(Debug, PartialEq, Eq)] SignerError { diff --git a/relayer-cli/src/commands.rs b/relayer-cli/src/commands.rs index ef9fd5cbf4..3291c20dd5 100644 --- a/relayer-cli/src/commands.rs +++ b/relayer-cli/src/commands.rs @@ -4,6 +4,7 @@ mod clear; mod completions; mod config; mod create; +mod fee; mod health; mod keys; mod listen; @@ -17,9 +18,9 @@ mod version; use self::{ clear::ClearCmds, completions::CompletionsCmd, config::ConfigCmd, create::CreateCmds, - health::HealthCheckCmd, keys::KeysCmd, listen::ListenCmd, misbehaviour::MisbehaviourCmd, - query::QueryCmd, start::StartCmd, tx::TxCmd, update::UpdateCmds, upgrade::UpgradeCmds, - version::VersionCmd, + fee::command::FeeCmd, health::HealthCheckCmd, keys::KeysCmd, listen::ListenCmd, + misbehaviour::MisbehaviourCmd, query::QueryCmd, start::StartCmd, tx::TxCmd, update::UpdateCmds, + upgrade::UpgradeCmds, version::VersionCmd, }; use core::time::Duration; @@ -77,6 +78,9 @@ pub enum CliCmd { #[clap(subcommand)] Tx(TxCmd), + #[clap(subcommand)] + Fee(FeeCmd), + /// Listen to and display IBC events emitted by a chain Listen(ListenCmd), diff --git a/relayer-cli/src/commands/fee/command.rs b/relayer-cli/src/commands/fee/command.rs new file mode 100644 index 0000000000..1dba17b57a --- /dev/null +++ b/relayer-cli/src/commands/fee/command.rs @@ -0,0 +1,10 @@ +//! `keys` subcommand +use abscissa_core::clap::Parser; +use abscissa_core::{Command, Runnable}; + +use crate::commands::fee::register_payee::RegisterPayeeCmd; + +#[derive(Command, Debug, Parser, Runnable)] +pub enum FeeCmd { + RegisterPayee(RegisterPayeeCmd), +} diff --git a/relayer-cli/src/commands/fee/mod.rs b/relayer-cli/src/commands/fee/mod.rs new file mode 100644 index 0000000000..3211062712 --- /dev/null +++ b/relayer-cli/src/commands/fee/mod.rs @@ -0,0 +1,2 @@ +pub mod command; +pub mod register_payee; diff --git a/relayer-cli/src/commands/fee/register_payee.rs b/relayer-cli/src/commands/fee/register_payee.rs new file mode 100644 index 0000000000..eac2fb252f --- /dev/null +++ b/relayer-cli/src/commands/fee/register_payee.rs @@ -0,0 +1,108 @@ +use abscissa_core::clap::Parser; +use abscissa_core::{Command, Runnable}; +use core::str::FromStr; +use ibc::applications::ics29_fee::msgs::register_payee::build_register_payee_message; +use ibc::core::ics24_host::identifier::{ChainId, ChannelId, PortId}; +use ibc::signer::Signer; +use ibc_relayer::chain::cosmos::encode::key_entry_to_signer; +use ibc_relayer::chain::cosmos::tx::simple_send_tx; +use ibc_relayer::chain::cosmos::types::config::TxConfig; +use ibc_relayer::keyring::KeyRing; +use tokio::runtime::Runtime; + +use crate::application::app_config; +use crate::error::Error; + +#[derive(Clone, Command, Debug, Parser, PartialEq)] +#[clap( + override_usage = "hermes keys add [OPTIONS] --chain --key-file + + hermes keys add [OPTIONS] --chain --mnemonic-file " +)] +pub struct RegisterPayeeCmd { + #[clap( + long = "chain", + required = true, + help_heading = "FLAGS", + help = "Identifier of the chain" + )] + chain_id: ChainId, + + #[clap( + long = "channel-id", + required = true, + help_heading = "FLAGS", + help = "Channel ID" + )] + channel_id: ChannelId, + + #[clap( + long = "port", + required = true, + help_heading = "FLAGS", + help = "Port ID" + )] + port_id: PortId, + + #[clap( + long = "payee-address", + required = true, + help_heading = "FLAGS", + help = "Payee address" + )] + payee_address: String, +} + +impl Runnable for RegisterPayeeCmd { + fn run(&self) { + run_register_payee_command( + &self.chain_id, + &self.channel_id, + &self.port_id, + &self.payee_address, + ) + .unwrap() + } +} + +fn run_register_payee_command( + chain_id: &ChainId, + channel_id: &ChannelId, + port_id: &PortId, + payee_address: &str, +) -> Result<(), Error> { + let payee = Signer::from_str(payee_address).map_err(Error::signer)?; + + let config = app_config(); + + let chain_config = config + .find_chain(chain_id) + .ok_or_else(|| Error::missing_chain_config(chain_id.clone()))?; + + let tx_config = TxConfig::try_from(chain_config).map_err(Error::relayer)?; + + let keyring = KeyRing::new( + chain_config.key_store_type, + &chain_config.account_prefix, + &chain_config.id, + ) + .map_err(Error::key_ring)?; + + let key_entry = keyring + .get_key(&chain_config.key_name) + .map_err(Error::key_ring)?; + + let signer = + key_entry_to_signer(&key_entry, &&chain_config.account_prefix).map_err(Error::relayer)?; + + let message = + build_register_payee_message(&signer, &payee, &channel_id, &port_id).map_err(Error::fee)?; + + let runtime = Runtime::new().map_err(Error::io)?; + + runtime + .block_on(simple_send_tx(&tx_config, &key_entry, vec![message])) + .map_err(Error::relayer)?; + + Ok(()) +} diff --git a/relayer-cli/src/error.rs b/relayer-cli/src/error.rs index 3dfd40d1e2..e7ef630190 100644 --- a/relayer-cli/src/error.rs +++ b/relayer-cli/src/error.rs @@ -1,16 +1,20 @@ //! All errors which can be raised from a command. -use flex_error::define_error; +use flex_error::{define_error, DisplayError}; +use std::io::Error as IoError; use tendermint::Error as TendermintError; +use ibc::applications::ics29_fee::error::Error as FeeError; use ibc::core::ics04_channel::channel::IdentifiedChannelEnd; use ibc::core::ics24_host::identifier::ChainId; +use ibc::signer::SignerError; use ibc_relayer::channel::ChannelError; use ibc_relayer::connection::ConnectionError; use ibc_relayer::error::Error as RelayerError; use ibc_relayer::foreign_client::ForeignClientError; +use ibc_relayer::keyring::errors::Error as KeyRingError; use ibc_relayer::link::error::LinkError; use ibc_relayer::spawn::SpawnError; use ibc_relayer::supervisor::Error as SupervisorError; @@ -24,6 +28,7 @@ define_error! { |_| { "config error" }, Io + [ DisplayError ] |_| { "I/O error" }, Query @@ -79,6 +84,10 @@ define_error! { [ ConnectionError ] |_| { "connection error" }, + Fee + [ FeeError ] + |_| { "fee error" }, + Transfer [ TransferError ] |_| { "transfer error" }, @@ -102,5 +111,13 @@ define_error! { UpgradeChain [ UpgradeChainError ] |_| { "upgrade chain error" }, + + Signer + [ SignerError ] + |_| { "signer error" }, + + KeyRing + [ KeyRingError ] + |_| { "keyring error" }, } } diff --git a/relayer/src/chain/cosmos.rs b/relayer/src/chain/cosmos.rs index 2ebfa23193..df719fba10 100644 --- a/relayer/src/chain/cosmos.rs +++ b/relayer/src/chain/cosmos.rs @@ -9,7 +9,6 @@ use core::{ use num_bigint::BigInt; use std::thread; -use bitcoin::hashes::hex::ToHex; use tendermint::block::Height as TmHeight; use tendermint::{ abci::{Event, Path as TendermintABCIPath}, @@ -55,7 +54,7 @@ use crate::chain::client::ClientSettings; use crate::chain::cosmos::batch::{ send_batched_messages_and_wait_check_tx, send_batched_messages_and_wait_commit, }; -use crate::chain::cosmos::encode::encode_to_bech32; +use crate::chain::cosmos::encode::key_entry_to_signer; use crate::chain::cosmos::fee::maybe_register_counterparty_payee; use crate::chain::cosmos::gas::{calculate_fee, mul_ceil}; use crate::chain::cosmos::query::account::get_or_fetch_account; @@ -609,15 +608,11 @@ impl ChainEndpoint for CosmosSdkChain { crate::time!("get_signer"); // Get the key from key seed file - let key = self - .keybase() - .get_key(&self.config.key_name) - .map_err(|e| Error::key_not_found(self.config.key_name.clone(), e))?; + let key_entry = self.key()?; + + let signer = key_entry_to_signer(&key_entry, &self.config.account_prefix)?; - let bech32 = encode_to_bech32(&key.address.to_hex(), &self.config.account_prefix)?; - bech32 - .parse() - .map_err(|e| Error::ics02(ClientError::signer(e))) + Ok(signer) } /// Get the chain configuration diff --git a/relayer/src/chain/cosmos/encode.rs b/relayer/src/chain/cosmos/encode.rs index 416bc049d0..e6735a4943 100644 --- a/relayer/src/chain/cosmos/encode.rs +++ b/relayer/src/chain/cosmos/encode.rs @@ -1,6 +1,9 @@ use bech32::{ToBase32, Variant}; +use bitcoin::hashes::hex::ToHex; use core::str::FromStr; +use ibc::core::ics02_client::error::Error as ClientError; use ibc::core::ics24_host::identifier::ChainId; +use ibc::signer::Signer; use ibc_proto::cosmos::tx::v1beta1::mode_info::{Single, Sum}; use ibc_proto::cosmos::tx::v1beta1::{AuthInfo, Fee, ModeInfo, SignDoc, SignerInfo, TxBody, TxRaw}; use ibc_proto::google::protobuf::Any; @@ -177,3 +180,12 @@ fn tx_body_and_bytes(proto_msgs: Vec, memo: &Memo) -> Result<(TxBody, Vec Result { + let bech32 = encode_to_bech32(&key_entry.address.to_hex(), account_prefix)?; + let signer = bech32 + .parse() + .map_err(|e| Error::ics02(ClientError::signer(e)))?; + + Ok(signer) +} diff --git a/relayer/src/chain/cosmos/tx.rs b/relayer/src/chain/cosmos/tx.rs index e6a0519e1f..63819fa637 100644 --- a/relayer/src/chain/cosmos/tx.rs +++ b/relayer/src/chain/cosmos/tx.rs @@ -1,3 +1,4 @@ +use ibc::events::IbcEvent; use ibc_proto::cosmos::tx::v1beta1::Fee; use ibc_proto::google::protobuf::Any; use tendermint_rpc::endpoint::broadcast::tx_sync::Response; @@ -5,8 +6,11 @@ use tendermint_rpc::{Client, HttpClient, Url}; use crate::chain::cosmos::encode::sign_and_encode_tx; use crate::chain::cosmos::estimate::estimate_tx_fees; +use crate::chain::cosmos::query::account::query_account; +use crate::chain::cosmos::query::tx::all_ibc_events_from_tx_search_response; use crate::chain::cosmos::types::account::Account; use crate::chain::cosmos::types::config::TxConfig; +use crate::chain::cosmos::wait::wait_tx_succeed; use crate::config::types::Memo; use crate::error::Error; use crate::keyring::KeyEntry; @@ -51,3 +55,45 @@ async fn broadcast_tx_sync( Ok(response) } + +/** + 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 response = + estimate_fee_and_send_tx(config, key_entry, &account, &Default::default(), messages) + .await?; + + if response.code.is_err() { + return Err(Error::check_tx(response)); + } + + let response = wait_tx_succeed( + &config.rpc_client, + &config.rpc_address, + &config.rpc_timeout, + &response.hash, + ) + .await?; + + let events = all_ibc_events_from_tx_search_response(&config.chain_id, response); + + Ok(events) +} diff --git a/relayer/src/error.rs b/relayer/src/error.rs index e664ef0e73..492ceb6e87 100644 --- a/relayer/src/error.rs +++ b/relayer/src/error.rs @@ -15,6 +15,7 @@ use tendermint_light_client::errors::{ use tendermint_proto::Error as TendermintProtoError; use tendermint_rpc::endpoint::abci_query::AbciQuery; use tendermint_rpc::endpoint::broadcast::tx_commit::TxResult; +use tendermint_rpc::endpoint::broadcast::tx_sync::Response as TxSyncResponse; use tendermint_rpc::Error as TendermintRpcError; use tonic::{ metadata::errors::InvalidMetadataValue, transport::Error as TransportError, @@ -57,10 +58,9 @@ define_error! { CheckTx { - detail: SdkError, - tx: TxResult + response: TxSyncResponse, } - |e| { format!("CheckTx commit returned an error: {0}, raw result: {1:?}", e.detail, e.tx) }, + | e | { format!("CheckTx returned an error: {:?}", e.response) }, DeliverTx { diff --git a/relayer/src/keyring.rs b/relayer/src/keyring.rs index a8361ac6b9..fd523213ac 100644 --- a/relayer/src/keyring.rs +++ b/relayer/src/keyring.rs @@ -3,7 +3,6 @@ use std::ffi::OsStr; use std::fs::{self, File}; use std::path::{Path, PathBuf}; -use crate::config::AddressType; use bech32::{ToBase32, Variant}; use bip39::{Language, Mnemonic, Seed}; use bitcoin::{ @@ -13,7 +12,7 @@ use bitcoin::{ }; use hdpath::StandardHDPath; use ibc::core::ics24_host::identifier::ChainId; -use k256::ecdsa::{signature::Signer, Signature, SigningKey}; +use k256::ecdsa::{signature::Signer as _, Signature, SigningKey}; use ripemd160::Ripemd160; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; @@ -25,6 +24,8 @@ pub use pub_key::EncodedPubKey; pub mod errors; mod pub_key; +use crate::config::AddressType; + pub type HDPath = StandardHDPath; pub const KEYSTORE_DEFAULT_FOLDER: &str = ".hermes/keys/"; diff --git a/relayer/src/spawn.rs b/relayer/src/spawn.rs index 186eb39571..e9b4d20cf8 100644 --- a/relayer/src/spawn.rs +++ b/relayer/src/spawn.rs @@ -27,7 +27,7 @@ define_error! { { chain_id: ChainId } | e | { format_args!("missing chain config for '{}' in configuration file", e.chain_id) - } + }, } } diff --git a/tools/test-framework/src/chain/tagged.rs b/tools/test-framework/src/chain/tagged.rs index c35da55fe1..63e5c4fe3e 100644 --- a/tools/test-framework/src/chain/tagged.rs +++ b/tools/test-framework/src/chain/tagged.rs @@ -4,6 +4,7 @@ use ibc::events::IbcEvent; use ibc_proto::google::protobuf::Any; +use ibc_relayer::chain::cosmos::tx::simple_send_tx; use ibc_relayer::chain::cosmos::types::config::TxConfig; use serde_json as json; @@ -12,7 +13,6 @@ use crate::chain::driver::ChainDriver; use crate::error::Error; use crate::ibc::denom::Denom; use crate::ibc::token::{TaggedDenomExt, TaggedToken, TaggedTokenRef}; -use crate::relayer::tx::simple_send_tx; use crate::types::id::TaggedChainIdRef; use crate::types::tagged::*; use crate::types::wallet::{Wallet, WalletAddress}; @@ -88,11 +88,14 @@ impl<'a, Chain: Send> TaggedChainDriverExt for MonoTagged, messages: Vec, ) -> Result, Error> { - self.value().runtime.block_on(simple_send_tx( - &self.value().tx_config, - &wallet.value().key, - messages, - )) + self.value() + .runtime + .block_on(simple_send_tx( + &self.value().tx_config, + &wallet.value().key, + messages, + )) + .map_err(Error::relayer) } fn query_balance( diff --git a/tools/test-framework/src/relayer/fee.rs b/tools/test-framework/src/relayer/fee.rs index 85141dbf9f..857d38bc7d 100644 --- a/tools/test-framework/src/relayer/fee.rs +++ b/tools/test-framework/src/relayer/fee.rs @@ -12,12 +12,12 @@ use ibc_relayer::chain::cosmos::query::fee::{ query_counterparty_payee as raw_query_counterparty_payee, query_incentivized_packets as raw_query_incentivized_packets, }; +use ibc_relayer::chain::cosmos::tx::simple_send_tx; use ibc_relayer::chain::cosmos::types::config::TxConfig; use crate::error::{handle_generic_error, Error}; use crate::ibc::token::{TaggedTokenExt, TaggedTokenRef}; use crate::relayer::transfer::build_transfer_message; -use crate::relayer::tx::simple_send_tx; use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef}; use crate::types::tagged::{DualTagged, MonoTagged}; use crate::types::wallet::{Wallet, WalletAddress}; @@ -85,7 +85,11 @@ pub async fn pay_packet_fee( ) .map_err(handle_generic_error)?; - simple_send_tx(tx_config.value(), &payer.value().key, vec![message]).await + let events = simple_send_tx(tx_config.value(), &payer.value().key, vec![message]) + .await + .map_err(Error::relayer)?; + + Ok(events) } pub async fn register_counterparty_payee( diff --git a/tools/test-framework/src/relayer/transfer.rs b/tools/test-framework/src/relayer/transfer.rs index 60c73845f5..937dc90169 100644 --- a/tools/test-framework/src/relayer/transfer.rs +++ b/tools/test-framework/src/relayer/transfer.rs @@ -10,13 +10,13 @@ use ibc::applications::transfer::error::Error as Ics20Error; use ibc::core::ics04_channel::timeout::TimeoutHeight; use ibc::timestamp::Timestamp; use ibc_proto::google::protobuf::Any; +use ibc_relayer::chain::cosmos::tx::simple_send_tx; use ibc_relayer::chain::cosmos::types::config::TxConfig; use ibc_relayer::transfer::build_transfer_message as raw_build_transfer_message; use ibc_relayer::transfer::TransferError; use crate::error::{handle_generic_error, Error}; use crate::ibc::token::TaggedTokenRef; -use crate::relayer::tx::simple_send_tx; use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef}; use crate::types::tagged::*; use crate::types::wallet::{Wallet, WalletAddress}; diff --git a/tools/test-framework/src/relayer/tx.rs b/tools/test-framework/src/relayer/tx.rs index 279c251de2..ec1b753512 100644 --- a/tools/test-framework/src/relayer/tx.rs +++ b/tools/test-framework/src/relayer/tx.rs @@ -1,20 +1,12 @@ 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::query::tx::all_ibc_events_from_tx_search_response; -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::wait::wait_tx_succeed; use ibc_relayer::config::GasPrice; -use ibc_relayer::keyring::KeyEntry; use tendermint_rpc::{HttpClient, Url}; use crate::error::{handle_generic_error, Error}; @@ -71,45 +63,3 @@ pub fn new_tx_config_for_test( address_type, }) } - -/** - 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 response = - estimate_fee_and_send_tx(config, key_entry, &account, &Default::default(), messages) - .await?; - - if response.code.is_err() { - return Err(eyre!("send_tx returns error response: {:?}", response).into()); - } - - let response = wait_tx_succeed( - &config.rpc_client, - &config.rpc_address, - &config.rpc_timeout, - &response.hash, - ) - .await?; - - let events = all_ibc_events_from_tx_search_response(&config.chain_id, response); - - Ok(events) -} From d68571d7d94bbe163507214ae42a54cdd1b87af9 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 20 Jul 2022 21:54:05 +0200 Subject: [PATCH 083/113] Add register counterparty payee CLI --- relayer-cli/src/commands/fee/command.rs | 2 + relayer-cli/src/commands/fee/mod.rs | 1 + .../fee/register_counterparty_payee.rs | 92 +++++++++++++++++++ .../src/commands/fee/register_payee.rs | 41 ++------- ...t_setup_with_fee_enabled_binary_channel.rs | 87 ++++++++++++++++++ 5 files changed, 192 insertions(+), 31 deletions(-) create mode 100644 relayer-cli/src/commands/fee/register_counterparty_payee.rs create mode 100644 tools/integration-test/src/bin/test_setup_with_fee_enabled_binary_channel.rs diff --git a/relayer-cli/src/commands/fee/command.rs b/relayer-cli/src/commands/fee/command.rs index 1dba17b57a..c20213f57d 100644 --- a/relayer-cli/src/commands/fee/command.rs +++ b/relayer-cli/src/commands/fee/command.rs @@ -2,9 +2,11 @@ use abscissa_core::clap::Parser; use abscissa_core::{Command, Runnable}; +use crate::commands::fee::register_counterparty_payee::RegisterCounterpartyPayeeCmd; use crate::commands::fee::register_payee::RegisterPayeeCmd; #[derive(Command, Debug, Parser, Runnable)] pub enum FeeCmd { RegisterPayee(RegisterPayeeCmd), + RegisterCounterpartyPayee(RegisterCounterpartyPayeeCmd), } diff --git a/relayer-cli/src/commands/fee/mod.rs b/relayer-cli/src/commands/fee/mod.rs index 3211062712..cbe7f03390 100644 --- a/relayer-cli/src/commands/fee/mod.rs +++ b/relayer-cli/src/commands/fee/mod.rs @@ -1,2 +1,3 @@ pub mod command; +pub mod register_counterparty_payee; pub mod register_payee; diff --git a/relayer-cli/src/commands/fee/register_counterparty_payee.rs b/relayer-cli/src/commands/fee/register_counterparty_payee.rs new file mode 100644 index 0000000000..046a3d2e7e --- /dev/null +++ b/relayer-cli/src/commands/fee/register_counterparty_payee.rs @@ -0,0 +1,92 @@ +use abscissa_core::clap::Parser; +use abscissa_core::{Command, Runnable}; +use core::str::FromStr; +use ibc::applications::ics29_fee::msgs::register_payee::build_register_counterparty_payee_message; +use ibc::core::ics24_host::identifier::{ChainId, ChannelId, PortId}; +use ibc::signer::Signer; +use ibc_relayer::chain::handle::ChainHandle; +use ibc_relayer::chain::tracking::TrackedMsgs; + +use crate::application::app_config; +use crate::cli_utils::spawn_chain_runtime; +use crate::error::Error; + +#[derive(Clone, Command, Debug, Parser, PartialEq)] +pub struct RegisterCounterpartyPayeeCmd { + #[clap( + long = "chain", + required = true, + help_heading = "FLAGS", + help = "Identifier of the chain" + )] + chain_id: ChainId, + + #[clap( + long = "channel-id", + required = true, + help_heading = "FLAGS", + help = "Channel ID" + )] + channel_id: ChannelId, + + #[clap( + long = "port", + required = true, + help_heading = "FLAGS", + help = "Port ID" + )] + port_id: PortId, + + #[clap( + long = "counterparty-payee-address", + required = true, + help_heading = "FLAGS", + help = "CounterpartyPayee address" + )] + counterparty_payee_address: String, +} + +impl Runnable for RegisterCounterpartyPayeeCmd { + fn run(&self) { + run_register_counterparty_payee_command( + &self.chain_id, + &self.channel_id, + &self.port_id, + &self.counterparty_payee_address, + ) + .unwrap() + } +} + +fn run_register_counterparty_payee_command( + chain_id: &ChainId, + channel_id: &ChannelId, + port_id: &PortId, + counterparty_payee_address: &str, +) -> Result<(), Error> { + let counterparty_payee = Signer::from_str(counterparty_payee_address).map_err(Error::signer)?; + + let config = app_config(); + + let chain_handle = spawn_chain_runtime(&config, &chain_id)?; + + let signer = chain_handle.get_signer().map_err(Error::relayer)?; + + let message = build_register_counterparty_payee_message( + &signer, + &counterparty_payee, + &channel_id, + &port_id, + ) + .map_err(Error::fee)?; + + let messages = TrackedMsgs::new_static(vec![message], "cli"); + + chain_handle + .send_messages_and_wait_commit(messages) + .map_err(Error::relayer)?; + + println!("Successfully registered counterparty payee."); + + Ok(()) +} diff --git a/relayer-cli/src/commands/fee/register_payee.rs b/relayer-cli/src/commands/fee/register_payee.rs index eac2fb252f..a12249bcc6 100644 --- a/relayer-cli/src/commands/fee/register_payee.rs +++ b/relayer-cli/src/commands/fee/register_payee.rs @@ -4,21 +4,14 @@ use core::str::FromStr; use ibc::applications::ics29_fee::msgs::register_payee::build_register_payee_message; use ibc::core::ics24_host::identifier::{ChainId, ChannelId, PortId}; use ibc::signer::Signer; -use ibc_relayer::chain::cosmos::encode::key_entry_to_signer; -use ibc_relayer::chain::cosmos::tx::simple_send_tx; -use ibc_relayer::chain::cosmos::types::config::TxConfig; -use ibc_relayer::keyring::KeyRing; -use tokio::runtime::Runtime; +use ibc_relayer::chain::handle::ChainHandle; +use ibc_relayer::chain::tracking::TrackedMsgs; use crate::application::app_config; +use crate::cli_utils::spawn_chain_runtime; use crate::error::Error; #[derive(Clone, Command, Debug, Parser, PartialEq)] -#[clap( - override_usage = "hermes keys add [OPTIONS] --chain --key-file - - hermes keys add [OPTIONS] --chain --mnemonic-file " -)] pub struct RegisterPayeeCmd { #[clap( long = "chain", @@ -75,34 +68,20 @@ fn run_register_payee_command( let config = app_config(); - let chain_config = config - .find_chain(chain_id) - .ok_or_else(|| Error::missing_chain_config(chain_id.clone()))?; - - let tx_config = TxConfig::try_from(chain_config).map_err(Error::relayer)?; - - let keyring = KeyRing::new( - chain_config.key_store_type, - &chain_config.account_prefix, - &chain_config.id, - ) - .map_err(Error::key_ring)?; + let chain_handle = spawn_chain_runtime(&config, &chain_id)?; - let key_entry = keyring - .get_key(&chain_config.key_name) - .map_err(Error::key_ring)?; - - let signer = - key_entry_to_signer(&key_entry, &&chain_config.account_prefix).map_err(Error::relayer)?; + let signer = chain_handle.get_signer().map_err(Error::relayer)?; let message = build_register_payee_message(&signer, &payee, &channel_id, &port_id).map_err(Error::fee)?; - let runtime = Runtime::new().map_err(Error::io)?; + let messages = TrackedMsgs::new_static(vec![message], "cli"); - runtime - .block_on(simple_send_tx(&tx_config, &key_entry, vec![message])) + chain_handle + .send_messages_and_wait_commit(messages) .map_err(Error::relayer)?; + println!("Successfully registered payee."); + Ok(()) } diff --git a/tools/integration-test/src/bin/test_setup_with_fee_enabled_binary_channel.rs b/tools/integration-test/src/bin/test_setup_with_fee_enabled_binary_channel.rs new file mode 100644 index 0000000000..82f31eed78 --- /dev/null +++ b/tools/integration-test/src/bin/test_setup_with_fee_enabled_binary_channel.rs @@ -0,0 +1,87 @@ +/*! + This is a simple wrapper around [`BinaryChannelTest`] and turn it into + an executable that can be used for manual testing with two test chains + with connected channel being setup. + + When the command is executed, you should see log messages such as + following near the end: + + ```bash + $ cargo run --bin test_setup_with_binary_channel + ... + INFO ibc_integration_test::framework::binary::channel: written channel environment to /path/to/ibc-rs/data/test-3742758098/binary-channels.env + WARN ibc_integration_test::util::suspend: suspending the test indefinitely. you can still interact with any spawned chains and relayers + ``` + + The `binary-channels.env` file generated contains the environment variables + that are essential for accessing the test chains. You can source it and + run the relayer commands in a separate terminal such as: + + ```bash + $ source /path/to/ibc-rs/data/test-1790156739/binary-channels.env + $ cargo run --bin hermes -- -c $RELAYER_CONFIG tx ft-transfer \ + $CHAIN_ID_B $CHAIN_ID_A $PORT_A $CHANNEL_ID_A 9999 -o 1000 \ + -k $NODE_A_WALLETS_USER1_KEY_ID -d $NODE_A_DENOM + ``` +*/ + +use ibc::core::ics04_channel::Version; +use ibc_relayer::keyring::Store; +use ibc_test_framework::prelude::*; +use std::env; +use std::path::PathBuf; + +struct Test { + store_dir: PathBuf, +} + +impl TestOverrides for Test { + fn modify_test_config(&self, config: &mut TestConfig) { + config.bootstrap_with_random_ids = false; + config.chain_store_dir = self.store_dir.clone(); + } + + fn modify_relayer_config(&self, config: &mut Config) { + for mut chain in config.chains.iter_mut() { + // Modify the key store type to `Store::Test` so that the wallet + // keys are stored to ~/.hermes/keys so that we can use them + // with external relayer commands. + chain.key_store_type = Store::Test; + } + } + + fn should_spawn_supervisor(&self) -> bool { + false + } + + fn channel_version(&self) -> Version { + Version::ics20_with_fee() + } +} + +impl BinaryChannelTest for Test { + fn run( + &self, + _config: &TestConfig, + _relayer: RelayerDriver, + _chains: ConnectedChains, + _channel: ConnectedChannel, + ) -> Result<(), Error> { + suspend() + } +} + +fn main() -> Result<(), Error> { + let store_dir = env::var("TEST_STORE_DIR").unwrap_or_else(|_| "data/test".to_string()); + + println!( + "Setting up binary channel test environment at {}. (Overridable with $TEST_STORE_DIR)", + store_dir + ); + + println!("Make sure the directory is clean for the setup to succeed"); + + run_binary_channel_test(&Test { + store_dir: store_dir.into(), + }) +} From b83c7f375894c52bb40fc8efece3c82c79c74c09 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Thu, 21 Jul 2022 12:05:29 +0200 Subject: [PATCH 084/113] Fix clippy --- relayer-cli/src/commands/fee/register_counterparty_payee.rs | 6 +++--- relayer-cli/src/commands/fee/register_payee.rs | 4 ++-- .../src/bin/test_setup_with_fee_enabled_binary_channel.rs | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/relayer-cli/src/commands/fee/register_counterparty_payee.rs b/relayer-cli/src/commands/fee/register_counterparty_payee.rs index 046a3d2e7e..f96cc75b04 100644 --- a/relayer-cli/src/commands/fee/register_counterparty_payee.rs +++ b/relayer-cli/src/commands/fee/register_counterparty_payee.rs @@ -68,15 +68,15 @@ fn run_register_counterparty_payee_command( let config = app_config(); - let chain_handle = spawn_chain_runtime(&config, &chain_id)?; + let chain_handle = spawn_chain_runtime(&config, chain_id)?; let signer = chain_handle.get_signer().map_err(Error::relayer)?; let message = build_register_counterparty_payee_message( &signer, &counterparty_payee, - &channel_id, - &port_id, + channel_id, + port_id, ) .map_err(Error::fee)?; diff --git a/relayer-cli/src/commands/fee/register_payee.rs b/relayer-cli/src/commands/fee/register_payee.rs index a12249bcc6..d51319a053 100644 --- a/relayer-cli/src/commands/fee/register_payee.rs +++ b/relayer-cli/src/commands/fee/register_payee.rs @@ -68,12 +68,12 @@ fn run_register_payee_command( let config = app_config(); - let chain_handle = spawn_chain_runtime(&config, &chain_id)?; + let chain_handle = spawn_chain_runtime(&config, chain_id)?; let signer = chain_handle.get_signer().map_err(Error::relayer)?; let message = - build_register_payee_message(&signer, &payee, &channel_id, &port_id).map_err(Error::fee)?; + build_register_payee_message(&signer, &payee, channel_id, port_id).map_err(Error::fee)?; let messages = TrackedMsgs::new_static(vec![message], "cli"); diff --git a/tools/integration-test/src/bin/test_setup_with_fee_enabled_binary_channel.rs b/tools/integration-test/src/bin/test_setup_with_fee_enabled_binary_channel.rs index 82f31eed78..7a9bfd89dc 100644 --- a/tools/integration-test/src/bin/test_setup_with_fee_enabled_binary_channel.rs +++ b/tools/integration-test/src/bin/test_setup_with_fee_enabled_binary_channel.rs @@ -1,13 +1,13 @@ /*! This is a simple wrapper around [`BinaryChannelTest`] and turn it into an executable that can be used for manual testing with two test chains - with connected channel being setup. + with connected channel with fee enabled. When the command is executed, you should see log messages such as following near the end: ```bash - $ cargo run --bin test_setup_with_binary_channel + $ cargo run --bin test_setup_with_fee_enabled_binary_channel ... INFO ibc_integration_test::framework::binary::channel: written channel environment to /path/to/ibc-rs/data/test-3742758098/binary-channels.env WARN ibc_integration_test::util::suspend: suspending the test indefinitely. you can still interact with any spawned chains and relayers From 8fba5c734fed1987b227278e86a7340f65fb7440 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Thu, 21 Jul 2022 12:15:38 +0200 Subject: [PATCH 085/113] Add test for registering invalid counterparty payee --- .../src/tests/fee/forward_relayer.rs | 2 +- .../src/tests/fee/no_forward_relayer.rs | 108 ++++++++++++++++++ 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/tools/integration-test/src/tests/fee/forward_relayer.rs b/tools/integration-test/src/tests/fee/forward_relayer.rs index 2acb5c16ef..f1cfd004be 100644 --- a/tools/integration-test/src/tests/fee/forward_relayer.rs +++ b/tools/integration-test/src/tests/fee/forward_relayer.rs @@ -33,8 +33,8 @@ impl BinaryChannelTest for ForwardRelayerTest { let port_a = channel.port_a.as_ref(); let port_b = channel.port_b.as_ref(); - let channel_id_a = channel.channel_id_a.as_ref(); + let channel_id_a = channel.channel_id_a.as_ref(); let channel_id_b = channel.channel_id_b.as_ref(); let wallets_a = chains.node_a.wallets(); diff --git a/tools/integration-test/src/tests/fee/no_forward_relayer.rs b/tools/integration-test/src/tests/fee/no_forward_relayer.rs index 5e4d247d0e..5246db7873 100644 --- a/tools/integration-test/src/tests/fee/no_forward_relayer.rs +++ b/tools/integration-test/src/tests/fee/no_forward_relayer.rs @@ -7,7 +7,13 @@ fn test_no_forward_relayer() -> Result<(), Error> { run_binary_channel_test(&NoForwardRelayerTest) } +#[test] +fn test_invalid_forward_relayer() -> Result<(), Error> { + run_binary_channel_test(&InvalidForwardRelayerTest) +} + struct NoForwardRelayerTest; +struct InvalidForwardRelayerTest; impl TestOverrides for NoForwardRelayerTest { fn modify_relayer_config(&self, config: &mut Config) { @@ -19,6 +25,16 @@ impl TestOverrides for NoForwardRelayerTest { } } +impl TestOverrides for InvalidForwardRelayerTest { + fn modify_relayer_config(&self, config: &mut Config) { + config.mode.packets.auto_register_counterparty_payee = false; + } + + fn channel_version(&self) -> Version { + Version::ics20_with_fee() + } +} + impl BinaryChannelTest for NoForwardRelayerTest { fn run( &self, @@ -96,3 +112,95 @@ impl BinaryChannelTest for NoForwardRelayerTest { Ok(()) } } + +impl BinaryChannelTest for InvalidForwardRelayerTest { + fn run( + &self, + _config: &TestConfig, + _relayer: RelayerDriver, + chains: ConnectedChains, + channel: ConnectedChannel, + ) -> Result<(), Error> { + let chain_driver_a = chains.node_a.chain_driver(); + let chain_driver_b = chains.node_b.chain_driver(); + + let denom_a = chains.node_a.denom(); + + let port_a = channel.port_a.as_ref(); + let port_b = channel.port_b.as_ref(); + + let channel_id_a = channel.channel_id_a.as_ref(); + let channel_id_b = channel.channel_id_b.as_ref(); + + let wallets_a = chains.node_a.wallets(); + let wallets_b = chains.node_b.wallets(); + + let relayer_a = wallets_a.relayer(); + let relayer_b = wallets_b.relayer(); + + let user_a = wallets_a.user1(); + let user_b = wallets_b.user1(); + + let balance_a1 = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; + + let relayer_balance_a = chain_driver_a.query_balance(&relayer_a.address(), &denom_a)?; + + let send_amount = random_u128_range(1000, 2000); + let receive_fee = random_u128_range(300, 400); + let ack_fee = random_u128_range(200, 300); + let timeout_fee = random_u128_range(100, 200); + + let total_sent = send_amount + receive_fee + ack_fee + timeout_fee; + + let balance_a2 = balance_a1 - total_sent; + + let invalid_address = + MonoTagged::new(WalletAddress("a very long and invalid address".to_string())); + + chain_driver_b.register_counterparty_payee( + &relayer_b, + &invalid_address.as_ref(), + &channel_id_b, + &port_b, + )?; + + chain_driver_a.ibc_token_transfer_with_fee( + &port_a, + &channel_id_a, + &user_a, + &user_b.address(), + &denom_a.with_amount(send_amount).as_ref(), + &denom_a.with_amount(receive_fee).as_ref(), + &denom_a.with_amount(ack_fee).as_ref(), + &denom_a.with_amount(timeout_fee).as_ref(), + Duration::from_secs(60), + )?; + + let denom_b = derive_ibc_denom( + &channel.port_b.as_ref(), + &channel.channel_id_b.as_ref(), + &denom_a, + )?; + + chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a2.as_ref())?; + + chain_driver_b.assert_eventual_wallet_amount( + &user_b.address(), + &denom_b.with_amount(send_amount).as_ref(), + )?; + + // receive fee and timeout fee should be refunded, + // as thecounterparty address registered is invalid. + chain_driver_a.assert_eventual_wallet_amount( + &user_a.address(), + &(balance_a2 + receive_fee + timeout_fee).as_ref(), + )?; + + chain_driver_a.assert_eventual_wallet_amount( + &relayer_a.address(), + &(relayer_balance_a + ack_fee).as_ref(), + )?; + + Ok(()) + } +} From cfff0872ec1b2f3a240a91b1e5d403763a66ac3b Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Thu, 21 Jul 2022 13:00:15 +0200 Subject: [PATCH 086/113] Add example config for auto_register_counterparty_payee --- config.toml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/config.toml b/config.toml index 3bb7339e2d..d42512e6ec 100644 --- a/config.toml +++ b/config.toml @@ -63,6 +63,15 @@ clear_on_start = true # [Default: true] tx_confirmation = true +# Auto register the counterparty payee on a destination chain to +# the relayer's address on the source chain. This can be used +# for simple configuration of the relayer to receive fees for +# relaying RecvPacket on fee-enabled channels. +# For more complex configuration, turn this off and use the CLI +# to manually register the payee addresses. +# [Default: false] +auto_register_counterparty_payee = false + # The REST section defines parameters for Hermes' built-in RESTful API. # https://hermes.informal.systems/rest.html [rest] From 3af047fa00506fadd86e8c00e5e73b0390af5565 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Thu, 18 Aug 2022 12:27:31 +0200 Subject: [PATCH 087/113] Fix clippy --- modules/src/applications/ics29_fee/events.rs | 2 +- rust-toolchain.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/src/applications/ics29_fee/events.rs b/modules/src/applications/ics29_fee/events.rs index b8b40df9ba..f9b4882b37 100644 --- a/modules/src/applications/ics29_fee/events.rs +++ b/modules/src/applications/ics29_fee/events.rs @@ -45,7 +45,7 @@ impl From for AbciEvent { fn from(event: IncentivizedPacket) -> AbciEvent { let attributes: Vec = vec![ new_tag("port_id", event.port_id.as_str()), - new_tag("channel_id", &event.channel_id.to_string()), + new_tag("channel_id", event.channel_id.as_ref()), new_tag("packet_sequence", &event.sequence.to_string()), new_tag("recv_fee", &event.total_recv_fee.iter().join(",")), new_tag("ack_fee", &event.total_ack_fee.iter().join(",")), diff --git a/rust-toolchain.toml b/rust-toolchain.toml index f99b82c1ad..5f0c0ace2e 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "1.61" +channel = "1.63" components = ["rustfmt", "clippy", "cargo"] From 903721f8d4a5d03f7675c6d4fd82cf2206096dbb Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Thu, 18 Aug 2022 12:44:18 +0200 Subject: [PATCH 088/113] Fix test_pay_packet_fee_async error caused by merge conflict --- modules/src/events.rs | 5 +++++ relayer/src/event.rs | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/modules/src/events.rs b/modules/src/events.rs index caff0e9ce6..605d7e967d 100644 --- a/modules/src/events.rs +++ b/modules/src/events.rs @@ -9,6 +9,7 @@ use serde_derive::{Deserialize, Serialize}; use tendermint::abci::tag::Tag; use tendermint::abci::Event as AbciEvent; +use crate::applications::ics29_fee::error::Error as FeeError; use crate::applications::ics29_fee::events::IncentivizedPacket; use crate::core::ics02_client::error as client_error; use crate::core::ics02_client::events::NewBlock; @@ -45,6 +46,10 @@ define_error! { [ channel_error::Error ] | _ | { "channel error" }, + Fee + [ FeeError ] + | _ | { "fee error" }, + Timestamp [ ParseTimestampError ] | _ | { "error parsing timestamp" }, diff --git a/relayer/src/event.rs b/relayer/src/event.rs index d78d858f99..20d587d339 100644 --- a/relayer/src/event.rs +++ b/relayer/src/event.rs @@ -1,4 +1,5 @@ use core::fmt::{self, Display, Formatter}; +use ibc::applications::ics29_fee::events::IncentivizedPacket; use ibc::{ core::ics02_client::{ error::Error as ClientError, @@ -127,6 +128,9 @@ pub fn ibc_event_try_from_abci_event(abci_event: &AbciEvent) -> Result Ok(IbcEvent::TimeoutPacket( timeout_packet_try_from_abci_event(abci_event).map_err(IbcEventError::channel)?, )), + Ok(IbcEventType::IncentivizedPacket) => Ok(IbcEvent::IncentivizedPacket( + IncentivizedPacket::try_from(&abci_event.attributes).map_err(IbcEventError::fee)?, + )), _ => Err(IbcEventError::unsupported_abci_event( abci_event.type_str.to_owned(), )), From 5ec8f41d7fe45ec97f43bc7a3a293019db0a2693 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 24 Aug 2022 11:47:28 +0200 Subject: [PATCH 089/113] Fix clippy --- relayer-cli/src/commands/fee/register_counterparty_payee.rs | 2 +- relayer-cli/src/commands/fee/register_payee.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/relayer-cli/src/commands/fee/register_counterparty_payee.rs b/relayer-cli/src/commands/fee/register_counterparty_payee.rs index f96cc75b04..b46e0d5369 100644 --- a/relayer-cli/src/commands/fee/register_counterparty_payee.rs +++ b/relayer-cli/src/commands/fee/register_counterparty_payee.rs @@ -11,7 +11,7 @@ use crate::application::app_config; use crate::cli_utils::spawn_chain_runtime; use crate::error::Error; -#[derive(Clone, Command, Debug, Parser, PartialEq)] +#[derive(Clone, Command, Debug, Parser, PartialEq, Eq)] pub struct RegisterCounterpartyPayeeCmd { #[clap( long = "chain", diff --git a/relayer-cli/src/commands/fee/register_payee.rs b/relayer-cli/src/commands/fee/register_payee.rs index d51319a053..182d829c07 100644 --- a/relayer-cli/src/commands/fee/register_payee.rs +++ b/relayer-cli/src/commands/fee/register_payee.rs @@ -11,7 +11,7 @@ use crate::application::app_config; use crate::cli_utils::spawn_chain_runtime; use crate::error::Error; -#[derive(Clone, Command, Debug, Parser, PartialEq)] +#[derive(Clone, Command, Debug, Parser, PartialEq, Eq)] pub struct RegisterPayeeCmd { #[clap( long = "chain", From be9c5d37c9172f0fe4c87599bfd53551d4fd96e3 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Thu, 8 Sep 2022 11:40:16 +0200 Subject: [PATCH 090/113] Refactor coin and amount constructs into separate modules --- modules/src/applications/transfer/amount.rs | 37 +++++ modules/src/applications/transfer/coin.rs | 157 ++++++++++++++++++++ modules/src/applications/transfer/denom.rs | 88 +---------- modules/src/applications/transfer/error.rs | 16 ++ modules/src/applications/transfer/mod.rs | 4 + 5 files changed, 215 insertions(+), 87 deletions(-) create mode 100644 modules/src/applications/transfer/amount.rs create mode 100644 modules/src/applications/transfer/coin.rs diff --git a/modules/src/applications/transfer/amount.rs b/modules/src/applications/transfer/amount.rs new file mode 100644 index 0000000000..c250e91901 --- /dev/null +++ b/modules/src/applications/transfer/amount.rs @@ -0,0 +1,37 @@ +use core::str::FromStr; +use derive_more::{Display, From, Into}; +use serde::{Deserialize, Serialize}; + +use super::error::Error; +use crate::bigint::U256; + +/// A type for representing token transfer amounts. +#[derive( + Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize, Display, From, Into, +)] +pub struct Amount(U256); + +impl Amount { + pub fn checked_add(self, rhs: Self) -> Option { + self.0.checked_add(rhs.0).map(Self) + } + + pub fn checked_sub(self, rhs: Self) -> Option { + self.0.checked_sub(rhs.0).map(Self) + } +} + +impl FromStr for Amount { + type Err = Error; + + fn from_str(s: &str) -> Result { + let amount = U256::from_dec_str(s).map_err(Error::invalid_amount)?; + Ok(Self(amount)) + } +} + +impl From for Amount { + fn from(v: u64) -> Self { + Self(v.into()) + } +} diff --git a/modules/src/applications/transfer/coin.rs b/modules/src/applications/transfer/coin.rs new file mode 100644 index 0000000000..fcac8c2d6c --- /dev/null +++ b/modules/src/applications/transfer/coin.rs @@ -0,0 +1,157 @@ +use core::fmt::{Display, Error as FmtError, Formatter}; +use core::str::{from_utf8, FromStr}; +use ibc_proto::cosmos::base::v1beta1::Coin as ProtoCoin; +use safe_regex::regex; +use serde::{Deserialize, Serialize}; + +use super::amount::Amount; +use super::denom::{BaseDenom, PrefixedDenom}; +use super::error::Error; +use crate::prelude::*; +use crate::serializers::serde_string; + +/// A `Coin` type with fully qualified `PrefixedDenom`. +pub type PrefixedCoin = Coin; + +/// A `Coin` type with an unprefixed denomination. +pub type BaseCoin = Coin; + +pub type RawCoin = Coin; + +/// Coin defines a token with a denomination and an amount. +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] +pub struct Coin { + /// Denomination + pub denom: D, + /// Amount + #[serde(with = "serde_string")] + pub amount: Amount, +} + +impl Coin +where + D::Err: Into, +{ + pub fn from_string_list(coin_str: &str) -> Result, Error> { + coin_str.split(',').map(FromStr::from_str).collect() + } +} + +impl FromStr for Coin +where + D::Err: Into, +{ + type Err = Error; + + #[allow(clippy::assign_op_pattern)] + fn from_str(coin_str: &str) -> Result { + // Denominations can be 3 ~ 128 characters long and support letters, followed by either + // a letter, a number or a separator ('/', ':', '.', '_' or '-'). + // Loosely copy the regex from here: + // https://github.com/cosmos/cosmos-sdk/blob/v0.45.5/types/coin.go#L760-L762 + let matcher = regex!(br"([0-9]+)([a-zA-Z0-9/:\\._\x2d]+)"); + + let (m1, m2) = matcher + .match_slices(coin_str.as_bytes()) + .ok_or_else(|| Error::invalid_coin(coin_str.to_string()))?; + + let amount = from_utf8(m1).map_err(Error::utf8_decode)?.parse()?; + + let denom = from_utf8(m2) + .map_err(Error::utf8_decode)? + .parse() + .map_err(Into::into)?; + + Ok(Coin { amount, denom }) + } +} + +impl TryFrom for Coin +where + D::Err: Into, +{ + type Error = Error; + + fn try_from(proto: ProtoCoin) -> Result, Self::Error> { + let denom = D::from_str(&proto.denom).map_err(Into::into)?; + let amount = Amount::from_str(&proto.amount)?; + Ok(Self { denom, amount }) + } +} + +impl From> for ProtoCoin { + fn from(coin: Coin) -> ProtoCoin { + ProtoCoin { + denom: coin.denom.to_string(), + amount: coin.amount.to_string(), + } + } +} + +impl From for PrefixedCoin { + fn from(coin: BaseCoin) -> PrefixedCoin { + PrefixedCoin { + denom: coin.denom.into(), + amount: coin.amount, + } + } +} + +impl Display for PrefixedCoin { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { + write!(f, "{}-{}", self.amount, self.denom) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parse_raw_coin() -> Result<(), Error> { + { + let coin = RawCoin::from_str("123stake")?; + assert_eq!(coin.denom, "stake"); + assert_eq!(coin.amount, 123u64.into()); + } + + { + let coin = RawCoin::from_str("1a1")?; + assert_eq!(coin.denom, "a1"); + assert_eq!(coin.amount, 1u64.into()); + } + + { + let coin = RawCoin::from_str("0x1/:.\\_-")?; + assert_eq!(coin.denom, "x1/:.\\_-"); + assert_eq!(coin.amount, 0u64.into()); + } + + { + // `!` is not allowed + let res = RawCoin::from_str("0x!"); + assert!(res.is_err()); + } + + Ok(()) + } + + #[test] + fn test_parse_raw_coin_list() -> Result<(), Error> { + { + let coins = RawCoin::from_string_list("123stake,1a1,999den0m")?; + assert_eq!(coins.len(), 3); + + assert_eq!(coins[0].denom, "stake"); + assert_eq!(coins[0].amount, 123u64.into()); + + assert_eq!(coins[1].denom, "a1"); + assert_eq!(coins[1].amount, 1u64.into()); + + assert_eq!(coins[2].denom, "den0m"); + assert_eq!(coins[2].amount, 999u64.into()); + } + + Ok(()) + } +} diff --git a/modules/src/applications/transfer/denom.rs b/modules/src/applications/transfer/denom.rs index 6e8ddb3d09..07ead21047 100644 --- a/modules/src/applications/transfer/denom.rs +++ b/modules/src/applications/transfer/denom.rs @@ -1,23 +1,15 @@ use core::fmt::{Display, Error as FmtError, Formatter}; use core::str::FromStr; -use derive_more::{Display, From, Into}; -use ibc_proto::cosmos::base::v1beta1::Coin as RawCoin; +use derive_more::{Display, From}; use ibc_proto::ibc::applications::transfer::v1::DenomTrace as RawDenomTrace; use serde::{Deserialize, Serialize}; use super::error::Error; -use crate::bigint::U256; use crate::core::ics24_host::identifier::{ChannelId, PortId}; use crate::prelude::*; use crate::serializers::serde_string; -/// A `Coin` type with fully qualified `PrefixedDenom`. -pub type PrefixedCoin = Coin; - -/// A `Coin` type with an unprefixed denomination. -pub type BaseCoin = Coin; - /// Base denomination type #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize, Display)] #[serde(transparent)] @@ -277,84 +269,6 @@ impl Display for PrefixedDenom { } } -/// A type for representing token transfer amounts. -#[derive( - Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize, Display, From, Into, -)] -pub struct Amount(U256); - -impl Amount { - pub fn checked_add(self, rhs: Self) -> Option { - self.0.checked_add(rhs.0).map(Self) - } - - pub fn checked_sub(self, rhs: Self) -> Option { - self.0.checked_sub(rhs.0).map(Self) - } -} - -impl FromStr for Amount { - type Err = Error; - - fn from_str(s: &str) -> Result { - let amount = U256::from_dec_str(s).map_err(Error::invalid_amount)?; - Ok(Self(amount)) - } -} - -impl From for Amount { - fn from(v: u64) -> Self { - Self(v.into()) - } -} - -/// Coin defines a token with a denomination and an amount. -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct Coin { - /// Denomination - pub denom: D, - /// Amount - #[serde(with = "serde_string")] - pub amount: Amount, -} - -impl TryFrom for Coin -where - Error: From<::Err>, -{ - type Error = Error; - - fn try_from(proto: RawCoin) -> Result, Self::Error> { - let denom = D::from_str(&proto.denom)?; - let amount = Amount::from_str(&proto.amount)?; - Ok(Self { denom, amount }) - } -} - -impl From> for RawCoin { - fn from(coin: Coin) -> RawCoin { - RawCoin { - denom: coin.denom.to_string(), - amount: coin.amount.to_string(), - } - } -} - -impl From for PrefixedCoin { - fn from(coin: BaseCoin) -> PrefixedCoin { - PrefixedCoin { - denom: coin.denom.into(), - amount: coin.amount, - } - } -} - -impl Display for PrefixedCoin { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "{}-{}", self.amount, self.denom) - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/modules/src/applications/transfer/error.rs b/modules/src/applications/transfer/error.rs index c289eb29fd..e13cb14fe1 100644 --- a/modules/src/applications/transfer/error.rs +++ b/modules/src/applications/transfer/error.rs @@ -1,5 +1,7 @@ use alloc::string::FromUtf8Error; +use core::convert::Infallible; +use core::str::Utf8Error; use flex_error::{define_error, DisplayOnly, TraceError}; use ibc_proto::protobuf::Error as TendermintProtoError; use subtle_encoding::Error as EncodingError; @@ -132,5 +134,19 @@ define_error! { UnknownMsgType { msg_type: String } | e | { format_args!("unknown msg type: {0}", e.msg_type) }, + + InvalidCoin + { coin: String } + | e | { format_args!("invalid coin string: {}", e.coin) }, + + Utf8Decode + [ TraceError ] + | _ | { "error decoding raw bytes as UTF8 string" }, + } +} + +impl From for Error { + fn from(e: Infallible) -> Self { + match e {} } } diff --git a/modules/src/applications/transfer/mod.rs b/modules/src/applications/transfer/mod.rs index 1a8a87a89a..36479d8936 100644 --- a/modules/src/applications/transfer/mod.rs +++ b/modules/src/applications/transfer/mod.rs @@ -2,6 +2,8 @@ //! constitutes a "fungible token transfer bridge module" between the IBC routing module and an //! asset tracking module. pub mod acknowledgement; +pub mod amount; +pub mod coin; pub mod context; pub mod denom; pub mod error; @@ -10,6 +12,8 @@ pub mod msgs; pub mod packet; pub mod relay; +pub use amount::*; +pub use coin::*; pub use denom::*; /// Module identifier for the ICS20 application. From b0f1f6dd1b6c6495a4aabf55bf9eba3f90ea6714 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Fri, 9 Sep 2022 10:22:25 +0200 Subject: [PATCH 091/113] Follow the same coin display format as in ibc-go --- modules/src/applications/transfer/coin.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/src/applications/transfer/coin.rs b/modules/src/applications/transfer/coin.rs index fcac8c2d6c..b6581c6fd3 100644 --- a/modules/src/applications/transfer/coin.rs +++ b/modules/src/applications/transfer/coin.rs @@ -97,9 +97,9 @@ impl From for PrefixedCoin { } } -impl Display for PrefixedCoin { +impl Display for Coin { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "{}-{}", self.amount, self.denom) + write!(f, "{}{}", self.amount, self.denom) } } From c181ce38d1a6cb5c4ee6917fe4c678a619112e78 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Fri, 9 Sep 2022 11:58:05 +0200 Subject: [PATCH 092/113] Initial token amount cannot exceed u64::MAX --- tools/test-framework/src/bootstrap/single.rs | 2 +- tools/test-framework/src/chain/cli/bootstrap.rs | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/test-framework/src/bootstrap/single.rs b/tools/test-framework/src/bootstrap/single.rs index 906cafe3ec..cfabfa6c35 100644 --- a/tools/test-framework/src/bootstrap/single.rs +++ b/tools/test-framework/src/bootstrap/single.rs @@ -54,7 +54,7 @@ pub fn bootstrap_single_node( // Evmos requires of at least 1_000_000_000_000_000_000 or else there will be the // error `error during handshake: error on replay: validator set is nil in genesis and still empty after InitChain` // when running `evmosd start`. - let initial_amount = random_u128_range(1_000_000_000_000_000_000, u128::MAX); + let initial_amount = random_u128_range(1_000_000_000_000_000_000, 2_000_000_000_000_000_000); let initial_stake = Token::new(stake_denom, initial_amount); let initial_coin = Token::new(denom.clone(), initial_amount); diff --git a/tools/test-framework/src/chain/cli/bootstrap.rs b/tools/test-framework/src/chain/cli/bootstrap.rs index aa684a6e00..7271301fe4 100644 --- a/tools/test-framework/src/chain/cli/bootstrap.rs +++ b/tools/test-framework/src/chain/cli/bootstrap.rs @@ -173,10 +173,13 @@ pub fn start_chain( match status { None => Ok(ChildProcess::new(child)), Some(status) => { + let stdout_output = fs::read_to_string(stdout_path)?; let stderr_output = fs::read_to_string(stderr_path)?; + Err(eyre!( - "expected full node process to be running, but it exited immediately with exit status {} and STDERR: {}", + "expected full node process to be running, but it exited immediately with exit status {} and output: {}\n{}", status, + stdout_output, stderr_output, ).into()) } From 757bb00a34a2be71faf941b52585aa0d5c5de248 Mon Sep 17 00:00:00 2001 From: Romain Ruetschi Date: Mon, 26 Sep 2022 17:23:03 +0200 Subject: [PATCH 093/113] Small cleanup of fee commands --- crates/relayer-cli/src/commands.rs | 3 ++- crates/relayer-cli/src/commands/fee.rs | 19 +++++++++++++++++++ .../relayer-cli/src/commands/fee/command.rs | 12 ------------ crates/relayer-cli/src/commands/fee/mod.rs | 3 --- .../fee/register_counterparty_payee.rs | 17 +++++++++-------- .../src/commands/fee/register_payee.rs | 17 +++++++++-------- 6 files changed, 39 insertions(+), 32 deletions(-) create mode 100644 crates/relayer-cli/src/commands/fee.rs delete mode 100644 crates/relayer-cli/src/commands/fee/command.rs delete mode 100644 crates/relayer-cli/src/commands/fee/mod.rs diff --git a/crates/relayer-cli/src/commands.rs b/crates/relayer-cli/src/commands.rs index 3291c20dd5..c2ce4cbeed 100644 --- a/crates/relayer-cli/src/commands.rs +++ b/crates/relayer-cli/src/commands.rs @@ -18,7 +18,7 @@ mod version; use self::{ clear::ClearCmds, completions::CompletionsCmd, config::ConfigCmd, create::CreateCmds, - fee::command::FeeCmd, health::HealthCheckCmd, keys::KeysCmd, listen::ListenCmd, + fee::FeeCmd, health::HealthCheckCmd, keys::KeysCmd, listen::ListenCmd, misbehaviour::MisbehaviourCmd, query::QueryCmd, start::StartCmd, tx::TxCmd, update::UpdateCmds, upgrade::UpgradeCmds, version::VersionCmd, }; @@ -78,6 +78,7 @@ pub enum CliCmd { #[clap(subcommand)] Tx(TxCmd), + /// Interact with the fee middleware #[clap(subcommand)] Fee(FeeCmd), diff --git a/crates/relayer-cli/src/commands/fee.rs b/crates/relayer-cli/src/commands/fee.rs new file mode 100644 index 0000000000..fbd70cf264 --- /dev/null +++ b/crates/relayer-cli/src/commands/fee.rs @@ -0,0 +1,19 @@ +//! `fee` subcommand + +use abscissa_core::clap::Parser; +use abscissa_core::{Command, Runnable}; + +use register_counterparty_payee::RegisterCounterpartyPayeeCmd; +use register_payee::RegisterPayeeCmd; + +pub mod register_counterparty_payee; +pub mod register_payee; + +#[derive(Command, Debug, Parser, Runnable)] +pub enum FeeCmd { + /// Register a payee for a channel + RegisterPayee(RegisterPayeeCmd), + + /// Register a counterparty payee for a channel + RegisterCounterpartyPayee(RegisterCounterpartyPayeeCmd), +} diff --git a/crates/relayer-cli/src/commands/fee/command.rs b/crates/relayer-cli/src/commands/fee/command.rs deleted file mode 100644 index c20213f57d..0000000000 --- a/crates/relayer-cli/src/commands/fee/command.rs +++ /dev/null @@ -1,12 +0,0 @@ -//! `keys` subcommand -use abscissa_core::clap::Parser; -use abscissa_core::{Command, Runnable}; - -use crate::commands::fee::register_counterparty_payee::RegisterCounterpartyPayeeCmd; -use crate::commands::fee::register_payee::RegisterPayeeCmd; - -#[derive(Command, Debug, Parser, Runnable)] -pub enum FeeCmd { - RegisterPayee(RegisterPayeeCmd), - RegisterCounterpartyPayee(RegisterCounterpartyPayeeCmd), -} diff --git a/crates/relayer-cli/src/commands/fee/mod.rs b/crates/relayer-cli/src/commands/fee/mod.rs deleted file mode 100644 index cbe7f03390..0000000000 --- a/crates/relayer-cli/src/commands/fee/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod command; -pub mod register_counterparty_payee; -pub mod register_payee; diff --git a/crates/relayer-cli/src/commands/fee/register_counterparty_payee.rs b/crates/relayer-cli/src/commands/fee/register_counterparty_payee.rs index b46e0d5369..ab7c689a6e 100644 --- a/crates/relayer-cli/src/commands/fee/register_counterparty_payee.rs +++ b/crates/relayer-cli/src/commands/fee/register_counterparty_payee.rs @@ -9,6 +9,7 @@ use ibc_relayer::chain::tracking::TrackedMsgs; use crate::application::app_config; use crate::cli_utils::spawn_chain_runtime; +use crate::conclude::{exit_with_unrecoverable_error, Output}; use crate::error::Error; #[derive(Clone, Command, Debug, Parser, PartialEq, Eq)] @@ -22,10 +23,10 @@ pub struct RegisterCounterpartyPayeeCmd { chain_id: ChainId, #[clap( - long = "channel-id", + long = "channel", required = true, help_heading = "FLAGS", - help = "Channel ID" + help = "Identifier of the channel" )] channel_id: ChannelId, @@ -33,15 +34,15 @@ pub struct RegisterCounterpartyPayeeCmd { long = "port", required = true, help_heading = "FLAGS", - help = "Port ID" + help = "Identifier of the port" )] port_id: PortId, #[clap( - long = "counterparty-payee-address", + long = "counterparty-payee", required = true, help_heading = "FLAGS", - help = "CounterpartyPayee address" + help = "Address of the counterparty payee" )] counterparty_payee_address: String, } @@ -54,7 +55,9 @@ impl Runnable for RegisterCounterpartyPayeeCmd { &self.port_id, &self.counterparty_payee_address, ) - .unwrap() + .unwrap_or_else(exit_with_unrecoverable_error); + + Output::success_msg("Successfully registered counterparty payee").exit() } } @@ -86,7 +89,5 @@ fn run_register_counterparty_payee_command( .send_messages_and_wait_commit(messages) .map_err(Error::relayer)?; - println!("Successfully registered counterparty payee."); - Ok(()) } diff --git a/crates/relayer-cli/src/commands/fee/register_payee.rs b/crates/relayer-cli/src/commands/fee/register_payee.rs index 182d829c07..63164aef9a 100644 --- a/crates/relayer-cli/src/commands/fee/register_payee.rs +++ b/crates/relayer-cli/src/commands/fee/register_payee.rs @@ -9,6 +9,7 @@ use ibc_relayer::chain::tracking::TrackedMsgs; use crate::application::app_config; use crate::cli_utils::spawn_chain_runtime; +use crate::conclude::{exit_with_unrecoverable_error, Output}; use crate::error::Error; #[derive(Clone, Command, Debug, Parser, PartialEq, Eq)] @@ -22,10 +23,10 @@ pub struct RegisterPayeeCmd { chain_id: ChainId, #[clap( - long = "channel-id", + long = "channel", required = true, help_heading = "FLAGS", - help = "Channel ID" + help = "Identifier of the channel" )] channel_id: ChannelId, @@ -33,15 +34,15 @@ pub struct RegisterPayeeCmd { long = "port", required = true, help_heading = "FLAGS", - help = "Port ID" + help = "Identifier of the port" )] port_id: PortId, #[clap( - long = "payee-address", + long = "payee", required = true, help_heading = "FLAGS", - help = "Payee address" + help = "Address of the payee" )] payee_address: String, } @@ -54,7 +55,9 @@ impl Runnable for RegisterPayeeCmd { &self.port_id, &self.payee_address, ) - .unwrap() + .unwrap_or_else(exit_with_unrecoverable_error); + + Output::success_msg("Successfully registered payee").exit() } } @@ -81,7 +84,5 @@ fn run_register_payee_command( .send_messages_and_wait_commit(messages) .map_err(Error::relayer)?; - println!("Successfully registered payee."); - Ok(()) } From 01e59409fef35b2be5866cfde8ed88bd0d288127 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 5 Oct 2022 11:57:14 +0200 Subject: [PATCH 094/113] Apply suggestions from code review Co-authored-by: Sean Chen Signed-off-by: Soares Chen --- crates/modules/src/applications/ics29_fee/mod.rs | 9 +++++++++ .../applications/ics29_fee/msgs/register_payee.rs | 12 ++++-------- .../modules/src/applications/ics29_fee/packet_fee.rs | 9 +++++++++ 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/crates/modules/src/applications/ics29_fee/mod.rs b/crates/modules/src/applications/ics29_fee/mod.rs index 40c2c44bf3..27057c9d07 100644 --- a/crates/modules/src/applications/ics29_fee/mod.rs +++ b/crates/modules/src/applications/ics29_fee/mod.rs @@ -1,3 +1,12 @@ +//! The implementation of the ICS 29 fee payment [spec](https://github.com/cosmos/ibc/blob/main/spec/app/ics-029-fee-payment/README.md). +//! Enables an incentivization layer for relayers such that relayer operators are rewarded +//! for successfully relaying packets. +//! +//! The documentation for this module makes use of some terminology, which is defined below: +//! 1. Forward relayer: The relayer that submits the `recv_packet` message for a given packet. +//! 2. Reverse relayer: The relayer that submits the `ack_packet` message for a given packet. +//! 3. Timeout relayer: The relayer that submits the `timeout_packet` message for a given packet. + pub mod error; pub mod events; pub mod msgs; diff --git a/crates/modules/src/applications/ics29_fee/msgs/register_payee.rs b/crates/modules/src/applications/ics29_fee/msgs/register_payee.rs index 0126643811..0e362841d2 100644 --- a/crates/modules/src/applications/ics29_fee/msgs/register_payee.rs +++ b/crates/modules/src/applications/ics29_fee/msgs/register_payee.rs @@ -24,12 +24,10 @@ pub fn build_register_counterparty_payee_message( let encoded = encode_message(&message).map_err(Error::encode)?; - let wrapped = Any { + Ok(Any { type_url: TYPE_URL.to_string(), value: encoded, - }; - - Ok(wrapped) + }) } pub fn build_register_payee_message( @@ -49,10 +47,8 @@ pub fn build_register_payee_message( let encoded = encode_message(&message).map_err(Error::encode)?; - let wrapped = Any { + Ok(Any { type_url: TYPE_URL.to_string(), value: encoded, - }; - - Ok(wrapped) + }) } diff --git a/crates/modules/src/applications/ics29_fee/packet_fee.rs b/crates/modules/src/applications/ics29_fee/packet_fee.rs index 12c4325ea7..96b615f21a 100644 --- a/crates/modules/src/applications/ics29_fee/packet_fee.rs +++ b/crates/modules/src/applications/ics29_fee/packet_fee.rs @@ -11,10 +11,19 @@ use crate::core::ics04_channel::packet_id::PacketId; use crate::prelude::*; use crate::signer::Signer; +/// The core type that encodes the different fees that are redeemable by relayers for relaying +/// different types of packets. #[derive(Debug, Clone)] pub struct Fee { + /// The amount that the forward relayer redeems for submitting a recv packet. + /// This fee is refunded to the payer in the case that the recv packet is not successfully relayed, i.e., + /// a timeout packet is relayed instead of the recv packet. pub recv_fee: Vec, + /// The amount that the reverse relayer redeems for relaying an acknowledgement packet. pub ack_fee: Vec, + /// The amount that the timeout relayer redeems for relaying a timeout packet. + /// This fee is refunded to the payer in the case that a timeout packet is not relayed, i.e., a + /// recv packet was successfully relayed instead. pub timeout_fee: Vec, } From 24c768607b2b5b23f8f4146db24f7a1a414ad323 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 5 Oct 2022 12:03:29 +0200 Subject: [PATCH 095/113] Update compatibility bound for ibc-go --- crates/modules/src/applications/ics29_fee/mod.rs | 2 +- crates/modules/src/applications/ics29_fee/packet_fee.rs | 2 +- crates/relayer/src/chain/cosmos/compatibility.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/modules/src/applications/ics29_fee/mod.rs b/crates/modules/src/applications/ics29_fee/mod.rs index 27057c9d07..4ae0fbfb48 100644 --- a/crates/modules/src/applications/ics29_fee/mod.rs +++ b/crates/modules/src/applications/ics29_fee/mod.rs @@ -1,6 +1,6 @@ //! The implementation of the ICS 29 fee payment [spec](https://github.com/cosmos/ibc/blob/main/spec/app/ics-029-fee-payment/README.md). //! Enables an incentivization layer for relayers such that relayer operators are rewarded -//! for successfully relaying packets. +//! for successfully relaying packets. //! //! The documentation for this module makes use of some terminology, which is defined below: //! 1. Forward relayer: The relayer that submits the `recv_packet` message for a given packet. diff --git a/crates/modules/src/applications/ics29_fee/packet_fee.rs b/crates/modules/src/applications/ics29_fee/packet_fee.rs index 96b615f21a..8112c550f3 100644 --- a/crates/modules/src/applications/ics29_fee/packet_fee.rs +++ b/crates/modules/src/applications/ics29_fee/packet_fee.rs @@ -11,7 +11,7 @@ use crate::core::ics04_channel::packet_id::PacketId; use crate::prelude::*; use crate::signer::Signer; -/// The core type that encodes the different fees that are redeemable by relayers for relaying +/// The core type that encodes the different fees that are redeemable by relayers for relaying /// different types of packets. #[derive(Debug, Clone)] pub struct Fee { diff --git a/crates/relayer/src/chain/cosmos/compatibility.rs b/crates/relayer/src/chain/cosmos/compatibility.rs index 1693e350a8..65123687eb 100644 --- a/crates/relayer/src/chain/cosmos/compatibility.rs +++ b/crates/relayer/src/chain/cosmos/compatibility.rs @@ -20,7 +20,7 @@ const SDK_MODULE_VERSION_REQ: &str = ">=0.41, <0.46"; /// # Note: Should be consistent with [features] guide page. /// /// [features]: https://hermes.informal.systems/features.html -const IBC_GO_MODULE_VERSION_REQ: &str = ">=1.1, <=3"; +const IBC_GO_MODULE_VERSION_REQ: &str = ">=1.1, <6"; #[derive(Error, Debug)] pub enum Diagnostic { From 36bea73e2abe38823cab801bc491d0eff9fc60f9 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Thu, 6 Oct 2022 11:00:22 +0200 Subject: [PATCH 096/113] Fix no-std check --- ci/no-std-check/Cargo.lock | 3 ++- ci/no-std-check/Cargo.toml | 2 +- ci/no-std-check/src/lib.rs | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ci/no-std-check/Cargo.lock b/ci/no-std-check/Cargo.lock index 97f2ea4fcc..afb0293674 100644 --- a/ci/no-std-check/Cargo.lock +++ b/ci/no-std-check/Cargo.lock @@ -746,6 +746,7 @@ dependencies = [ "flex-error", "ibc-proto", "ics23", + "itertools", "num-traits", "primitive-types 0.12.0", "prost", @@ -766,7 +767,7 @@ dependencies = [ [[package]] name = "ibc-proto" version = "0.20.1" -source = "git+https://github.com/cosmos/ibc-proto-rs#3fac7ce93c80126cc690d565c85be042e384b31c" +source = "git+https://github.com/cosmos/ibc-proto-rs?branch=romac/ibc-v5#a4c4e17bcbb020bbecf1257729aa6ecb95519a48" dependencies = [ "base64", "bytes", diff --git a/ci/no-std-check/Cargo.toml b/ci/no-std-check/Cargo.toml index fc1f26f383..74fe3260e3 100644 --- a/ci/no-std-check/Cargo.toml +++ b/ci/no-std-check/Cargo.toml @@ -32,7 +32,7 @@ substrate-std = [ ] [patch.crates-io] -ibc-proto = { git = "https://github.com/cosmos/ibc-proto-rs" } +ibc-proto = { git = "https://github.com/cosmos/ibc-proto-rs", branch = "romac/ibc-v5" } # tendermint = { git = "https://github.com/informalsystems/tendermint-rs", branch = "v0.23.x" } # tendermint-proto = { git = "https://github.com/informalsystems/tendermint-rs", branch = "v0.23.x" } # tendermint-light-client-verifier = { git = "https://github.com/informalsystems/tendermint-rs", branch = "v0.23.x" } diff --git a/ci/no-std-check/src/lib.rs b/ci/no-std-check/src/lib.rs index 13eea2c515..ac5bdced58 100644 --- a/ci/no-std-check/src/lib.rs +++ b/ci/no-std-check/src/lib.rs @@ -9,8 +9,8 @@ extern crate alloc; use ibc; use ibc_proto; use tendermint; -use tendermint_proto; use tendermint_light_client_verifier; +use tendermint_proto; #[cfg(feature = "sp-core")] use sp_core; From 4878f8b6f62c14800bd665523acbda6b7f80d1a6 Mon Sep 17 00:00:00 2001 From: Romain Ruetschi Date: Mon, 10 Oct 2022 10:43:39 +0200 Subject: [PATCH 097/113] ICS29: Add `fee transfer` command (#2682) * WIP: Add `fee transfer` command * Added config override in order to change used to transfer tokens with fee * Added unit tests for command argument parsing * Updated command in order to send a pay message for each transfer message * Cargo fmt and cargo clippy fixes * Use main branch of `ibc-proto` * Update guide templates and fix script * Added changelog entry * Added comments in the body of the 'check_can_send_on_channel' function * Moved imports to top level in 'cli_utils.rs' * Removed branch specification for ibc-proto repo in no-std-check Cargo.toml * Added warning when not GNU sed is used Co-authored-by: Luca Joss --- .../2714-fee-transfer-command.md | 2 + Cargo.lock | 10 +- Cargo.toml | 2 +- ci/no-std-check/Cargo.toml | 2 +- crates/relayer-cli/src/cli_utils.rs | 88 +- crates/relayer-cli/src/commands.rs | 1 + crates/relayer-cli/src/commands/fee.rs | 22 +- .../relayer-cli/src/commands/fee/transfer.rs | 789 ++++++++++++++++++ .../relayer-cli/src/commands/tx/transfer.rs | 95 +-- crates/relayer/src/transfer.rs | 55 +- .../fee/register-counterparty-payee_1.md | 1 + .../commands/hermes/fee/register-payee_1.md | 1 + .../commands/hermes/fee/transfer_1.md | 1 + guide/src/templates/commands/hermes/fee_1.md | 1 + guide/src/templates/help_templates/fee.md | 14 + .../fee/register-counterparty-payee.md | 14 + .../help_templates/fee/register-payee.md | 14 + .../templates/help_templates/fee/transfer.md | 53 ++ guide/src/templates/help_templates/help.md | 1 + scripts/auto_gen_templates.sh | 57 +- .../src/tests/manual/simulation.rs | 4 +- 21 files changed, 1091 insertions(+), 136 deletions(-) create mode 100644 .changelog/unreleased/features/ibc-relayer-cli/2714-fee-transfer-command.md create mode 100644 crates/relayer-cli/src/commands/fee/transfer.rs create mode 100644 guide/src/templates/commands/hermes/fee/register-counterparty-payee_1.md create mode 100644 guide/src/templates/commands/hermes/fee/register-payee_1.md create mode 100644 guide/src/templates/commands/hermes/fee/transfer_1.md create mode 100644 guide/src/templates/commands/hermes/fee_1.md create mode 100644 guide/src/templates/help_templates/fee.md create mode 100644 guide/src/templates/help_templates/fee/register-counterparty-payee.md create mode 100644 guide/src/templates/help_templates/fee/register-payee.md create mode 100644 guide/src/templates/help_templates/fee/transfer.md diff --git a/.changelog/unreleased/features/ibc-relayer-cli/2714-fee-transfer-command.md b/.changelog/unreleased/features/ibc-relayer-cli/2714-fee-transfer-command.md new file mode 100644 index 0000000000..cec265c7c0 --- /dev/null +++ b/.changelog/unreleased/features/ibc-relayer-cli/2714-fee-transfer-command.md @@ -0,0 +1,2 @@ +- New command `fee transfer` which transfers tokens with fees + ([#2714](https://github.com/informalsystems/ibc-rs/issues/2714)) \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 6d650ba3b2..97f830f27e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1353,9 +1353,9 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "handlebars" -version = "4.3.4" +version = "4.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56b224eaa4987c03c30b251de7ef0c15a6a59f34222905850dbc3026dfb24d5f" +checksum = "433e4ab33f1213cdc25b5fa45c76881240cfe79284cf2b395e8b9e312a30a2fd" dependencies = [ "log", "pest", @@ -1680,7 +1680,7 @@ dependencies = [ [[package]] name = "ibc-proto" version = "0.20.1" -source = "git+https://github.com/cosmos/ibc-proto-rs?branch=romac/ibc-v5#a4c4e17bcbb020bbecf1257729aa6ecb95519a48" +source = "git+https://github.com/cosmos/ibc-proto-rs#65c050e3a20e3a1ef3c1247788b5013112e207d7" dependencies = [ "base64", "bytes", @@ -3718,9 +3718,9 @@ dependencies = [ [[package]] name = "signature" -version = "1.6.3" +version = "1.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deb766570a2825fa972bceff0d195727876a9cdf2460ab2e52d455dc2de47fd9" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" dependencies = [ "digest 0.10.5", "rand_core 0.6.4", diff --git a/Cargo.toml b/Cargo.toml index 2cbd9051f9..302778425a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ exclude = [ ] [patch.crates-io] -ibc-proto = { git = "https://github.com/cosmos/ibc-proto-rs", branch = "romac/ibc-v5" } +ibc-proto = { git = "https://github.com/cosmos/ibc-proto-rs" } # tendermint = { git = "https://github.com/informalsystems/tendermint-rs", branch = "v0.23.x" } # tendermint-rpc = { git = "https://github.com/informalsystems/tendermint-rs", branch = "v0.23.x" } # tendermint-proto = { git = "https://github.com/informalsystems/tendermint-rs", branch = "v0.23.x" } diff --git a/ci/no-std-check/Cargo.toml b/ci/no-std-check/Cargo.toml index 74fe3260e3..fc1f26f383 100644 --- a/ci/no-std-check/Cargo.toml +++ b/ci/no-std-check/Cargo.toml @@ -32,7 +32,7 @@ substrate-std = [ ] [patch.crates-io] -ibc-proto = { git = "https://github.com/cosmos/ibc-proto-rs", branch = "romac/ibc-v5" } +ibc-proto = { git = "https://github.com/cosmos/ibc-proto-rs" } # tendermint = { git = "https://github.com/informalsystems/tendermint-rs", branch = "v0.23.x" } # tendermint-proto = { git = "https://github.com/informalsystems/tendermint-rs", branch = "v0.23.x" } # tendermint-light-client-verifier = { git = "https://github.com/informalsystems/tendermint-rs", branch = "v0.23.x" } diff --git a/crates/relayer-cli/src/cli_utils.rs b/crates/relayer-cli/src/cli_utils.rs index cd29369801..bab0471477 100644 --- a/crates/relayer-cli/src/cli_utils.rs +++ b/crates/relayer-cli/src/cli_utils.rs @@ -1,12 +1,15 @@ //! Various utilities for the Hermes CLI use alloc::sync::Arc; - +use eyre::eyre; use tokio::runtime::Runtime as TokioRuntime; +use tracing::debug; use ibc::core::ics02_client::client_state::ClientState; use ibc::core::ics24_host::identifier::{ChainId, ChannelId, PortId}; - +use ibc_relayer::chain::requests::{ + IncludeProof, QueryChannelRequest, QueryClientStateRequest, QueryConnectionRequest, QueryHeight, +}; use ibc_relayer::{ chain::{ counterparty::{channel_connection_client, ChannelConnectionClient}, @@ -102,3 +105,84 @@ pub fn spawn_chain_counterparty( channel_connection_client, )) } + +/// Check that the relayer can send on the given channel and ensure that channels and chain identifiers match. +/// To do this, fetch from the source chain the channel end, then the associated connection +/// end, and then the underlying client state; finally, check that this client is verifying +/// headers for the destination chain. +pub fn check_can_send_on_channel( + src_chain: &Chain, + src_channel_id: &ChannelId, + src_port_id: &PortId, + dst_chain_id: &ChainId, +) -> Result<(), eyre::Report> { + // Fetch from the source chain the channel end and check that it is open. + let (channel_end_src, _) = src_chain.query_channel( + QueryChannelRequest { + port_id: src_port_id.clone(), + channel_id: src_channel_id.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + )?; + + if !channel_end_src.is_open() { + return Err(eyre!( + "the requested port/channel ('{}'/'{}') on chain id '{}' is in state '{}'; expected 'open' state", + src_port_id, + src_channel_id, + src_chain.id(), + channel_end_src.state + )); + } + + let conn_id = match channel_end_src.connection_hops.first() { + Some(cid) => cid, + None => { + return Err(eyre!( + "could not retrieve the connection hop underlying port/channel '{}'/'{}' on chain '{}'", + src_port_id, src_channel_id, src_chain.id() + )); + } + }; + + // Fetch the associated connection end. + let (conn_end, _) = src_chain.query_connection( + QueryConnectionRequest { + connection_id: conn_id.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + )?; + + debug!("connection hop underlying the channel: {:?}", conn_end); + + // Fetch the underlying client state. + let (src_chain_client_state, _) = src_chain.query_client_state( + QueryClientStateRequest { + client_id: conn_end.client_id().clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + )?; + + debug!( + "client state underlying the channel: {:?}", + src_chain_client_state + ); + + // Check that this client is verifying headers for the destination chain. + if &src_chain_client_state.chain_id() != dst_chain_id { + return Err(eyre!( + "the requested port/channel ('{}'/'{}') provides a path from chain '{}' to \ + chain '{}' (not to the destination chain '{}'). Bailing due to mismatching arguments.", + src_port_id, + src_channel_id, + src_chain.id(), + src_chain_client_state.chain_id(), + dst_chain_id + )); + } + + Ok(()) +} diff --git a/crates/relayer-cli/src/commands.rs b/crates/relayer-cli/src/commands.rs index c2ce4cbeed..92b61ac1f7 100644 --- a/crates/relayer-cli/src/commands.rs +++ b/crates/relayer-cli/src/commands.rs @@ -153,6 +153,7 @@ impl Configurable for CliCmd { match self { CliCmd::Tx(cmd) => cmd.override_config(config), + CliCmd::Fee(cmd) => cmd.override_config(config), // CliCmd::Help(cmd) => cmd.override_config(config), // CliCmd::Keys(cmd) => cmd.override_config(config), // CliCmd::Create(cmd) => cmd.override_config(config), diff --git a/crates/relayer-cli/src/commands/fee.rs b/crates/relayer-cli/src/commands/fee.rs index fbd70cf264..0c8af55ed7 100644 --- a/crates/relayer-cli/src/commands/fee.rs +++ b/crates/relayer-cli/src/commands/fee.rs @@ -1,14 +1,18 @@ //! `fee` subcommand use abscissa_core::clap::Parser; -use abscissa_core::{Command, Runnable}; +use abscissa_core::{config::Override, Command, Runnable}; +use ibc_relayer::config::Config; -use register_counterparty_payee::RegisterCounterpartyPayeeCmd; -use register_payee::RegisterPayeeCmd; +use self::register_counterparty_payee::RegisterCounterpartyPayeeCmd; +use self::register_payee::RegisterPayeeCmd; +use self::transfer::FeeTransferCmd; pub mod register_counterparty_payee; pub mod register_payee; +pub mod transfer; +#[allow(clippy::large_enum_variant)] #[derive(Command, Debug, Parser, Runnable)] pub enum FeeCmd { /// Register a payee for a channel @@ -16,4 +20,16 @@ pub enum FeeCmd { /// Register a counterparty payee for a channel RegisterCounterpartyPayee(RegisterCounterpartyPayeeCmd), + + /// Perform a token transfer supported with a fee + Transfer(FeeTransferCmd), +} + +impl Override for FeeCmd { + fn override_config(&self, config: Config) -> Result { + match self { + Self::Transfer(cmd) => cmd.override_config(config), + _ => Ok(config), + } + } } diff --git a/crates/relayer-cli/src/commands/fee/transfer.rs b/crates/relayer-cli/src/commands/fee/transfer.rs new file mode 100644 index 0000000000..e74e5f9c72 --- /dev/null +++ b/crates/relayer-cli/src/commands/fee/transfer.rs @@ -0,0 +1,789 @@ +use core::time::Duration; + +use abscissa_core::{ + clap::Parser, config::Override, Command, FrameworkError, FrameworkErrorKind, Runnable, +}; +use eyre::eyre; + +use ibc::{ + applications::{ + ics29_fee::msgs::pay_packet::build_pay_packet_message, + transfer::{Amount, Coin}, + }, + core::ics24_host::identifier::{ChainId, ChannelId, PortId}, +}; +use ibc_relayer::{ + chain::handle::ChainHandle, + config::Config, + transfer::{build_transfer_messages, send_messages, TransferOptions}, +}; + +use crate::{ + cli_utils::{check_can_send_on_channel, ChainHandlePair}, + conclude::{exit_with_unrecoverable_error, Output}, + prelude::*, +}; + +#[derive(Clone, Command, Debug, Parser, PartialEq, Eq)] +pub struct FeeTransferCmd { + #[clap( + long = "dst-chain", + required = true, + value_name = "DST_CHAIN_ID", + help_heading = "FLAGS", + help = "Identifier of the destination chain" + )] + dst_chain_id: ChainId, + + #[clap( + long = "src-chain", + required = true, + value_name = "SRC_CHAIN_ID", + help_heading = "FLAGS", + help = "Identifier of the source chain" + )] + src_chain_id: ChainId, + + #[clap( + long = "src-port", + required = true, + value_name = "SRC_PORT_ID", + help_heading = "FLAGS", + help = "Identifier of the source port" + )] + src_port_id: PortId, + + #[clap( + long = "src-channel", + visible_alias = "src-chan", + required = true, + value_name = "SRC_CHANNEL_ID", + help_heading = "FLAGS", + help = "Identifier of the source channel" + )] + src_channel_id: ChannelId, + + #[clap( + long = "amount", + required = true, + value_name = "AMOUNT", + help_heading = "FLAGS", + help = "Amount of coins (samoleans, by default) to send (e.g. `100000`)" + )] + amount: Amount, + + #[clap( + long = "denom", + value_name = "DENOM", + help = "Denomination of the coins to send. Default: samoleans", + default_value = "samoleans" + )] + denom: String, + + #[clap( + long = "recipient", + value_name = "RECIPIENT", + help = "The account address on the destination chain which will receive the tokens. If omitted, the relayer's wallet on the destination chain will be used" + )] + recipient: Option, + + #[clap( + long = "number-msgs", + value_name = "NUMBER_MSGS", + help = "Number of messages to send" + )] + number_msgs: Option, + + #[clap( + long = "key-name", + value_name = "KEY_NAME", + help = "Use the given signing key name (default: `key_name` config)" + )] + key_name: Option, + + #[clap( + long = "timeout-height-offset", + default_value = "0", + value_name = "TIMEOUT_HEIGHT_OFFSET", + help = "Timeout in number of blocks since current. Default: 0" + )] + timeout_height_offset: u64, + + #[clap( + long = "timeout-seconds", + default_value = "0", + value_name = "TIMEOUT_SECONDS", + help = "Timeout in seconds since current. Default: 0" + )] + timeout_seconds: u64, + + #[clap( + long = "receive-fee", + value_name = "RECEIVE_FEE", + help = "Fee to pay for the Recv message. Default: 0", + default_value = "0" + )] + receive_fee: Amount, + + #[clap( + long = "ack-fee", + value_name = "ACK_FEE", + help = "Fee to pay for the Ack message. Default: 0", + default_value = "0" + )] + ack_fee: Amount, + + #[clap( + long = "timeout-fee", + value_name = "TIMEOUT_FEE", + help = "Fee to pay for the Timeout message. Default: 0", + default_value = "0" + )] + timeout_fee: Amount, +} + +impl Override for FeeTransferCmd { + fn override_config(&self, mut config: Config) -> Result { + let src_chain_config = config.find_chain_mut(&self.src_chain_id).ok_or_else(|| { + FrameworkErrorKind::ComponentError.context(format!( + "missing configuration for source chain '{}'", + self.src_chain_id + )) + })?; + + if let Some(ref key_name) = self.key_name { + src_chain_config.key_name = key_name.to_string(); + } + + Ok(config) + } +} + +impl FeeTransferCmd { + fn validate_options(&self, config: &Config) -> eyre::Result { + config.find_chain(&self.src_chain_id).ok_or_else(|| { + eyre!( + "missing configuration for source chain '{}'", + self.src_chain_id + ) + })?; + + config.find_chain(&self.dst_chain_id).ok_or_else(|| { + eyre!( + "missing configuration for destination chain '{}'", + self.dst_chain_id + ) + })?; + + let denom = self.denom.clone(); + + let number_msgs = self.number_msgs.unwrap_or(1); + if number_msgs == 0 { + return Err(eyre!("number of messages should be greater than zero")); + } + + let opts = FeeTransferOptions { + src_chain_id: self.src_chain_id.clone(), + dst_chain_id: self.dst_chain_id.clone(), + src_port_id: self.src_port_id.clone(), + src_channel_id: self.src_channel_id.clone(), + amount: self.amount, + denom, + receiver: self.recipient.clone(), + timeout_height_offset: self.timeout_height_offset, + timeout_duration: Duration::from_secs(self.timeout_seconds), + number_msgs, + receive_fee: self.receive_fee, + ack_fee: self.ack_fee, + timeout_fee: self.timeout_fee, + }; + + Ok(opts) + } +} + +impl Runnable for FeeTransferCmd { + fn run(&self) { + let config = app_config(); + + let opts = match self.validate_options(&config) { + Err(err) => Output::error(err).exit(), + Ok(result) => result, + }; + + let chains = ChainHandlePair::spawn(&config, &self.src_chain_id, &self.dst_chain_id) + .unwrap_or_else(exit_with_unrecoverable_error); + + fee_transfer(chains, opts).unwrap_or_else(exit_with_unrecoverable_error); + } +} + +#[derive(Clone, Debug)] +pub struct FeeTransferOptions { + pub src_chain_id: ChainId, + pub dst_chain_id: ChainId, + pub src_port_id: PortId, + pub src_channel_id: ChannelId, + pub amount: Amount, + pub denom: String, + pub receiver: Option, + pub timeout_height_offset: u64, + pub timeout_duration: Duration, + pub number_msgs: usize, + pub receive_fee: Amount, + pub ack_fee: Amount, + pub timeout_fee: Amount, +} + +impl From for TransferOptions { + fn from(f: FeeTransferOptions) -> Self { + TransferOptions { + src_port_id: f.src_port_id, + src_channel_id: f.src_channel_id, + amount: f.amount, + denom: f.denom, + receiver: f.receiver, + timeout_height_offset: f.timeout_height_offset, + timeout_duration: f.timeout_duration, + number_msgs: f.number_msgs, + } + } +} + +fn fee_transfer(chains: ChainHandlePair, opts: FeeTransferOptions) -> Result<(), eyre::Report> { + check_can_send_on_channel( + &chains.src, + &opts.src_channel_id, + &opts.src_port_id, + &opts.dst_chain_id, + )?; + + let sender = chains.src.get_signer()?; + let receive_fee = Coin::new(opts.denom.clone(), opts.receive_fee); + let ack_fee = Coin::new(opts.denom.clone(), opts.ack_fee); + let timeout_fee = Coin::new(opts.denom.clone(), opts.timeout_fee); + + let pay_message = build_pay_packet_message( + &opts.src_port_id, + &opts.src_channel_id, + &sender, + vec![receive_fee], + vec![ack_fee], + vec![timeout_fee], + )?; + + // Recommended by ICS29 https://github.com/cosmos/ibc/blob/main/spec/app/ics-029-fee-payment/README.md: + // "it is recommended that fee middleware require their messages to be placed before the send packet message and escrow + // fees for the next sequence on the given channel." + // In addition, a fee message is sent for every transfer message. + let mut msgs = vec![]; + + let transfer = build_transfer_messages(&chains.src, &chains.dst, &opts.into())?; + for t in transfer { + msgs.push(pay_message.clone()); + msgs.push(t); + } + + let res = send_messages(&chains.src, msgs); + + match res { + Ok(ev) => Output::success(ev).exit(), + Err(e) => Output::error(format!("{}", e)).exit(), + } +} + +#[cfg(test)] +mod tests { + + use super::FeeTransferCmd; + + use abscissa_core::clap::Parser; + use std::str::FromStr; + + use ibc::{ + applications::transfer::Amount, + core::ics24_host::identifier::{ChainId, ChannelId, PortId}, + }; + + #[test] + fn test_fee_transfer_required_only() { + assert_eq!( + FeeTransferCmd { + dst_chain_id: ChainId::from_string("chain_b"), + src_chain_id: ChainId::from_string("chain_a"), + src_port_id: PortId::from_str("port_a").unwrap(), + src_channel_id: ChannelId::from_str("channel_a").unwrap(), + amount: Amount::from(1000u64), + denom: "samoleans".to_owned(), + recipient: None, + number_msgs: None, + key_name: None, + timeout_height_offset: 0, + timeout_seconds: 0, + receive_fee: Amount::from(0u64), + ack_fee: Amount::from(0u64), + timeout_fee: Amount::from(0u64), + }, + FeeTransferCmd::parse_from(&[ + "test", + "--dst-chain", + "chain_b", + "--src-chain", + "chain_a", + "--src-port", + "port_a", + "--src-channel", + "channel_a", + "--amount", + "1000" + ]) + ) + } + + #[test] + fn test_fee_transfer_channel_alias() { + assert_eq!( + FeeTransferCmd { + dst_chain_id: ChainId::from_string("chain_b"), + src_chain_id: ChainId::from_string("chain_a"), + src_port_id: PortId::from_str("port_a").unwrap(), + src_channel_id: ChannelId::from_str("channel_a").unwrap(), + amount: Amount::from(1000u64), + denom: "samoleans".to_owned(), + recipient: None, + number_msgs: None, + key_name: None, + timeout_height_offset: 0, + timeout_seconds: 0, + receive_fee: Amount::from(0u64), + ack_fee: Amount::from(0u64), + timeout_fee: Amount::from(0u64), + }, + FeeTransferCmd::parse_from(&[ + "test", + "--dst-chain", + "chain_b", + "--src-chain", + "chain_a", + "--src-port", + "port_a", + "--src-chan", + "channel_a", + "--amount", + "1000" + ]) + ) + } + + #[test] + fn test_fee_transfer_denom() { + assert_eq!( + FeeTransferCmd { + dst_chain_id: ChainId::from_string("chain_b"), + src_chain_id: ChainId::from_string("chain_a"), + src_port_id: PortId::from_str("port_a").unwrap(), + src_channel_id: ChannelId::from_str("channel_a").unwrap(), + amount: Amount::from(1000u64), + denom: "stake".to_owned(), + recipient: None, + number_msgs: None, + key_name: None, + timeout_height_offset: 0, + timeout_seconds: 0, + receive_fee: Amount::from(0u64), + ack_fee: Amount::from(0u64), + timeout_fee: Amount::from(0u64), + }, + FeeTransferCmd::parse_from(&[ + "test", + "--dst-chain", + "chain_b", + "--src-chain", + "chain_a", + "--src-port", + "port_a", + "--src-channel", + "channel_a", + "--amount", + "1000", + "--denom", + "stake" + ]) + ) + } + + #[test] + fn test_fee_transfer_recipient() { + assert_eq!( + FeeTransferCmd { + dst_chain_id: ChainId::from_string("chain_b"), + src_chain_id: ChainId::from_string("chain_a"), + src_port_id: PortId::from_str("port_a").unwrap(), + src_channel_id: ChannelId::from_str("channel_a").unwrap(), + amount: Amount::from(1000u64), + denom: "samoleans".to_owned(), + recipient: Some("other_recipient".to_owned()), + number_msgs: None, + key_name: None, + timeout_height_offset: 0, + timeout_seconds: 0, + receive_fee: Amount::from(0u64), + ack_fee: Amount::from(0u64), + timeout_fee: Amount::from(0u64), + }, + FeeTransferCmd::parse_from(&[ + "test", + "--dst-chain", + "chain_b", + "--src-chain", + "chain_a", + "--src-port", + "port_a", + "--src-channel", + "channel_a", + "--amount", + "1000", + "--recipient", + "other_recipient" + ]) + ) + } + + #[test] + fn test_fee_transfer_number_msgs() { + assert_eq!( + FeeTransferCmd { + dst_chain_id: ChainId::from_string("chain_b"), + src_chain_id: ChainId::from_string("chain_a"), + src_port_id: PortId::from_str("port_a").unwrap(), + src_channel_id: ChannelId::from_str("channel_a").unwrap(), + amount: Amount::from(1000u64), + denom: "samoleans".to_owned(), + recipient: None, + number_msgs: Some(10), + key_name: None, + timeout_height_offset: 0, + timeout_seconds: 0, + receive_fee: Amount::from(0u64), + ack_fee: Amount::from(0u64), + timeout_fee: Amount::from(0u64), + }, + FeeTransferCmd::parse_from(&[ + "test", + "--dst-chain", + "chain_b", + "--src-chain", + "chain_a", + "--src-port", + "port_a", + "--src-channel", + "channel_a", + "--amount", + "1000", + "--number-msgs", + "10" + ]) + ) + } + + #[test] + fn test_fee_transfer_key_name() { + assert_eq!( + FeeTransferCmd { + dst_chain_id: ChainId::from_string("chain_b"), + src_chain_id: ChainId::from_string("chain_a"), + src_port_id: PortId::from_str("port_a").unwrap(), + src_channel_id: ChannelId::from_str("channel_a").unwrap(), + amount: Amount::from(1000u64), + denom: "samoleans".to_owned(), + recipient: None, + number_msgs: None, + key_name: Some("other_wallet".to_owned()), + timeout_height_offset: 0, + timeout_seconds: 0, + receive_fee: Amount::from(0u64), + ack_fee: Amount::from(0u64), + timeout_fee: Amount::from(0u64), + }, + FeeTransferCmd::parse_from(&[ + "test", + "--dst-chain", + "chain_b", + "--src-chain", + "chain_a", + "--src-port", + "port_a", + "--src-channel", + "channel_a", + "--amount", + "1000", + "--key-name", + "other_wallet" + ]) + ) + } + + #[test] + fn test_fee_transfer_timeout_heightoffset() { + assert_eq!( + FeeTransferCmd { + dst_chain_id: ChainId::from_string("chain_b"), + src_chain_id: ChainId::from_string("chain_a"), + src_port_id: PortId::from_str("port_a").unwrap(), + src_channel_id: ChannelId::from_str("channel_a").unwrap(), + amount: Amount::from(1000u64), + denom: "samoleans".to_owned(), + recipient: None, + number_msgs: None, + key_name: None, + timeout_height_offset: 42, + timeout_seconds: 0, + receive_fee: Amount::from(0u64), + ack_fee: Amount::from(0u64), + timeout_fee: Amount::from(0u64), + }, + FeeTransferCmd::parse_from(&[ + "test", + "--dst-chain", + "chain_b", + "--src-chain", + "chain_a", + "--src-port", + "port_a", + "--src-channel", + "channel_a", + "--amount", + "1000", + "--timeout-height-offset", + "42" + ]) + ) + } + + #[test] + fn test_fee_transfer_timeout_seconds() { + assert_eq!( + FeeTransferCmd { + dst_chain_id: ChainId::from_string("chain_b"), + src_chain_id: ChainId::from_string("chain_a"), + src_port_id: PortId::from_str("port_a").unwrap(), + src_channel_id: ChannelId::from_str("channel_a").unwrap(), + amount: Amount::from(1000u64), + denom: "samoleans".to_owned(), + recipient: None, + number_msgs: None, + key_name: None, + timeout_height_offset: 0, + timeout_seconds: 21, + receive_fee: Amount::from(0u64), + ack_fee: Amount::from(0u64), + timeout_fee: Amount::from(0u64), + }, + FeeTransferCmd::parse_from(&[ + "test", + "--dst-chain", + "chain_b", + "--src-chain", + "chain_a", + "--src-port", + "port_a", + "--src-channel", + "channel_a", + "--amount", + "1000", + "--timeout-seconds", + "21" + ]) + ) + } + + #[test] + fn test_fee_transfer_receive_fee() { + assert_eq!( + FeeTransferCmd { + dst_chain_id: ChainId::from_string("chain_b"), + src_chain_id: ChainId::from_string("chain_a"), + src_port_id: PortId::from_str("port_a").unwrap(), + src_channel_id: ChannelId::from_str("channel_a").unwrap(), + amount: Amount::from(1000u64), + denom: "samoleans".to_owned(), + recipient: None, + number_msgs: None, + key_name: None, + timeout_height_offset: 0, + timeout_seconds: 0, + receive_fee: Amount::from(51u64), + ack_fee: Amount::from(0u64), + timeout_fee: Amount::from(0u64), + }, + FeeTransferCmd::parse_from(&[ + "test", + "--dst-chain", + "chain_b", + "--src-chain", + "chain_a", + "--src-port", + "port_a", + "--src-channel", + "channel_a", + "--amount", + "1000", + "--receive-fee", + "51" + ]) + ) + } + #[test] + fn test_fee_transfer_ack_fee() { + assert_eq!( + FeeTransferCmd { + dst_chain_id: ChainId::from_string("chain_b"), + src_chain_id: ChainId::from_string("chain_a"), + src_port_id: PortId::from_str("port_a").unwrap(), + src_channel_id: ChannelId::from_str("channel_a").unwrap(), + amount: Amount::from(1000u64), + denom: "samoleans".to_owned(), + recipient: None, + number_msgs: None, + key_name: None, + timeout_height_offset: 0, + timeout_seconds: 0, + receive_fee: Amount::from(0u64), + ack_fee: Amount::from(52u64), + timeout_fee: Amount::from(0u64), + }, + FeeTransferCmd::parse_from(&[ + "test", + "--dst-chain", + "chain_b", + "--src-chain", + "chain_a", + "--src-port", + "port_a", + "--src-channel", + "channel_a", + "--amount", + "1000", + "--ack-fee", + "52" + ]) + ) + } + + #[test] + fn test_fee_transfer_timeout_fee() { + assert_eq!( + FeeTransferCmd { + dst_chain_id: ChainId::from_string("chain_b"), + src_chain_id: ChainId::from_string("chain_a"), + src_port_id: PortId::from_str("port_a").unwrap(), + src_channel_id: ChannelId::from_str("channel_a").unwrap(), + amount: Amount::from(1000u64), + denom: "samoleans".to_owned(), + recipient: None, + number_msgs: None, + key_name: None, + timeout_height_offset: 0, + timeout_seconds: 0, + receive_fee: Amount::from(0u64), + ack_fee: Amount::from(0u64), + timeout_fee: Amount::from(53u64), + }, + FeeTransferCmd::parse_from(&[ + "test", + "--dst-chain", + "chain_b", + "--src-chain", + "chain_a", + "--src-port", + "port_a", + "--src-channel", + "channel_a", + "--amount", + "1000", + "--timeout-fee", + "53" + ]) + ) + } + + #[test] + fn test_fee_transfer_no_amount() { + assert!(FeeTransferCmd::try_parse_from(&[ + "test", + "--dst-chain", + "chain_b", + "--src-chain", + "chain_a", + "--src-port", + "port_a", + "--src-channel", + "channel_a" + ]) + .is_err()) + } + + #[test] + fn test_fee_transfer_no_src_channel() { + assert!(FeeTransferCmd::try_parse_from(&[ + "test", + "--dst-chain", + "chain_b", + "--src-chain", + "chain_a", + "--src-port", + "port_a", + "--amount", + "1000" + ]) + .is_err()) + } + + #[test] + fn test_fee_transfer_no_src_port() { + assert!(FeeTransferCmd::try_parse_from(&[ + "test", + "--dst-chain", + "chain_b", + "--src-chain", + "chain_a", + "--src-channel", + "channel_a", + "--amount", + "1000" + ]) + .is_err()) + } + + #[test] + fn test_fee_transfer_no_src_chain() { + assert!(FeeTransferCmd::try_parse_from(&[ + "test", + "--dst-chain", + "chain_b", + "--src-port", + "port_a", + "--src-channel", + "channel_a", + "--amount", + "1000" + ]) + .is_err()) + } + + #[test] + fn test_fee_transfer_no_dst_chain() { + assert!(FeeTransferCmd::try_parse_from(&[ + "test", + "--src-chain", + "chain_a", + "--src-port", + "port_a", + "--src-channel", + "channel_a", + "--amount", + "1000" + ]) + .is_err()) + } +} diff --git a/crates/relayer-cli/src/commands/tx/transfer.rs b/crates/relayer-cli/src/commands/tx/transfer.rs index 923a7650db..f265e84316 100644 --- a/crates/relayer-cli/src/commands/tx/transfer.rs +++ b/crates/relayer-cli/src/commands/tx/transfer.rs @@ -5,22 +5,16 @@ use core::time::Duration; use eyre::eyre; use ibc::{ applications::transfer::Amount, - core::{ - ics02_client::client_state::ClientState, - ics24_host::identifier::{ChainId, ChannelId, PortId}, - }, + core::ics24_host::identifier::{ChainId, ChannelId, PortId}, events::IbcEvent, }; use ibc_relayer::chain::handle::ChainHandle; -use ibc_relayer::chain::requests::{ - IncludeProof, QueryChannelRequest, QueryClientStateRequest, QueryConnectionRequest, QueryHeight, -}; use ibc_relayer::{ config::Config, transfer::{build_and_send_transfer_messages, TransferOptions}, }; -use crate::cli_utils::ChainHandlePair; +use crate::cli_utils::{check_can_send_on_channel, ChainHandlePair}; use crate::conclude::{exit_with_unrecoverable_error, Output}; use crate::error::Error; use crate::prelude::*; @@ -160,8 +154,8 @@ impl TxIcs20MsgTransferCmd { } let opts = TransferOptions { - packet_src_port_id: self.src_port_id.clone(), - packet_src_channel_id: self.src_channel_id.clone(), + src_port_id: self.src_port_id.clone(), + src_channel_id: self.src_channel_id.clone(), amount: self.amount, denom, receiver: self.receiver.clone(), @@ -186,80 +180,13 @@ impl Runnable for TxIcs20MsgTransferCmd { let chains = ChainHandlePair::spawn(&config, &self.src_chain_id, &self.dst_chain_id) .unwrap_or_else(exit_with_unrecoverable_error); - // Double check that channels and chain identifiers match. - // To do this, fetch from the source chain the channel end, then the associated connection - // end, and then the underlying client state; finally, check that this client is verifying - // headers for the destination chain. - let (channel_end_src, _) = chains - .src - .query_channel( - QueryChannelRequest { - port_id: opts.packet_src_port_id.clone(), - channel_id: opts.packet_src_channel_id.clone(), - height: QueryHeight::Latest, - }, - IncludeProof::No, - ) - .unwrap_or_else(exit_with_unrecoverable_error); - if !channel_end_src.is_open() { - Output::error(format!( - "the requested port/channel ('{}'/'{}') on chain id '{}' is in state '{}'; expected 'open' state", - opts.packet_src_port_id, - opts.packet_src_channel_id, - self.src_chain_id, - channel_end_src.state - )) - .exit(); - } - - let conn_id = match channel_end_src.connection_hops.first() { - None => { - Output::error(format!( - "could not retrieve the connection hop underlying port/channel '{}'/'{}' on chain '{}'", - opts.packet_src_port_id, opts.packet_src_channel_id, self.src_chain_id - )) - .exit(); - } - Some(cid) => cid, - }; - - let (conn_end, _) = chains - .src - .query_connection( - QueryConnectionRequest { - connection_id: conn_id.clone(), - height: QueryHeight::Latest, - }, - IncludeProof::No, - ) - .unwrap_or_else(exit_with_unrecoverable_error); - - debug!("connection hop underlying the channel: {:?}", conn_end); - - let (src_chain_client_state, _) = chains - .src - .query_client_state( - QueryClientStateRequest { - client_id: conn_end.client_id().clone(), - height: QueryHeight::Latest, - }, - IncludeProof::No, - ) - .unwrap_or_else(exit_with_unrecoverable_error); - - debug!( - "client state underlying the channel: {:?}", - src_chain_client_state - ); - - if src_chain_client_state.chain_id() != self.dst_chain_id { - Output::error( - format!("the requested port/channel ('{}'/'{}') provides a path from chain '{}' to \ - chain '{}' (not to the destination chain '{}'). Bailing due to mismatching arguments.", - opts.packet_src_port_id, opts.packet_src_channel_id, - self.src_chain_id, - src_chain_client_state.chain_id(), self.dst_chain_id)).exit(); - } + check_can_send_on_channel( + &chains.src, + &opts.src_channel_id, + &opts.src_port_id, + &chains.dst.id(), + ) + .unwrap_or_else(exit_with_unrecoverable_error); // Checks pass, build and send the tx let res: Result, Error> = diff --git a/crates/relayer/src/transfer.rs b/crates/relayer/src/transfer.rs index 1acff0f02e..5f85a47748 100644 --- a/crates/relayer/src/transfer.rs +++ b/crates/relayer/src/transfer.rs @@ -116,8 +116,8 @@ impl TransferTimeout { #[derive(Clone, Debug)] pub struct TransferOptions { - pub packet_src_port_id: PortId, - pub packet_src_channel_id: ChannelId, + pub src_port_id: PortId, + pub src_channel_id: ChannelId, pub amount: Amount, pub denom: String, pub receiver: Option, @@ -127,8 +127,8 @@ pub struct TransferOptions { } pub fn build_transfer_message( - packet_src_port_id: PortId, - packet_src_channel_id: ChannelId, + src_port_id: PortId, + src_channel_id: ChannelId, amount: Amount, denom: String, sender: Signer, @@ -137,8 +137,8 @@ pub fn build_transfer_message( timeout_timestamp: Timestamp, ) -> Any { let msg = MsgTransfer { - source_port: packet_src_port_id, - source_channel: packet_src_channel_id, + source_port: src_port_id, + source_channel: src_channel_id, token: Coin { denom, amount: amount.to_string(), @@ -152,19 +152,19 @@ pub fn build_transfer_message( 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 +pub fn build_transfer_messages( + src_chain: &SrcChain, // the chain whose account is debited + dst_chain: &DstChain, // the chain whose account eventually gets credited opts: &TransferOptions, -) -> Result, TransferError> { +) -> Result, TransferError> { let receiver = match &opts.receiver { Some(receiver) => Signer::from_str(receiver).map_err(TransferError::receiver_address)?, - None => packet_dst_chain.get_signer().map_err(TransferError::key)?, + None => dst_chain.get_signer().map_err(TransferError::key)?, }; - let sender = packet_src_chain.get_signer().map_err(TransferError::key)?; + let sender = src_chain.get_signer().map_err(TransferError::key)?; - let destination_chain_status = packet_dst_chain + let destination_chain_status = dst_chain .query_application_status() .map_err(TransferError::relayer)?; @@ -175,8 +175,8 @@ pub fn build_and_send_transfer_messages( + // the chain to send the messages to + chain: &Chain, + // messages to send the chain + msgs: Vec, +) -> Result, TransferError> { + let events_with_heights = chain .send_messages_and_wait_commit(TrackedMsgs::new_static(msgs, "ft-transfer")) - .map_err(|e| TransferError::submit(packet_src_chain.id(), e))?; + .map_err(|e| TransferError::submit(chain.id(), e))?; // Check if the chain rejected the transaction let result = events_with_heights @@ -210,3 +219,15 @@ pub fn build_and_send_transfer_messages( + // the chain whose account is debited + src_chain: &SrcChain, + // the chain whose account eventually gets credited + dst_chain: &DstChain, + // options describing the transfer + opts: &TransferOptions, +) -> Result, TransferError> { + let msgs = build_transfer_messages(src_chain, dst_chain, opts)?; + send_messages(src_chain, msgs) +} diff --git a/guide/src/templates/commands/hermes/fee/register-counterparty-payee_1.md b/guide/src/templates/commands/hermes/fee/register-counterparty-payee_1.md new file mode 100644 index 0000000000..16ba2d7833 --- /dev/null +++ b/guide/src/templates/commands/hermes/fee/register-counterparty-payee_1.md @@ -0,0 +1 @@ +[[#BINARY hermes]][[#GLOBALOPTIONS]] fee register-counterparty-payee --chain [[#CHAIN_ID]] --channel [[#CHANNEL_ID]] --port [[#PORT_ID]] --counterparty-payee [[#COUNTERPARTY_PAYEE_ADDRESS]] \ No newline at end of file diff --git a/guide/src/templates/commands/hermes/fee/register-payee_1.md b/guide/src/templates/commands/hermes/fee/register-payee_1.md new file mode 100644 index 0000000000..aa6093733f --- /dev/null +++ b/guide/src/templates/commands/hermes/fee/register-payee_1.md @@ -0,0 +1 @@ +[[#BINARY hermes]][[#GLOBALOPTIONS]] fee register-payee --chain [[#CHAIN_ID]] --channel [[#CHANNEL_ID]] --port [[#PORT_ID]] --payee [[#PAYEE_ADDRESS]] \ No newline at end of file diff --git a/guide/src/templates/commands/hermes/fee/transfer_1.md b/guide/src/templates/commands/hermes/fee/transfer_1.md new file mode 100644 index 0000000000..ebd0e125c2 --- /dev/null +++ b/guide/src/templates/commands/hermes/fee/transfer_1.md @@ -0,0 +1 @@ +[[#BINARY hermes]][[#GLOBALOPTIONS]] fee transfer[[#OPTIONS]] --dst-chain [[#DST_CHAIN_ID]] --src-chain [[#SRC_CHAIN_ID]] --src-port [[#SRC_PORT_ID]] --src-channel [[#SRC_CHANNEL_ID]] --amount [[#AMOUNT]] \ No newline at end of file diff --git a/guide/src/templates/commands/hermes/fee_1.md b/guide/src/templates/commands/hermes/fee_1.md new file mode 100644 index 0000000000..0020a68d1c --- /dev/null +++ b/guide/src/templates/commands/hermes/fee_1.md @@ -0,0 +1 @@ +[[#BINARY hermes]][[#GLOBALOPTIONS]] fee [[#SUBCOMMAND]] \ No newline at end of file diff --git a/guide/src/templates/help_templates/fee.md b/guide/src/templates/help_templates/fee.md new file mode 100644 index 0000000000..400e6faa8c --- /dev/null +++ b/guide/src/templates/help_templates/fee.md @@ -0,0 +1,14 @@ +DESCRIPTION: +Interact with the fee middleware + +USAGE: + hermes fee + +OPTIONS: + -h, --help Print help information + +SUBCOMMANDS: + help Print this message or the help of the given subcommand(s) + register-counterparty-payee Register a counterparty payee for a channel + register-payee Register a payee for a channel + transfer Perform a token transfer supported with a fee diff --git a/guide/src/templates/help_templates/fee/register-counterparty-payee.md b/guide/src/templates/help_templates/fee/register-counterparty-payee.md new file mode 100644 index 0000000000..ab8d423d13 --- /dev/null +++ b/guide/src/templates/help_templates/fee/register-counterparty-payee.md @@ -0,0 +1,14 @@ +DESCRIPTION: +Register a counterparty payee for a channel + +USAGE: + hermes fee register-counterparty-payee --chain --channel --port --counterparty-payee + +OPTIONS: + -h, --help Print help information + +FLAGS: + --chain Identifier of the chain + --channel Identifier of the channel + --counterparty-payee Address of the counterparty payee + --port Identifier of the port diff --git a/guide/src/templates/help_templates/fee/register-payee.md b/guide/src/templates/help_templates/fee/register-payee.md new file mode 100644 index 0000000000..77b29be1d3 --- /dev/null +++ b/guide/src/templates/help_templates/fee/register-payee.md @@ -0,0 +1,14 @@ +DESCRIPTION: +Register a payee for a channel + +USAGE: + hermes fee register-payee --chain --channel --port --payee + +OPTIONS: + -h, --help Print help information + +FLAGS: + --chain Identifier of the chain + --channel Identifier of the channel + --payee Address of the payee + --port Identifier of the port diff --git a/guide/src/templates/help_templates/fee/transfer.md b/guide/src/templates/help_templates/fee/transfer.md new file mode 100644 index 0000000000..6ae3faf741 --- /dev/null +++ b/guide/src/templates/help_templates/fee/transfer.md @@ -0,0 +1,53 @@ +DESCRIPTION: +Perform a token transfer supported with a fee + +USAGE: + hermes fee transfer [OPTIONS] --dst-chain --src-chain --src-port --src-channel --amount + +OPTIONS: + --ack-fee + Fee to pay for the Ack message. Default: 0 [default: 0] + + --denom + Denomination of the coins to send. Default: samoleans [default: samoleans] + + -h, --help + Print help information + + --key-name + Use the given signing key name (default: `key_name` config) + + --number-msgs + Number of messages to send + + --receive-fee + Fee to pay for the Recv message. Default: 0 [default: 0] + + --recipient + The account address on the destination chain which will receive the tokens. If omitted, + the relayer's wallet on the destination chain will be used + + --timeout-fee + Fee to pay for the Timeout message. Default: 0 [default: 0] + + --timeout-height-offset + Timeout in number of blocks since current. Default: 0 [default: 0] + + --timeout-seconds + Timeout in seconds since current. Default: 0 [default: 0] + +FLAGS: + --amount + Amount of coins (samoleans, by default) to send (e.g. `100000`) + + --dst-chain + Identifier of the destination chain + + --src-chain + Identifier of the source chain + + --src-channel + Identifier of the source channel [aliases: src-chan] + + --src-port + Identifier of the source port diff --git a/guide/src/templates/help_templates/help.md b/guide/src/templates/help_templates/help.md index 4083a04133..6c56d6d60d 100644 --- a/guide/src/templates/help_templates/help.md +++ b/guide/src/templates/help_templates/help.md @@ -15,6 +15,7 @@ SUBCOMMANDS: clear Clear objects, such as outstanding packets on a channel config Validate Hermes configuration file create Create objects (client, connection, or channel) on chains + fee Interact with the fee middleware health-check Performs a health check of all chains in the the config help Print this message or the help of the given subcommand(s) keys Manage keys in the relayer for each chain diff --git a/scripts/auto_gen_templates.sh b/scripts/auto_gen_templates.sh index bdfba92903..5ad8363f5e 100644 --- a/scripts/auto_gen_templates.sh +++ b/scripts/auto_gen_templates.sh @@ -2,6 +2,7 @@ # This script is used to generate the templates for the guide SCRIPT_NAME="$0" +SED=$(command -v gsed || command -v sed) function usage() { echo "Usage: $SCRIPT_NAME --mode " @@ -71,28 +72,32 @@ function print_array() { } function generate_commands_rec(){ - # Called by generate_commands to generate every command or Hermes. + # Called by generate_commands to generate every command or Hermes. # Echo all the subcommands of the commands given by $2. - # Args : + # Args : # - $1: Command prefix with whitespaces replaced by '/' # - $2: Beginning of the array of commands - local cmd_prefix=$(echo $1 | sed 's/\// /g') + local cmd_prefix=$(echo $1 | $SED 's/\// /g') shift for command in "$@"; do # Since there is no delimiter between two subcommands, a trick can be to cut the line up to the N-th character - if [ $command = "tx" ]; then + if [ $command = "fee" ]; then + # The fee command needs a longer cut than the others + local cut=31 + elif [ $command = "tx" ]; then # The tx command needs a longer cut than the others local cut=25 - else + else local cut=19 fi + # if command is not help and not empty then echo its subcommands and call the function recursively if [ "$command" != "help" ] && [ ! -z "$command" ]; then - local new_commands=$(cargo run -q --bin hermes $cmd_prefix $command --help | sed '0,/^SUBCOMMANDS:.*/d' | cut -c 1-$cut | sed '/^\s*$/d ; s/\s\+\(\S\+\)\s*.*/\1/') + local new_commands=$(cargo run -q --bin hermes $cmd_prefix $command --help | $SED '0,/^SUBCOMMANDS:.*/d' | cut -c 1-$cut | $SED '/^\s*$/d ; s/\s\+\(\S\+\)\s*.*/\1/') if [ -z "$cmd_prefix" ]; then local new_cmd_prefix=$command else - local new_cmd_prefix=$(echo $cmd_prefix"/"$command | sed 's/ /\//g') + local new_cmd_prefix=$(echo $cmd_prefix"/"$command | $SED 's/ /\//g') fi if [ ! -z "$new_commands" ]; then print_array_with_prefix $new_cmd_prefix $new_commands @@ -106,7 +111,7 @@ function generate_commands_rec(){ function generate_commands(){ # Generates the list of every commands of Hermes echo "version" # Special case - local new_commands=$(cargo run -q --bin hermes help | sed '0,/^SUBCOMMANDS:.*/d ; s/\s\+\(\S\+\)\s*.*/\1/') + local new_commands=$(cargo run -q --bin hermes help | $SED '0,/^SUBCOMMANDS:.*/d ; s/\s\+\(\S\+\)\s*.*/\1/') print_array $new_commands generate_commands_rec "" $new_commands } @@ -114,23 +119,23 @@ function generate_commands(){ function generate_help(){ # - In "update" mode, it will generate the help for each command and store it in the # corresponding file in the $HELP_DIR directory. - # + # # - In "check" mode, it will verify that the help files are up to date. # # Args : # - $1 : Array of commands where subcommands are separated by '/'. (e.g. ["query/channels", "config"]) if [ $MODE = "update" ]; then echo "Updating help templates. If any file is modified, please modify the guide accordingly." - else + else echo "Checking if help templates are up to date." fi for path in "$@"; do - command=$(echo "$path" | sed -e 's/\// /g') + command=$(echo "$path" | $SED -e 's/\// /g') # help commands are edge cases if [ $path != "help" ]; then - local command=$(echo "$path" | sed -e 's/\// /g')" --help" - else + local command=$(echo "$path" | $SED -e 's/\// /g')" --help" + else local command="help" fi @@ -141,7 +146,7 @@ function generate_help(){ dir="${filename%/*}" mkdir -p $dir - cargo run -q --bin hermes $command | sed '1s/.*/DESCRIPTION:/' > $TMP_PATH + cargo run -q --bin hermes $command | $SED '1s/.*/DESCRIPTION:/' > $TMP_PATH if ! cmp -s $TMP_PATH $filename; then if [ $MODE = "update" ]; then mv $TMP_PATH $filename @@ -156,7 +161,7 @@ function generate_help(){ } function generate_templates(){ - # - In update mode, it generates templates from the USAGE section of the help and stores it in the + # - In update mode, it generates templates from the USAGE section of the help and stores it in the # corresponding file in the $COMMAND_DIR directory. # - In check mode, it will verify that the template files are up to date. # @@ -164,24 +169,24 @@ function generate_templates(){ # - $1 : Array of commands where subcommands are separated by '/'. (e.g. ["query/channels", "config"]) if [ $MODE = "update" ]; then echo "Updating templates. If any file is modified, please modify the guide accordingly." - else + else echo "Checking if templates are up to date." fi for path in "$@"; do # help commands are edge cases if [ $path != "help" ]; then - local command=$(echo "$path" | sed -e 's/\// /g')" --help" - else + local command=$(echo "$path" | $SED -e 's/\// /g')" --help" + else local command="help" fi - + # Create the directory (if they don't exist) and the file local tmp="$COMMAND_DIR$path" local dir="${tmp%/*}" mkdir -p $dir local cpt=1 - cargo run -q --bin hermes $command | sed -n '/USAGE:/, /OPTIONS:/{ /USAGE:/! { /OPTIONS:/! p }}' | sed -r '/^\s*$/d ; s/^\s+// ; s//]]/g; s/hermes/[[#BINARY hermes]][[#GLOBALOPTIONS]]/ ; s/ \[(OPTIONS|SUBCOMMAND)]/\[\[#\1]]/g ;' | while read line || [[ -n $line ]] + cargo run -q --bin hermes $command | $SED -n '/USAGE:/, /OPTIONS:/{ /USAGE:/! { /OPTIONS:/! p }}' | $SED -r '/^\s*$/d ; s/^\s+// ; s//]]/g; s/hermes/[[#BINARY hermes]][[#GLOBALOPTIONS]]/ ; s/ \[(OPTIONS|SUBCOMMAND)]/\[\[#\1]]/g ;' | while read line || [[ -n $line ]] do # Create a template for every usage filename=$COMMAND_DIR$path"_$cpt.md" @@ -200,8 +205,18 @@ function generate_templates(){ done } +function is_gnu_sed() { + $SED --version > /dev/null 2>&1 +} + +# BSD sed does not have a --version option: https://www.freebsd.org/cgi/man.cgi?query=sed&sektion=&n=1 +# GNU sed has a --version option: https://www.gnu.org/software/sed/manual/sed.pdf +if ! is_gnu_sed ; then + echo "WARNING: gsed unavailable, using not GNU sed" +fi + commands=$(generate_commands) generate_help $commands generate_templates $commands -exit $OUTPUT \ No newline at end of file +exit $OUTPUT diff --git a/tools/integration-test/src/tests/manual/simulation.rs b/tools/integration-test/src/tests/manual/simulation.rs index 20296194bf..b44544229e 100644 --- a/tools/integration-test/src/tests/manual/simulation.rs +++ b/tools/integration-test/src/tests/manual/simulation.rs @@ -82,8 +82,8 @@ fn tx_raw_ft_transfer( 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().clone(), + src_port_id: channel.port_a.value().clone(), + src_channel_id: channel.channel_id_a.value().clone(), amount: amount.into(), denom: denom.value().to_string(), receiver: Some(recipient.value().0.clone()), From d426a69b6fe99b70147b0df4d52681108c205d99 Mon Sep 17 00:00:00 2001 From: Luca Joss Date: Mon, 10 Oct 2022 12:09:27 +0200 Subject: [PATCH 098/113] Added 'value_name', 'visible_alias' and unit-tests to the two new commands 'register-counterparty-payee' and 'register-payee' --- .../fee/register_counterparty_payee.rs | 118 ++++++++++++++++++ .../src/commands/fee/register_payee.rs | 117 +++++++++++++++++ 2 files changed, 235 insertions(+) diff --git a/crates/relayer-cli/src/commands/fee/register_counterparty_payee.rs b/crates/relayer-cli/src/commands/fee/register_counterparty_payee.rs index ab7c689a6e..41f68d4b8b 100644 --- a/crates/relayer-cli/src/commands/fee/register_counterparty_payee.rs +++ b/crates/relayer-cli/src/commands/fee/register_counterparty_payee.rs @@ -17,6 +17,7 @@ pub struct RegisterCounterpartyPayeeCmd { #[clap( long = "chain", required = true, + value_name = "CHAIN_ID", help_heading = "FLAGS", help = "Identifier of the chain" )] @@ -24,7 +25,9 @@ pub struct RegisterCounterpartyPayeeCmd { #[clap( long = "channel", + visible_alias = "chan", required = true, + value_name = "CHANNEL_ID", help_heading = "FLAGS", help = "Identifier of the channel" )] @@ -33,6 +36,7 @@ pub struct RegisterCounterpartyPayeeCmd { #[clap( long = "port", required = true, + value_name = "PORT_ID", help_heading = "FLAGS", help = "Identifier of the port" )] @@ -41,6 +45,7 @@ pub struct RegisterCounterpartyPayeeCmd { #[clap( long = "counterparty-payee", required = true, + value_name = "COUNTERPARTY_PAYEE_ADDRESS", help_heading = "FLAGS", help = "Address of the counterparty payee" )] @@ -91,3 +96,116 @@ fn run_register_counterparty_payee_command( Ok(()) } + +#[cfg(test)] +mod tests { + + use super::RegisterCounterpartyPayeeCmd; + + use abscissa_core::clap::Parser; + use std::str::FromStr; + + use ibc::core::ics24_host::identifier::{ChainId, ChannelId, PortId}; + + #[test] + fn test_register_counterparty_payee() { + assert_eq!( + RegisterCounterpartyPayeeCmd { + chain_id: ChainId::from_string("chain_a"), + channel_id: ChannelId::from_str("channel_a").unwrap(), + port_id: PortId::from_str("port_a").unwrap(), + counterparty_payee_address: "counterparty_address_hash".to_owned(), + }, + RegisterCounterpartyPayeeCmd::parse_from(&[ + "test", + "--chain", + "chain_a", + "--channel", + "channel_a", + "--port", + "port_a", + "--counterparty-payee", + "counterparty_address_hash" + ]) + ) + } + + #[test] + fn test_register_counterparty_payee_alias() { + assert_eq!( + RegisterCounterpartyPayeeCmd { + chain_id: ChainId::from_string("chain_a"), + channel_id: ChannelId::from_str("channel_a").unwrap(), + port_id: PortId::from_str("port_a").unwrap(), + counterparty_payee_address: "counterparty_address_hash".to_owned(), + }, + RegisterCounterpartyPayeeCmd::parse_from(&[ + "test", + "--chain", + "chain_a", + "--chan", + "channel_a", + "--port", + "port_a", + "--counterparty-payee", + "counterparty_address_hash" + ]) + ) + } + + #[test] + fn test_register_counterparty_payee_no_counterparty_payee() { + assert!(RegisterCounterpartyPayeeCmd::try_parse_from(&[ + "test", + "--chain", + "chain_a", + "--channel", + "channel_a", + "--port", + "port_a" + ]) + .is_err()) + } + + #[test] + fn test_register_counterparty_payee_no_port() { + assert!(RegisterCounterpartyPayeeCmd::try_parse_from(&[ + "test", + "--chain", + "chain_a", + "--channel", + "channel_a", + "--counterparty-payee", + "counterparty_address_hash" + ]) + .is_err()) + } + + #[test] + fn test_register_counterparty_payee_no_channel() { + assert!(RegisterCounterpartyPayeeCmd::try_parse_from(&[ + "test", + "--chain", + "chain_a", + "--port", + "port_a", + "--counterparty-payee", + "counterparty_address_hash" + ]) + .is_err()) + } + + #[test] + fn test_register_counterparty_payee_no_chain() { + assert!(RegisterCounterpartyPayeeCmd::try_parse_from(&[ + "test", + "--channel", + "channel_a", + "--port", + "port_a", + "--counterparty-payee", + "counterparty_address_hash" + ]) + .is_err()) + } +} diff --git a/crates/relayer-cli/src/commands/fee/register_payee.rs b/crates/relayer-cli/src/commands/fee/register_payee.rs index 63164aef9a..10c4f95b77 100644 --- a/crates/relayer-cli/src/commands/fee/register_payee.rs +++ b/crates/relayer-cli/src/commands/fee/register_payee.rs @@ -17,6 +17,7 @@ pub struct RegisterPayeeCmd { #[clap( long = "chain", required = true, + value_name = "CHAIN_ID", help_heading = "FLAGS", help = "Identifier of the chain" )] @@ -24,7 +25,9 @@ pub struct RegisterPayeeCmd { #[clap( long = "channel", + visible_alias = "chan", required = true, + value_name = "CHANNEL_ID", help_heading = "FLAGS", help = "Identifier of the channel" )] @@ -33,6 +36,7 @@ pub struct RegisterPayeeCmd { #[clap( long = "port", required = true, + value_name = "PORT_ID", help_heading = "FLAGS", help = "Identifier of the port" )] @@ -41,6 +45,7 @@ pub struct RegisterPayeeCmd { #[clap( long = "payee", required = true, + value_name = "PAYEE_ADDRESS", help_heading = "FLAGS", help = "Address of the payee" )] @@ -86,3 +91,115 @@ fn run_register_payee_command( Ok(()) } + +#[cfg(test)] +mod tests { + + use super::RegisterPayeeCmd; + + use abscissa_core::clap::Parser; + use std::str::FromStr; + + use ibc::core::ics24_host::identifier::{ChainId, ChannelId, PortId}; + + #[test] + fn test_regiser_payee() { + assert_eq!( + RegisterPayeeCmd { + chain_id: ChainId::from_string("chain_a"), + channel_id: ChannelId::from_str("channel_a").unwrap(), + port_id: PortId::from_str("port_a").unwrap(), + payee_address: "payee_address_hash".to_owned(), + }, + RegisterPayeeCmd::parse_from(&[ + "test", + "--chain", + "chain_a", + "--channel", + "channel_a", + "--port", + "port_a", + "--payee", + "payee_address_hash" + ]) + ) + } + #[test] + fn test_regiser_payee_alias() { + assert_eq!( + RegisterPayeeCmd { + chain_id: ChainId::from_string("chain_a"), + channel_id: ChannelId::from_str("channel_a").unwrap(), + port_id: PortId::from_str("port_a").unwrap(), + payee_address: "payee_address_hash".to_owned(), + }, + RegisterPayeeCmd::parse_from(&[ + "test", + "--chain", + "chain_a", + "--chan", + "channel_a", + "--port", + "port_a", + "--payee", + "payee_address_hash" + ]) + ) + } + + #[test] + fn test_register_payee_no_payee() { + assert!(RegisterPayeeCmd::try_parse_from(&[ + "test", + "--chain", + "chain_a", + "--channel", + "channel_a", + "--port", + "port_a" + ]) + .is_err()) + } + + #[test] + fn test_register_payee_no_port() { + assert!(RegisterPayeeCmd::try_parse_from(&[ + "test", + "--chain", + "chain_a", + "--channel", + "channel_a", + "--payee", + "payee_address_hash" + ]) + .is_err()) + } + + #[test] + fn test_register_payee_no_channel() { + assert!(RegisterPayeeCmd::try_parse_from(&[ + "test", + "--chain", + "chain_a", + "--port", + "port_a", + "--payee", + "payee_address_hash" + ]) + .is_err()) + } + + #[test] + fn test_register_payee_no_chain() { + assert!(RegisterPayeeCmd::try_parse_from(&[ + "test", + "--channel", + "channel_a", + "--port", + "port_a", + "--payee", + "payee_address_hash" + ]) + .is_err()) + } +} From 6f4c6344eea368d28f33c0eafeb90b1287720e9a Mon Sep 17 00:00:00 2001 From: Luca Joss Date: Mon, 10 Oct 2022 17:19:35 +0200 Subject: [PATCH 099/113] Missed renaming some 'ibc' to 'ibc_relayer_types' --- tools/integration-test/src/tests/fee/auto_forward_relayer.rs | 2 +- tools/integration-test/src/tests/fee/forward_relayer.rs | 2 +- tools/integration-test/src/tests/fee/no_forward_relayer.rs | 2 +- tools/integration-test/src/tests/fee/pay_fee_async.rs | 4 ++-- tools/integration-test/src/tests/fee/register_payee.rs | 2 +- tools/integration-test/src/tests/fee/timeout_fee.rs | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/integration-test/src/tests/fee/auto_forward_relayer.rs b/tools/integration-test/src/tests/fee/auto_forward_relayer.rs index 43ba51f9f5..e3478c9a53 100644 --- a/tools/integration-test/src/tests/fee/auto_forward_relayer.rs +++ b/tools/integration-test/src/tests/fee/auto_forward_relayer.rs @@ -1,4 +1,4 @@ -use ibc::core::ics04_channel::Version; +use ibc_relayer_types::core::ics04_channel::version::Version; use ibc_test_framework::prelude::*; use ibc_test_framework::util::random::random_u128_range; diff --git a/tools/integration-test/src/tests/fee/forward_relayer.rs b/tools/integration-test/src/tests/fee/forward_relayer.rs index f1cfd004be..74b7545f3b 100644 --- a/tools/integration-test/src/tests/fee/forward_relayer.rs +++ b/tools/integration-test/src/tests/fee/forward_relayer.rs @@ -1,4 +1,4 @@ -use ibc::core::ics04_channel::Version; +use ibc_relayer_types::core::ics04_channel::version::Version; use ibc_test_framework::prelude::*; use ibc_test_framework::util::random::random_u128_range; diff --git a/tools/integration-test/src/tests/fee/no_forward_relayer.rs b/tools/integration-test/src/tests/fee/no_forward_relayer.rs index 5246db7873..130825de4b 100644 --- a/tools/integration-test/src/tests/fee/no_forward_relayer.rs +++ b/tools/integration-test/src/tests/fee/no_forward_relayer.rs @@ -1,4 +1,4 @@ -use ibc::core::ics04_channel::Version; +use ibc_relayer_types::core::ics04_channel::version::Version; use ibc_test_framework::prelude::*; use ibc_test_framework::util::random::random_u128_range; diff --git a/tools/integration-test/src/tests/fee/pay_fee_async.rs b/tools/integration-test/src/tests/fee/pay_fee_async.rs index 9c4996c0e3..5c3fe29738 100644 --- a/tools/integration-test/src/tests/fee/pay_fee_async.rs +++ b/tools/integration-test/src/tests/fee/pay_fee_async.rs @@ -1,5 +1,5 @@ -use ibc::core::ics04_channel::Version; -use ibc::events::IbcEvent; +use ibc_relayer_types::core::ics04_channel::version::Version; +use ibc_relayer_types::events::IbcEvent; use ibc_test_framework::prelude::*; use ibc_test_framework::util::random::random_u128_range; diff --git a/tools/integration-test/src/tests/fee/register_payee.rs b/tools/integration-test/src/tests/fee/register_payee.rs index 1d2de7ce4d..6abccd3d80 100644 --- a/tools/integration-test/src/tests/fee/register_payee.rs +++ b/tools/integration-test/src/tests/fee/register_payee.rs @@ -1,4 +1,4 @@ -use ibc::core::ics04_channel::Version; +use ibc_relayer_types::core::ics04_channel::version::Version; use ibc_test_framework::prelude::*; use ibc_test_framework::util::random::random_u128_range; diff --git a/tools/integration-test/src/tests/fee/timeout_fee.rs b/tools/integration-test/src/tests/fee/timeout_fee.rs index f6b4938f28..70951bfe1a 100644 --- a/tools/integration-test/src/tests/fee/timeout_fee.rs +++ b/tools/integration-test/src/tests/fee/timeout_fee.rs @@ -1,4 +1,4 @@ -use ibc::core::ics04_channel::Version; +use ibc_relayer_types::core::ics04_channel::version::Version; use ibc_test_framework::prelude::*; use ibc_test_framework::util::random::random_u128_range; use std::thread; From bad93ffa0c1a47cbcab048b78754f1a632d253d8 Mon Sep 17 00:00:00 2001 From: Luca Joss Date: Mon, 10 Oct 2022 18:00:46 +0200 Subject: [PATCH 100/113] Regenerated Cargo.lock for no-std-check --- ci/no-std-check/Cargo.lock | 177 +++++++++++++++++++++++++++++-------- 1 file changed, 138 insertions(+), 39 deletions(-) diff --git a/ci/no-std-check/Cargo.lock b/ci/no-std-check/Cargo.lock index 667d6c8db6..421b6e90b3 100644 --- a/ci/no-std-check/Cargo.lock +++ b/ci/no-std-check/Cargo.lock @@ -263,6 +263,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + [[package]] name = "constant_time_eq" version = "0.1.5" @@ -346,6 +356,50 @@ dependencies = [ "zeroize", ] +[[package]] +name = "cxx" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f39818dcfc97d45b03953c1292efc4e80954e1583c4aa770bac1383e2310a4" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e580d70777c116df50c390d1211993f62d40302881e54d4b79727acb83d0199" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56a46460b88d1cec95112c8c363f0e2c39afdb237f60583b0b36343bf627ea9c" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "747b608fecf06b0d72d440f27acc99288207324b793be2c17991839f3d4995ea" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -724,21 +778,32 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.50" +version = "0.1.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd911b35d940d2bd0bea0f9100068e5b97b51a1cbe13d13382f132e0365257a0" +checksum = "f5a6ef98976b22b3b7f2f3a806f858cb862044cfa66805aa3ad84cb3d3b785ed" dependencies = [ "android_system_properties", "core-foundation-sys", + "iana-time-zone-haiku", "js-sys", "wasm-bindgen", "winapi", ] +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fde6edd6cef363e9359ed3c98ba64590ba9eecba2293eb5a723ab32aee8926aa" +dependencies = [ + "cxx", + "cxx-build", +] + [[package]] name = "ibc-proto" version = "0.20.1" -source = "git+https://github.com/cosmos/ibc-proto-rs#3fac7ce93c80126cc690d565c85be042e384b31c" +source = "git+https://github.com/cosmos/ibc-proto-rs#65c050e3a20e3a1ef3c1247788b5013112e207d7" dependencies = [ "base64", "bytes", @@ -760,6 +825,7 @@ dependencies = [ "flex-error", "ibc-proto", "ics23", + "itertools", "num-traits", "primitive-types 0.12.0", "prost", @@ -859,15 +925,9 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - -[[package]] -name = "itoa" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" +checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" [[package]] name = "js-sys" @@ -892,9 +952,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.134" +version = "0.2.135" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "329c933548736bc49fd575ee68c89e8be4d260064184389a5b77517cddd99ffb" +checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c" [[package]] name = "libsecp256k1" @@ -944,6 +1004,15 @@ dependencies = [ "libsecp256k1-core", ] +[[package]] +name = "link-cplusplus" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" +dependencies = [ + "cc", +] + [[package]] name = "lock_api" version = "0.4.9" @@ -1020,8 +1089,8 @@ dependencies = [ name = "no-std-check" version = "0.1.0" dependencies = [ - "ibc", "ibc-proto", + "ibc-relayer-types", "sp-core", "sp-io", "sp-runtime", @@ -1061,12 +1130,12 @@ dependencies = [ [[package]] name = "num-format" -version = "0.4.0" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bafe4179722c2894288ee77a9f044f02811c86af699344c498b0840c698a2465" +checksum = "54b862ff8df690cf089058c98b183676a7ed0f974cc08b426800093227cbff3b" dependencies = [ - "arrayvec 0.4.12", - "itoa 0.4.8", + "arrayvec 0.7.2", + "itoa", ] [[package]] @@ -1455,18 +1524,18 @@ dependencies = [ [[package]] name = "ref-cast" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed13bcd201494ab44900a96490291651d200730904221832b9547d24a87d332b" +checksum = "b8ebf632f3e32bf35133f620cf481f29c99ae0fb01450fd3d85eee0225274ec1" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5234cd6063258a5e32903b53b1b6ac043a0541c8adc1f610f67b0326c7a578fa" +checksum = "caab98faa75ce294d40512ce514a46b15eafe78d72c9397a68ea45b3a88201b6" dependencies = [ "proc-macro2", "quote", @@ -1628,6 +1697,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "scratch" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" + [[package]] name = "secrecy" version = "0.8.0" @@ -1668,11 +1743,11 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.85" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" +checksum = "41feea4228a6f1cd09ec7a3593a682276702cd67b5273544757dae23c096f074" dependencies = [ - "itoa 1.0.3", + "itoa", "ryu", "serde", ] @@ -1745,9 +1820,9 @@ dependencies = [ [[package]] name = "signature" -version = "1.6.3" +version = "1.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deb766570a2825fa972bceff0d195727876a9cdf2460ab2e52d455dc2de47fd9" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" [[package]] name = "slab" @@ -2124,9 +2199,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.101" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2" +checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1" dependencies = [ "proc-macro2", "quote", @@ -2211,6 +2286,15 @@ dependencies = [ "time", ] +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + [[package]] name = "thiserror" version = "1.0.37" @@ -2242,9 +2326,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.11" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c91f41dcb2f096c05f0873d667dceec1087ce5bcf984ec8ffb19acddbb3217" +checksum = "d634a985c4d4238ec39cacaed2e7ae552fbd3c476b552c1deac3021b7d7eaf0c" dependencies = [ "libc", "num_threads", @@ -2311,9 +2395,9 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.36" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if", "pin-project-lite", @@ -2323,9 +2407,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" +checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" dependencies = [ "proc-macro2", "quote", @@ -2334,9 +2418,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.29" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" dependencies = [ "once_cell", "valuable", @@ -2438,9 +2522,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" [[package]] name = "unicode-normalization" @@ -2451,6 +2535,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + [[package]] name = "unicode-xid" version = "0.2.4" @@ -2575,6 +2665,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" From 0bc7350f6ebf5b68569c4757dfbae96b3b28000a Mon Sep 17 00:00:00 2001 From: Luca Joss Date: Mon, 10 Oct 2022 18:21:29 +0200 Subject: [PATCH 101/113] Updated guide --- .../fee/register-counterparty-payee.md | 15 +++++++++++---- .../help_templates/fee/register-payee.md | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/guide/src/templates/help_templates/fee/register-counterparty-payee.md b/guide/src/templates/help_templates/fee/register-counterparty-payee.md index ab8d423d13..cd1ba0d1bc 100644 --- a/guide/src/templates/help_templates/fee/register-counterparty-payee.md +++ b/guide/src/templates/help_templates/fee/register-counterparty-payee.md @@ -8,7 +8,14 @@ OPTIONS: -h, --help Print help information FLAGS: - --chain Identifier of the chain - --channel Identifier of the channel - --counterparty-payee Address of the counterparty payee - --port Identifier of the port + --chain + Identifier of the chain + + --channel + Identifier of the channel [aliases: chan] + + --counterparty-payee + Address of the counterparty payee + + --port + Identifier of the port diff --git a/guide/src/templates/help_templates/fee/register-payee.md b/guide/src/templates/help_templates/fee/register-payee.md index 77b29be1d3..aca9613267 100644 --- a/guide/src/templates/help_templates/fee/register-payee.md +++ b/guide/src/templates/help_templates/fee/register-payee.md @@ -9,6 +9,6 @@ OPTIONS: FLAGS: --chain Identifier of the chain - --channel Identifier of the channel + --channel Identifier of the channel [aliases: chan] --payee Address of the payee --port Identifier of the port From 65a9ccb0437fff37a8a6c58f69c4f2539b93a680 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Tue, 11 Oct 2022 15:10:20 +0200 Subject: [PATCH 102/113] Run more CI integration tests for fee --- .github/workflows/integration.yaml | 19 +++++++++++++++++-- flake.nix | 1 + 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml index 51bf169d79..0fbb836635 100644 --- a/.github/workflows/integration.yaml +++ b/.github/workflows/integration.yaml @@ -37,6 +37,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 60 strategy: + fail-fast: false matrix: chain: - package: gaia5 @@ -170,6 +171,19 @@ jobs: ics29-fee-test: runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + chain: + - package: gaia-main + command: gaiad + account_prefix: cosmos + - package: ibc-go-v5-simapp + command: simd + account_prefix: cosmos + - package: ibc-go-v6-simapp + command: simd + account_prefix: cosmos steps: - uses: actions/checkout@v2 - uses: cachix/install-nix-action@v15 @@ -194,9 +208,10 @@ jobs: RUST_LOG: info RUST_BACKTRACE: 1 NO_COLOR_LOG: 1 - CHAIN_COMMAND_PATH: simd + CHAIN_COMMAND_PATH: ${{ matrix.chain.command }} + ACCOUNT_PREFIX: ${{ matrix.chain.account_prefix }} run: | - nix shell .#ibc-go-v4-simapp -c cargo \ + nix shell .#${{ matrix.chain.package }} -c cargo \ test -p ibc-integration-test --features ics29-fee --no-fail-fast -- \ --nocapture --test-threads=1 fee:: diff --git a/flake.nix b/flake.nix index cd9c5c247a..f04e7db1f6 100644 --- a/flake.nix +++ b/flake.nix @@ -32,6 +32,7 @@ gaia5 gaia6 gaia7 + gaia-main ica osmosis wasmd From df077e6e0c634e13cd9bd19d10e648362a09976c Mon Sep 17 00:00:00 2001 From: Luca Joss Date: Mon, 17 Oct 2022 11:55:57 +0200 Subject: [PATCH 103/113] Removed ICS29 fee tests using gaia-main, as it has not yet activated the ICS29 feature --- .github/workflows/integration.yaml | 3 --- flake.nix | 1 - 2 files changed, 4 deletions(-) diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml index 0fbb836635..af9ca0a62c 100644 --- a/.github/workflows/integration.yaml +++ b/.github/workflows/integration.yaml @@ -175,9 +175,6 @@ jobs: fail-fast: false matrix: chain: - - package: gaia-main - command: gaiad - account_prefix: cosmos - package: ibc-go-v5-simapp command: simd account_prefix: cosmos diff --git a/flake.nix b/flake.nix index f04e7db1f6..cd9c5c247a 100644 --- a/flake.nix +++ b/flake.nix @@ -32,7 +32,6 @@ gaia5 gaia6 gaia7 - gaia-main ica osmosis wasmd From 855767d387a3768de63d6fe8fbb350688b98c66a Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Thu, 20 Oct 2022 11:34:36 -0500 Subject: [PATCH 104/113] Update tools/integration-test/src/tests/fee/register_payee.rs Signed-off-by: Sean Chen --- .../integration-test/src/tests/fee/register_payee.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tools/integration-test/src/tests/fee/register_payee.rs b/tools/integration-test/src/tests/fee/register_payee.rs index 6abccd3d80..1e0ff21b9e 100644 --- a/tools/integration-test/src/tests/fee/register_payee.rs +++ b/tools/integration-test/src/tests/fee/register_payee.rs @@ -1,3 +1,15 @@ +//! This test ensures the correctness of the fee module in the case when the payee is not +//! the default. +//! +//! `register_payee` allows the user to specify the payee that receives the `ack_fee`. +//! In the default case, when only `register_counterparty_payee` is called, then both the +//! `recv_fee` and `ack_fee` will be paid to the counterparty payee. If `register_payee` is called +//! as well, then the payee will be paid the `ack_fee` and the counterparty payee will be paid +//! the `recv_fee`. +//! +//! One possible usage of this would be in the case when the forward and reverse relayer are +//! the same, but the relayer wishes to store the `recv_fee` and `ack_fee` in separate wallets. + use ibc_relayer_types::core::ics04_channel::version::Version; use ibc_test_framework::prelude::*; use ibc_test_framework::util::random::random_u128_range; From e10ac9db2416d0e5fc3ff530c91540971d1f4c95 Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Thu, 20 Oct 2022 11:34:49 -0500 Subject: [PATCH 105/113] Update tools/integration-test/src/tests/fee/pay_fee_async.rs Signed-off-by: Sean Chen --- .../src/tests/fee/pay_fee_async.rs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tools/integration-test/src/tests/fee/pay_fee_async.rs b/tools/integration-test/src/tests/fee/pay_fee_async.rs index 5c3fe29738..e750d25517 100644 --- a/tools/integration-test/src/tests/fee/pay_fee_async.rs +++ b/tools/integration-test/src/tests/fee/pay_fee_async.rs @@ -1,3 +1,23 @@ +//! Tests the capability of the fee module to pay packet fees for a packet that has already +//! been sent. +//! +//! This test starts off by performing an `ibc_token_transfer_with_fee` with the relayer configured +//! to not spawn a supervisor. The token transfer will thus be in a pending un-relayed state, with +//! the fees locked in escrow (i.e. they've been debited from the source chain's balance). +//! +//! A token transfer with fee operation consists of two separate events: the event itself, +//! in the form of an `IbcEvent::SendPacket`, as well as a separate event containing the fees, +//! in the form of an `IbcEvent::IncentivizedPacket`. The test checks that these events' sequences +//! match up. +//! +//! The test then checks the behavior or the `pay_packet_fee` function, which pays some additional +//! fees to the relayer of the `IbcEvent::SendPacket` after it has already been sent. In this case, +//! calling `pay_packet_fee` doesn't construct a new `IbcEvent::IncentivizedPacket`; the additional +//! fees are added to the initial fees contained in the incentivized packet. +//! +//! Finally, the test initializes the supervisor in order to relay the pending packets so that the +//! balances on the two chains can be asserted. + use ibc_relayer_types::core::ics04_channel::version::Version; use ibc_relayer_types::events::IbcEvent; use ibc_test_framework::prelude::*; From 5518b128dd7ffe6d0d407111095a68a06404f98e Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Thu, 20 Oct 2022 11:35:16 -0500 Subject: [PATCH 106/113] Update tools/integration-test/src/bin/test_setup_with_fee_enabled_binary_channel.rs Signed-off-by: Sean Chen --- .../src/bin/test_setup_with_fee_enabled_binary_channel.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/integration-test/src/bin/test_setup_with_fee_enabled_binary_channel.rs b/tools/integration-test/src/bin/test_setup_with_fee_enabled_binary_channel.rs index 947ff84bf8..aff3c1be07 100644 --- a/tools/integration-test/src/bin/test_setup_with_fee_enabled_binary_channel.rs +++ b/tools/integration-test/src/bin/test_setup_with_fee_enabled_binary_channel.rs @@ -1,5 +1,5 @@ /*! - This is a simple wrapper around [`BinaryChannelTest`] and turn it into + This is a simple wrapper around [`BinaryChannelTest`] to turn it into an executable that can be used for manual testing with two test chains with connected channel with fee enabled. From f9cee946af0fc2ac3e80eb632e3685205273e8ea Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Thu, 20 Oct 2022 11:35:59 -0500 Subject: [PATCH 107/113] Update tools/integration-test/src/bin/test_setup_with_fee_enabled_binary_channel.rs Signed-off-by: Sean Chen --- .../src/bin/test_setup_with_fee_enabled_binary_channel.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/integration-test/src/bin/test_setup_with_fee_enabled_binary_channel.rs b/tools/integration-test/src/bin/test_setup_with_fee_enabled_binary_channel.rs index aff3c1be07..a5909cac86 100644 --- a/tools/integration-test/src/bin/test_setup_with_fee_enabled_binary_channel.rs +++ b/tools/integration-test/src/bin/test_setup_with_fee_enabled_binary_channel.rs @@ -3,7 +3,7 @@ an executable that can be used for manual testing with two test chains with connected channel with fee enabled. - When the command is executed, you should see log messages such as + When the command is executed, you should see log messages such as the following near the end: ```bash From 2806a3848bf2b707dc47dd85dc61988490237001 Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Thu, 20 Oct 2022 11:36:15 -0500 Subject: [PATCH 108/113] Update tools/integration-test/src/tests/fee/no_forward_relayer.rs Signed-off-by: Sean Chen --- .../src/tests/fee/no_forward_relayer.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tools/integration-test/src/tests/fee/no_forward_relayer.rs b/tools/integration-test/src/tests/fee/no_forward_relayer.rs index 130825de4b..a51f5d390d 100644 --- a/tools/integration-test/src/tests/fee/no_forward_relayer.rs +++ b/tools/integration-test/src/tests/fee/no_forward_relayer.rs @@ -1,3 +1,13 @@ +//! This test tests two different cases. +//! +//! The `NoForwardRelayerTest` tests the case where the +//! `counterparty_payee`'s address is not registered. The +//! `InvalidForwardRelayerTest` tests the case where the +//! `counterparty_payee` address is invalidly registered. In both tests, the +//! `auto_register_counterparty_payee` option is toggled off. The tests then +//! checks that the `receive_fee` and the `timeout_fee` are refunded to +//! the payer. + use ibc_relayer_types::core::ics04_channel::version::Version; use ibc_test_framework::prelude::*; use ibc_test_framework::util::random::random_u128_range; From af91874b0855757b9a232fdfac8ab654d0c729b1 Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Thu, 20 Oct 2022 11:36:41 -0500 Subject: [PATCH 109/113] Update tools/integration-test/src/tests/fee/timeout_fee.rs Signed-off-by: Sean Chen --- tools/integration-test/src/tests/fee/timeout_fee.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/integration-test/src/tests/fee/timeout_fee.rs b/tools/integration-test/src/tests/fee/timeout_fee.rs index 70951bfe1a..8cd7c2f20b 100644 --- a/tools/integration-test/src/tests/fee/timeout_fee.rs +++ b/tools/integration-test/src/tests/fee/timeout_fee.rs @@ -1,3 +1,6 @@ +//! This test ensures that a `timeout_fee` is correctly paid to a relayer in the case that +//! it relays a timeout packet when an `ibc_token_transfer_with_fee` operation times out. + use ibc_relayer_types::core::ics04_channel::version::Version; use ibc_test_framework::prelude::*; use ibc_test_framework::util::random::random_u128_range; From d0cf6a8bea37021a54209dfa61882e04f980976d Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Thu, 20 Oct 2022 11:36:59 -0500 Subject: [PATCH 110/113] Update tools/integration-test/src/tests/fee/auto_forward_relayer.rs Signed-off-by: Sean Chen --- .../src/tests/fee/auto_forward_relayer.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/integration-test/src/tests/fee/auto_forward_relayer.rs b/tools/integration-test/src/tests/fee/auto_forward_relayer.rs index e3478c9a53..40b9040484 100644 --- a/tools/integration-test/src/tests/fee/auto_forward_relayer.rs +++ b/tools/integration-test/src/tests/fee/auto_forward_relayer.rs @@ -1,3 +1,12 @@ +//! Tests the relayer's support for the `auto_register_counterparty_payee` configuration option. +//! When this option is toggled on, the relayer will discover the address of the counterparty payee +//! automatically without the user needing to provide it. +//! +//! The test enables this option and then performs an `ibc_token_transfer_with_fee` between +//! `chain_driver_a` (the source chain) and `chain_driver_b` (the destination chain) without +//! explicitly registering the counterparty's address. It then checks to make sure all the +//! appropriate fees are paid out to the correct parties involved in the transaction. + use ibc_relayer_types::core::ics04_channel::version::Version; use ibc_test_framework::prelude::*; use ibc_test_framework::util::random::random_u128_range; From 49c28923fc01434c7a82c9a9241f766d1fd51fcf Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Thu, 20 Oct 2022 11:37:28 -0500 Subject: [PATCH 111/113] Update tools/integration-test/src/bin/test_setup_with_fee_enabled_binary_channel.rs Signed-off-by: Sean Chen --- .../src/bin/test_setup_with_fee_enabled_binary_channel.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/integration-test/src/bin/test_setup_with_fee_enabled_binary_channel.rs b/tools/integration-test/src/bin/test_setup_with_fee_enabled_binary_channel.rs index a5909cac86..d4db32105d 100644 --- a/tools/integration-test/src/bin/test_setup_with_fee_enabled_binary_channel.rs +++ b/tools/integration-test/src/bin/test_setup_with_fee_enabled_binary_channel.rs @@ -13,7 +13,7 @@ WARN ibc_integration_test::util::suspend: suspending the test indefinitely. you can still interact with any spawned chains and relayers ``` - The `binary-channels.env` file generated contains the environment variables + The generated `binary-channels.env` file contains the environment variables that are essential for accessing the test chains. You can source it and run the relayer commands in a separate terminal such as: From 08f02ffef3652fde6794c46c39f9921ab5e4e02d Mon Sep 17 00:00:00 2001 From: Romain Ruetschi Date: Mon, 24 Oct 2022 11:57:48 +0200 Subject: [PATCH 112/113] Formatting --- .../src/tests/fee/auto_forward_relayer.rs | 8 ++++---- .../src/tests/fee/no_forward_relayer.rs | 14 +++++++------- .../src/tests/fee/pay_fee_async.rs | 14 +++++++------- .../src/tests/fee/register_payee.rs | 16 ++++++++-------- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/tools/integration-test/src/tests/fee/auto_forward_relayer.rs b/tools/integration-test/src/tests/fee/auto_forward_relayer.rs index 40b9040484..8ebbf29069 100644 --- a/tools/integration-test/src/tests/fee/auto_forward_relayer.rs +++ b/tools/integration-test/src/tests/fee/auto_forward_relayer.rs @@ -1,10 +1,10 @@ //! Tests the relayer's support for the `auto_register_counterparty_payee` configuration option. //! When this option is toggled on, the relayer will discover the address of the counterparty payee -//! automatically without the user needing to provide it. -//! -//! The test enables this option and then performs an `ibc_token_transfer_with_fee` between +//! automatically without the user needing to provide it. +//! +//! The test enables this option and then performs an `ibc_token_transfer_with_fee` between //! `chain_driver_a` (the source chain) and `chain_driver_b` (the destination chain) without -//! explicitly registering the counterparty's address. It then checks to make sure all the +//! explicitly registering the counterparty's address. It then checks to make sure all the //! appropriate fees are paid out to the correct parties involved in the transaction. use ibc_relayer_types::core::ics04_channel::version::Version; diff --git a/tools/integration-test/src/tests/fee/no_forward_relayer.rs b/tools/integration-test/src/tests/fee/no_forward_relayer.rs index a51f5d390d..88b4933c61 100644 --- a/tools/integration-test/src/tests/fee/no_forward_relayer.rs +++ b/tools/integration-test/src/tests/fee/no_forward_relayer.rs @@ -1,12 +1,12 @@ -//! This test tests two different cases. -//! -//! The `NoForwardRelayerTest` tests the case where the -//! `counterparty_payee`'s address is not registered. The -//! `InvalidForwardRelayerTest` tests the case where the +//! This test tests two different cases. +//! +//! The `NoForwardRelayerTest` tests the case where the +//! `counterparty_payee`'s address is not registered. The +//! `InvalidForwardRelayerTest` tests the case where the //! `counterparty_payee` address is invalidly registered. In both tests, the //! `auto_register_counterparty_payee` option is toggled off. The tests then -//! checks that the `receive_fee` and the `timeout_fee` are refunded to -//! the payer. +//! checks that the `receive_fee` and the `timeout_fee` are refunded to +//! the payer. use ibc_relayer_types::core::ics04_channel::version::Version; use ibc_test_framework::prelude::*; diff --git a/tools/integration-test/src/tests/fee/pay_fee_async.rs b/tools/integration-test/src/tests/fee/pay_fee_async.rs index e750d25517..645f985a1a 100644 --- a/tools/integration-test/src/tests/fee/pay_fee_async.rs +++ b/tools/integration-test/src/tests/fee/pay_fee_async.rs @@ -2,20 +2,20 @@ //! been sent. //! //! This test starts off by performing an `ibc_token_transfer_with_fee` with the relayer configured -//! to not spawn a supervisor. The token transfer will thus be in a pending un-relayed state, with -//! the fees locked in escrow (i.e. they've been debited from the source chain's balance). -//! -//! A token transfer with fee operation consists of two separate events: the event itself, +//! to not spawn a supervisor. The token transfer will thus be in a pending un-relayed state, with +//! the fees locked in escrow (i.e. they've been debited from the source chain's balance). +//! +//! A token transfer with fee operation consists of two separate events: the event itself, //! in the form of an `IbcEvent::SendPacket`, as well as a separate event containing the fees, //! in the form of an `IbcEvent::IncentivizedPacket`. The test checks that these events' sequences //! match up. -//! +//! //! The test then checks the behavior or the `pay_packet_fee` function, which pays some additional //! fees to the relayer of the `IbcEvent::SendPacket` after it has already been sent. In this case, //! calling `pay_packet_fee` doesn't construct a new `IbcEvent::IncentivizedPacket`; the additional -//! fees are added to the initial fees contained in the incentivized packet. +//! fees are added to the initial fees contained in the incentivized packet. //! -//! Finally, the test initializes the supervisor in order to relay the pending packets so that the +//! Finally, the test initializes the supervisor in order to relay the pending packets so that the //! balances on the two chains can be asserted. use ibc_relayer_types::core::ics04_channel::version::Version; diff --git a/tools/integration-test/src/tests/fee/register_payee.rs b/tools/integration-test/src/tests/fee/register_payee.rs index 1e0ff21b9e..858c618b3c 100644 --- a/tools/integration-test/src/tests/fee/register_payee.rs +++ b/tools/integration-test/src/tests/fee/register_payee.rs @@ -1,14 +1,14 @@ -//! This test ensures the correctness of the fee module in the case when the payee is not -//! the default. -//! +//! This test ensures the correctness of the fee module in the case when the payee is not +//! the default. +//! //! `register_payee` allows the user to specify the payee that receives the `ack_fee`. -//! In the default case, when only `register_counterparty_payee` is called, then both the +//! In the default case, when only `register_counterparty_payee` is called, then both the //! `recv_fee` and `ack_fee` will be paid to the counterparty payee. If `register_payee` is called //! as well, then the payee will be paid the `ack_fee` and the counterparty payee will be paid -//! the `recv_fee`. -//! -//! One possible usage of this would be in the case when the forward and reverse relayer are -//! the same, but the relayer wishes to store the `recv_fee` and `ack_fee` in separate wallets. +//! the `recv_fee`. +//! +//! One possible usage of this would be in the case when the forward and reverse relayer are +//! the same, but the relayer wishes to store the `recv_fee` and `ack_fee` in separate wallets. use ibc_relayer_types::core::ics04_channel::version::Version; use ibc_test_framework::prelude::*; From b150711127a4e7f8c8158aeb71a4fc7c1d0fcd9f Mon Sep 17 00:00:00 2001 From: Romain Ruetschi Date: Mon, 24 Oct 2022 13:06:34 +0200 Subject: [PATCH 113/113] Increment `maybe_register_counterparty_payee` metric Co-authored-by: Luca Joss <43531661+ljoss17@users.noreply.github.com> Signed-off-by: Romain Ruetschi --- crates/relayer/src/chain/handle/counting.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/relayer/src/chain/handle/counting.rs b/crates/relayer/src/chain/handle/counting.rs index dd8c3ffa95..dab49fe77a 100644 --- a/crates/relayer/src/chain/handle/counting.rs +++ b/crates/relayer/src/chain/handle/counting.rs @@ -480,6 +480,7 @@ impl ChainHandle for CountingChainHandle { port_id: PortId, counterparty_payee: Signer, ) -> Result<(), Error> { + self.inc_metric("maybe_register_counterparty_payee"); self.inner .maybe_register_counterparty_payee(channel_id, port_id, counterparty_payee) }