diff --git a/.changelog/unreleased/improvements/ibc-integration-test/3353-improve-ica-tests.md b/.changelog/unreleased/improvements/ibc-integration-test/3353-improve-ica-tests.md new file mode 100644 index 0000000000..f1cf359f98 --- /dev/null +++ b/.changelog/unreleased/improvements/ibc-integration-test/3353-improve-ica-tests.md @@ -0,0 +1,2 @@ +- Update ICA tests to use ibc-go's `simd` instead of `interchain-accounts-demo`. + ([#3353](https://github.com/informalsystems/hermes/issues/3353)) \ No newline at end of file diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml index 2d632448d7..b107f6728c 100644 --- a/.github/workflows/integration.yaml +++ b/.github/workflows/integration.yaml @@ -148,6 +148,16 @@ jobs: ica-filter-test: runs-on: ubuntu-20.04 + strategy: + fail-fast: false + matrix: + chain: + - package: ibc-go-v6-simapp + command: simd + account_prefix: cosmos + - package: ibc-go-v7-simapp + command: simd + account_prefix: cosmos steps: - uses: actions/checkout@v3 - uses: cachix/install-nix-action@v21 @@ -172,9 +182,10 @@ jobs: RUST_LOG: info RUST_BACKTRACE: 1 NO_COLOR_LOG: 1 - CHAIN_COMMAND_PATHS: icad + CHAIN_COMMAND_PATHS: ${{ matrix.chain.command }} + ACCOUNT_PREFIXES: ${{ matrix.chain.account_prefix }} run: | - nix shell .#python .#ica -c cargo \ + nix shell .#${{ matrix.chain.package }} -c cargo \ test -p ibc-integration-test --features ica --no-fail-fast -- \ --nocapture --test-threads=1 test_ica_filter diff --git a/Cargo.lock b/Cargo.lock index 464f6da00e..3350803535 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -58,9 +58,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aho-corasick" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" dependencies = [ "memchr", ] @@ -409,9 +409,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.25" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdbc37d37da9e5bce8173f3a41b71d9bf3c674deebbaceacd0ebdabde76efb03" +checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" dependencies = [ "android-tzdata", "iana-time-zone", @@ -991,9 +991,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" dependencies = [ "percent-encoding", ] @@ -1117,9 +1117,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -1425,9 +1425,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.56" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" +checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1484,9 +1484,9 @@ dependencies = [ [[package]] name = "ibc-proto" -version = "0.31.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc198998f950ed48ffcd405a6b147e2a4ee7fc25ed9531857774d170e1562ea1" +checksum = "c888103095b45bee90cb9104513ade30abd69902153b0682b5ad81940ae1f865" dependencies = [ "base64 0.21.2", "bytes", @@ -1731,9 +1731,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -1855,9 +1855,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.144" +version = "0.2.146" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" +checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" [[package]] name = "linux-raw-sys" @@ -1867,9 +1867,9 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ "autocfg", "scopeguard", @@ -1943,9 +1943,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eebffdb73fe72e917997fad08bdbf31ac50b0fa91cec93e69a0662e4264d454c" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", "wasi 0.11.0+wasi-snapshot-preview1", @@ -2051,18 +2051,18 @@ dependencies = [ [[package]] name = "object" -version = "0.30.3" +version = "0.30.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" +checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.17.2" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "oneline-eyre" @@ -2172,15 +2172,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if 1.0.0", "libc", - "redox_syscall 0.2.16", + "redox_syscall 0.3.5", "smallvec", - "windows-sys 0.45.0", + "windows-targets 0.48.0", ] [[package]] @@ -2237,9 +2237,9 @@ checksum = "c719dcf55f09a3a7e764c6649ab594c18a177e3599c467983cdf644bfc0a4088" [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pin-project" @@ -2481,7 +2481,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.9", + "getrandom 0.2.10", ] [[package]] @@ -2526,16 +2526,16 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom 0.2.9", + "getrandom 0.2.10", "redox_syscall 0.2.16", "thiserror", ] [[package]] name = "regex" -version = "1.8.3" +version = "1.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81ca098a9821bd52d6b24fd8b10bd081f47d39c22778cafaa75a2857a62c6390" +checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" dependencies = [ "aho-corasick", "memchr", @@ -3483,7 +3483,7 @@ dependencies = [ "bytes", "flex-error", "futures", - "getrandom 0.2.9", + "getrandom 0.2.10", "http", "hyper", "hyper-proxy", @@ -4057,9 +4057,9 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" dependencies = [ "form_urlencoded", "idna", @@ -4096,7 +4096,7 @@ version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "345444e32442451b267fc254ae85a209c64be56d2890e601a0c37ff0c3c5ecd2" dependencies = [ - "getrandom 0.2.9", + "getrandom 0.2.10", ] [[package]] diff --git a/crates/chain-registry/Cargo.toml b/crates/chain-registry/Cargo.toml index 3feb33efa4..827a50d0c3 100644 --- a/crates/chain-registry/Cargo.toml +++ b/crates/chain-registry/Cargo.toml @@ -12,7 +12,7 @@ description = """ """ [dependencies] -ibc-proto = { version = "0.31.0" } +ibc-proto = { version = "0.32.0" } ibc-relayer-types = { version = "0.24.1", path = "../relayer-types" } tendermint-rpc = { version = "0.32.0", features = ["http-client", "websocket-client"] } diff --git a/crates/relayer-types/Cargo.toml b/crates/relayer-types/Cargo.toml index e29e036248..fc2c2b5aa7 100644 --- a/crates/relayer-types/Cargo.toml +++ b/crates/relayer-types/Cargo.toml @@ -24,7 +24,7 @@ mocks = ["tendermint-testgen", "clock"] [dependencies] # Proto definitions for all IBC-related interfaces, e.g., connections or channels. -ibc-proto = { version = "0.31.0" } +ibc-proto = { version = "0.32.0" } ics23 = { version = "0.10.1", features = ["std", "host-functions"] } time = { version = ">=0.3.0, <0.3.23" } serde_derive = { version = "1.0.104" } diff --git a/crates/relayer-types/src/applications/ics27_ica/cosmos_tx.rs b/crates/relayer-types/src/applications/ics27_ica/cosmos_tx.rs new file mode 100644 index 0000000000..8503d027dd --- /dev/null +++ b/crates/relayer-types/src/applications/ics27_ica/cosmos_tx.rs @@ -0,0 +1,49 @@ +use ibc_proto::google::protobuf::Any; +use ibc_proto::ibc::applications::interchain_accounts::v1::CosmosTx as RawCosmosTx; +use ibc_proto::protobuf::Protobuf; +use serde_derive::Deserialize; +use serde_derive::Serialize; + +use crate::applications::ics27_ica::error::Error; +use crate::core::ics24_host::error::ValidationError; +use crate::tx_msg::Msg; + +pub const TYPE_URL: &str = "/ibc.applications.interchain_accounts.v1.CosmosTx"; + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct CosmosTx { + pub messages: Vec, +} + +impl Msg for CosmosTx { + type ValidationError = ValidationError; + type Raw = RawCosmosTx; + + fn route(&self) -> String { + crate::keys::ROUTER_KEY.to_string() + } + + fn type_url(&self) -> String { + TYPE_URL.to_string() + } +} + +impl Protobuf for CosmosTx {} + +impl TryFrom for CosmosTx { + type Error = Error; + + fn try_from(value: RawCosmosTx) -> Result { + Ok(CosmosTx { + messages: value.messages, + }) + } +} + +impl From for RawCosmosTx { + fn from(value: CosmosTx) -> Self { + RawCosmosTx { + messages: value.messages, + } + } +} diff --git a/crates/relayer-types/src/applications/ics27_ica/error.rs b/crates/relayer-types/src/applications/ics27_ica/error.rs new file mode 100644 index 0000000000..52f2027496 --- /dev/null +++ b/crates/relayer-types/src/applications/ics27_ica/error.rs @@ -0,0 +1,24 @@ +use crate::core::ics24_host::error::ValidationError; +use crate::signer::SignerError; + +use flex_error::define_error; + +define_error! { + #[derive(Debug, PartialEq, Eq)] + Error { + Owner + [ SignerError ] + | _ | { "failed to parse owner" }, + + InvalidConnectionIdentifier + [ ValidationError ] + | _ | { "connection identifier error" }, + + InvalidPacketData + | _ | { "packet data is None" }, + + InvalidRelativeTimeout + { timestamp: u64 } + | e | { format_args!("invalid packet timeout timestamp value: `{}`", e.timestamp) }, + } +} diff --git a/crates/relayer-types/src/applications/ics27_ica/mod.rs b/crates/relayer-types/src/applications/ics27_ica/mod.rs new file mode 100644 index 0000000000..c42612c711 --- /dev/null +++ b/crates/relayer-types/src/applications/ics27_ica/mod.rs @@ -0,0 +1,4 @@ +pub mod cosmos_tx; +pub mod error; +pub mod msgs; +pub mod packet_data; diff --git a/crates/relayer-types/src/applications/ics27_ica/msgs/mod.rs b/crates/relayer-types/src/applications/ics27_ica/msgs/mod.rs new file mode 100644 index 0000000000..f522273a9b --- /dev/null +++ b/crates/relayer-types/src/applications/ics27_ica/msgs/mod.rs @@ -0,0 +1,2 @@ +pub mod register; +pub mod send_tx; diff --git a/crates/relayer-types/src/applications/ics27_ica/msgs/register.rs b/crates/relayer-types/src/applications/ics27_ica/msgs/register.rs new file mode 100644 index 0000000000..67954b27d5 --- /dev/null +++ b/crates/relayer-types/src/applications/ics27_ica/msgs/register.rs @@ -0,0 +1,61 @@ +use serde::{Deserialize, Serialize}; + +use ibc_proto::ibc::applications::interchain_accounts::controller::v1::MsgRegisterInterchainAccount as RawMsgRegisterInterchainAccount; +use ibc_proto::protobuf::Protobuf; + +use crate::applications::ics27_ica::error::Error; +use crate::core::ics04_channel::version::Version; +use crate::core::ics24_host::error::ValidationError; +use crate::core::ics24_host::identifier::ConnectionId; +use crate::signer::Signer; +use crate::tx_msg::Msg; + +pub const TYPE_URL: &str = + "/ibc.applications.interchain_accounts.controller.v1.MsgRegisterInterchainAccount"; + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct MsgRegisterInterchainAccount { + pub owner: Signer, + pub connection_id: ConnectionId, + pub version: Version, +} + +impl Msg for MsgRegisterInterchainAccount { + type ValidationError = ValidationError; + type Raw = RawMsgRegisterInterchainAccount; + + fn route(&self) -> String { + crate::keys::ROUTER_KEY.to_string() + } + + fn type_url(&self) -> String { + TYPE_URL.to_string() + } +} + +impl Protobuf for MsgRegisterInterchainAccount {} + +impl TryFrom for MsgRegisterInterchainAccount { + type Error = Error; + + fn try_from(value: RawMsgRegisterInterchainAccount) -> Result { + Ok(MsgRegisterInterchainAccount { + owner: value.owner.parse().map_err(Error::owner)?, + connection_id: value + .connection_id + .parse() + .map_err(Error::invalid_connection_identifier)?, + version: value.version.into(), + }) + } +} + +impl From for RawMsgRegisterInterchainAccount { + fn from(value: MsgRegisterInterchainAccount) -> Self { + RawMsgRegisterInterchainAccount { + owner: value.owner.to_string(), + connection_id: value.connection_id.to_string(), + version: value.version.to_string(), + } + } +} diff --git a/crates/relayer-types/src/applications/ics27_ica/msgs/send_tx.rs b/crates/relayer-types/src/applications/ics27_ica/msgs/send_tx.rs new file mode 100644 index 0000000000..40c11a9646 --- /dev/null +++ b/crates/relayer-types/src/applications/ics27_ica/msgs/send_tx.rs @@ -0,0 +1,70 @@ +use serde_derive::{Deserialize, Serialize}; + +use ibc_proto::ibc::applications::interchain_accounts::controller::v1::MsgSendTx as RawMsgSendTx; +use ibc_proto::protobuf::Protobuf; + +use crate::applications::ics27_ica::error::Error; +use crate::applications::ics27_ica::packet_data::InterchainAccountPacketData; +use crate::core::ics24_host::error::ValidationError; +use crate::core::ics24_host::identifier::ConnectionId; +use crate::signer::Signer; +use crate::timestamp::Timestamp; +use crate::tx_msg::Msg; + +pub const TYPE_URL: &str = "/ibc.applications.interchain_accounts.controller.v1.MsgSendTx"; + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct MsgSendTx { + pub owner: Signer, + pub connection_id: ConnectionId, + pub packet_data: InterchainAccountPacketData, + pub relative_timeout: Timestamp, +} + +impl Msg for MsgSendTx { + type ValidationError = ValidationError; + type Raw = RawMsgSendTx; + + fn route(&self) -> String { + crate::keys::ROUTER_KEY.to_string() + } + + fn type_url(&self) -> String { + TYPE_URL.to_string() + } +} + +impl Protobuf for MsgSendTx {} + +impl TryFrom for MsgSendTx { + type Error = Error; + + fn try_from(value: RawMsgSendTx) -> Result { + let relative_timeout = Timestamp::from_nanoseconds(value.relative_timeout) + .map_err(|_| Error::invalid_relative_timeout(value.relative_timeout))?; + let raw_packet_data = value + .packet_data + .ok_or(()) + .map_err(|_| Error::invalid_packet_data())?; + Ok(MsgSendTx { + owner: value.owner.parse().map_err(Error::owner)?, + connection_id: value + .connection_id + .parse() + .map_err(Error::invalid_connection_identifier)?, + packet_data: raw_packet_data.try_into()?, + relative_timeout, + }) + } +} + +impl From for RawMsgSendTx { + fn from(value: MsgSendTx) -> Self { + RawMsgSendTx { + owner: value.owner.to_string(), + connection_id: value.connection_id.to_string(), + packet_data: Some(value.packet_data.into()), + relative_timeout: value.relative_timeout.nanoseconds(), + } + } +} diff --git a/crates/relayer-types/src/applications/ics27_ica/packet_data.rs b/crates/relayer-types/src/applications/ics27_ica/packet_data.rs new file mode 100644 index 0000000000..fc5e9b260d --- /dev/null +++ b/crates/relayer-types/src/applications/ics27_ica/packet_data.rs @@ -0,0 +1,46 @@ +use ibc_proto::ibc::{ + applications::interchain_accounts::v1::InterchainAccountPacketData as RawInterchainAccountPacketData, + apps::interchain_accounts::v1::Type, +}; +use serde_derive::{Deserialize, Serialize}; + +use crate::applications::ics27_ica::error::Error; + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct InterchainAccountPacketData { + pub r#type: i32, + pub data: Vec, + pub memo: String, +} + +impl InterchainAccountPacketData { + pub fn new(data: Vec) -> Self { + InterchainAccountPacketData { + r#type: Type::ExecuteTx.into(), + data, + memo: String::default(), + } + } +} + +impl TryFrom for InterchainAccountPacketData { + type Error = Error; + + fn try_from(value: RawInterchainAccountPacketData) -> Result { + Ok(InterchainAccountPacketData { + r#type: value.r#type, + data: value.data, + memo: value.memo, + }) + } +} + +impl From for RawInterchainAccountPacketData { + fn from(value: InterchainAccountPacketData) -> Self { + RawInterchainAccountPacketData { + r#type: value.r#type, + data: value.data, + memo: value.memo, + } + } +} diff --git a/crates/relayer-types/src/applications/mod.rs b/crates/relayer-types/src/applications/mod.rs index f38fb631b2..539225bf08 100644 --- a/crates/relayer-types/src/applications/mod.rs +++ b/crates/relayer-types/src/applications/mod.rs @@ -1,5 +1,6 @@ //! Various packet encoding semantics which underpin the various types of transactions. +pub mod ics27_ica; pub mod ics29_fee; pub mod ics31_icq; pub mod transfer; diff --git a/crates/relayer-types/src/applications/transfer/msgs.rs b/crates/relayer-types/src/applications/transfer/msgs/mod.rs similarity index 56% rename from crates/relayer-types/src/applications/transfer/msgs.rs rename to crates/relayer-types/src/applications/transfer/msgs/mod.rs index 014e52f277..b3caa7e353 100644 --- a/crates/relayer-types/src/applications/transfer/msgs.rs +++ b/crates/relayer-types/src/applications/transfer/msgs/mod.rs @@ -1 +1,2 @@ +pub mod send; pub mod transfer; diff --git a/crates/relayer-types/src/applications/transfer/msgs/send.rs b/crates/relayer-types/src/applications/transfer/msgs/send.rs new file mode 100644 index 0000000000..8529453880 --- /dev/null +++ b/crates/relayer-types/src/applications/transfer/msgs/send.rs @@ -0,0 +1,68 @@ +use std::fmt::Display; +use std::str::FromStr; + +use ibc_proto::protobuf::Protobuf; +use serde_derive::Deserialize; +use serde_derive::Serialize; + +use ibc_proto::cosmos::bank::v1beta1::MsgSend as RawMsgSend; + +use crate::applications::transfer::error::Error; +use crate::applications::transfer::Coin; +use crate::core::ics24_host::error::ValidationError; +use crate::tx_msg::Msg; + +pub const TYPE_URL: &str = "/cosmos.bank.v1beta1.MsgSend"; + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MsgSend { + pub from_address: String, + pub to_address: String, + pub amount: Vec>, +} + +impl Msg for MsgSend { + type ValidationError = ValidationError; + type Raw = RawMsgSend; + + fn route(&self) -> String { + crate::keys::ROUTER_KEY.to_string() + } + + fn type_url(&self) -> String { + TYPE_URL.to_string() + } +} + +impl Protobuf for MsgSend where D::Err: Into {} + +impl TryFrom for MsgSend +where + D::Err: Into, +{ + type Error = Error; + + fn try_from(value: RawMsgSend) -> Result { + let amount: Vec> = value + .amount + .into_iter() + .map(Coin::try_from) + .collect::>, _>>()?; + Ok(MsgSend { + from_address: value.from_address, + to_address: value.to_address, + amount, + }) + } +} + +impl From> for RawMsgSend { + fn from(value: MsgSend) -> Self { + let amount = value.amount.into_iter().map(|coin| coin.into()).collect(); + RawMsgSend { + from_address: value.from_address, + to_address: value.to_address, + amount, + } + } +} diff --git a/crates/relayer/Cargo.toml b/crates/relayer/Cargo.toml index 04dfc1859e..5bf755ba2e 100644 --- a/crates/relayer/Cargo.toml +++ b/crates/relayer/Cargo.toml @@ -20,7 +20,7 @@ default = ["flex-error/std", "flex-error/eyre_tracer"] telemetry = ["ibc-telemetry"] [dependencies] -ibc-proto = { version = "0.31.0" } +ibc-proto = { version = "0.32.0" } ibc-telemetry = { version = "0.24.1", path = "../telemetry", optional = true } ibc-relayer-types = { version = "0.24.1", path = "../relayer-types", features = ["mocks"] } diff --git a/flake.nix b/flake.nix index e049622b3a..1d56d7ec7f 100644 --- a/flake.nix +++ b/flake.nix @@ -34,7 +34,6 @@ gaia7 gaia8 gaia9 - ica osmosis wasmd gaia6-ordered diff --git a/tools/integration-test/src/tests/ica.rs b/tools/integration-test/src/tests/ica.rs index 39f6876d61..982f78d712 100644 --- a/tools/integration-test/src/tests/ica.rs +++ b/tools/integration-test/src/tests/ica.rs @@ -1,13 +1,28 @@ use std::collections::HashMap; use std::str::FromStr; -use serde::Serialize; - +use ibc_relayer::chain::handle::ChainHandle; +use ibc_relayer::chain::tracking::TrackedMsgs; use ibc_relayer::config::{ filter::{ChannelFilters, ChannelPolicy, FilterPattern}, PacketFilter, }; -use ibc_relayer_types::core::ics04_channel::channel::State; +use ibc_relayer::event::IbcEventWithHeight; +use ibc_relayer_types::applications::ics27_ica::msgs::send_tx::MsgSendTx; +use ibc_relayer_types::applications::ics27_ica::packet_data::InterchainAccountPacketData; +use ibc_relayer_types::core::ics04_channel::version::Version; +use ibc_relayer_types::signer::Signer; +use ibc_relayer_types::{ + applications::{ + ics27_ica::{cosmos_tx::CosmosTx, msgs::register::MsgRegisterInterchainAccount}, + transfer::{msgs::send::MsgSend, Amount, Coin}, + }, + bigint::U256, + core::ics04_channel::channel::State, + events::IbcEvent, + timestamp::Timestamp, + tx_msg::Msg, +}; use ibc_test_framework::{ ibc::denom::Denom, @@ -76,15 +91,13 @@ impl BinaryConnectionTest for IcaFilterTestAllow { fn run( &self, _config: &TestConfig, - relayer: RelayerDriver, + _relayer: RelayerDriver, chains: ConnectedChains, connection: ConnectedConnection, ) -> Result<(), Error> { // Register an interchain account on behalf of // controller wallet `user1` where the counterparty chain is the interchain accounts host. - // Then spawn the supervisor. - let (_handle, wallet, channel_id, port_id) = - register_interchain_account(&relayer, &chains, &connection)?; + let (wallet, channel_id, port_id) = register_interchain_account(&chains, &connection)?; // Check that the corresponding ICA channel is eventually established. let _counterparty_channel_id = assert_eventually_channel_established( @@ -102,16 +115,9 @@ impl BinaryConnectionTest for IcaFilterTestAllow { let stake_denom: MonoTagged = MonoTagged::new(Denom::base("stake")); - // Query the interchain account balance on the host chain. It should be empty. - let ica_balance = chains - .node_b - .chain_driver() - .query_balance(&ica_address.as_ref(), &stake_denom.as_ref())?; - - assert_eq( - "balance of ICA account should be 0", - &ica_balance.amount(), - &0u64.into(), + chains.node_b.chain_driver().assert_eventual_wallet_amount( + &ica_address.as_ref(), + &stake_denom.with_amount(0u64).as_ref(), )?; // Send funds to the interchain account. @@ -123,39 +129,42 @@ impl BinaryConnectionTest for IcaFilterTestAllow { &stake_denom.with_amount(ica_fund).as_ref(), )?; - #[derive(Serialize)] - struct MsgSend { - #[serde(rename = "@type")] - tpe: String, - from_address: String, - to_address: String, - amount: Vec, - } - - #[derive(Serialize)] - struct Amount { - denom: String, - amount: String, - } + chains.node_b.chain_driver().assert_eventual_wallet_amount( + &ica_address.as_ref(), + &stake_denom.with_amount(ica_fund).as_ref(), + )?; let amount = 12345; let msg = MsgSend { - tpe: "/cosmos.bank.v1beta1.MsgSend".to_string(), from_address: ica_address.to_string(), - to_address: chains.node_a.wallets().user2().address().to_string(), - amount: vec![Amount { + to_address: chains.node_b.wallets().user2().address().to_string(), + amount: vec![Coin { denom: stake_denom.to_string(), - amount: amount.to_string(), + amount: Amount(U256::from(amount)), }], }; + let raw_msg = msg.to_any(); + + let cosmos_tx = CosmosTx { + messages: vec![raw_msg], + }; + + let raw_cosmos_tx = cosmos_tx.to_any(); + + let interchain_account_packet_data = InterchainAccountPacketData::new(raw_cosmos_tx.value); + + let signer = Signer::from_str(&wallet.address().to_string()).unwrap(); + // Send funds from the ICA account to the `user2` account on the host chain on behalf // of the `user1` account on the controller chain. - chains.node_a.chain_driver().interchain_submit( - &wallet.address(), - &connection.connection_id_a.as_ref(), - &msg, + interchain_send_tx( + chains.handle_a(), + &signer, + &connection.connection_id_a.0, + interchain_account_packet_data, + Timestamp::from_nanoseconds(120000000000).unwrap(), )?; // Check that the ICA account's balance has been debited the sent amount. @@ -163,11 +172,33 @@ impl BinaryConnectionTest for IcaFilterTestAllow { &ica_address.as_ref(), &stake_denom.with_amount(ica_fund - amount).as_ref(), )?; - Ok(()) } } +fn interchain_send_tx( + chain: &ChainA, + from: &Signer, + connection: &ConnectionId, + msg: InterchainAccountPacketData, + relative_timeout: Timestamp, +) -> Result, Error> { + let msg = MsgSendTx { + owner: from.clone(), + connection_id: connection.clone(), + packet_data: msg, + relative_timeout, + }; + + let msg_any = msg.to_any(); + + let tm = TrackedMsgs::new_static(vec![msg_any], "SendTx"); + + chain + .send_messages_and_wait_commit(tm) + .map_err(Error::relayer) +} + #[test] fn test_ica_filter_deny() -> Result<(), Error> { run_binary_connection_test(&IcaFilterTestDeny) @@ -193,15 +224,13 @@ impl BinaryConnectionTest for IcaFilterTestDeny { fn run( &self, _config: &TestConfig, - relayer: RelayerDriver, + _relayer: RelayerDriver, chains: ConnectedChains, connection: ConnectedConnection, ) -> Result<(), Error> { // Register an interchain account on behalf of controller wallet `user1` // where the counterparty chain is the interchain accounts host. - // Then spawn the supervisor. - let (_handle, _, channel_id, port_id) = - register_interchain_account(&relayer, &chains, &connection)?; + let (_, channel_id, port_id) = register_interchain_account(&chains, &connection)?; // Wait a bit, the relayer will refuse to complete the channel handshake // because the port is explicitly disallowed by the filter. @@ -221,33 +250,46 @@ impl BinaryConnectionTest for IcaFilterTestDeny { #[allow(clippy::type_complexity)] fn register_interchain_account( - relayer: &RelayerDriver, chains: &ConnectedChains, connection: &ConnectedConnection, ) -> Result< ( - SupervisorHandle, MonoTagged, TaggedChannelId, TaggedPortId, ), Error, > { - let wallet = chains.node_a.wallets().user1().cloned(); - let handle = relayer.spawn_supervisor()?; - - chains - .node_a - .chain_driver() - .register_interchain_account(&wallet.address(), &connection.connection_id_a.as_ref())?; - - let channel_id: TaggedChannelId = - TaggedChannelId::new("channel-0".parse().unwrap()); - - let icacontroller = - PortId::from_str(&format!("icacontroller-{}", wallet.address().value())).unwrap(); - - let port_id: TaggedPortId = TaggedPortId::new(icacontroller); + let wallet = chains.node_a.wallets().relayer().cloned(); + + let owner = chains.handle_a().get_signer()?; + + let version_str = format!("{{\"version\":\"ics27-1\",\"encoding\":\"proto3\",\"tx_type\":\"sdk_multi_msg\",\"controller_connection_id\":\"{}\",\"host_connection_id\":\"{}\"}}", connection.connection_id_a.0, connection.connection_id_b.0); + let msg = MsgRegisterInterchainAccount { + owner, + connection_id: connection.connection_id_a.0.clone(), + version: Version::new(version_str), + }; + + let msg_any = msg.to_any(); + + let tm = TrackedMsgs::new_static(vec![msg_any], "RegisterInterchainAccount"); + + let events = chains + .handle_a() + .send_messages_and_wait_commit(tm) + .map_err(Error::relayer)?; + + for event in events.iter() { + if let IbcEvent::OpenInitChannel(open_init) = &event.event { + let channel_id = open_init.channel_id.clone().ok_or(()).map_err(|_| Error::generic(eyre!("channel_id is empty in the event response after sending MsgRegisterInterchainAccount")))?; + return Ok(( + wallet, + TaggedChannelId::new(channel_id), + TaggedPortId::new(open_init.port_id.clone()), + )); + } + } - Ok((handle, wallet, channel_id, port_id)) + Err(Error::generic(eyre!("could not retrieve an OpenInitChannel event resonse after sending MsgRegisterInterchainAccount"))) } diff --git a/tools/test-framework/Cargo.toml b/tools/test-framework/Cargo.toml index acb2c3c551..367ff756e6 100644 --- a/tools/test-framework/Cargo.toml +++ b/tools/test-framework/Cargo.toml @@ -17,7 +17,7 @@ description = """ ibc-relayer-types = { version = "=0.24.1", path = "../../crates/relayer-types" } ibc-relayer = { version = "=0.24.1", path = "../../crates/relayer" } ibc-relayer-cli = { version = "=1.5.1", path = "../../crates/relayer-cli" } -ibc-proto = { version = "0.31.0" } +ibc-proto = { version = "0.32.0" } tendermint-rpc = { version = "0.32.0", features = ["http-client", "websocket-client"] } http = "0.2.9" diff --git a/tools/test-framework/src/chain/cli/ica.rs b/tools/test-framework/src/chain/cli/ica.rs index ec5c675547..9dc0d6d3b0 100644 --- a/tools/test-framework/src/chain/cli/ica.rs +++ b/tools/test-framework/src/chain/cli/ica.rs @@ -59,63 +59,25 @@ pub fn query_interchain_account( "--output", "json", "query", - "intertx", - "interchainaccounts", - connection_id, + "interchain-accounts", + "controller", + "interchain-account", account, + connection_id, ]; 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 - .get("interchain_account_address") - .ok_or_else(|| eyre!("expected `interchain_account_address` field"))? + .get("address") + .ok_or_else(|| eyre!("expected `address` field"))? .as_str() .ok_or_else(|| eyre!("expected string field"))?; Ok(address.to_string()) } -/// Submit a msg from a controller account over an ICA channel -/// using the given connection. -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 args = &[ - "--home", - home_path, - "--node", - rpc_listen_address, - "--output", - "json", - "tx", - "intertx", - "submit", - msg, - "--connection-id", - connection_id, - "--from", - from, - "--chain-id", - chain_id, - "--keyring-backend", - "test", - "-y", - ]; - - let res = simple_exec(chain_id, command_path, args)?.stdout; - check_result_code(&res)?; - - Ok(()) -} - /// Check that a command succeeded, by ensuring that the JSON emitted /// contains a `code` integer field set to 0. fn check_result_code(res: &str) -> Result<(), Error> { diff --git a/tools/test-framework/src/chain/ext/ica.rs b/tools/test-framework/src/chain/ext/ica.rs index 2395a77121..6552e6f7a5 100644 --- a/tools/test-framework/src/chain/ext/ica.rs +++ b/tools/test-framework/src/chain/ext/ica.rs @@ -1,8 +1,4 @@ -use serde::Serialize; - -use crate::chain::cli::ica::{ - interchain_submit, query_interchain_account, register_interchain_account, -}; +use crate::chain::cli::ica::{query_interchain_account, register_interchain_account}; use crate::chain::driver::ChainDriver; use crate::error::Error; use crate::prelude::TaggedConnectionIdRef; @@ -21,13 +17,6 @@ pub trait InterchainAccountMethodsExt { 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 { @@ -64,24 +53,4 @@ impl<'a, Chain: Send> InterchainAccountMethodsExt for MonoTagged( - &self, - from: &MonoTagged, - connection_id: &TaggedConnectionIdRef, - msg: &T, - ) -> Result<(), Error> { - 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, - ) - } }