Skip to content

Commit

Permalink
Add ICA transfer test to interchain-security tests (#3493)
Browse files Browse the repository at this point in the history
  • Loading branch information
ljoss17 authored Jul 22, 2023
1 parent a226d3a commit 83e42c4
Show file tree
Hide file tree
Showing 7 changed files with 312 additions and 78 deletions.
41 changes: 39 additions & 2 deletions .github/workflows/integration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ jobs:
test -p ibc-integration-test --features clean-workers --no-fail-fast -- \
--nocapture --test-threads=1 clean_workers::
interchain-security:
interchain-security-no-ica:
runs-on: ubuntu-20.04
strategy:
fail-fast: false
Expand All @@ -415,6 +415,43 @@ jobs:
- package: neutron
command: neutrond
account_prefix: neutron
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v22
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@v12
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 --features interchain-security --no-fail-fast --no-run
- env:
RUST_LOG: info
RUST_BACKTRACE: 1
NO_COLOR_LOG: 1
CHAIN_COMMAND_PATHS: gaiad,${{ matrix.chain.command }}
ACCOUNT_PREFIXES: cosmos,${{ matrix.chain.account_prefix }}
run: |
nix shell .#gaia9 .#${{ matrix.chain.package }} -c cargo \
test -p ibc-integration-test --features interchain-security --no-fail-fast -- \
--nocapture --test-threads=1 interchain_security::
interchain-security-ica:
runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
chain:
- package: stride-consumer
command: strided
account_prefix: stride
Expand Down Expand Up @@ -446,7 +483,7 @@ jobs:
ACCOUNT_PREFIXES: cosmos,${{ matrix.chain.account_prefix }}
run: |
nix shell .#gaia9 .#${{ matrix.chain.package }} -c cargo \
test -p ibc-integration-test --features interchain-security --no-fail-fast -- \
test -p ibc-integration-test --features interchain-security,ica --no-fail-fast -- \
--nocapture --test-threads=1 interchain_security::
model-based-test:
Expand Down
83 changes: 18 additions & 65 deletions tools/integration-test/src/tests/ica.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,21 @@ use ibc_relayer::config::{
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_relayer_types::applications::{
ics27_ica::cosmos_tx::CosmosTx,
transfer::{msgs::send::MsgSend, Amount, Coin},
};

use ibc_test_framework::{
ibc::denom::Denom,
prelude::*,
relayer::channel::{assert_eventually_channel_established, query_channel_end},
use ibc_relayer_types::bigint::U256;
use ibc_relayer_types::core::ics04_channel::channel::State;
use ibc_relayer_types::signer::Signer;
use ibc_relayer_types::timestamp::Timestamp;
use ibc_relayer_types::tx_msg::Msg;

use ibc_test_framework::chain::ext::ica::register_interchain_account;
use ibc_test_framework::ibc::denom::Denom;
use ibc_test_framework::prelude::*;
use ibc_test_framework::relayer::channel::{
assert_eventually_channel_established, query_channel_end,
};

#[test]
Expand Down Expand Up @@ -97,7 +94,8 @@ impl BinaryConnectionTest for IcaFilterTestAllow {
) -> Result<(), Error> {
// Register an interchain account on behalf of
// controller wallet `user1` where the counterparty chain is the interchain accounts host.
let (wallet, channel_id, port_id) = register_interchain_account(&chains, &connection)?;
let (wallet, channel_id, port_id) =
register_interchain_account(&chains.node_a, chains.handle_a(), &connection)?;

// Check that the corresponding ICA channel is eventually established.
let _counterparty_channel_id = assert_eventually_channel_established(
Expand Down Expand Up @@ -230,7 +228,8 @@ impl BinaryConnectionTest for IcaFilterTestDeny {
) -> Result<(), Error> {
// Register an interchain account on behalf of controller wallet `user1`
// where the counterparty chain is the interchain accounts host.
let (_, channel_id, port_id) = register_interchain_account(&chains, &connection)?;
let (_, channel_id, port_id) =
register_interchain_account(&chains.node_a, chains.handle_a(), &connection)?;

// Wait a bit, the relayer will refuse to complete the channel handshake
// because the port is explicitly disallowed by the filter.
Expand All @@ -247,49 +246,3 @@ impl BinaryConnectionTest for IcaFilterTestDeny {
)
}
}

#[allow(clippy::type_complexity)]
fn register_interchain_account<ChainA: ChainHandle, ChainB: ChainHandle>(
chains: &ConnectedChains<ChainA, ChainB>,
connection: &ConnectedConnection<ChainA, ChainB>,
) -> Result<
(
MonoTagged<ChainA, Wallet>,
TaggedChannelId<ChainA, ChainB>,
TaggedPortId<ChainA, ChainB>,
),
Error,
> {
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()),
));
}
}

Err(Error::generic(eyre!("could not retrieve an OpenInitChannel event resonse after sending MsgRegisterInterchainAccount")))
}
188 changes: 188 additions & 0 deletions tools/integration-test/src/tests/interchain_security/ica_transfer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
//! The following tests are for the Interchain Security.
//! These tests require the first chain to be a Provider chain and
//! the second chain a Consumer chain.
use std::str::FromStr;

use ibc_relayer::chain::tracking::TrackedMsgs;
use ibc_relayer::event::IbcEventWithHeight;
use ibc_relayer_types::applications::ics27_ica::cosmos_tx::CosmosTx;
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::applications::transfer::msgs::send::MsgSend;
use ibc_relayer_types::applications::transfer::{Amount, Coin};
use ibc_relayer_types::bigint::U256;
use ibc_relayer_types::signer::Signer;
use ibc_relayer_types::timestamp::Timestamp;
use ibc_relayer_types::tx_msg::Msg;
use ibc_test_framework::chain::config::set_voting_period;
use ibc_test_framework::chain::ext::ica::register_interchain_account;
use ibc_test_framework::framework::binary::channel::run_binary_interchain_security_channel_test;
use ibc_test_framework::prelude::*;
use ibc_test_framework::relayer::channel::assert_eventually_channel_established;

#[test]
fn test_ics_ica_transfer() -> Result<(), Error> {
run_binary_interchain_security_channel_test(&InterchainSecurityIcaTransferTest)
}

struct InterchainSecurityIcaTransferTest;

impl TestOverrides for InterchainSecurityIcaTransferTest {
fn modify_genesis_file(&self, genesis: &mut serde_json::Value) -> Result<(), Error> {
use serde_json::Value;

// Allow MsgSend messages over ICA
let allow_messages = genesis
.get_mut("app_state")
.and_then(|app_state| app_state.get_mut("interchainaccounts"))
.and_then(|ica| ica.get_mut("host_genesis_state"))
.and_then(|state| state.get_mut("params"))
.and_then(|params| params.get_mut("allow_messages"))
.and_then(|allow_messages| allow_messages.as_array_mut());

if let Some(allow_messages) = allow_messages {
allow_messages.push(Value::String("/cosmos.bank.v1beta1.MsgSend".to_string()));
} else {
return Err(Error::generic(eyre!("failed to update genesis file")));
}

// Consumer chain doesn't have a gov key.
if genesis
.get_mut("app_state")
.and_then(|app_state| app_state.get("gov"))
.is_some()
{
set_voting_period(genesis, "10s")?;
}
Ok(())
}

// The `ccv_consumer_chain` must be `true` for the Consumer chain.
// The `trusting_period` must be strictly smaller than the `unbonding_period`
// specified in the Consumer chain proposal. The test framework uses 100s in
// the proposal.
fn modify_relayer_config(&self, config: &mut Config) {
config.mode.channels.enabled = true;

for chain_config in config.chains.iter_mut() {
if chain_config.id == ChainId::from_string("ibcconsumer") {
chain_config.ccv_consumer_chain = true;
chain_config.trusting_period = Some(Duration::from_secs(99));
}
}
}
}

impl BinaryChannelTest for InterchainSecurityIcaTransferTest {
fn run<ChainA: ChainHandle, ChainB: ChainHandle>(
&self,
_config: &TestConfig,
_relayer: RelayerDriver,
chains: ConnectedChains<ChainA, ChainB>,
channel: ConnectedChannel<ChainA, ChainB>,
) -> Result<(), Error> {
let connection_b_to_a = channel.connection.clone().flip();
let (wallet, channel_id, port_id) =
register_interchain_account(&chains.node_b, chains.handle_b(), &connection_b_to_a)?;

// Check that the corresponding ICA channel is eventually established.
let _counterparty_channel_id = assert_eventually_channel_established(
chains.handle_b(),
chains.handle_a(),
&channel_id.as_ref(),
&port_id.as_ref(),
)?;

// Query the controller chain for the address of the ICA wallet on the host chain.
let ica_address = chains.node_b.chain_driver().query_interchain_account(
&wallet.address(),
&channel.connection.connection_id_b.as_ref(),
)?;

let stake_denom: MonoTagged<ChainA, Denom> = MonoTagged::new(Denom::base("stake"));

chains.node_a.chain_driver().assert_eventual_wallet_amount(
&ica_address.as_ref(),
&stake_denom.with_amount(0u64).as_ref(),
)?;

// Send funds to the interchain account.
let ica_fund = 42000u64;

chains.node_a.chain_driver().local_transfer_token(
&chains.node_a.wallets().user1(),
&ica_address.as_ref(),
&stake_denom.with_amount(ica_fund).as_ref(),
)?;

chains.node_a.chain_driver().assert_eventual_wallet_amount(
&ica_address.as_ref(),
&stake_denom.with_amount(ica_fund).as_ref(),
)?;

let amount = 12345;

let msg = MsgSend {
from_address: ica_address.to_string(),
to_address: chains.node_a.wallets().user2().address().to_string(),
amount: vec![Coin {
denom: stake_denom.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.
let ica_events = interchain_send_tx(
chains.handle_b(),
&signer,
&channel.connection.connection_id_b.0,
interchain_account_packet_data,
Timestamp::from_nanoseconds(120000000000).unwrap(),
)?;

info!("ICA events from `CosmosTx`: {ica_events:#?}");

// Check that the ICA account's balance has been debited the sent amount.
chains.node_a.chain_driver().assert_eventual_wallet_amount(
&ica_address.as_ref(),
&stake_denom.with_amount(ica_fund - amount).as_ref(),
)?;
Ok(())
}
}

fn interchain_send_tx<ChainA: ChainHandle>(
chain: &ChainA,
from: &Signer,
connection: &ConnectionId,
msg: InterchainAccountPacketData,
relative_timeout: Timestamp,
) -> Result<Vec<IbcEventWithHeight>, 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)
}
3 changes: 3 additions & 0 deletions tools/integration-test/src/tests/interchain_security/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#[cfg(any(doc, feature = "ica"))]
pub mod ica_transfer;
pub mod simple_transfer;
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//! The following tests are for the Interchain Security.
//! These tests require the first chain to be a Producer chain and
//! These tests require the first chain to be a Provider chain and
//! the second chain a Consumer chain.
use ibc_test_framework::chain::config::set_voting_period;
use ibc_test_framework::framework::binary::channel::run_binary_interchain_security_channel_test;
Expand All @@ -8,12 +8,12 @@ use ibc_test_framework::util::random::random_u128_range;

#[test]
fn test_ics_transfer() -> Result<(), Error> {
run_binary_interchain_security_channel_test(&InterchainSecurityTest)
run_binary_interchain_security_channel_test(&InterchainSecurityTransferTest)
}

struct InterchainSecurityTest;
struct InterchainSecurityTransferTest;

impl TestOverrides for InterchainSecurityTest {
impl TestOverrides for InterchainSecurityTransferTest {
fn modify_genesis_file(&self, genesis: &mut serde_json::Value) -> Result<(), Error> {
// Consumer chain doesn't have a gov key.
if genesis
Expand All @@ -40,7 +40,7 @@ impl TestOverrides for InterchainSecurityTest {
}
}

impl BinaryChannelTest for InterchainSecurityTest {
impl BinaryChannelTest for InterchainSecurityTransferTest {
fn run<ChainA: ChainHandle, ChainB: ChainHandle>(
&self,
_config: &TestConfig,
Expand Down
Loading

0 comments on commit 83e42c4

Please sign in to comment.