Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add integration tests for fee granters #3418

Merged
merged 6 commits into from
Jun 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Add integration tests for the Fee Grant module.
([#3416](https://github.com/informalsystems/hermes/issues/3416))
42 changes: 42 additions & 0 deletions .github/workflows/integration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,48 @@ jobs:
nix shell ${{ matrix.chain.package }} -c cargo \
test -p ibc-integration-test --features ics31 --no-fail-fast -- \
--nocapture --test-threads=1 ics31::
fee-grant:
runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
chain:
- package: stride
command: strided
account_prefix: stride
- package: evmos
command: evmosd
account_prefix: evmos
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v21
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 fee-grant --no-fail-fast --no-run
- env:
RUST_LOG: info
RUST_BACKTRACE: 1
NO_COLOR_LOG: 1
CHAIN_COMMAND_PATHS: ${{ matrix.chain.command }}
ACCOUNT_PREFIXES: ${{ matrix.chain.account_prefix }}
run: |
nix shell .#${{ matrix.chain.package }} -c cargo \
test -p ibc-integration-test --features fee-grant --no-fail-fast -- \
--nocapture --test-threads=1 fee_grant::

clean-workers:
runs-on: ubuntu-20.04
Expand Down
1 change: 1 addition & 0 deletions tools/integration-test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ mbt = []
forward-packet = []
ics31 = []
clean-workers = []
fee-grant = []

[[bin]]
name = "test_setup_with_binary_channel"
Expand Down
264 changes: 264 additions & 0 deletions tools/integration-test/src/tests/fee_grant.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
//! This test tests the fee_grant configuration:
//!
//! - The `FeeGrant` will register the address of `user2` as the granter
//! for `user1` and will configure the `fee_granter` in Hermes. It will
//! then assert that the `user1` doesn't pay any fees for a transfer and
//! `user2` pays the fees.
//!
//! - The `NoFeeGrant` will register the address of `user2` as the granter
//! for `user1`, but it will not configure the `fee_granter` in Hermes. It will
//! then assert that the `user1` pays the fees and
//! `user2` doesn't pay any fees.

use std::thread;

use ibc_relayer::config::ChainConfig;
use ibc_relayer_types::bigint::U256;
use ibc_test_framework::chain::ext::fee_grant::FeeGrantMethodsExt;
use ibc_test_framework::prelude::*;

#[test]
fn test_fee_grant() -> Result<(), Error> {
run_binary_channel_test(&FeeGrantTest)
}

#[test]
fn test_no_fee_grant() -> Result<(), Error> {
run_binary_channel_test(&NoFeeGrantTest)
}

struct FeeGrantTest;

impl TestOverrides for FeeGrantTest {}

impl BinaryChannelTest for FeeGrantTest {
fn run<ChainA: ChainHandle, ChainB: ChainHandle>(
&self,
_config: &TestConfig,
relayer: RelayerDriver,
chains: ConnectedChains<ChainA, ChainB>,
channels: ConnectedChannel<ChainA, ChainB>,
) -> Result<(), Error> {
let denom_a = chains.node_a.denom();
let wallet_a = chains.node_a.wallets().user1().cloned();
let wallet_b = chains.node_b.wallets().user1().cloned();

let a_to_b_amount = 12345u64;
let granter = chains
.node_a
.wallets()
.user2()
.address()
.value()
.to_string();
let grantee = chains
.node_a
.wallets()
.user1()
.address()
.value()
.to_string();

chains
.node_a
.chain_driver()
.feegrant_grant(&granter, &grantee)?;

// Wait for the feegrant to be processed
thread::sleep(Duration::from_secs(5));

let denom_b = derive_ibc_denom(
&channels.port_b.as_ref(),
&channels.channel_id_b.as_ref(),
&denom_a,
)?;

let gas_denom: MonoTagged<ChainA, Denom> = MonoTagged::new(Denom::Base("stake".to_owned()));

let balance_user1_before = chains
.node_a
.chain_driver()
.query_balance(&wallet_a.address(), &gas_denom.as_ref())?;
let balance_user2_before = chains.node_a.chain_driver().query_balance(
&chains.node_a.wallets().user2().address(),
&gas_denom.as_ref(),
)?;

let mut modified_relayer = relayer;

let new_chain_configs: Vec<ChainConfig> = modified_relayer
.config
.chains
.iter_mut()
.map(|c| {
if c.id == chains.node_a.chain_id().0.clone() {
c.fee_granter = Some("user2".to_owned());
}
c.clone()
})
.collect();

modified_relayer.config.chains = new_chain_configs;

let mut modified_driver = chains.node_a.chain_driver().0.clone();

let mut modified_tx_config = chains.node_a.chain_driver().tx_config().0.clone();

modified_tx_config.gas_config.fee_granter =
chains.node_a.wallets().user2().address().to_string();

modified_driver.tx_config = modified_tx_config;

let md: MonoTagged<ChainA, &ChainDriver> = MonoTagged::new(&modified_driver);

md.ibc_transfer_token(
&channels.port_a.as_ref(),
&channels.channel_id_a.as_ref(),
&wallet_a.as_ref(),
&wallet_b.address(),
&denom_a.with_amount(a_to_b_amount).as_ref(),
)?;

thread::sleep(Duration::from_secs(10));

let balance_after_a2 = chains.node_a.chain_driver().query_balance(
&chains.node_a.wallets().user2().address(),
&gas_denom.as_ref(),
)?;

// Assert that user on chain B received the tokens
chains.node_b.chain_driver().assert_eventual_wallet_amount(
&wallet_b.address(),
&denom_b.with_amount(a_to_b_amount).as_ref(),
)?;

// Assert that user1 has not paid any fees
chains
.node_a
.chain_driver()
.assert_eventual_wallet_amount(&wallet_a.address(), &balance_user1_before.as_ref())?;

let paid_fees = balance_user2_before
.amount()
.checked_sub(balance_after_a2.amount());

assert!(
paid_fees.is_some(),
"subtraction between queried amounts should be Some"
);

// Only assert that the paid fees are non zero since they might vary
assert_ne!(
paid_fees.unwrap().0,
U256::from(0),
"granter should have paid the fees"
);

Ok(())
}
}

struct NoFeeGrantTest;

impl TestOverrides for NoFeeGrantTest {}

impl BinaryChannelTest for NoFeeGrantTest {
fn run<ChainA: ChainHandle, ChainB: ChainHandle>(
&self,
_config: &TestConfig,
_relayer: RelayerDriver,
chains: ConnectedChains<ChainA, ChainB>,
channels: ConnectedChannel<ChainA, ChainB>,
) -> Result<(), Error> {
let denom_a = chains.node_a.denom();
let wallet_a = chains.node_a.wallets().user1().cloned();
let wallet_a2 = chains.node_a.wallets().user2().cloned();
let wallet_b = chains.node_b.wallets().user1().cloned();

let a_to_b_amount = 12345u64;
let granter = chains
.node_a
.wallets()
.user2()
.address()
.value()
.to_string();
let grantee = chains
.node_a
.wallets()
.user1()
.address()
.value()
.to_string();

chains
.node_a
.chain_driver()
.feegrant_grant(&granter, &grantee)?;

// Wait for the feegrant to be processed
thread::sleep(Duration::from_secs(5));

let denom_b = derive_ibc_denom(
&channels.port_b.as_ref(),
&channels.channel_id_b.as_ref(),
&denom_a,
)?;

let gas_denom: MonoTagged<ChainA, Denom> = MonoTagged::new(Denom::Base("stake".to_owned()));

let balance_user1_before = chains
.node_a
.chain_driver()
.query_balance(&wallet_a.address(), &gas_denom.as_ref())?;
let balance_user2_before = chains.node_a.chain_driver().query_balance(
&chains.node_a.wallets().user2().address(),
&gas_denom.as_ref(),
)?;

chains.node_a.chain_driver().ibc_transfer_token(
&channels.port_a.as_ref(),
&channels.channel_id_a.as_ref(),
&wallet_a.as_ref(),
&wallet_b.address(),
&denom_a.with_amount(a_to_b_amount).as_ref(),
)?;

thread::sleep(Duration::from_secs(10));

let balance_user1_after = chains.node_a.chain_driver().query_balance(
&chains.node_a.wallets().user1().address(),
&gas_denom.as_ref(),
)?;

// Assert that user on chain B received the tokens
chains.node_b.chain_driver().assert_eventual_wallet_amount(
&wallet_b.address(),
&denom_b.with_amount(a_to_b_amount).as_ref(),
)?;

// Assert that user2 has not paid any fees
chains
.node_a
.chain_driver()
.assert_eventual_wallet_amount(&wallet_a2.address(), &balance_user2_before.as_ref())?;

let paid_fees = balance_user1_before
.amount()
.checked_sub(balance_user1_after.amount());

assert!(
paid_fees.is_some(),
"subtraction between queried amounts should be Some"
);

// Only assert that the paid fees are non zero since they might vary
assert_ne!(
paid_fees.unwrap().0,
U256::from(0),
"granter should not have paid the fees"
);

Ok(())
}
}
3 changes: 3 additions & 0 deletions tools/integration-test/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,6 @@ pub mod ics31;

#[cfg(any(doc, feature = "clean-workers"))]
pub mod clean_workers;

#[cfg(any(doc, feature = "fee-grant"))]
pub mod fee_grant;
34 changes: 34 additions & 0 deletions tools/test-framework/src/chain/cli/fee_grant.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use crate::chain::exec::simple_exec;
use crate::error::Error;

pub fn feegrant_grant(
chain_id: &str,
command_path: &str,
home_path: &str,
rpc_listen_address: &str,
granter: &str,
grantee: &str,
) -> Result<(), Error> {
simple_exec(
chain_id,
command_path,
&[
"--home",
home_path,
"--chain-id",
chain_id,
"--node",
rpc_listen_address,
"--keyring-backend",
"test",
"tx",
"feegrant",
"grant",
granter,
grantee,
"--yes",
],
)?;

Ok(())
}
1 change: 1 addition & 0 deletions tools/test-framework/src/chain/cli/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod bootstrap;
pub mod fee_grant;
pub mod host_zone;
pub mod ica;
pub mod query;
Expand Down
20 changes: 20 additions & 0 deletions tools/test-framework/src/chain/ext/fee_grant.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use crate::chain::cli::fee_grant::feegrant_grant;
use crate::error::Error;
use crate::prelude::ChainDriver;
use crate::types::tagged::MonoTagged;
pub trait FeeGrantMethodsExt<Chain> {
fn feegrant_grant(&self, granter: &str, grantee: &str) -> Result<(), Error>;
}

impl<'a, Chain: Send> FeeGrantMethodsExt<Chain> for MonoTagged<Chain, &'a ChainDriver> {
fn feegrant_grant(&self, granter: &str, grantee: &str) -> Result<(), Error> {
feegrant_grant(
self.value().chain_id.as_str(),
&self.value().command_path,
&self.value().home_path,
&self.value().rpc_listen_address(),
granter,
grantee,
)
}
}
Loading