diff --git a/.changelog/unreleased/testing/3601-clean-ibc-e2e.md b/.changelog/unreleased/testing/3601-clean-ibc-e2e.md new file mode 100644 index 0000000000..f6cc86a015 --- /dev/null +++ b/.changelog/unreleased/testing/3601-clean-ibc-e2e.md @@ -0,0 +1,2 @@ +- Clean IBC E2E tests and refine IBC client upgrade test with Gaia + ([\#3601](https://github.com/anoma/namada/issues/3601)) \ No newline at end of file diff --git a/.github/workflows/scripts/e2e.json b/.github/workflows/scripts/e2e.json index 867edb432a..163a87fa99 100644 --- a/.github/workflows/scripts/e2e.json +++ b/.github/workflows/scripts/e2e.json @@ -1,12 +1,10 @@ { "e2e::eth_bridge_tests::everything": 4, - "e2e::ibc_tests::run_ledger_ibc": 110, - "e2e::ibc_tests::run_ledger_ibc_with_hermes": 230, - "e2e::ibc_tests::pgf_over_ibc_with_hermes": 810, - "e2e::ibc_tests::proposal_ibc_token_inflation": 1100, - "e2e::ibc_tests::ibc_rate_limit": 430, - "e2e::ibc_tests::ibc_namada_gaia": 180, - "e2e::ibc_tests::ibc_upgrade_client": 550, + "e2e::ibc_tests::ibc_transfers": 414, + "e2e::ibc_tests::pgf_over_ibc": 415, + "e2e::ibc_tests::ibc_token_inflation": 840, + "e2e::ibc_tests::ibc_rate_limit": 485, + "e2e::ibc_tests::ibc_upgrade_client": 280, "e2e::eth_bridge_tests::test_add_to_bridge_pool": 10, "e2e::ledger_tests::double_signing_gets_slashed": 12, "e2e::ledger_tests::ledger_many_txs_in_a_block": 55, @@ -32,4 +30,4 @@ "e2e::wallet_tests::wallet_encrypted_key_cmds_env_var": 1, "e2e::wallet_tests::wallet_unencrypted_key_cmds": 1, "e2e::ledger_tests::masp_txs_and_queries": 82 -} \ No newline at end of file +} diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index 8da61eeb9b..e519a8dd41 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs @@ -27,7 +27,6 @@ pub enum TestWasms { TxProposalCode, TxProposalMaspRewards, TxProposalIbcTokenInflation, - TxProposalIbcClientUpgrade, TxReadStorageKey, TxWriteStorageKey, VpAlwaysFalse, @@ -55,9 +54,6 @@ impl TestWasms { TestWasms::TxProposalIbcTokenInflation => { "tx_proposal_ibc_token_inflation.wasm" } - TestWasms::TxProposalIbcClientUpgrade => { - "tx_proposal_ibc_client_upgrade.wasm" - } TestWasms::TxReadStorageKey => "tx_read_storage_key.wasm", TestWasms::TxWriteStorageKey => "tx_write.wasm", TestWasms::VpAlwaysFalse => "vp_always_false.wasm", diff --git a/crates/tests/src/e2e/helpers.rs b/crates/tests/src/e2e/helpers.rs index a437992b07..381c2e57e1 100644 --- a/crates/tests/src/e2e/helpers.rs +++ b/crates/tests/src/e2e/helpers.rs @@ -16,8 +16,6 @@ use data_encoding::HEXLOWER; use escargot::CargoBuild; use eyre::eyre; use namada_apps_lib::cli::context::ENV_VAR_CHAIN_ID; -use namada_apps_lib::config::genesis::chain::DeriveEstablishedAddress; -use namada_apps_lib::config::genesis::templates; use namada_apps_lib::config::utils::convert_tm_addr_to_socket_addr; use namada_apps_lib::config::{Config, TendermintMode}; use namada_core::token::NATIVE_MAX_DECIMAL_PLACES; @@ -179,28 +177,6 @@ pub fn get_actor_rpc(test: &Test, who: Who) -> String { format!("http://{}:{}", socket_addr.ip(), socket_addr.port()) } -/// Get some nodes's wallet. -pub fn get_node_wallet(test: &Test, who: Who) -> Wallet { - let wallet_store_dir = - test.get_base_dir(who).join(test.net.chain_id.as_str()); - let mut wallet = FsWalletUtils::new(wallet_store_dir); - wallet.load().expect("Failed to load wallet"); - wallet -} - -/// Get the public key of the validator -pub fn get_validator_pk(test: &Test, who: Who) -> Option { - let index = match who { - Who::NonValidator => return None, - Who::Validator(i) => i, - }; - let mut wallet = get_node_wallet(test, who); - let sk = wallet - .find_secret_key(format!("validator-{index}-balance-key"), None) - .ok()?; - Some(sk.ref_to()) -} - /// Get a pregenesis wallet. pub fn get_pregenesis_wallet>( base_dir_path: P, @@ -214,30 +190,6 @@ pub fn get_pregenesis_wallet>( wallet } -/// Get a pregenesis public key. -pub fn get_pregenesis_pk>( - alias: &str, - base_dir_path: P, -) -> Option { - let wallet = get_pregenesis_wallet(base_dir_path); - wallet.find_public_key(alias).ok() -} - -/// Get a pregenesis public key. -pub fn get_established_addr_from_pregenesis>( - alias: &str, - base_dir_path: P, - genesis: &templates::All, -) -> Option
{ - let pk = get_pregenesis_pk(alias, base_dir_path)?; - let established_accounts = - genesis.transactions.established_account.as_ref()?; - let acct = established_accounts.iter().find(|&acct| { - acct.public_keys.len() == 1 && acct.public_keys[0].raw == pk - })?; - Some(acct.derive_address()) -} - /// Find the address of an account by its alias from the wallet #[allow(dead_code)] pub fn find_keypair( @@ -660,6 +612,7 @@ fn make_hermes_chain_config_for_gaia(test: &Test) -> Value { Value::String(key_dir.to_string_lossy().to_string()), ); chain.insert("store_prefix".to_owned(), Value::String("ibc".to_owned())); + chain.insert("gas_multiplier".to_owned(), Value::Float(1.3)); let mut table = toml::map::Map::new(); table.insert("price".to_owned(), Value::Float(0.001)); table.insert("denom".to_owned(), Value::String("stake".to_string())); @@ -707,6 +660,44 @@ pub fn update_gaia_config(test: &Test) -> Result<()> { file.write_all(values.to_string().as_bytes()) .map_err(|e| eyre!(format!("Writing a Gaia app.toml failed: {}", e)))?; + let genesis_path = test.test_dir.as_ref().join("gaia/config/genesis.json"); + let s = std::fs::read_to_string(&genesis_path) + .expect("Reading Gaia genesis.json failed"); + let mut genesis: serde_json::Value = + serde_json::from_str(&s).expect("Decoding Gaia genesis.json failed"); + // gas + if let Some(min_base_gas_price) = + genesis.pointer_mut("/app_state/feemarket/params/min_base_gas_price") + { + *min_base_gas_price = + serde_json::Value::String("0.000000000000000001".to_string()); + } + if let Some(base_gas_price) = + genesis.pointer_mut("/app_state/feemarket/state/base_gas_price") + { + *base_gas_price = + serde_json::Value::String("0.000000000000000001".to_string()); + } + // gov + if let Some(max_deposit_period) = + genesis.pointer_mut("/app_state/gov/params/max_deposit_period") + { + *max_deposit_period = serde_json::Value::String("10s".to_string()); + } + if let Some(voting_period) = + genesis.pointer_mut("/app_state/gov/params/voting_period") + { + *voting_period = serde_json::Value::String("10s".to_string()); + } + + let file = OpenOptions::new() + .write(true) + .truncate(true) + .open(&genesis_path)?; + let writer = std::io::BufWriter::new(file); + serde_json::to_writer_pretty(writer, &genesis) + .expect("Writing Gaia genesis.toml failed"); + Ok(()) } @@ -727,3 +718,11 @@ pub fn find_gaia_address( Ok(matched.trim().to_string()) } + +pub fn get_gaia_gov_address(test: &Test) -> Result { + let args = ["query", "auth", "module-account", "gov"]; + let mut gaia = run_gaia_cmd(test, args, Some(40))?; + let (_, matched) = gaia.exp_regex("cosmos[a-z0-9]+")?; + + Ok(matched.trim().to_string()) +} diff --git a/crates/tests/src/e2e/ibc_tests.rs b/crates/tests/src/e2e/ibc_tests.rs index 694f1d52bb..6c14698c13 100644 --- a/crates/tests/src/e2e/ibc_tests.rs +++ b/crates/tests/src/e2e/ibc_tests.rs @@ -11,394 +11,70 @@ use core::str::FromStr; use core::time::Duration; -use std::collections::BTreeSet; use std::path::{Path, PathBuf}; use color_eyre::eyre::Result; use eyre::eyre; -use namada_apps_lib::cli::context::ENV_VAR_CHAIN_ID; -use namada_apps_lib::client::rpc::{ - query_pos_parameters, query_storage_value, query_storage_value_bytes, -}; -use namada_apps_lib::client::utils::id_from_pk; -use namada_apps_lib::config::genesis::{chain, templates}; -use namada_apps_lib::config::utils::set_port; -use namada_apps_lib::config::{ethereum_bridge, TendermintMode}; -use namada_apps_lib::tendermint::block::Header as TmHeader; -use namada_apps_lib::tendermint::merkle::proof::ProofOps as TmProof; +use namada_apps_lib::client::rpc::query_storage_value_bytes; +use namada_apps_lib::config::ethereum_bridge; +use namada_apps_lib::config::genesis::templates; use namada_apps_lib::tendermint_rpc::{Client, HttpClient, Url}; -use namada_core::string_encoding::StringEncoded; -use namada_sdk::address::{Address, InternalAddress, MASP}; -use namada_sdk::chain::{BlockHeight, Epoch}; -use namada_sdk::events::extend::ReadFromEventAttributes; +use namada_sdk::address::MASP; +use namada_sdk::chain::Epoch; use namada_sdk::governance::cli::onchain::PgfFunding; use namada_sdk::governance::pgf::ADDRESS as PGF_ADDRESS; use namada_sdk::governance::storage::proposal::{PGFIbcTarget, PGFTarget}; -use namada_sdk::ibc::apps::transfer::types::VERSION as ICS20_VERSION; use namada_sdk::ibc::clients::tendermint::client_state::ClientState as TmClientState; -use namada_sdk::ibc::clients::tendermint::consensus_state::ConsensusState as TmConsensusState; -use namada_sdk::ibc::clients::tendermint::types::{ - AllowUpdate, ClientState as TmClientStateType, Header as IbcTmHeader, - TrustThreshold, -}; -use namada_sdk::ibc::core::channel::types::channel::Order as ChanOrder; -use namada_sdk::ibc::core::channel::types::msgs::{ - MsgAcknowledgement, MsgChannelOpenAck, MsgChannelOpenConfirm, - MsgChannelOpenInit, MsgChannelOpenTry, MsgRecvPacket as IbcMsgRecvPacket, - MsgTimeout as IbcMsgTimeout, -}; -use namada_sdk::ibc::core::channel::types::packet::Packet; -use namada_sdk::ibc::core::channel::types::Version as ChanVersion; -use namada_sdk::ibc::core::client::context::client_state::ClientStateCommon; -use namada_sdk::ibc::core::client::types::msgs::{ - MsgCreateClient, MsgUpdateClient, -}; use namada_sdk::ibc::core::client::types::Height; -use namada_sdk::ibc::core::commitment_types::commitment::{ - CommitmentPrefix, CommitmentProofBytes, -}; -use namada_sdk::ibc::core::commitment_types::merkle::MerkleProof; -use namada_sdk::ibc::core::connection::types::msgs::{ - MsgConnectionOpenAck, MsgConnectionOpenConfirm, MsgConnectionOpenInit, - MsgConnectionOpenTry, -}; -use namada_sdk::ibc::core::connection::types::version::Version as ConnVersion; -use namada_sdk::ibc::core::connection::types::Counterparty as ConnCounterparty; use namada_sdk::ibc::core::host::types::identifiers::{ - ChainId, ChannelId, ClientId, ConnectionId, PortId, + ChannelId, ClientId, PortId, }; -use namada_sdk::ibc::event::IbcEventType; use namada_sdk::ibc::primitives::proto::Any; -use namada_sdk::ibc::primitives::{Signer, ToProto}; use namada_sdk::ibc::storage::*; -use namada_sdk::ibc::{event as ibc_events, COMMITMENT_PREFIX}; -use namada_sdk::key::PublicKey; -use namada_sdk::masp::fs::FsShieldedUtils; +use namada_sdk::ibc::trace::ibc_token; use namada_sdk::masp::PaymentAddress; -use namada_sdk::parameters::{storage as param_storage, EpochDuration}; -use namada_sdk::queries::RPC; -use namada_sdk::state::ics23_specs::ibc_proof_specs; -use namada_sdk::state::Sha256Hasher; -use namada_sdk::storage::Key; -use namada_sdk::tendermint::abci::Event as AbciEvent; -use namada_sdk::tendermint::block::Height as TmHeight; use namada_sdk::token::Amount; use namada_test_utils::TestWasms; use prost::Message; use setup::constants::*; use sha2::{Digest, Sha256}; -use tendermint_light_client::components::io::{Io, ProdIo as TmLightClientIo}; use crate::e2e::helpers::{ epochs_per_year_from_min_duration, find_address, find_gaia_address, - get_actor_rpc, get_epoch, get_established_addr_from_pregenesis, - get_validator_pk, wait_for_wasm_pre_compile, + get_actor_rpc, get_epoch, get_gaia_gov_address, }; -use crate::e2e::ledger_tests::{prepare_proposal_data, write_json_file}; -use crate::e2e::setup::{ - self, apply_use_device, ensure_hot_addr, ensure_hot_key, run_gaia_cmd, - run_hermes_cmd, set_ethereum_bridge_mode, setup_gaia, setup_hermes, sleep, - Bin, NamadaCmd, Test, Who, +use crate::e2e::ledger_tests::{ + start_namada_ledger_node_wait_wasm, write_json_file, }; -use crate::strings::{ - LEDGER_STARTED, TX_APPLIED_SUCCESS, TX_FAILED, VALIDATOR_NODE, +use crate::e2e::setup::{ + self, apply_use_device, run_gaia_cmd, run_hermes_cmd, + set_ethereum_bridge_mode, setup_gaia, setup_hermes, sleep, Bin, NamadaCmd, + Test, Who, }; +use crate::strings::TX_APPLIED_SUCCESS; use crate::{run, run_as}; const IBC_REFUND_TARGET_ALIAS: &str = "ibc-refund-target"; - -#[test] -fn run_ledger_ibc() -> Result<()> { - let update_genesis = - |mut genesis: templates::All, base_dir: &_| { - genesis.parameters.parameters.epochs_per_year = - epochs_per_year_from_min_duration(1800); - genesis.parameters.ibc_params.default_mint_limit = - Amount::max_signed(); - genesis - .parameters - .ibc_params - .default_per_epoch_throughput_limit = Amount::max_signed(); - setup::set_validators(1, genesis, base_dir, |_| 0, vec![]) - }; - let (ledger_a, ledger_b, test_a, test_b) = run_two_nets(update_genesis)?; - let _bg_ledger_a = ledger_a.background(); - let _bg_ledger_b = ledger_b.background(); - - let (client_id_a, client_id_b) = create_client(&test_a, &test_b)?; - - let (conn_id_a, conn_id_b) = - connection_handshake(&test_a, &test_b, &client_id_a, &client_id_b)?; - - let ((port_id_a, channel_id_a), (port_id_b, channel_id_b)) = - channel_handshake( - &test_a, - &test_b, - &client_id_a, - &client_id_b, - &conn_id_a, - &conn_id_b, - )?; - - // Transfer 100000 from the normal account on Chain A to Chain B - transfer_token( - &test_a, - &test_b, - &client_id_a, - &client_id_b, - &port_id_a, - &channel_id_a, - )?; - check_balances(&port_id_b, &channel_id_b, &test_a, &test_b)?; - - // Try invalid transfers and they will fail - try_invalid_transfers(&test_a, &test_b, &port_id_a, &channel_id_a)?; - - // Transfer 50000 received over IBC on Chain B - let token = format!("{port_id_b}/{channel_id_b}/nam"); - transfer_on_chain( - &test_b, - "transparent-transfer", - BERTHA, - ALBERT, - token, - 50_000_000_000, - BERTHA_KEY, - )?; - check_balances_after_non_ibc(&port_id_b, &channel_id_b, &test_b)?; - - // Transfer 50000 back from the origin-specific account on Chain B to Chain - // A - transfer_back( - &test_a, - &test_b, - &client_id_a, - &client_id_b, - &port_id_b, - &channel_id_b, - )?; - check_balances_after_back(&port_id_b, &channel_id_b, &test_a, &test_b)?; - - // Transfer a token and it will time out and refund - transfer_timeout( - &test_a, - &test_b, - &client_id_a, - &port_id_a, - &channel_id_a, - )?; - // The balance should not be changed - check_balances_after_back(&port_id_b, &channel_id_b, &test_a, &test_b)?; - - // Shielded transfers are tested with Hermes - - // Skip tests for closing a channel and timeout_on_close since the transfer - // channel cannot be closed - - Ok(()) -} - -#[test] -fn run_ledger_ibc_with_hermes() -> Result<()> { - let update_genesis = - |mut genesis: templates::All, base_dir: &_| { - genesis.parameters.parameters.epochs_per_year = - epochs_per_year_from_min_duration(1800); - genesis.parameters.ibc_params.default_mint_limit = - Amount::max_signed(); - genesis - .parameters - .ibc_params - .default_per_epoch_throughput_limit = Amount::max_signed(); - setup::set_validators(1, genesis, base_dir, |_| 0, vec![]) - }; - let (ledger_a, ledger_b, test_a, test_b) = run_two_nets(update_genesis)?; - let _bg_ledger_a = ledger_a.background(); - let _bg_ledger_b = ledger_b.background(); - - setup_hermes(&test_a, &test_b)?; - let port_id_a = "transfer".parse().unwrap(); - let port_id_b = "transfer".parse().unwrap(); - let (channel_id_a, channel_id_b) = - create_channel_with_hermes(&test_a, &test_b)?; - - // Start relaying - let hermes = run_hermes(&test_a)?; - let bg_hermes = hermes.background(); - - // Transfer 100000 from the normal account on Chain A to Chain B - std::env::set_var(ENV_VAR_CHAIN_ID, test_b.net.chain_id.to_string()); - let receiver = find_address(&test_b, BERTHA)?; - transfer( - &test_a, - ALBERT, - receiver.to_string(), - NAM, - 100000.0, - Some(ALBERT_KEY), - &port_id_a, - &channel_id_a, - None, - None, - None, - false, - )?; - wait_for_packet_relay(&port_id_a, &channel_id_a, &test_a)?; - check_balances(&port_id_b, &channel_id_b, &test_a, &test_b)?; - - // Transfer 50000 received over IBC on Chain B - let token = format!("{port_id_b}/{channel_id_b}/nam"); - transfer_on_chain( - &test_b, - "transparent-transfer", - BERTHA, - ALBERT, - token, - 50_000_000_000, - BERTHA_KEY, - )?; - check_balances_after_non_ibc(&port_id_b, &channel_id_b, &test_b)?; - - // Transfer 50000 back from the origin-specific account on Chain B to Chain - // A - std::env::set_var(ENV_VAR_CHAIN_ID, test_a.net.chain_id.to_string()); - let receiver = find_address(&test_a, ALBERT)?; - // Chain A was the source for the sent token - let ibc_denom = format!("{port_id_b}/{channel_id_b}/nam"); - // Send a token from Chain B - transfer( - &test_b, - BERTHA, - receiver.to_string(), - ibc_denom, - 50_000_000_000.0, - Some(BERTHA_KEY), - &port_id_b, - &channel_id_b, - None, - None, - None, - false, - )?; - wait_for_packet_relay(&port_id_a, &channel_id_a, &test_a)?; - check_balances_after_back(&port_id_b, &channel_id_b, &test_a, &test_b)?; - - // Send a token to the shielded address on Chain A - transfer_on_chain( - &test_a, - "shield", - ALBERT, - AA_PAYMENT_ADDRESS, - BTC, - 100, - ALBERT_KEY, - )?; - // Send some token for masp fee payment - transfer_on_chain( - &test_a, - "shield", - ALBERT, - AA_PAYMENT_ADDRESS, - NAM, - 10_000, - ALBERT_KEY, - )?; - shielded_sync(&test_a, AA_VIEWING_KEY)?; - // Shieded transfer from Chain A to Chain B - std::env::set_var(ENV_VAR_CHAIN_ID, test_a.net.chain_id.to_string()); - let token_addr = find_address(&test_a, BTC)?.to_string(); - let shielding_data_path = gen_ibc_shielding_data( - &test_b, - AB_PAYMENT_ADDRESS, - &token_addr, - 1_000_000_000, - &port_id_b, - &channel_id_b, - )?; - transfer( - &test_a, - A_SPENDING_KEY, - AB_PAYMENT_ADDRESS, - BTC, - 10.0, - None, - &port_id_a, - &channel_id_a, - None, - Some(shielding_data_path), - None, - false, - )?; - wait_for_packet_relay(&port_id_a, &channel_id_a, &test_a)?; - check_shielded_balances(&port_id_b, &channel_id_b, &test_a, &test_b)?; - - // Shielded transfer to an invalid receiver address (refund) - transfer( - &test_a, - A_SPENDING_KEY, - "invalid_receiver", - BTC, - 10.0, - Some(ALBERT_KEY), - &port_id_a, - &channel_id_a, - None, - None, - None, - false, - )?; - wait_for_packet_relay(&port_id_a, &channel_id_a, &test_a)?; - // Check the balance of the source shielded account - check_balance(&test_a, AA_VIEWING_KEY, BTC, 80)?; - // Check the refund - check_balance(&test_a, IBC_REFUND_TARGET_ALIAS, BTC, 10)?; - - // Stop Hermes for timeout test - let mut hermes = bg_hermes.foreground(); - hermes.interrupt()?; - - // Send transfer will be timed out (refund) - let shielding_data_path = gen_ibc_shielding_data( - &test_b, - AB_PAYMENT_ADDRESS, - token_addr, - 1_000_000_000, - &port_id_b, - &channel_id_b, - )?; - transfer( - &test_a, - A_SPENDING_KEY, - AB_PAYMENT_ADDRESS, - BTC, - 10.0, - Some(ALBERT_KEY), - &port_id_a, - &channel_id_a, - Some(Duration::new(10, 0)), - Some(shielding_data_path), - None, - false, - )?; - // wait for the timeout - sleep(10); - - // Restart relaying - let hermes = run_hermes(&test_a)?; - let _bg_hermes = hermes.background(); - - wait_for_packet_relay(&port_id_a, &channel_id_a, &test_a)?; - // Check the balance of the source shielded account - check_balance(&test_a, AA_VIEWING_KEY, BTC, 70)?; - // Check the refund - check_balance(&test_a, IBC_REFUND_TARGET_ALIAS, BTC, 10)?; - - Ok(()) -} - +const IBC_CLINET_ID: &str = "07-tendermint-0"; +const UPGRADED_CHAIN_ID: &str = "upgraded-chain"; + +/// IBC transfer tests: +/// 1. Transparent transfers +/// - Namada -> Gaia -> Namada +/// - Gaia -> Namada -> Gaia +/// 2. Invalid transfers +/// 3. Shielding/Unshielding transfers +/// - Gaia -> Namada -> (shielded transfer) -> Namada -> Gaia +/// 4. Shielding transfer the received token back to a shielded account on +/// Namada +/// 5. Refunding when transfer failure +/// - Ack with an error (invalid receiver) +/// - Timeout +/// - When unshielding transfer failure, +/// - Mint the IBC token for the refund +/// - Unescrow the token for the refund #[test] -fn ibc_namada_gaia() -> Result<()> { - // epoch per 100 seconds +fn ibc_transfers() -> Result<()> { let update_genesis = |mut genesis: templates::All, base_dir: &_| { genesis.parameters.parameters.epochs_per_year = @@ -411,15 +87,8 @@ fn ibc_namada_gaia() -> Result<()> { .default_per_epoch_throughput_limit = Amount::max_signed(); setup::set_validators(1, genesis, base_dir, |_| 0, vec![]) }; - let (ledger, mut ledger_b, test, _test_b) = run_two_nets(update_genesis)?; + let (ledger, gaia, test, test_gaia) = run_namada_gaia(update_genesis)?; let _bg_ledger = ledger.background(); - // chain B isn't used - ledger_b.interrupt()?; - - // gaia - let test_gaia = setup_gaia()?; - let gaia = run_gaia(&test_gaia)?; - sleep(5); let _bg_gaia = gaia.background(); setup_hermes(&test, &test_gaia)?; @@ -430,16 +99,18 @@ fn ibc_namada_gaia() -> Result<()> { // Start relaying let hermes = run_hermes(&test)?; - let _bg_hermes = hermes.background(); + let bg_hermes = hermes.background(); - // Transfer from Namada to Gaia - let receiver = find_gaia_address(&test_gaia, GAIA_USER)?; + // 1. Transparent transfers + + // Transfer 2 APFEL from Namada to Gaia + let gaia_receiver = find_gaia_address(&test_gaia, GAIA_USER)?; transfer( &test, ALBERT, - receiver, + &gaia_receiver, APFEL, - 200.0, + 2, Some(ALBERT_KEY), &port_id_namada, &channel_id_namada, @@ -450,54 +121,58 @@ fn ibc_namada_gaia() -> Result<()> { )?; wait_for_packet_relay(&port_id_namada, &channel_id_namada, &test)?; - // Check the received token on Gaia + check_balance(&test, ALBERT, APFEL, 999_998)?; let token_addr = find_address(&test, APFEL)?; - let ibc_denom = format!("{port_id_gaia}/{channel_id_gaia}/{token_addr}"); - check_gaia_balance(&test_gaia, GAIA_USER, &ibc_denom, 200000000)?; + let ibc_denom_on_gaia = + format!("{port_id_gaia}/{channel_id_gaia}/{token_addr}"); + check_gaia_balance(&test_gaia, GAIA_USER, &ibc_denom_on_gaia, 2_000_000)?; - // Transfer back from Gaia to Namada - let receiver = find_address(&test, ALBERT)?.to_string(); + // Transfer 1 APFEL back from Gaia to Namada + let namada_receiver = find_address(&test, ALBERT)?.to_string(); transfer_from_gaia( &test_gaia, GAIA_USER, - receiver, - get_gaia_denom_hash(ibc_denom), - 100000000, + &namada_receiver, + get_gaia_denom_hash(&ibc_denom_on_gaia), + 1_000_000, &port_id_gaia, &channel_id_gaia, None, + None, )?; wait_for_packet_relay(&port_id_gaia, &channel_id_gaia, &test)?; - // Check the token on Namada - check_balance(&test, ALBERT, APFEL, 999900)?; + // Check the balances + check_balance(&test, ALBERT, APFEL, 999_999)?; + check_gaia_balance(&test_gaia, GAIA_USER, &ibc_denom_on_gaia, 1_000_000)?; - // Transfer a token from Gaia to Namada - let receiver = find_address(&test, ALBERT)?.to_string(); + // Transfer 200 samoleans from Gaia to Namada transfer_from_gaia( &test_gaia, GAIA_USER, - receiver, + &namada_receiver, GAIA_COIN, 200, &port_id_gaia, &channel_id_gaia, None, + None, )?; wait_for_packet_relay(&port_id_gaia, &channel_id_gaia, &test)?; // Check the token on Namada - let ibc_denom = format!("{port_id_namada}/{channel_id_namada}/{GAIA_COIN}"); - check_balance(&test, ALBERT, &ibc_denom, 200)?; + let ibc_denom_on_namada = + format!("{port_id_namada}/{channel_id_namada}/{GAIA_COIN}"); + check_balance(&test, ALBERT, &ibc_denom_on_namada, 200)?; + check_gaia_balance(&test_gaia, GAIA_USER, GAIA_COIN, 800)?; - // Transfer back from Namada to Gaia - let receiver = find_gaia_address(&test_gaia, GAIA_USER)?; + // Transfer 100 samoleans back from Namada to Gaia transfer( &test, ALBERT, - &receiver, - ibc_denom, - 100.0, + &gaia_receiver, + &ibc_denom_on_namada, + 100, Some(ALBERT_KEY), &port_id_namada, &channel_id_namada, @@ -507,11 +182,23 @@ fn ibc_namada_gaia() -> Result<()> { false, )?; wait_for_packet_relay(&port_id_namada, &channel_id_namada, &test)?; - // Check the received token on Gaia + + // Check the balances + check_balance(&test, ALBERT, &ibc_denom_on_namada, 100)?; check_gaia_balance(&test_gaia, GAIA_USER, GAIA_COIN, 900)?; - // Shielding transfer from Gaia to Namada - let memo_path = gen_ibc_shielding_data( + // 2. Invalid transfers + try_invalid_transfers( + &test, + &gaia_receiver, + &port_id_namada, + &channel_id_namada, + )?; + + // 3. Shielding/Unshielding transfers + + // Shielding transfer 100 samoleans from Gaia to Namada + let shielding_data_path = gen_ibc_shielding_data( &test, AA_PAYMENT_ADDRESS, GAIA_COIN, @@ -527,34 +214,34 @@ fn ibc_namada_gaia() -> Result<()> { 100, &port_id_gaia, &channel_id_gaia, - Some(memo_path), + Some(shielding_data_path), + None, )?; wait_for_packet_relay(&port_id_gaia, &channel_id_gaia, &test_gaia)?; - // Check the token on Namada - let ibc_denom = format!("{port_id_namada}/{channel_id_namada}/{GAIA_COIN}"); - check_balance(&test, AA_VIEWING_KEY, &ibc_denom, 100)?; + check_balance(&test, AA_VIEWING_KEY, &ibc_denom_on_namada, 100)?; + check_gaia_balance(&test_gaia, GAIA_USER, GAIA_COIN, 800)?; - // Shielded transfer on Namada + // Shielded transfer 50 samoleans on Namada transfer_on_chain( &test, "transfer", A_SPENDING_KEY, AB_PAYMENT_ADDRESS, - &ibc_denom, + &ibc_denom_on_namada, 50, ALBERT_KEY, )?; - check_balance(&test, AA_VIEWING_KEY, &ibc_denom, 50)?; - check_balance(&test, AB_VIEWING_KEY, &ibc_denom, 50)?; + check_balance(&test, AA_VIEWING_KEY, &ibc_denom_on_namada, 50)?; + check_balance(&test, AB_VIEWING_KEY, &ibc_denom_on_namada, 50)?; - // Unshielding transfer from Namada to Gaia + // Unshielding transfer 10 samoleans from Namada to Gaia transfer( &test, B_SPENDING_KEY, - &receiver, - &ibc_denom, - 10.0, + &gaia_receiver, + &ibc_denom_on_namada, + 10, Some(BERTHA_KEY), &port_id_namada, &channel_id_namada, @@ -564,16 +251,16 @@ fn ibc_namada_gaia() -> Result<()> { false, )?; wait_for_packet_relay(&port_id_namada, &channel_id_namada, &test)?; - check_balance(&test, AB_VIEWING_KEY, &ibc_denom, 40)?; + check_balance(&test, AB_VIEWING_KEY, &ibc_denom_on_namada, 40)?; check_gaia_balance(&test_gaia, GAIA_USER, GAIA_COIN, 810)?; - // Shielding transfer back from Gaia to Namada - let ibc_denom = format!("{port_id_gaia}/{channel_id_gaia}/{token_addr}"); + // 4. Shielding transfer the received token back to a shielded account on + // Namada let memo_path = gen_ibc_shielding_data( &test, AA_PAYMENT_ADDRESS, - &ibc_denom, - 100, + &ibc_denom_on_gaia, + 1, &port_id_namada, &channel_id_namada, )?; @@ -581,60 +268,158 @@ fn ibc_namada_gaia() -> Result<()> { &test_gaia, GAIA_USER, AA_PAYMENT_ADDRESS, - get_gaia_denom_hash(&ibc_denom), - 100000000, + get_gaia_denom_hash(&ibc_denom_on_gaia), + 1_000_000, &port_id_gaia, &channel_id_gaia, Some(memo_path), + None, )?; wait_for_packet_relay(&port_id_gaia, &channel_id_gaia, &test)?; - // Check the token on Namada - check_balance(&test, AA_VIEWING_KEY, APFEL, 100)?; + check_balance(&test, AA_VIEWING_KEY, APFEL, 1)?; + + // 5. Refunding when transfer failure + + // Transfer to an invalid receiver address to check the refund for the + // escrowed token + transfer( + &test, + ALBERT, + "invalid_receiver", + APFEL, + 10, + Some(ALBERT_KEY), + &port_id_namada, + &channel_id_namada, + None, + None, + None, + false, + )?; + wait_for_packet_relay(&port_id_namada, &channel_id_namada, &test)?; + // The balance should not be changed + check_balance(&test, ALBERT, APFEL, 999_999)?; + + // Stop Hermes for timeout test + let mut hermes = bg_hermes.foreground(); + hermes.interrupt()?; + + // Transfer will be timed out to check the refund for the burned IBC token + transfer( + &test, + ALBERT, + &gaia_receiver, + &ibc_denom_on_namada, + 10, + Some(ALBERT_KEY), + &port_id_namada, + &channel_id_namada, + Some(Duration::new(10, 0)), + None, + None, + false, + )?; + // wait for the timeout + sleep(10); + + // Restart relaying + let hermes = run_hermes(&test)?; + let bg_hermes = hermes.background(); + + wait_for_packet_relay(&port_id_namada, &channel_id_namada, &test)?; + // The balance should not be changed + check_balance(&test, ALBERT, &ibc_denom_on_namada, 100)?; + + // Unshielding transfer to Gaia's invalid account to check the refund for + // the burned IBC token + transfer( + &test, + A_SPENDING_KEY, + "invalid_receiver", + &ibc_denom_on_namada, + 10, + Some(ALBERT_KEY), + &port_id_namada, + &channel_id_namada, + None, + None, + None, + false, + )?; + wait_for_packet_relay(&port_id_namada, &channel_id_namada, &test)?; + // Check the token has been refunded to the refund target + check_balance(&test, AA_VIEWING_KEY, &ibc_denom_on_namada, 40)?; + check_balance(&test, IBC_REFUND_TARGET_ALIAS, &ibc_denom_on_namada, 10)?; + + // Stop Hermes for timeout test + let mut hermes = bg_hermes.foreground(); + hermes.interrupt()?; + + // Unshielding transfer will be timed out to check the refund for the + // escrowed IBC token + transfer( + &test, + A_SPENDING_KEY, + &gaia_receiver, + APFEL, + 1, + Some(ALBERT_KEY), + &port_id_namada, + &channel_id_namada, + Some(Duration::new(10, 0)), + None, + None, + false, + )?; + // wait for the timeout + sleep(10); + + // Restart relaying + let hermes = run_hermes(&test)?; + let _bg_hermes = hermes.background(); + + wait_for_packet_relay(&port_id_namada, &channel_id_namada, &test)?; + // Check the token has been refunded to the refund target + check_balance(&test, AA_VIEWING_KEY, APFEL, 0)?; + check_balance(&test, IBC_REFUND_TARGET_ALIAS, APFEL, 1)?; Ok(()) } #[test] -fn pgf_over_ibc_with_hermes() -> Result<()> { - let update_genesis = |mut genesis: templates::All< - templates::Unvalidated, - >, - base_dir: &_| { - genesis.parameters.parameters.epochs_per_year = - epochs_per_year_from_min_duration(20); - // for the trusting period of IBC client - genesis.parameters.pos_params.pipeline_len = 5; - genesis.parameters.parameters.max_proposal_bytes = Default::default(); - genesis.parameters.pgf_params.stewards = - BTreeSet::from_iter([get_established_addr_from_pregenesis( - ALBERT_KEY, base_dir, &genesis, - ) - .unwrap()]); - genesis.parameters.ibc_params.default_mint_limit = Amount::max_signed(); - genesis - .parameters - .ibc_params - .default_per_epoch_throughput_limit = Amount::max_signed(); - setup::set_validators(1, genesis, base_dir, |_| 0, vec![]) - }; - let (ledger_a, ledger_b, test_a, test_b) = run_two_nets(update_genesis)?; - let _bg_ledger_a = ledger_a.background(); - let _bg_ledger_b = ledger_b.background(); +fn pgf_over_ibc() -> Result<()> { + const PIPELINE_LEN: u64 = 5; + let update_genesis = + |mut genesis: templates::All, base_dir: &_| { + genesis.parameters.parameters.epochs_per_year = + epochs_per_year_from_min_duration(20); + // for the trusting period of IBC client + genesis.parameters.pos_params.pipeline_len = PIPELINE_LEN; + genesis.parameters.gov_params.min_proposal_grace_epochs = 3; + genesis + .parameters + .ibc_params + .default_per_epoch_throughput_limit = Amount::max_signed(); + setup::set_validators(1, genesis, base_dir, |_| 0, vec![]) + }; + let (ledger, gaia, test, test_gaia) = run_namada_gaia(update_genesis)?; + let _bg_ledger = ledger.background(); + let _bg_gaia = gaia.background(); - setup_hermes(&test_a, &test_b)?; - let port_id_a = "transfer".parse().unwrap(); - let port_id_b = "transfer".parse().unwrap(); - let (channel_id_a, channel_id_b) = - create_channel_with_hermes(&test_a, &test_b)?; + setup_hermes(&test, &test_gaia)?; + let port_id_namada = "transfer".parse().unwrap(); + let port_id_gaia: PortId = "transfer".parse().unwrap(); + let (channel_id_namada, channel_id_gaia) = + create_channel_with_hermes(&test, &test_gaia)?; // Start relaying - let hermes = run_hermes(&test_a)?; + let hermes = run_hermes(&test)?; let _bg_hermes = hermes.background(); // Transfer to PGF account transfer_on_chain( - &test_a, + &test, "transparent-transfer", ALBERT, PGF_ADDRESS.to_string(), @@ -643,42 +428,58 @@ fn pgf_over_ibc_with_hermes() -> Result<()> { ALBERT_KEY, )?; - // Proposal on Chain A + // Proposal on Namada // Delegate some token - delegate_token(&test_a)?; - let rpc_a = get_actor_rpc(&test_a, Who::Validator(0)); - let mut epoch = get_epoch(&test_a, &rpc_a).unwrap(); - let delegated = epoch + 5u64; - while epoch <= delegated { + delegate_token(&test)?; + let rpc = get_actor_rpc(&test, Who::Validator(0)); + let mut epoch = get_epoch(&test, &rpc).unwrap(); + let delegated = epoch + PIPELINE_LEN; + while epoch < delegated { sleep(5); - epoch = get_epoch(&test_a, &rpc_a).unwrap(); + epoch = get_epoch(&test, &rpc).unwrap(); } // funding proposal - let start_epoch = - propose_funding(&test_a, &test_b, &port_id_a, &channel_id_a)?; - let mut epoch = get_epoch(&test_a, &rpc_a).unwrap(); + let continuous_receiver = find_gaia_address(&test_gaia, GAIA_RELAYER)?; + let retro_receiver = find_gaia_address(&test_gaia, GAIA_USER)?; + let start_epoch = propose_funding( + &test, + continuous_receiver, + retro_receiver, + &port_id_namada, + &channel_id_namada, + )?; + let mut epoch = get_epoch(&test, &rpc).unwrap(); // Vote - while epoch <= start_epoch { + while epoch < start_epoch { sleep(5); - epoch = get_epoch(&test_a, &rpc_a).unwrap(); + epoch = get_epoch(&test, &rpc).unwrap(); } - submit_votes(&test_a)?; + submit_votes(&test)?; // wait for the grace - let activation_epoch = start_epoch + 12u64 + 6u64 + 1u64; - while epoch <= activation_epoch { + let grace_epoch = start_epoch + 6u64; + while epoch < grace_epoch { sleep(5); - epoch = get_epoch(&test_a, &rpc_a).unwrap(); + epoch = get_epoch(&test, &rpc).unwrap(); } + wait_for_packet_relay(&port_id_namada, &channel_id_namada, &test)?; // Check balances after funding over IBC - check_funded_balances(&port_id_b, &channel_id_b, &test_b)?; + let token_addr = find_address(&test, NAM)?; + let ibc_denom = format!("{port_id_gaia}/{channel_id_gaia}/{token_addr}"); + check_gaia_balance(&test_gaia, GAIA_RELAYER, &ibc_denom, 10_000_000)?; + check_gaia_balance(&test_gaia, GAIA_USER, &ibc_denom, 5_000_000)?; Ok(()) } +/// IBC token inflation test +/// - Propose the inflation of an IBC token received from Gaia +/// - Shielding transfer of the token from Gaia +/// - Check the inflation #[test] -fn proposal_ibc_token_inflation() -> Result<()> { +fn ibc_token_inflation() -> Result<()> { + const PIPELINE_LEN: u64 = 2; const MASP_EPOCH_MULTIPLIER: u64 = 2; let update_genesis = |mut genesis: templates::All, base_dir: &_| { @@ -695,244 +496,208 @@ fn proposal_ibc_token_inflation() -> Result<()> { .default_per_epoch_throughput_limit = Amount::max_signed(); setup::set_validators(1, genesis, base_dir, |_| 0, vec![]) }; - let (ledger_a, ledger_b, test_a, test_b) = run_two_nets(update_genesis)?; - let _bg_ledger_a = ledger_a.background(); - let _bg_ledger_b = ledger_b.background(); + let (ledger, gaia, test, test_gaia) = run_namada_gaia(update_genesis)?; + let _bg_ledger = ledger.background(); + let _bg_gaia = gaia.background(); - // Proposal on the destination (Chain B) + // Proposal on Namada // Delegate some token - delegate_token(&test_b)?; - let rpc_b = get_actor_rpc(&test_b, Who::Validator(0)); - let mut epoch = get_epoch(&test_b, &rpc_b).unwrap(); - let delegated = epoch + 2u64; - while epoch <= delegated { + delegate_token(&test)?; + let rpc = get_actor_rpc(&test, Who::Validator(0)); + let mut epoch = get_epoch(&test, &rpc).unwrap(); + let delegated = epoch + PIPELINE_LEN; + while epoch < delegated { sleep(10); - epoch = get_epoch(&test_b, &rpc_b).unwrap_or_default(); + epoch = get_epoch(&test, &rpc).unwrap_or_default(); } - // inflation proposal on Chain B - let start_epoch = propose_inflation(&test_b)?; - let mut epoch = get_epoch(&test_b, &rpc_b).unwrap(); + // inflation proposal on Namada + let start_epoch = propose_inflation(&test)?; + let mut epoch = get_epoch(&test, &rpc).unwrap(); // Vote - while epoch <= start_epoch { + while epoch < start_epoch { sleep(10); - epoch = get_epoch(&test_b, &rpc_b).unwrap_or_default(); + epoch = get_epoch(&test, &rpc).unwrap_or_default(); } - submit_votes(&test_b)?; - - // wait for the next epoch of the grace - wait_epochs(&test_b, 6 + 1)?; - - setup_hermes(&test_a, &test_b)?; - let port_id_a = "transfer".parse().unwrap(); - let port_id_b = "transfer".parse().unwrap(); - let (channel_id_a, channel_id_b) = - create_channel_with_hermes(&test_a, &test_b)?; + submit_votes(&test)?; + // Create an IBC channel while waiting the grace epoch + setup_hermes(&test, &test_gaia)?; + let port_id_namada = "transfer".parse().unwrap(); + let port_id_gaia = "transfer".parse().unwrap(); + let (channel_id_namada, channel_id_gaia) = + create_channel_with_hermes(&test, &test_gaia)?; // Start relaying - let hermes = run_hermes(&test_a)?; + let hermes = run_hermes(&test)?; let _bg_hermes = hermes.background(); - // wait the next epoch not to update the epoch during the IBC transfer - wait_epochs(&test_b, 1)?; + // wait for the grace + let grace_epoch = start_epoch + 6u64; + while epoch < grace_epoch { + sleep(5); + epoch = get_epoch(&test, &rpc).unwrap(); + } - // Transfer 1 from Chain A to a z-address on Chain B - std::env::set_var(ENV_VAR_CHAIN_ID, test_a.net.chain_id.to_string()); - let token_addr = find_address(&test_a, APFEL)?.to_string(); + // Check the target balance is zero before the inflation + check_balance(&test, AA_VIEWING_KEY, NAM, 0)?; + // Shielding transfer 1 samoleans from Gaia to Namada let shielding_data_path = gen_ibc_shielding_data( - &test_b, - AB_PAYMENT_ADDRESS, - token_addr, - 1_000_000, - &port_id_b, - &channel_id_b, + &test, + AA_PAYMENT_ADDRESS, + GAIA_COIN, + 1, + &port_id_namada, + &channel_id_namada, )?; - transfer( - &test_a, - ALBERT, - AB_PAYMENT_ADDRESS, - APFEL, - 1.0, - Some(ALBERT_KEY), - &port_id_a, - &channel_id_a, - None, + transfer_from_gaia( + &test_gaia, + GAIA_USER, + AA_PAYMENT_ADDRESS, + GAIA_COIN, + 1, + &port_id_gaia, + &channel_id_gaia, Some(shielding_data_path), None, - false, )?; - wait_for_packet_relay(&port_id_a, &channel_id_a, &test_a)?; + wait_for_packet_relay(&port_id_gaia, &channel_id_gaia, &test)?; // wait the next masp epoch to dispense the reward - wait_epochs(&test_b, MASP_EPOCH_MULTIPLIER)?; + let mut epoch = get_epoch(&test, &rpc).unwrap(); + let new_epoch = epoch + MASP_EPOCH_MULTIPLIER; + while epoch < new_epoch { + sleep(10); + epoch = get_epoch(&test, &rpc).unwrap_or_default(); + } // Check balances - check_inflated_balance(&test_b)?; + check_inflated_balance(&test, AA_VIEWING_KEY)?; Ok(()) } #[test] fn ibc_upgrade_client() -> Result<()> { - // To avoid the client expiration, stop updating the client near the - // first height of the grace epoch. It is set 340 because the grace epoch in - // this test will be Epoch 18 and the number of blocks per epoch is 20. - const MIN_UPGRADE_HEIGHT: u64 = 340; - const PIPELINE_LEN: u64 = 8; + const UPGRADE_HEIGHT_OFFSET: u64 = 20; let update_genesis = |mut genesis: templates::All, base_dir: &_| { genesis.parameters.parameters.epochs_per_year = - epochs_per_year_from_min_duration(20); - // for the trusting period of IBC client - genesis.parameters.pos_params.pipeline_len = PIPELINE_LEN; - genesis.parameters.gov_params.min_proposal_grace_epochs = 3; - genesis.parameters.ibc_params.default_mint_limit = - Amount::max_signed(); - genesis - .parameters - .ibc_params - .default_per_epoch_throughput_limit = Amount::max_signed(); + epochs_per_year_from_min_duration(1800); setup::set_validators(1, genesis, base_dir, |_| 0, vec![]) }; - let (ledger_a, ledger_b, test_a, test_b) = run_two_nets(update_genesis)?; - let _bg_ledger_a = ledger_a.background(); - let _bg_ledger_b = ledger_b.background(); + let (ledger, gaia, test, test_gaia) = run_namada_gaia(update_genesis)?; + let _bg_ledger = ledger.background(); + let _bg_gaia = gaia.background(); - // Proposal on Chain B - // Delegate some token - delegate_token(&test_b)?; - let rpc_b = get_actor_rpc(&test_b, Who::Validator(0)); - let mut epoch = get_epoch(&test_b, &rpc_b).unwrap(); - let delegated = epoch + PIPELINE_LEN; - while epoch <= delegated { - sleep(10); - epoch = get_epoch(&test_b, &rpc_b).unwrap_or_default(); - } - // Upgrade proposal on Chain B - // The transaction will store the upgraded client state and consensus state - // as if Chain B will be upgraded - let start_epoch = propose_upgrade_client(&test_b)?; - let mut epoch = get_epoch(&test_b, &rpc_b).unwrap(); - // Vote - while epoch < start_epoch { - sleep(10); - epoch = get_epoch(&test_b, &rpc_b).unwrap_or_default(); - } - submit_votes(&test_b)?; + setup_hermes(&test, &test_gaia)?; + create_channel_with_hermes(&test, &test_gaia)?; - // creating IBC channel while waiting the grace epoch - setup_hermes(&test_a, &test_b)?; - create_channel_with_hermes(&test_a, &test_b)?; - // Start relaying to update clients - let hermes = run_hermes(&test_a)?; - let bg_hermes = hermes.background(); + let height = query_height(&test_gaia)?; + let upgrade_height = height.revision_height() + UPGRADE_HEIGHT_OFFSET; - let mut height = query_height(&test_b)?; - while height.revision_height() < MIN_UPGRADE_HEIGHT { - sleep(10); - height = query_height(&test_b)?; - } - // Stop Hermes not to update a client after the upgrade height - let mut hermes = bg_hermes.foreground(); - hermes.interrupt()?; + // upgrade proposal + propose_upgrade_client(&test, &test_gaia, upgrade_height)?; - // wait for the grace epoch - let grace_epoch = start_epoch + 6u64; - std::env::set_var(ENV_VAR_CHAIN_ID, test_b.net.chain_id.to_string()); - while epoch < grace_epoch { - sleep(10); - epoch = get_epoch(&test_b, &rpc_b).unwrap_or_default(); + // vote + vote_on_gaia(&test_gaia)?; + wait_for_pass(&test_gaia)?; + + // wait for the halt height + let mut height = query_height(&test_gaia)?; + while height.revision_height() < upgrade_height { + sleep(5); + height = query_height(&test_gaia)?; } - // Check the upgraded height - let upgraded_height = get_upgraded_height(&test_b, MIN_UPGRADE_HEIGHT)?; - // Upgrade the IBC client of Chain B on Chain A with Hermes - upgrade_client(&test_a, test_a.net.chain_id.to_string(), upgraded_height)?; - sleep(1); + // Upgrade the IBC client of Gaia on Namada with Hermes + upgrade_client(&test, test.net.chain_id.to_string(), upgrade_height)?; // Check the upgraded client - let current_height = query_height(&test_a)?; - let (upgraded_client_state, _, _) = get_client_states( - &test_a, - &"07-tendermint-0".parse().unwrap(), - current_height, - )?; + let upgraded_client_state = + get_client_state(&test, &IBC_CLINET_ID.parse().unwrap())?; assert_eq!( upgraded_client_state.inner().chain_id.as_str(), - "upgraded-chain" + UPGRADED_CHAIN_ID ); Ok(()) } +/// IBC rate limit test +/// 1. Test per-epoch throuput +/// - The per-epoch throughput is 1 NAM +/// - Transfer 1 NAM in an epoch will succeed +/// - Transfer 1 NAM in the same epoch will fail +/// - Transfer 1 NAM in the next epoch will succeed +/// 2. Test the mint limit +/// - The mint limit is 1 +/// - Receiving 2 samoleans from Gaia will fail #[test] fn ibc_rate_limit() -> Result<()> { // Mint limit 2 transfer/channel-0/nam, per-epoch throughput limit 1 NAM - let update_genesis = - |mut genesis: templates::All, base_dir: &_| { - genesis.parameters.parameters.epochs_per_year = - epochs_per_year_from_min_duration(50); - genesis.parameters.ibc_params.default_mint_limit = - Amount::from_u64(2_000_000); - genesis - .parameters - .ibc_params - .default_per_epoch_throughput_limit = - Amount::from_u64(1_000_000); - setup::set_validators(1, genesis, base_dir, |_| 0, vec![]) - }; - let (ledger_a, ledger_b, test_a, test_b) = run_two_nets(update_genesis)?; - let _bg_ledger_a = ledger_a.background(); - let _bg_ledger_b = ledger_b.background(); + let update_genesis = |mut genesis: templates::All< + templates::Unvalidated, + >, + base_dir: &_| { + genesis.parameters.parameters.epochs_per_year = + epochs_per_year_from_min_duration(50); + genesis.parameters.ibc_params.default_mint_limit = Amount::from_u64(1); + genesis + .parameters + .ibc_params + .default_per_epoch_throughput_limit = Amount::from_u64(1_000_000); + setup::set_validators(1, genesis, base_dir, |_| 0, vec![]) + }; + let (ledger, gaia, test, test_gaia) = run_namada_gaia(update_genesis)?; + let _bg_ledger = ledger.background(); + let _bg_gaia = gaia.background(); - setup_hermes(&test_a, &test_b)?; - let port_id_a = "transfer".parse().unwrap(); - let port_id_b: PortId = "transfer".parse().unwrap(); - let (channel_id_a, channel_id_b) = - create_channel_with_hermes(&test_a, &test_b)?; + setup_hermes(&test, &test_gaia)?; + let port_id_namada = "transfer".parse().unwrap(); + let port_id_gaia: PortId = "transfer".parse().unwrap(); + let (channel_id_namada, channel_id_gaia) = + create_channel_with_hermes(&test, &test_gaia)?; // Start relaying - let hermes = run_hermes(&test_a)?; + let hermes = run_hermes(&test)?; let _bg_hermes = hermes.background(); // wait for the next epoch - std::env::set_var(ENV_VAR_CHAIN_ID, test_a.net.chain_id.to_string()); - let rpc_a = get_actor_rpc(&test_a, Who::Validator(0)); - let mut epoch = get_epoch(&test_a, &rpc_a).unwrap(); + let rpc = get_actor_rpc(&test, Who::Validator(0)); + let mut epoch = get_epoch(&test, &rpc).unwrap(); let next_epoch = epoch.next(); while epoch <= next_epoch { sleep(5); - epoch = get_epoch(&test_a, &rpc_a).unwrap(); + epoch = get_epoch(&test, &rpc).unwrap(); } - // Transfer 1 NAM from Chain A to Chain B - std::env::set_var(ENV_VAR_CHAIN_ID, test_b.net.chain_id.to_string()); - let receiver = find_address(&test_b, BERTHA)?; + // Transfer 1 NAM from Namada to Gaia + let gaia_receiver = find_gaia_address(&test_gaia, GAIA_USER)?; transfer( - &test_a, + &test, ALBERT, - receiver.to_string(), + &gaia_receiver, NAM, - 1.0, + 1, Some(ALBERT_KEY), - &port_id_a, - &channel_id_a, + &port_id_namada, + &channel_id_namada, None, None, None, false, )?; - // Transfer 1 NAM from Chain A to Chain B again will fail + // Transfer 1 NAM from Namada to Gaia again will fail transfer( - &test_a, + &test, ALBERT, - receiver.to_string(), + &gaia_receiver, NAM, - 1.0, + 1, Some(ALBERT_KEY), - &port_id_a, - &channel_id_a, + &port_id_namada, + &channel_id_namada, None, None, // expect an error of the throughput limit @@ -943,23 +708,23 @@ fn ibc_rate_limit() -> Result<()> { )?; // wait for the next epoch - let mut epoch = get_epoch(&test_a, &rpc_a).unwrap(); + let mut epoch = get_epoch(&test, &rpc).unwrap(); let next_epoch = epoch.next(); while epoch <= next_epoch { sleep(5); - epoch = get_epoch(&test_a, &rpc_a).unwrap(); + epoch = get_epoch(&test, &rpc).unwrap(); } - // Transfer 1 NAM from Chain A to Chain B will succeed in the new epoch + // Transfer 1 NAM from Namada to Gaia will succeed in the new epoch transfer( - &test_a, + &test, ALBERT, - receiver.to_string(), + &gaia_receiver, NAM, - 1.0, + 1, Some(ALBERT_KEY), - &port_id_a, - &channel_id_a, + &port_id_namada, + &channel_id_namada, None, None, None, @@ -967,164 +732,63 @@ fn ibc_rate_limit() -> Result<()> { )?; // wait for the next epoch - let mut epoch = get_epoch(&test_a, &rpc_a).unwrap(); + let mut epoch = get_epoch(&test, &rpc).unwrap(); let next_epoch = epoch.next(); while epoch <= next_epoch { sleep(5); - epoch = get_epoch(&test_a, &rpc_a).unwrap(); + epoch = get_epoch(&test, &rpc).unwrap(); } - // Transfer 1 NAM from Chain A to Chain B will succeed, but Chain B can't + // Transfer 2 samoleans from Gaia to Namada will succeed, but Namada can't // receive due to the mint limit and the packet will be timed out - transfer( - &test_a, - ALBERT, - receiver.to_string(), - NAM, - 1.0, - Some(ALBERT_KEY), - &port_id_a, - &channel_id_a, - Some(Duration::new(20, 0)), - None, + let namada_receiver = find_address(&test, ALBERT)?.to_string(); + transfer_from_gaia( + &test_gaia, + GAIA_USER, + namada_receiver, + GAIA_COIN, + 2, + &port_id_gaia, + &channel_id_gaia, None, - false, + Some(Duration::new(10, 0)), )?; - wait_for_packet_relay(&port_id_a, &channel_id_a, &test_a)?; + wait_for_packet_relay(&port_id_gaia, &channel_id_gaia, &test)?; - // Check the balance on Chain B - let ibc_denom = format!("{port_id_b}/{channel_id_b}/nam"); - std::env::set_var(ENV_VAR_CHAIN_ID, test_b.net.chain_id.to_string()); - let rpc_b = get_actor_rpc(&test_b, Who::Validator(0)); - let query_args = vec![ - "balance", "--owner", BERTHA, "--token", &ibc_denom, "--node", &rpc_b, - ]; - let expected = format!("{ibc_denom}: 2"); - let mut client = run!(test_b, Bin::Client, query_args, Some(40))?; - client.exp_string(&expected)?; - client.assert_success(); + // Check if Namada hasn't receive it + let ibc_denom = format!("{port_id_namada}/{channel_id_namada}/{GAIA_COIN}"); + // Need the raw address to check the balance because the token shouldn't be + // received + let token_addr = ibc_token(ibc_denom).to_string(); + check_balance(&test, ALBERT, token_addr, 0)?; Ok(()) } -fn run_two_nets( - update_genesis: impl FnMut( +fn run_namada_gaia( + mut update_genesis: impl FnMut( templates::All, &Path, ) -> templates::All, ) -> Result<(NamadaCmd, NamadaCmd, Test, Test)> { - let (test_a, test_b) = setup_two_single_node_nets(update_genesis)?; - set_ethereum_bridge_mode( - &test_a, - &test_a.net.chain_id, - Who::Validator(0), - ethereum_bridge::ledger::Mode::Off, - None, - ); + let test = setup::network(&mut update_genesis, None)?; + set_ethereum_bridge_mode( - &test_b, - &test_b.net.chain_id, + &test, + &test.net.chain_id, Who::Validator(0), ethereum_bridge::ledger::Mode::Off, None, ); - // Run Chain A - std::env::set_var(ENV_VAR_CHAIN_ID, test_a.net.chain_id.to_string()); - let mut ledger_a = - run_as!(test_a, Who::Validator(0), Bin::Node, &["ledger"], Some(40))?; - ledger_a.exp_string(LEDGER_STARTED)?; - ledger_a.exp_string(VALIDATOR_NODE)?; - // Run Chain B - std::env::set_var(ENV_VAR_CHAIN_ID, test_b.net.chain_id.to_string()); - let mut ledger_b = - run_as!(test_b, Who::Validator(0), Bin::Node, &["ledger"], Some(40))?; - ledger_b.exp_string(LEDGER_STARTED)?; - ledger_b.exp_string(VALIDATOR_NODE)?; - - wait_for_wasm_pre_compile(&mut ledger_a)?; - wait_for_wasm_pre_compile(&mut ledger_b)?; + let ledger = start_namada_ledger_node_wait_wasm(&test, Some(0), Some(40))?; + // gaia + let test_gaia = setup_gaia()?; + let gaia = run_gaia(&test_gaia)?; sleep(5); - Ok((ledger_a, ledger_b, test_a, test_b)) -} - -/// Set up two Namada chains to talk to each other via IBC. -fn setup_two_single_node_nets( - mut update_genesis: impl FnMut( - templates::All, - &Path, - ) -> templates::All, -) -> Result<(Test, Test)> { - const ANOTHER_PROXY_APP: u16 = 27659u16; - const ANOTHER_RPC: u16 = 27660u16; - const ANOTHER_P2P: u16 = 26655u16; - // Download the shielded pool parameters before starting node - let _ = FsShieldedUtils::new(PathBuf::new()); - - let test_a = setup::network(&mut update_genesis, None)?; - let test_b = setup::network(update_genesis, None)?; - let genesis_b_dir = test_b - .test_dir - .path() - .join(namada_apps_lib::client::utils::NET_ACCOUNTS_DIR) - .join("validator-0"); - let mut genesis_b = chain::Finalized::read_toml_files( - &genesis_b_dir.join(test_b.net.chain_id.as_str()), - ) - .map_err(|_| eyre!("Could not read genesis files from test b"))?; - // chain b's validator needs to listen on a different port than chain a's - // validator - let validator_pk = get_validator_pk(&test_b, Who::Validator(0)).unwrap(); - let validator_addr = genesis_b - .transactions - .established_account - .as_ref() - .unwrap() - .iter() - .find_map(|acct| { - acct.tx - .public_keys - .contains(&StringEncoded::new(validator_pk.clone())) - .then(|| acct.address.clone()) - }) - .unwrap(); - let validator_tx = genesis_b - .transactions - .validator_account - .as_mut() - .unwrap() - .iter_mut() - .find(|val| { - Address::Established(val.tx.data.address.raw.clone()) - == validator_addr - }) - .unwrap(); - let new_port = validator_tx.tx.data.net_address.port() - + setup::ANOTHER_CHAIN_PORT_OFFSET; - validator_tx.tx.data.net_address.set_port(new_port); - genesis_b - .write_toml_files(&genesis_b_dir.join(test_b.net.chain_id.as_str())) - .map_err(|_| eyre!("Could not write genesis toml files for test_b"))?; - // modify chain b to use different ports for cometbft - let mut config = namada_apps_lib::config::Config::load( - &genesis_b_dir, - &test_b.net.chain_id, - Some(TendermintMode::Validator), - ); - let proxy_app = &mut config.ledger.cometbft.proxy_app; - set_port(proxy_app, ANOTHER_PROXY_APP); - let rpc_addr = &mut config.ledger.cometbft.rpc.laddr; - set_port(rpc_addr, ANOTHER_RPC); - let p2p_addr = &mut config.ledger.cometbft.p2p.laddr; - set_port(p2p_addr, ANOTHER_P2P); - config - .write(&genesis_b_dir, &test_b.net.chain_id, true) - .map_err(|e| { - eyre!("Unable to modify chain b's config file due to {}", e) - })?; - Ok((test_a, test_b)) + Ok((ledger, gaia, test, test_gaia)) } fn create_channel_with_hermes( @@ -1226,33 +890,6 @@ fn wait_for_packet_relay( Err(eyre!("Pending packet is still left")) } -fn get_upgraded_height(test: &Test, min_upgrade_height: u64) -> Result { - std::env::set_var(ENV_VAR_CHAIN_ID, test.net.chain_id.to_string()); - // Search the storage for the upgraded client state - let rpc = get_actor_rpc(test, Who::Validator(0)); - let max_height = min_upgrade_height + 100; - let mut height = min_upgrade_height; - while height < max_height { - height += 1; - let key = upgraded_client_state_key(Height::new(0, height).unwrap()); - let query_args = [ - "query-bytes", - "--storage-key", - &key.to_string(), - "--node", - &rpc, - ]; - let mut client = run!(test, Bin::Client, query_args, Some(10))?; - if client.exp_string("No data found").is_ok() { - sleep(1); - continue; - } else { - return Ok(height); - } - } - panic!("No upgraded client state on the chain"); -} - fn upgrade_client( test: &Test, host_chain_id: impl AsRef, @@ -1275,610 +912,52 @@ fn upgrade_client( Ok(()) } -fn wait_epochs(test: &Test, duration_epochs: u64) -> Result<()> { - std::env::set_var(ENV_VAR_CHAIN_ID, test.net.chain_id.to_string()); - let rpc = get_actor_rpc(test, Who::Validator(0)); - let mut epoch = None; - for _ in 0..10 { - match get_epoch(test, &rpc) { - Ok(e) => { - epoch = Some(e); - break; - } - Err(_) => sleep(10), - } - } - let (mut epoch, target_epoch) = match epoch { - Some(e) => (e, e + duration_epochs), - None => return Err(eyre!("Query epoch failed")), - }; - while epoch < target_epoch { - sleep(10); - epoch = get_epoch(test, &rpc).unwrap_or_default(); - } - Ok(()) -} - -fn create_client(test_a: &Test, test_b: &Test) -> Result<(ClientId, ClientId)> { - let height = query_height(test_b)?; - let client_state = make_client_state(test_b, height); - let height = client_state.latest_height(); - let message = MsgCreateClient { - client_state: client_state.into(), - consensus_state: make_consensus_state(test_b, height)?.into(), - signer: signer(), - }; - let height_a = submit_ibc_tx( - test_a, - make_ibc_data(message.to_any()), - ensure_hot_addr(ALBERT), - ensure_hot_key(ALBERT_KEY), - false, - )?; - - let height = query_height(test_a)?; - let client_state = make_client_state(test_a, height); - let height = client_state.latest_height(); - let message = MsgCreateClient { - client_state: client_state.into(), - consensus_state: make_consensus_state(test_a, height)?.into(), - signer: signer(), - }; - let height_b = submit_ibc_tx( - test_b, - make_ibc_data(message.to_any()), - ensure_hot_addr(ALBERT), - ensure_hot_key(ALBERT_KEY), - false, - )?; - - let events = get_events(test_a, height_a)?; - let client_id_a = - get_client_id_from_events(&events).ok_or(eyre!(TX_FAILED))?; - let events = get_events(test_b, height_b)?; - let client_id_b = - get_client_id_from_events(&events).ok_or(eyre!(TX_FAILED))?; - - // `client_id_a` represents the ID of the B's client on Chain A - Ok((client_id_a, client_id_b)) -} - -fn make_client_state(test: &Test, height: Height) -> TmClientState { +fn get_client_state( + test: &Test, + client_id: &ClientId, +) -> Result { let rpc = get_actor_rpc(test, Who::Validator(0)); let tendermint_url = Url::from_str(&rpc).unwrap(); let client = HttpClient::new(tendermint_url).unwrap(); + let key = client_state_key(client_id); - let pos_params = - test.async_runtime().block_on(query_pos_parameters(&client)); - let pipeline_len = pos_params.pipeline_len; - - let key = param_storage::get_epoch_duration_storage_key(); - let epoch_duration = test + let result = test .async_runtime() - .block_on(query_storage_value::( - &client, &key, - )) - .unwrap(); - let unbonding_period = pipeline_len * epoch_duration.min_duration.0; - - let trusting_period = 2 * unbonding_period / 3; - let max_clock_drift = Duration::new(60, 0); - let chain_id = ChainId::from_str(test.net.chain_id.as_str()).unwrap(); - - TmClientStateType::new( - chain_id, - TrustThreshold::TWO_THIRDS, - Duration::from_secs(trusting_period), - Duration::from_secs(unbonding_period), - max_clock_drift, - height, - ibc_proof_specs::().try_into().unwrap(), - vec![], - AllowUpdate { - after_expiry: true, - after_misbehaviour: true, - }, - ) - .unwrap() - .into() -} - -fn make_consensus_state( - test: &Test, - height: Height, -) -> Result { - let header = query_header(test, height)?; - Ok(TmConsensusState::from(header)) -} - -fn update_client_with_height( - src_test: &Test, - target_test: &Test, - target_client_id: &ClientId, - target_height: Height, -) -> Result<()> { - // check the current(stale) state on the target chain - let key = client_state_key(target_client_id); - let (value, _) = query_value_with_proof(target_test, &key, None)?; - let cs = match value { - Some(v) => Any::decode(&v[..]) + .block_on(query_storage_value_bytes(&client, &key, None, false)); + let cs = match result { + (Some(v), _) => Any::decode(&v[..]) .map_err(|e| eyre!("Decoding the client state failed: {}", e))?, - None => { + _ => { return Err(eyre!( "The client state doesn't exist: client ID {}", - target_client_id + client_id )); } }; + let client_state = TmClientState::try_from(cs) .expect("the state should be a TmClientState"); - let trusted_height = client_state.latest_height(); - - update_client( - src_test, - target_test, - target_client_id, - trusted_height, - target_height, - ) -} - -fn update_client( - src_test: &Test, - target_test: &Test, - client_id: &ClientId, - trusted_height: Height, - target_height: Height, -) -> Result<()> { - let io = make_light_client_io(src_test); - - let height = TmHeight::try_from(trusted_height.revision_height()) - .expect("invalid height"); - let trusted_block = io - .fetch_light_block(height.into()) - .expect("the light client couldn't get a light block"); - - let height = TmHeight::try_from(target_height.revision_height()) - .expect("invalid height"); - let target_block = io - .fetch_light_block(height.into()) - .expect("the light client couldn't get a light block"); - - let header = IbcTmHeader { - signed_header: target_block.signed_header, - validator_set: target_block.validators, - trusted_height: Height::new(0, u64::from(trusted_block.height())) - .expect("invalid height"), - trusted_next_validator_set: trusted_block.next_validators, - }; - let message = MsgUpdateClient { - client_id: client_id.clone(), - client_message: header.into(), - signer: signer(), - }; - submit_ibc_tx( - target_test, - make_ibc_data(message.to_any()), - ensure_hot_addr(ALBERT), - ensure_hot_key(ALBERT_KEY), - false, - )?; - - check_ibc_update_query( - target_test, - client_id, - BlockHeight(target_height.revision_height()), - )?; - Ok(()) -} - -fn make_light_client_io(test: &Test) -> TmLightClientIo { - let rpc = get_actor_rpc(test, Who::Validator(0)); - let rpc_addr = Url::from_str(&rpc).unwrap(); - let rpc_client = HttpClient::new(rpc_addr).unwrap(); - let rpc_timeout = Duration::new(10, 0); - - let pk = get_validator_pk(test, Who::Validator(0)).unwrap(); - let peer_id = id_from_pk(&PublicKey::try_from_pk(&pk).unwrap()); - - TmLightClientIo::new(peer_id, rpc_client, Some(rpc_timeout)) -} - -fn connection_handshake( - test_a: &Test, - test_b: &Test, - client_id_a: &ClientId, - client_id_b: &ClientId, -) -> Result<(ConnectionId, ConnectionId)> { - let msg = MsgConnectionOpenInit { - client_id_on_a: client_id_a.clone(), - counterparty: ConnCounterparty::new( - client_id_b.clone(), - None, - commitment_prefix(), - ), - version: Some(ConnVersion::compatibles().first().unwrap().clone()), - delay_period: Duration::new(0, 0), - signer: signer(), - }; - // OpenInitConnection on Chain A - let height = submit_ibc_tx( - test_a, - make_ibc_data(msg.to_any()), - ensure_hot_addr(ALBERT), - ensure_hot_key(ALBERT_KEY), - false, - )?; - let events = get_events(test_a, height)?; - let conn_id_a = get_connection_id_from_events(&events) - .ok_or(eyre!("No connection ID is set"))?; - - // get the proofs from Chain A - let height_a = query_height(test_a)?; - let conn_proof = get_connection_proof(test_a, &conn_id_a, height_a)?; - let (client_state, client_state_proof, consensus_proof) = - get_client_states(test_a, client_id_a, height_a)?; - let counterparty = ConnCounterparty::new( - client_id_a.clone(), - Some(conn_id_a.clone()), - commitment_prefix(), - ); - #[allow(deprecated)] - let msg = MsgConnectionOpenTry { - client_id_on_b: client_id_b.clone(), - client_state_of_b_on_a: client_state.clone().into(), - counterparty, - versions_on_a: ConnVersion::compatibles(), - proofs_height_on_a: height_a, - proof_conn_end_on_a: conn_proof, - proof_client_state_of_b_on_a: client_state_proof, - proof_consensus_state_of_b_on_a: consensus_proof, - consensus_height_of_b_on_a: client_state.latest_height(), - delay_period: Duration::from_secs(0), - signer: "test".to_string().into(), - proof_consensus_state_of_b: None, - previous_connection_id: ConnectionId::zero().to_string(), - }; - // Update the client state of Chain A on Chain B - update_client_with_height(test_a, test_b, client_id_b, height_a)?; - // OpenTryConnection on Chain B - let height = submit_ibc_tx( - test_b, - make_ibc_data(msg.to_any()), - ensure_hot_addr(ALBERT), - ensure_hot_key(ALBERT_KEY), - false, - )?; - let events = get_events(test_b, height)?; - let conn_id_b = get_connection_id_from_events(&events) - .ok_or(eyre!("No connection ID is set"))?; - - // get the A's proofs on Chain B - let height_b = query_height(test_b)?; - let conn_proof = get_connection_proof(test_b, &conn_id_b, height_b)?; - let (client_state, client_state_proof, consensus_proof) = - get_client_states(test_b, client_id_b, height_b)?; - let consensus_height_of_a_on_b = client_state.latest_height(); - let msg = MsgConnectionOpenAck { - conn_id_on_a: conn_id_a.clone(), - conn_id_on_b: conn_id_b.clone(), - client_state_of_a_on_b: client_state.into(), - proof_conn_end_on_b: conn_proof, - proof_client_state_of_a_on_b: client_state_proof, - proof_consensus_state_of_a_on_b: consensus_proof, - proofs_height_on_b: height_b, - consensus_height_of_a_on_b, - version: ConnVersion::compatibles().first().unwrap().clone(), - signer: signer(), - proof_consensus_state_of_a: None, - }; - // Update the client state of Chain B on Chain A - update_client_with_height(test_b, test_a, client_id_a, height_b)?; - // OpenAckConnection on Chain A - submit_ibc_tx( - test_a, - make_ibc_data(msg.to_any()), - ensure_hot_addr(ALBERT), - ensure_hot_key(ALBERT_KEY), - false, - )?; - - // get the proofs on Chain A - let height_a = query_height(test_a)?; - let proof = get_connection_proof(test_a, &conn_id_a, height_a)?; - let msg = MsgConnectionOpenConfirm { - conn_id_on_b: conn_id_b.clone(), - proof_conn_end_on_a: proof, - proof_height_on_a: height_a, - signer: signer(), - }; - // Update the client state of Chain A on Chain B - update_client_with_height(test_a, test_b, client_id_b, height_a)?; - // OpenConfirmConnection on Chain B - submit_ibc_tx( - test_b, - make_ibc_data(msg.to_any()), - ensure_hot_addr(ALBERT), - ensure_hot_key(ALBERT_KEY), - false, - )?; - - Ok((conn_id_a, conn_id_b)) -} - -// get the proofs on the target height -fn get_connection_proof( - test: &Test, - conn_id: &ConnectionId, - target_height: Height, -) -> Result { - // we need proofs at the height of the previous block - let query_height = target_height.decrement().unwrap(); - let key = connection_key(conn_id); - let (_, tm_proof) = query_value_with_proof(test, &key, Some(query_height))?; - convert_proof(tm_proof) -} - -fn channel_handshake( - test_a: &Test, - test_b: &Test, - client_id_a: &ClientId, - client_id_b: &ClientId, - conn_id_a: &ConnectionId, - conn_id_b: &ConnectionId, -) -> Result<((PortId, ChannelId), (PortId, ChannelId))> { - // OpenInitChannel on Chain A - let port_id = PortId::transfer(); - let connection_hops_on_a = vec![conn_id_a.clone()]; - let channel_version = ChanVersion::new(ICS20_VERSION.to_string()); - let msg = MsgChannelOpenInit { - port_id_on_a: port_id.clone(), - connection_hops_on_a, - port_id_on_b: port_id.clone(), - ordering: ChanOrder::Unordered, - signer: signer(), - version_proposal: channel_version.clone(), - }; - let height = submit_ibc_tx( - test_a, - make_ibc_data(msg.to_any()), - ensure_hot_addr(ALBERT), - ensure_hot_key(ALBERT_KEY), - false, - )?; - let events = get_events(test_a, height)?; - let channel_id_a = - get_channel_id_from_events(&events).ok_or(eyre!(TX_FAILED))?; - - // get the proofs from Chain A - let height_a = query_height(test_a)?; - let proof_chan_end_on_a = - get_channel_proof(test_a, &port_id, &channel_id_a, height_a)?; - let connection_hops_on_b = vec![conn_id_b.clone()]; - #[allow(deprecated)] - let msg = MsgChannelOpenTry { - port_id_on_b: port_id.clone(), - connection_hops_on_b, - port_id_on_a: port_id.clone(), - chan_id_on_a: channel_id_a.clone(), - version_supported_on_a: channel_version.clone(), - proof_chan_end_on_a, - proof_height_on_a: height_a, - ordering: ChanOrder::Unordered, - signer: signer(), - version_proposal: channel_version.clone(), - }; - - // Update the client state of Chain A on Chain B - update_client_with_height(test_a, test_b, client_id_b, height_a)?; - // OpenTryChannel on Chain B - let height = submit_ibc_tx( - test_b, - make_ibc_data(msg.to_any()), - ensure_hot_addr(ALBERT), - ensure_hot_key(ALBERT_KEY), - false, - )?; - let events = get_events(test_b, height)?; - let channel_id_b = - get_channel_id_from_events(&events).ok_or(eyre!(TX_FAILED))?; - - // get the A's proofs on Chain B - let height_b = query_height(test_b)?; - let proof_chan_end_on_b = - get_channel_proof(test_b, &port_id, &channel_id_b, height_b)?; - let msg = MsgChannelOpenAck { - port_id_on_a: port_id.clone(), - chan_id_on_a: channel_id_a.clone(), - chan_id_on_b: channel_id_b.clone(), - version_on_b: channel_version, - proof_chan_end_on_b, - proof_height_on_b: height_b, - signer: signer(), - }; - // Update the client state of Chain B on Chain A - update_client_with_height(test_b, test_a, client_id_a, height_b)?; - // OpenAckChannel on Chain A - submit_ibc_tx( - test_a, - make_ibc_data(msg.to_any()), - ensure_hot_addr(ALBERT), - ensure_hot_key(ALBERT_KEY), - false, - )?; - - // get the proofs on Chain A - let height_a = query_height(test_a)?; - let proof_chan_end_on_a = - get_channel_proof(test_a, &port_id, &channel_id_a, height_a)?; - let msg = MsgChannelOpenConfirm { - port_id_on_b: port_id.clone(), - chan_id_on_b: channel_id_b.clone(), - proof_chan_end_on_a, - proof_height_on_a: height_a, - signer: signer(), - }; - // Update the client state of Chain A on Chain B - update_client_with_height(test_a, test_b, client_id_b, height_a)?; - // OpenConfirmChannel on Chain B - submit_ibc_tx( - test_b, - make_ibc_data(msg.to_any()), - ensure_hot_addr(ALBERT), - ensure_hot_key(ALBERT_KEY), - false, - )?; - - Ok(((port_id.clone(), channel_id_a), (port_id, channel_id_b))) + Ok(client_state) } -fn get_channel_proof( +fn try_invalid_transfers( test: &Test, + receiver: impl AsRef, port_id: &PortId, channel_id: &ChannelId, - target_height: Height, -) -> Result { - // we need proofs at the height of the previous block - let query_height = target_height.decrement().unwrap(); - let key = channel_key(port_id, channel_id); - let (_, tm_proof) = query_value_with_proof(test, &key, Some(query_height))?; - convert_proof(tm_proof) -} - -// get the client state, the proof of the client state, and the proof of the -// consensus state -fn get_client_states( - test: &Test, - client_id: &ClientId, - target_height: Height, // should have been already decremented -) -> Result<(TmClientState, CommitmentProofBytes, CommitmentProofBytes)> { - // we need proofs at the height of the previous block - let query_height = target_height.decrement().unwrap(); - let key = client_state_key(client_id); - let (value, tm_proof) = - query_value_with_proof(test, &key, Some(query_height))?; - let cs = match value { - Some(v) => Any::decode(&v[..]) - .map_err(|e| eyre!("Decoding the client state failed: {}", e))?, - None => { - return Err(eyre!( - "The client state doesn't exist: client ID {}", - client_id - )); - } - }; - let client_state = TmClientState::try_from(cs) - .expect("the state should be a TmClientState"); - let client_state_proof = convert_proof(tm_proof)?; - - let height = client_state.latest_height(); - let ibc_height = Height::new(0, height.revision_height()).unwrap(); - let key = consensus_state_key(client_id, ibc_height); - let (_, tm_proof) = query_value_with_proof(test, &key, Some(query_height))?; - let consensus_proof = convert_proof(tm_proof)?; - - Ok((client_state, client_state_proof, consensus_proof)) -} - -fn transfer_token( - test_a: &Test, - test_b: &Test, - client_id_a: &ClientId, - client_id_b: &ClientId, - port_id_a: &PortId, - channel_id_a: &ChannelId, -) -> Result<()> { - // Send a token from Chain A - std::env::set_var(ENV_VAR_CHAIN_ID, test_b.net.chain_id.to_string()); - let receiver = find_address(test_b, BERTHA)?; - let height = transfer( - test_a, - ALBERT, - receiver.to_string(), - NAM, - 100000.0, - Some(ALBERT_KEY), - port_id_a, - channel_id_a, - None, - None, - None, - false, - )?; - let events = get_events(test_a, height)?; - let packet = get_packet_from_events(&events).ok_or(eyre!(TX_FAILED))?; - check_ibc_packet_query(test_a, "send_packet", &packet)?; - - let height_a = query_height(test_a)?; - let proof_commitment_on_a = - get_commitment_proof(test_a, &packet, height_a)?; - let msg = IbcMsgRecvPacket { - packet, - proof_commitment_on_a, - proof_height_on_a: height_a, - signer: signer(), - }; - // Update the client state of Chain A on Chain B - update_client_with_height(test_a, test_b, client_id_b, height_a)?; - // Receive the token on Chain B - let height = submit_ibc_tx( - test_b, - make_ibc_data(msg.to_any()), - ensure_hot_addr(ALBERT), - ensure_hot_key(ALBERT_KEY), - false, - )?; - let events = get_events(test_b, height)?; - let packet = get_packet_from_events(&events).ok_or(eyre!(TX_FAILED))?; - let ack = get_ack_from_events(&events).ok_or(eyre!(TX_FAILED))?; - check_ibc_packet_query(test_b, "write_acknowledgement", &packet)?; - - // get the proof on Chain B - let height_b = query_height(test_b)?; - let proof_acked_on_b = get_ack_proof(test_b, &packet, height_b)?; - let msg = MsgAcknowledgement { - packet, - acknowledgement: ack.try_into().expect("invalid ack"), - proof_acked_on_b, - proof_height_on_b: height_b, - signer: signer(), - }; - // Update the client state of Chain B on Chain A - update_client_with_height(test_b, test_a, client_id_a, height_b)?; - // Acknowledge on Chain A - submit_ibc_tx( - test_a, - make_ibc_data(msg.to_any()), - ensure_hot_addr(ALBERT), - ensure_hot_key(ALBERT_KEY), - false, - )?; - - Ok(()) -} - -fn try_invalid_transfers( - test_a: &Test, - test_b: &Test, - port_id_a: &PortId, - channel_id_a: &ChannelId, ) -> Result<()> { - std::env::set_var(ENV_VAR_CHAIN_ID, test_b.net.chain_id.to_string()); - let receiver = find_address(test_b, BERTHA)?; - // invalid port - std::env::set_var(ENV_VAR_CHAIN_ID, test_a.net.chain_id.to_string()); - let nam_addr = find_address(test_a, NAM)?; + let nam_addr = find_address(test, NAM)?; transfer( - test_a, + test, ALBERT, - receiver.to_string(), + receiver.as_ref(), NAM, - 10.0, + 10, Some(ALBERT_KEY), &"port".parse().unwrap(), - channel_id_a, + channel_id, None, None, // the IBC denom can't be parsed when using an invalid port @@ -1888,13 +967,13 @@ fn try_invalid_transfers( // invalid channel transfer( - test_a, + test, ALBERT, - receiver.to_string(), + receiver.as_ref(), NAM, - 10.0, + 10, Some(ALBERT_KEY), - port_id_a, + port_id, &"channel-42".parse().unwrap(), None, None, @@ -1905,263 +984,38 @@ fn try_invalid_transfers( Ok(()) } -#[allow(clippy::too_many_arguments)] -fn transfer_on_chain( - test: &Test, - kind: impl AsRef, - sender: impl AsRef, - receiver: impl AsRef, - token: impl AsRef, - amount: u64, - signer: impl AsRef, -) -> Result<()> { - std::env::set_var(ENV_VAR_CHAIN_ID, test.net.chain_id.to_string()); - let rpc = get_actor_rpc(test, Who::Validator(0)); - let amount = amount.to_string(); - let tx_args = apply_use_device(vec![ - kind.as_ref(), - "--source", - sender.as_ref(), - "--target", - receiver.as_ref(), - "--token", - token.as_ref(), - "--amount", - &amount, - "--signing-keys", - signer.as_ref(), - "--node", - &rpc, - ]); - let mut client = run!(test, Bin::Client, tx_args, Some(120))?; - client.exp_string(TX_APPLIED_SUCCESS)?; - client.assert_success(); - - Ok(()) -} - -/// Give the token back after transfer_token -fn transfer_back( - test_a: &Test, - test_b: &Test, - client_id_a: &ClientId, - client_id_b: &ClientId, - port_id_b: &PortId, - channel_id_b: &ChannelId, -) -> Result<()> { - std::env::set_var(ENV_VAR_CHAIN_ID, test_a.net.chain_id.to_string()); - let receiver = find_address(test_a, ALBERT)?; - - // Chain A was the source for the sent token - let ibc_denom = format!("{port_id_b}/{channel_id_b}/nam"); - // Send a token from Chain B - let height = transfer( - test_b, - BERTHA, - receiver.to_string(), - ibc_denom, - 50_000_000_000.0, - Some(BERTHA_KEY), - port_id_b, - channel_id_b, - None, - None, - None, - false, - )?; - let events = get_events(test_b, height)?; - let packet = get_packet_from_events(&events).ok_or(eyre!(TX_FAILED))?; - - let height_b = query_height(test_b)?; - let proof = get_commitment_proof(test_b, &packet, height_b)?; - let msg = IbcMsgRecvPacket { - packet, - proof_commitment_on_a: proof, - proof_height_on_a: height_b, - signer: signer(), - }; - // Update the client state of Chain B on Chain A - update_client_with_height(test_b, test_a, client_id_a, height_b)?; - // Receive the token on Chain A - let height = submit_ibc_tx( - test_a, - make_ibc_data(msg.to_any()), - ensure_hot_addr(ALBERT), - ensure_hot_key(ALBERT_KEY), - false, - )?; - let events = get_events(test_a, height)?; - let packet = get_packet_from_events(&events).ok_or(eyre!(TX_FAILED))?; - let ack = get_ack_from_events(&events).ok_or(eyre!(TX_FAILED))?; - - // get the proof on Chain A - let height_a = query_height(test_a)?; - let proof_acked_on_b = get_ack_proof(test_a, &packet, height_a)?; - let msg = MsgAcknowledgement { - packet, - acknowledgement: ack.try_into().expect("invalid ack"), - proof_acked_on_b, - proof_height_on_b: height_a, - signer: signer(), - }; - // Update the client state of Chain A on Chain B - update_client_with_height(test_a, test_b, client_id_b, height_a)?; - // Acknowledge on Chain B - submit_ibc_tx( - test_b, - make_ibc_data(msg.to_any()), - ensure_hot_addr(ALBERT), - ensure_hot_key(ALBERT_KEY), - false, - )?; - - Ok(()) -} - -fn transfer_timeout( - test_a: &Test, - test_b: &Test, - client_id_a: &ClientId, - port_id_a: &PortId, - channel_id_a: &ChannelId, -) -> Result<()> { - std::env::set_var(ENV_VAR_CHAIN_ID, test_b.net.chain_id.to_string()); - let receiver = find_address(test_b, BERTHA)?; - - // Send a token from Chain A - let height = transfer( - test_a, - ALBERT, - receiver.to_string(), - NAM, - 100000.0, - Some(ALBERT_KEY), - port_id_a, - channel_id_a, - Some(Duration::new(5, 0)), - None, - None, - false, - )?; - let events = get_events(test_a, height)?; - let packet = get_packet_from_events(&events).ok_or(eyre!(TX_FAILED))?; - - // wait for the timeout - sleep(5); - - let height_b = query_height(test_b)?; - let proof_unreceived_on_b = - get_receipt_absence_proof(test_b, &packet, height_b)?; - let msg = IbcMsgTimeout { - packet, - next_seq_recv_on_b: 1.into(), // not used - proof_unreceived_on_b, - proof_height_on_b: height_b, - signer: signer(), - }; - // Update the client state of Chain B on Chain A - update_client_with_height(test_b, test_a, client_id_a, height_b)?; - // Timeout on Chain A - submit_ibc_tx( - test_a, - make_ibc_data(msg.to_any()), - ensure_hot_addr(ALBERT), - ensure_hot_key(ALBERT_KEY), - false, - )?; - - Ok(()) -} - -fn get_commitment_proof( - test: &Test, - packet: &Packet, - target_height: Height, -) -> Result { - // we need proofs at the height of the previous block - let query_height = target_height.decrement().unwrap(); - let key = commitment_key( - &packet.port_id_on_a, - &packet.chan_id_on_a, - packet.seq_on_a, - ); - let (_, tm_proof) = query_value_with_proof(test, &key, Some(query_height))?; - convert_proof(tm_proof) -} - -fn get_ack_proof( - test: &Test, - packet: &Packet, - target_height: Height, -) -> Result { - // we need proofs at the height of the previous block - let query_height = target_height.decrement().unwrap(); - let key = - ack_key(&packet.port_id_on_b, &packet.chan_id_on_b, packet.seq_on_a); - let (_, tm_proof) = query_value_with_proof(test, &key, Some(query_height))?; - convert_proof(tm_proof) -} - -fn get_receipt_absence_proof( - test: &Test, - packet: &Packet, - target_height: Height, -) -> Result { - // we need proofs at the height of the previous block - let query_height = target_height.decrement().unwrap(); - let key = receipt_key( - &packet.port_id_on_b, - &packet.chan_id_on_b, - packet.seq_on_a, - ); - let (_, tm_proof) = query_value_with_proof(test, &key, Some(query_height))?; - convert_proof(tm_proof) -} - -fn commitment_prefix() -> CommitmentPrefix { - CommitmentPrefix::from(COMMITMENT_PREFIX.as_bytes().to_vec()) -} - -fn submit_ibc_tx( +#[allow(clippy::too_many_arguments)] +fn transfer_on_chain( test: &Test, - data: Vec, - owner: &str, - signer: &str, - wait_reveal_pk: bool, -) -> Result { - std::env::set_var(ENV_VAR_CHAIN_ID, test.net.chain_id.to_string()); - let data_path = test.test_dir.path().join("tx.data"); - std::fs::write(&data_path, data).expect("writing data failed"); - - let data_path = data_path.to_string_lossy(); + kind: impl AsRef, + sender: impl AsRef, + receiver: impl AsRef, + token: impl AsRef, + amount: u64, + signer: impl AsRef, +) -> Result<()> { let rpc = get_actor_rpc(test, Who::Validator(0)); - let mut client = run!( - test, - Bin::Client, - apply_use_device(vec![ - "tx", - "--code-path", - TX_IBC_WASM, - "--data-path", - &data_path, - "--owner", - owner, - "--signing-keys", - signer, - "--gas-token", - NAM, - "--gas-limit", - "200000", - "--node", - &rpc - ]), - Some(40) - )?; + let amount = amount.to_string(); + let tx_args = apply_use_device(vec![ + kind.as_ref(), + "--source", + sender.as_ref(), + "--target", + receiver.as_ref(), + "--token", + token.as_ref(), + "--amount", + &amount, + "--signing-keys", + signer.as_ref(), + "--node", + &rpc, + ]); + let mut client = run!(test, Bin::Client, tx_args, Some(120))?; client.exp_string(TX_APPLIED_SUCCESS)?; - if wait_reveal_pk { - client.exp_string(TX_APPLIED_SUCCESS)?; - } - check_tx_height(test, &mut client) + client.assert_success(); + + Ok(()) } #[allow(clippy::too_many_arguments)] @@ -2170,7 +1024,7 @@ fn transfer( sender: impl AsRef, receiver: impl AsRef, token: impl AsRef, - amount: f64, + amount: u64, signer: Option<&str>, port_id: &PortId, channel_id: &ChannelId, @@ -2179,7 +1033,6 @@ fn transfer( expected_err: Option<&str>, wait_reveal_pk: bool, ) -> Result { - std::env::set_var(ENV_VAR_CHAIN_ID, test.net.chain_id.to_string()); let rpc = get_actor_rpc(test, Who::Validator(0)); let channel_id = channel_id.to_string(); @@ -2261,7 +1114,6 @@ fn transfer( } fn delegate_token(test: &Test) -> Result<()> { - std::env::set_var(ENV_VAR_CHAIN_ID, test.net.chain_id.to_string()); let rpc = get_actor_rpc(test, Who::Validator(0)); let tx_args = apply_use_device(vec![ "bond", @@ -2281,58 +1133,27 @@ fn delegate_token(test: &Test) -> Result<()> { } fn propose_funding( - test_a: &Test, - test_b: &Test, + test: &Test, + continuous_receiver: impl AsRef, + retro_receiver: impl AsRef, src_port_id: &PortId, src_channel_id: &ChannelId, ) -> Result { - std::env::set_var(ENV_VAR_CHAIN_ID, test_b.net.chain_id.to_string()); - let bertha = find_address(test_b, BERTHA)?; - let christel = find_address(test_b, CHRISTEL)?; - let pgf_funding = PgfFunding { continuous: vec![PGFTarget::Ibc(PGFIbcTarget { amount: Amount::native_whole(10), - target: bertha.to_string(), + target: continuous_receiver.as_ref().to_string(), port_id: src_port_id.clone(), channel_id: src_channel_id.clone(), })], retro: vec![PGFTarget::Ibc(PGFIbcTarget { amount: Amount::native_whole(5), - target: christel.to_string(), + target: retro_receiver.as_ref().to_string(), port_id: src_port_id.clone(), channel_id: src_channel_id.clone(), })], }; - std::env::set_var(ENV_VAR_CHAIN_ID, test_a.net.chain_id.to_string()); - let albert = find_address(test_a, ALBERT)?; - let rpc_a = get_actor_rpc(test_a, Who::Validator(0)); - let epoch = get_epoch(test_a, &rpc_a)?; - let start_epoch = (epoch.0 + 6) / 3 * 3; - let proposal_json_path = prepare_proposal_data( - test_a.test_dir.path(), - albert, - pgf_funding, - start_epoch, - ); - - let submit_proposal_args = apply_use_device(vec![ - "init-proposal", - "--pgf-funding", - "--data-path", - proposal_json_path.to_str().unwrap(), - "--node", - &rpc_a, - ]); - let mut client = run!(test_a, Bin::Client, submit_proposal_args, Some(40))?; - client.exp_string(TX_APPLIED_SUCCESS)?; - client.assert_success(); - Ok(start_epoch.into()) -} - -fn propose_inflation(test: &Test) -> Result { - std::env::set_var(ENV_VAR_CHAIN_ID, test.net.chain_id.to_string()); let albert = find_address(test, ALBERT)?; let rpc = get_actor_rpc(test, Who::Validator(0)); let epoch = get_epoch(test, &rpc)?; @@ -2340,14 +1161,14 @@ fn propose_inflation(test: &Test) -> Result { let proposal_json = serde_json::json!({ "proposal": { "content": { - "title": "TheTitle", + "title": "PGF", "authors": "test@test.com", "discussions-to": "www.github.com/anoma/aip/1", "created": "2022-03-10T08:54:37Z", "license": "MIT", - "abstract": "Ut convallis eleifend orci vel venenatis. Duis vulputate metus in lacus sollicitudin vestibulum. Suspendisse vel velit ac est consectetur feugiat nec ac urna. Ut faucibus ex nec dictum fermentum. Morbi aliquet purus at sollicitudin ultrices. Quisque viverra varius cursus. Praesent sed mauris gravida, pharetra turpis non, gravida eros. Nullam sed ex justo. Ut at placerat ipsum, sit amet rhoncus libero. Sed blandit non purus non suscipit. Phasellus sed quam nec augue bibendum bibendum ut vitae urna. Sed odio diam, ornare nec sapien eget, congue viverra enim.", - "motivation": "Ut convallis eleifend orci vel venenatis. Duis vulputate metus in lacus sollicitudin vestibulum. Suspendisse vel velit ac est consectetur feugiat nec ac urna. Ut faucibus ex nec dictum fermentum. Morbi aliquet purus at sollicitudin ultrices.", - "details": "Ut convallis eleifend orci vel venenatis. Duis vulputate metus in lacus sollicitudin vestibulum. Suspendisse vel velit ac est consectetur feugiat nec ac urna. Ut faucibus ex nec dictum fermentum. Morbi aliquet purus at sollicitudin ultrices. Quisque viverra varius cursus. Praesent sed mauris gravida, pharetra turpis non, gravida eros.", + "abstract": "PGF proposal", + "motivation": "PGF proposal test", + "details": "PGF proposal", "requires": "2" }, "author": albert, @@ -2355,29 +1176,26 @@ fn propose_inflation(test: &Test) -> Result { "voting_end_epoch": start_epoch + 3_u64, "activation_epoch": start_epoch + 6_u64, }, - "data": TestWasms::TxProposalIbcTokenInflation.read_bytes() + "data": pgf_funding, }); - let proposal_json_path = test.test_dir.path().join("proposal.json"); write_json_file(proposal_json_path.as_path(), proposal_json); let submit_proposal_args = apply_use_device(vec![ "init-proposal", + "--pgf-funding", "--data-path", proposal_json_path.to_str().unwrap(), - "--gas-limit", - "4000000", "--node", &rpc, ]); - let mut client = run!(test, Bin::Client, submit_proposal_args, Some(100))?; + let mut client = run!(test, Bin::Client, submit_proposal_args, Some(40))?; client.exp_string(TX_APPLIED_SUCCESS)?; client.assert_success(); Ok(start_epoch.into()) } -fn propose_upgrade_client(test: &Test) -> Result { - std::env::set_var(ENV_VAR_CHAIN_ID, test.net.chain_id.to_string()); +fn propose_inflation(test: &Test) -> Result { let albert = find_address(test, ALBERT)?; let rpc = get_actor_rpc(test, Who::Validator(0)); let epoch = get_epoch(test, &rpc)?; @@ -2385,14 +1203,14 @@ fn propose_upgrade_client(test: &Test) -> Result { let proposal_json = serde_json::json!({ "proposal": { "content": { - "title": "TheTitle", + "title": "IBC token inflation", "authors": "test@test.com", "discussions-to": "www.github.com/anoma/aip/1", "created": "2022-03-10T08:54:37Z", "license": "MIT", - "abstract": "upgrade chain", - "motivation": "upgrade chain", - "details": "upgrade chain", + "abstract": "IBC token inflation", + "motivation": "IBC token inflation", + "details": "IBC token inflation", "requires": "2" }, "author": albert, @@ -2400,12 +1218,13 @@ fn propose_upgrade_client(test: &Test) -> Result { "voting_end_epoch": start_epoch + 3_u64, "activation_epoch": start_epoch + 6_u64, }, - "data": TestWasms::TxProposalIbcClientUpgrade.read_bytes() + "data": TestWasms::TxProposalIbcTokenInflation.read_bytes() }); + let proposal_json_path = test.test_dir.path().join("proposal.json"); write_json_file(proposal_json_path.as_path(), proposal_json); - let submit_proposal_args = vec![ + let submit_proposal_args = apply_use_device(vec![ "init-proposal", "--data-path", proposal_json_path.to_str().unwrap(), @@ -2413,15 +1232,121 @@ fn propose_upgrade_client(test: &Test) -> Result { "4000000", "--node", &rpc, - ]; - let mut client = run!(test, Bin::Client, submit_proposal_args, Some(40))?; + ]); + let mut client = run!(test, Bin::Client, submit_proposal_args, Some(100))?; client.exp_string(TX_APPLIED_SUCCESS)?; client.assert_success(); Ok(start_epoch.into()) } +fn propose_upgrade_client( + test_namada: &Test, + test_gaia: &Test, + upgrade_height: u64, +) -> Result<()> { + let client_state = + get_client_state(test_namada, &IBC_CLINET_ID.parse().unwrap())?; + let mut client_state = client_state.inner().clone(); + client_state.chain_id = UPGRADED_CHAIN_ID.parse().unwrap(); + client_state.latest_height = Height::new(0, upgrade_height + 1).unwrap(); + client_state.zero_custom_fields(); + let any_client_state = Any::from(client_state.clone()); + + let proposer = get_gaia_gov_address(test_gaia)?; + + let proposal_json = serde_json::json!({ + "messages": [ + { + "@type": "/ibc.core.client.v1.MsgIBCSoftwareUpgrade", + "plan": { + "name": "Upgrade", + "height": upgrade_height, + "info": "" + }, + "upgraded_client_state": { + "@type": any_client_state.type_url, + "chain_id": client_state.chain_id().to_string(), + "unbonding_period": format!("{}s", client_state.unbonding_period.as_secs()), + "latest_height": client_state.latest_height, + "proof_specs": client_state.proof_specs, + "upgrade_path": client_state.upgrade_path, + }, + "signer": proposer + } + ], + "metadata": "ipfs://CID", + "deposit": "10000000stake", + "title": "Upgrade", + "summary": "Upgrade Gaia chain", + "expedited": false + }); + let proposal_json_path = test_gaia.test_dir.path().join("proposal.json"); + write_json_file(proposal_json_path.as_path(), proposal_json); + + let rpc = format!("tcp://{GAIA_RPC}"); + let submit_proposal_args = vec![ + "tx", + "gov", + "submit-proposal", + proposal_json_path.to_str().unwrap(), + "--from", + GAIA_USER, + "--gas", + "250000", + "--gas-prices", + "0.001stake", + "--node", + &rpc, + "--keyring-backend", + "test", + "--chain-id", + GAIA_CHAIN_ID, + "--yes", + ]; + let mut gaia = run_gaia_cmd(test_gaia, submit_proposal_args, Some(40))?; + gaia.assert_success(); + Ok(()) +} + +fn wait_for_pass(test: &Test) -> Result<()> { + let args = ["query", "gov", "proposal", "1"]; + for _ in 0..10 { + sleep(5); + let mut gaia = run_gaia_cmd(test, args, Some(40))?; + let (_, matched) = gaia.exp_regex("status: .*")?; + if matched.split(' ').last().unwrap() == "PROPOSAL_STATUS_PASSED" { + break; + } + } + Ok(()) +} + +fn vote_on_gaia(test: &Test) -> Result<()> { + let rpc = format!("tcp://{GAIA_RPC}"); + let args = vec![ + "tx", + "gov", + "vote", + "1", + "yes", + "--from", + GAIA_VALIDATOR, + "--gas-prices", + "0.001stake", + "--node", + &rpc, + "--keyring-backend", + "test", + "--chain-id", + GAIA_CHAIN_ID, + "--yes", + ]; + let mut gaia = run_gaia_cmd(test, args, Some(40))?; + gaia.assert_success(); + Ok(()) +} + fn submit_votes(test: &Test) -> Result<()> { - std::env::set_var(ENV_VAR_CHAIN_ID, test.net.chain_id.to_string()); let rpc = get_actor_rpc(test, Who::Validator(0)); let submit_proposal_vote = vec![ @@ -2474,6 +1399,7 @@ fn transfer_from_gaia( port_id: &PortId, channel_id: &ChannelId, memo_path: Option, + timeout_sec: Option, ) -> Result<()> { let port_id = port_id.to_string(); let channel_id = channel_id.to_string(); @@ -2517,6 +1443,15 @@ fn transfer_from_gaia( args.push(&memo); } + let timeout_nanosec = timeout_sec + .as_ref() + .map(|d| d.as_nanos().to_string()) + .unwrap_or_default(); + if timeout_sec.is_some() { + args.push("--packet-timeout-timestamp"); + args.push(&timeout_nanosec); + } + let mut gaia = run_gaia_cmd(test, args, Some(40))?; gaia.assert_success(); Ok(()) @@ -2543,13 +1478,6 @@ fn check_tx_height(test: &Test, client: &mut NamadaCmd) -> Result { Ok(height) } -fn make_ibc_data(message: Any) -> Vec { - let mut tx_data = vec![]; - prost::Message::encode(&message, &mut tx_data) - .expect("encoding IBC message shouldn't fail"); - tx_data -} - fn query_height(test: &Test) -> Result { let rpc = get_actor_rpc(test, Who::Validator(0)); let tendermint_url = Url::from_str(&rpc).unwrap(); @@ -2563,107 +1491,12 @@ fn query_height(test: &Test) -> Result { Ok(Height::new(0, status.sync_info.latest_block_height.into()).unwrap()) } -fn query_header(test: &Test, height: Height) -> Result { - let rpc = get_actor_rpc(test, Who::Validator(0)); - let tendermint_url = Url::from_str(&rpc).unwrap(); - let client = HttpClient::new(tendermint_url).unwrap(); - let height = height.revision_height() as u32; - let result = test - .async_runtime() - .block_on(client.blockchain(height, height)); - match result { - Ok(mut response) => match response.block_metas.pop() { - Some(meta) => Ok(meta.header), - None => Err(eyre!("No meta exists")), - }, - Err(e) => Err(eyre!("Header query failed: {}", e)), - } -} - -fn check_ibc_update_query( - test: &Test, - client_id: &ClientId, - consensus_height: BlockHeight, -) -> Result<()> { - let rpc = get_actor_rpc(test, Who::Validator(0)); - let tendermint_url = Url::from_str(&rpc).unwrap(); - let client = HttpClient::new(tendermint_url).unwrap(); - match test.async_runtime().block_on(RPC.shell().ibc_client_update( - &client, - client_id, - &consensus_height, - )) { - Ok(Some(_)) => Ok(()), - Ok(None) => Err(eyre!("No update event for the client {}", client_id)), - Err(e) => Err(eyre!("IBC update event query failed: {}", e)), - } -} - -fn check_ibc_packet_query( - test: &Test, - event_type: &str, - packet: &Packet, -) -> Result<()> { - let rpc = get_actor_rpc(test, Who::Validator(0)); - let tendermint_url = Url::from_str(&rpc).unwrap(); - let client = HttpClient::new(tendermint_url).unwrap(); - match test.async_runtime().block_on(RPC.shell().ibc_packet( - &client, - &IbcEventType(event_type.to_owned()), - &packet.port_id_on_a, - &packet.chan_id_on_a, - &packet.port_id_on_b, - &packet.chan_id_on_b, - &packet.seq_on_a, - )) { - Ok(Some(_)) => Ok(()), - Ok(None) => Err(eyre!("No packet event for the packet {}", packet)), - Err(e) => Err(eyre!("IBC packet event query failed: {}", e)), - } -} - -fn query_value_with_proof( - test: &Test, - key: &Key, - height: Option, -) -> Result<(Option>, TmProof)> { - let rpc = get_actor_rpc(test, Who::Validator(0)); - let tendermint_url = Url::from_str(&rpc).unwrap(); - let client = HttpClient::new(tendermint_url).unwrap(); - let result = test.async_runtime().block_on(query_storage_value_bytes( - &client, - key, - height.map(|h| BlockHeight(h.revision_height())), - true, - )); - match result { - (value, Some(proof)) => Ok((value, proof)), - _ => Err(eyre!("Query failed: key {}", key)), - } -} - -fn convert_proof(tm_proof: TmProof) -> Result { - let mut proofs = Vec::new(); - for op in &tm_proof.ops { - let mut parsed = ics23::CommitmentProof { proof: None }; - prost::Message::merge(&mut parsed, op.data.as_slice()) - .expect("merging CommitmentProof failed"); - proofs.push(parsed); - } - - let merkle_proof = MerkleProof { proofs }; - CommitmentProofBytes::try_from(merkle_proof).map_err(|e| { - eyre!("Proof conversion to CommitmentProofBytes failed: {}", e) - }) -} - fn check_balance( test: &Test, owner: impl AsRef, token: impl AsRef, expected_amount: u64, ) -> Result<()> { - std::env::set_var(ENV_VAR_CHAIN_ID, test.net.chain_id.to_string()); let rpc = get_actor_rpc(test, Who::Validator(0)); if owner.as_ref().starts_with("zvk") { @@ -2687,26 +1520,6 @@ fn check_balance( Ok(()) } -/// Check balances after IBC transfer -fn check_balances( - dest_port_id: &PortId, - dest_channel_id: &ChannelId, - test_a: &Test, - test_b: &Test, -) -> Result<()> { - // Check the balances on Chain A - let escrow = Address::Internal(InternalAddress::Ibc).to_string(); - check_balance(test_a, escrow, NAM, 100000)?; - // Check the source balance - check_balance(test_a, ALBERT, NAM, 1900000)?; - - // Check the balance on Chain B - let ibc_denom = format!("{dest_port_id}/{dest_channel_id}/nam"); - check_balance(test_b, BERTHA, ibc_denom, 100_000_000_000)?; - - Ok(()) -} - fn get_gaia_denom_hash(denom: impl AsRef) -> String { let mut hasher = Sha256::new(); hasher.update(denom.as_ref()); @@ -2740,112 +1553,17 @@ fn check_gaia_balance( Ok(()) } -/// Check balances after non IBC transfer -fn check_balances_after_non_ibc( - port_id: &PortId, - channel_id: &ChannelId, - test_b: &Test, -) -> Result<()> { - // Check the source on Chain B - let ibc_denom = format!("{port_id}/{channel_id}/nam"); - check_balance(test_b, BERTHA, &ibc_denom, 50_000_000_000)?; - - // Check the traget on Chain B - check_balance(test_b, ALBERT, &ibc_denom, 50_000_000_000)?; - - Ok(()) -} - -/// Check balances after IBC transfer back -fn check_balances_after_back( - dest_port_id: &PortId, - dest_channel_id: &ChannelId, - test_a: &Test, - test_b: &Test, -) -> Result<()> { - // Check the escrowed balance on Chain A - let escrow = Address::Internal(InternalAddress::Ibc).to_string(); - check_balance(test_a, escrow, NAM, 50000)?; - // Check the source balance on Chain A - check_balance(test_a, ALBERT, NAM, 1950000)?; - - // Check the balance on Chain B - let ibc_denom = format!("{dest_port_id}/{dest_channel_id}/nam"); - check_balance(test_b, BERTHA, ibc_denom, 0)?; - - Ok(()) -} - -/// Check balances after IBC shielded transfer -fn check_shielded_balances( - dest_port_id: &PortId, - dest_channel_id: &ChannelId, - test_a: &Test, - test_b: &Test, -) -> Result<()> { - // Check the shielded balance on Chain A - check_balance(test_a, AA_VIEWING_KEY, BTC, 90)?; - - // Check the shielded balance on Chain B - let ibc_denom = format!("{dest_port_id}/{dest_channel_id}/btc"); - check_balance(test_b, AB_VIEWING_KEY, ibc_denom, 1_000_000_000)?; - - Ok(()) -} - -fn check_funded_balances( - dest_port_id: &PortId, - dest_channel_id: &ChannelId, - test_b: &Test, +fn check_inflated_balance( + test: &Test, + viewing_key: impl AsRef, ) -> Result<()> { - std::env::set_var(ENV_VAR_CHAIN_ID, test_b.net.chain_id.to_string()); - // Check the balances on Chain B - let ibc_denom = format!("{dest_port_id}/{dest_channel_id}/nam"); - let rpc_b = get_actor_rpc(test_b, Who::Validator(0)); - let query_args = vec![ - "balance", "--owner", BERTHA, "--token", &ibc_denom, "--node", &rpc_b, - ]; - let mut client = run!(test_b, Bin::Client, query_args, Some(40))?; - let regex = format!("{ibc_denom}: .*"); - let (_, matched) = client.exp_regex(®ex)?; - let regex = regex::Regex::new(r"[0-9]+").unwrap(); - let iter = regex.find_iter(&matched); - let balance: u64 = iter.last().unwrap().as_str().parse().unwrap(); - assert!(balance >= 10); - client.assert_success(); - - let query_args = vec![ - "balance", "--owner", CHRISTEL, "--token", &ibc_denom, "--node", &rpc_b, - ]; - let mut client = run!(test_b, Bin::Client, query_args, Some(40))?; - let regex = format!("{ibc_denom}: .*"); - let (_, matched) = client.exp_regex(®ex)?; - let regex = regex::Regex::new(r"[0-9]+").unwrap(); - let iter = regex.find_iter(&matched); - let balance: u64 = iter.last().unwrap().as_str().parse().unwrap(); - assert!(balance >= 5); - client.assert_success(); - - Ok(()) -} + shielded_sync(test, viewing_key.as_ref())?; -fn check_inflated_balance(test: &Test) -> Result<()> { - std::env::set_var(ENV_VAR_CHAIN_ID, test.net.chain_id.to_string()); let rpc = get_actor_rpc(test, Who::Validator(0)); - let tx_args = vec![ - "shielded-sync", - "--viewing-keys", - AB_VIEWING_KEY, - "--node", - &rpc, - ]; - let mut client = run!(test, Bin::Client, tx_args, Some(120))?; - client.assert_success(); - let query_args = vec![ "balance", "--owner", - AB_VIEWING_KEY, + viewing_key.as_ref(), "--token", NAM, "--node", @@ -2862,73 +1580,7 @@ fn check_inflated_balance(test: &Test) -> Result<()> { Ok(()) } -fn signer() -> Signer { - "signer".to_string().into() -} - -fn get_client_id_from_events(events: &[AbciEvent]) -> Option { - get_attribute_from_events::(events) -} - -fn get_connection_id_from_events(events: &[AbciEvent]) -> Option { - get_attribute_from_events::(events) -} - -fn get_channel_id_from_events(events: &[AbciEvent]) -> Option { - get_attribute_from_events::(events) -} - -fn get_ack_from_events(events: &[AbciEvent]) -> Option> { - get_attribute_from_events::(events) - .map(String::into_bytes) -} - -fn get_attribute_from_events<'value, DATA>( - events: &[AbciEvent], -) -> Option<>::Value> -where - DATA: ReadFromEventAttributes<'value>, -{ - events.iter().find_map(|event| { - DATA::read_from_event_attributes(&event.attributes).ok() - }) -} - -fn get_packet_from_events(events: &[AbciEvent]) -> Option { - events.iter().find_map(|event| { - ibc_events::packet_from_event_attributes(&event.attributes).ok() - }) -} - -fn get_events(test: &Test, height: u32) -> Result> { - let rpc = get_actor_rpc(test, Who::Validator(0)); - let tendermint_url = Url::from_str(&rpc).unwrap(); - let client = HttpClient::new(tendermint_url).unwrap(); - - let response = test - .async_runtime() - .block_on(client.block_results(height)) - .map_err(|e| eyre!("block_results() for an IBC event failed: {}", e))?; - let tx_results = response.txs_results.ok_or_else(|| { - eyre!("No transaction has been executed: height {}", height) - })?; - for result in tx_results { - if result.code.is_err() { - return Err(eyre!( - "The transaction failed: code {:?}, log {}", - result.code, - result.log - )); - } - } - - response - .end_block_events - .ok_or_else(|| eyre!("IBC event was not found: height {}", height)) -} - fn shielded_sync(test: &Test, viewing_key: impl AsRef) -> Result<()> { - std::env::set_var(ENV_VAR_CHAIN_ID, test.net.chain_id.to_string()); let rpc = get_actor_rpc(test, Who::Validator(0)); let tx_args = vec![ "shielded-sync", @@ -2952,7 +1604,6 @@ fn gen_ibc_shielding_data( port_id: &PortId, channel_id: &ChannelId, ) -> Result { - std::env::set_var(ENV_VAR_CHAIN_ID, dst_test.net.chain_id.to_string()); let rpc = get_actor_rpc(dst_test, Who::Validator(0)); let output_folder = dst_test.test_dir.path().to_string_lossy(); diff --git a/crates/tests/src/e2e/ledger_tests.rs b/crates/tests/src/e2e/ledger_tests.rs index 822400db5a..4470a85e39 100644 --- a/crates/tests/src/e2e/ledger_tests.rs +++ b/crates/tests/src/e2e/ledger_tests.rs @@ -77,7 +77,7 @@ fn start_namada_ledger_node( Ok(node) } -fn start_namada_ledger_node_wait_wasm( +pub fn start_namada_ledger_node_wait_wasm( test: &Test, idx: Option, timeout_sec: Option, diff --git a/crates/tests/src/e2e/setup.rs b/crates/tests/src/e2e/setup.rs index e3fa45c778..b2651d6a0d 100644 --- a/crates/tests/src/e2e/setup.rs +++ b/crates/tests/src/e2e/setup.rs @@ -71,9 +71,6 @@ pub struct Network { pub chain_id: ChainId, } -/// Offset the ports used in the network configuration to avoid shared resources -pub const ANOTHER_CHAIN_PORT_OFFSET: u16 = 1000; - /// Apply the --use-device flag depending on the environment variables pub fn apply_use_device(mut tx_args: Vec<&str>) -> Vec<&str> { if is_use_device() { @@ -94,15 +91,6 @@ pub fn ensure_hot_key(key: &str) -> &str { } } -/// Same as ensure_hot_key but for addressees -pub fn ensure_hot_addr(key: &str) -> &str { - if is_use_device() { - constants::FRANK - } else { - key - } -} - /// Default functions for offsetting ports when /// adding multiple validators to a network pub fn default_port_offset(ix: u8) -> u16 { @@ -1325,7 +1313,7 @@ pub fn setup_gaia() -> Result { "genesis", "add-genesis-account", &account, - "10000stake,1000samoleans", + "100000000stake,1000samoleans", ]; let mut gaia = run_gaia_cmd(&test, args, Some(10))?; gaia.assert_success(); @@ -1338,8 +1326,12 @@ pub fn setup_gaia() -> Result { // Add the stake token to the validator let validator = find_gaia_address(&test, constants::GAIA_VALIDATOR)?; - let stake = "100000000000stake"; - let args = ["genesis", "add-genesis-account", &validator, stake]; + let args = [ + "genesis", + "add-genesis-account", + &validator, + "200000000000stake", + ]; let mut gaia = run_gaia_cmd(&test, args, Some(10))?; gaia.assert_success(); @@ -1348,7 +1340,7 @@ pub fn setup_gaia() -> Result { "genesis", "gentx", constants::GAIA_VALIDATOR, - stake, + "100000000000stake", "--keyring-backend", "test", "--chain-id", @@ -1429,9 +1421,6 @@ where #[allow(dead_code)] pub mod constants { - // Paths to the WASMs used for tests - pub use namada_sdk::tx::TX_IBC_WASM; - // User addresses aliases pub const ALBERT: &str = "Albert"; pub const ALBERT_KEY: &str = "Albert-key"; diff --git a/wasm_for_tests/Cargo.lock b/wasm_for_tests/Cargo.lock index 184c3f9f03..bc9fb2d037 100644 --- a/wasm_for_tests/Cargo.lock +++ b/wasm_for_tests/Cargo.lock @@ -3575,16 +3575,6 @@ dependencies = [ "rlsf", ] -[[package]] -name = "tx_proposal_ibc_client_upgrade" -version = "0.41.0" -dependencies = [ - "getrandom", - "namada_test_utils", - "namada_tx_prelude", - "rlsf", -] - [[package]] name = "tx_proposal_ibc_token_inflation" version = "0.41.0" diff --git a/wasm_for_tests/Cargo.toml b/wasm_for_tests/Cargo.toml index fc782df086..34b65d16a5 100644 --- a/wasm_for_tests/Cargo.toml +++ b/wasm_for_tests/Cargo.toml @@ -9,7 +9,6 @@ members = [ "tx_memory_limit", "tx_no_op", "tx_proposal_code", - "tx_proposal_ibc_client_upgrade", "tx_proposal_ibc_token_inflation", "tx_proposal_masp_reward", "tx_read_storage_key", diff --git a/wasm_for_tests/Makefile b/wasm_for_tests/Makefile index 91c1785d28..93ba19f33b 100644 --- a/wasm_for_tests/Makefile +++ b/wasm_for_tests/Makefile @@ -12,7 +12,6 @@ wasms += tx_invalid_data wasms += tx_memory_limit wasms += tx_no_op wasms += tx_proposal_code -wasms += tx_proposal_ibc_client_upgrade wasms += tx_proposal_ibc_token_inflation wasms += tx_proposal_masp_reward wasms += tx_read_storage_key diff --git a/wasm_for_tests/tx_proposal_ibc_client_upgrade/Cargo.toml b/wasm_for_tests/tx_proposal_ibc_client_upgrade/Cargo.toml deleted file mode 100644 index 25fb0ada75..0000000000 --- a/wasm_for_tests/tx_proposal_ibc_client_upgrade/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "tx_proposal_ibc_client_upgrade" -description = "Wasm transaction used for testing." -authors.workspace = true -edition.workspace = true -license.workspace = true -version.workspace = true - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -namada_test_utils.workspace = true -namada_tx_prelude.workspace = true -rlsf.workspace = true -getrandom.workspace = true - -[lib] -crate-type = ["cdylib"] diff --git a/wasm_for_tests/tx_proposal_ibc_client_upgrade/src/lib.rs b/wasm_for_tests/tx_proposal_ibc_client_upgrade/src/lib.rs deleted file mode 100644 index 82db4e42b2..0000000000 --- a/wasm_for_tests/tx_proposal_ibc_client_upgrade/src/lib.rs +++ /dev/null @@ -1,30 +0,0 @@ -use namada_test_utils::ibc::{ - make_new_client_state_bytes, make_new_consensus_state_bytes, -}; -use namada_tx_prelude::*; - -#[transaction] -fn apply_tx(ctx: &mut Ctx, _tx_data: BatchedTx) -> TxResult { - // This transaction will just store the IBC client state and the consensus - // state as if the chain was upgraded - let current_height = ctx.get_block_height()?.0; - // Make the states based on the last committed height - let last_committed_height = current_height - 1; - // Need to read the upgrade state with the next height - let upgrade_height = current_height + 1; - // The height of the new client state is the next after the upgrade - let height_after_upgrade = upgrade_height + 1; - let client_state = make_new_client_state_bytes(height_after_upgrade); - - let header = ctx.get_block_header(last_committed_height.into())?.unwrap(); - let consensus_state = make_new_consensus_state_bytes(header); - - let height = format!("0-{upgrade_height}").parse().unwrap(); - let upgraded_client_state_key = ibc::upgraded_client_state_key(height); - ctx.write_bytes(&upgraded_client_state_key, client_state)?; - let upgraded_consensus_state_key = - ibc::upgraded_consensus_state_key(height); - ctx.write_bytes(&upgraded_consensus_state_key, consensus_state)?; - - Ok(()) -} diff --git a/wasm_for_tests/tx_proposal_ibc_token_inflation/src/lib.rs b/wasm_for_tests/tx_proposal_ibc_token_inflation/src/lib.rs index 568901835c..d07031339e 100644 --- a/wasm_for_tests/tx_proposal_ibc_token_inflation/src/lib.rs +++ b/wasm_for_tests/tx_proposal_ibc_token_inflation/src/lib.rs @@ -6,7 +6,7 @@ use namada_tx_prelude::*; // Denom of tokens over IBC is always zero const IBC_TOKEN_DENOM: u8 = 0; const CHANNEL_ID: &str = "channel-0"; -const BASE_TOKEN: &str = "tnam1qyvfwdkz8zgs9n3qn9xhp8scyf8crrxwuq26r6gy"; +const BASE_TOKEN: &str = "samoleans"; #[transaction] fn apply_tx(ctx: &mut Ctx, _tx_data: BatchedTx) -> TxResult {