From 04868db11466498be5e8975e7a99eb3fe91b1e7f Mon Sep 17 00:00:00 2001 From: Luca Joss <43531661+ljoss17@users.noreply.github.com> Date: Tue, 23 Jan 2024 11:27:53 +0100 Subject: [PATCH] Port Osmosis EIP fee query feature (#3771) * Fix README badge (#3675) * Fix a bug in `query_next_sequence_receive`, where if we didnt ask for a proof, then the query height was ignored (#3662) * Enable serde feature of ibc-proto (#3678) * Update misbehaviour-ics tests (#3681) * Update light_client_attack_freeze_test.sh Update script to work with ICS `feat/ics-misbehaviour-handling` branch binary at `28e0c14b`. Signed-off-by: Simon Noetzlin * Update nix flake and remaining misbehaviour tests * Fix env variable increment * Use Cosmos Nix 'master' branch --------- Signed-off-by: Simon Noetzlin Co-authored-by: Luca Joss * Bump version to v1.7.1 * Do not perform client update if consensus state already exists (#3555) * Do not perform client update if consensus state already exists On some chains there are a few active channels using the same connection and therefore clients. This PR adds a check in the client update code and not create the message if the consensus state at desired height is already present. This helps with reducing relayer fees, state bloating, etc by eliminating redundant updates. * Improve error message in `update client` command * Add changelog entry for #3521 * Fix guide config files and balance outputs (#3690) * Add per chain `clear_interval` configuration (#3693) * Add per chain clear_interval configuration * Add changelog entry * Add guide entry for packet clearing * Reword config comment Signed-off-by: Romain Ruetschi --------- Signed-off-by: Romain Ruetschi Co-authored-by: Romain Ruetschi * Add CompatMode configuration (#3667) * Update test bootstrap to work with Celestia chain * Update Nix flake and add Celestia CI job * Add changelog entry * Add guide section for 'compat_mode' configuration * Apply suggestions from code review Co-authored-by: Romain Ruetschi Signed-off-by: Luca Joss <43531661+ljoss17@users.noreply.github.com> * Implement serialization and deserialization for CompatMode * Update crates/relayer/src/util/compat_mode.rs Co-authored-by: Romain Ruetschi Signed-off-by: Luca Joss <43531661+ljoss17@users.noreply.github.com> --------- Signed-off-by: Luca Joss <43531661+ljoss17@users.noreply.github.com> Co-authored-by: Romain Ruetschi * docs: fix typos (#3687) * docs: fix typos * test: fix error because of typo * Fix misbehaviour test --------- Co-authored-by: Luca Joss Co-authored-by: Luca Joss <43531661+ljoss17@users.noreply.github.com> * Update changelog * Apply suggestions from code review Co-authored-by: Luca Joss <43531661+ljoss17@users.noreply.github.com> Signed-off-by: Romain Ruetschi * Release Hermes v1.7.2 (#3709) * Add metric to count skipped client update messages (#3706) * Add metric to count skipped client update messages * Update guide with new metric * Add changelog entry * Update versions * Fix cargo doc warnings and update version reference in relayer crate * Fix clippy error * Fix relayer-rest test * Fix typo in changelog * Add `broadcast_errors` metric (#3710) * Add metric for broadcast errors * Update the guide with the new broadcast error metric * Add changelog entry * Update release date * Update changelog and summary message * Apply github suggestion and add missing entry in Changelog * Release Hermes v1.7.3 (#3715) * evidence: More reliable evidence reporting + couple of bug fixes (#3702) * evidence: Only fetch counterparty clients of chains present in the config * Harden the evidence reporting code in the face of runtime errors * Fix bug where the counterparty client id returned was actually the original client id * Bump version to v1.7.3 * Release changelog * Release Hermes v1.7.4 (#3729) * Improve `broadcast_errors` metric (#3719) * Use short description for 'broadcast_errors' metric * Add changelog entry * Fix hyperlink in doc comment Signed-off-by: Romain Ruetschi * Fix hyperlink in doc comment --------- Signed-off-by: Romain Ruetschi Co-authored-by: Romain Ruetschi * Fetch the light block at trusted_height + 1 when detecting misbehavior (#3727) * fetch the light block at trusted_height+1 when detecting misbehaviour * Add changelog entry * Fix typo --------- Co-authored-by: beer-1 <147697694+beer-1@users.noreply.github.com> * Initialise v1.7.4 release * Avoid retrieving a worker which is being removed by the idle worker clean-up process (#3725) * prevent returning stopping workers * clear only the specific worker * Add ibc-go v8 to integration tests (#3694) * Add simapp v8 to CI jobs * Add simapp v8 to nix flake * Handle CLI breaking changes of Cosmos SDK v0.50 in test bootstrap * Handle genesis config 'voting_perdiod' and CLI 'query txs' changes for Cosmos SDK v0.50.1 * Use 'MsgSubmitProposal' instead of deprecated 'UpgradeProposal' to initiate a chain upgrade * Update 'tx upgrade-chain' CLI template * Fix 'tx chain-upgrade' tests * Update chain upgrade for compatibility between different ibc-go versions * Improve assertion for client upgrade tests * Update ibc-proto-rs to v0.39.0 * Add changelog entry * Fix and improve guide section for client upgrade * Wait before querying client state for client upgrade tests * Apply suggestions from code review Co-authored-by: Romain Ruetschi Signed-off-by: Luca Joss <43531661+ljoss17@users.noreply.github.com> * Rename method 'ibc_version()' to 'version_specs' * Extract the verification of legacy version in a method * Implement 'FromStr' instead of 'TryFrom' for 'ProposalStatus' * Fix cargo-doc warning * Add changelog entry for CLI * Change the '--gov-account' flag as optional but will fail if trying to upgrade a chain with ibc-go v8+ * Update guide * Move and update changelog entry for CLI * Return a 'Specs' struct in 'version_specs()' method * Fix clippy errors --------- Signed-off-by: Luca Joss <43531661+ljoss17@users.noreply.github.com> Co-authored-by: Romain Ruetschi * Update Gaia used in tests from v12 to v13 & v14 (#3700) * Update Gaia v12 to v13 and v14 in tests * Fix Celestia CI job * Replace Gaia v12 with v13 and v14 in multi-chain tests (#3701) * Add changelog entry --------- Signed-off-by: Luca Joss <43531661+ljoss17@users.noreply.github.com> Co-authored-by: beer-1 <147697694+beer-1@users.noreply.github.com> Co-authored-by: Romain Ruetschi * Add PR 3703 to patch release * Improve `backlog` metrics (#3722) * Update backlog metric when packet clearing is triggered * Fix update backlog and add unit tests * Uncomment conditional compilation from telemetry tests * Add changelog entry * Update guide section regarding 'backlog_*' metrics * Correctly update the backlog when querying commitments on chain * Update backlog_oldest_timestamp to backlog_latest_update_timestamp * Update changelog entry * Fix bug in backlog update * Guard tests module by test cfg Signed-off-by: Romain Ruetschi * Update from GitHub suggestions --------- Signed-off-by: Romain Ruetschi Co-authored-by: Romain Ruetschi * Update changelog * Update release summary --------- Signed-off-by: Romain Ruetschi Signed-off-by: Luca Joss <43531661+ljoss17@users.noreply.github.com> Co-authored-by: Romain Ruetschi Co-authored-by: beer-1 <147697694+beer-1@users.noreply.github.com> * Fix changelog * add query for eip value * add lcd as optional field * initial integration * using dynamic * dynamic pricing * added better logs * use block_on * remove lcd * Add DynamicGas configuration * Add test for dynamic gas configuration * Fix dynamic gas price computation * Remove test related changes * Remove dynamic gas test * Change dynamic_gas_price to dynamic_gas configuration name * Correctly deserialize DynamicGas config * Fix formatting following merge * dynamic gas price: Add integration test (#3788) * Dynamic gas fee test * Add dynamic gas fee test to CI * Fix issue with nested calls to `block_on` (#3789) * Fix test for dynamic gas price --------- Co-authored-by: Luca Joss * Avoid depending on `cosmwasm-std` and `osmosis-std` * Cleanup * Use rustls instead of openssl with reqwest * Use same feature flag as tendermint-rpc for reqwest * Cleanup feature flag for reqwest dep in chain-registry * Undo changes to Cargo.lock * Add dynamic gas fees metrics (#3798) * Add simple metric for dynamic gas price after multiplication * Add max gas price configuration to dynamic gas configuration * Apply dynamic max gas configuration * Add 2 new metrics for dynamic gas fees * Add guide entry for Dynamic gas configuration and metrics * Fix EIP query parsing * Use chain id instead of RPC address in emitted metrics --------- Co-authored-by: Romain Ruetschi <106849+romac@users.noreply.github.com> * Add changelog entry * Reword changelog entry * Remove lower bound on max dynamic gas price * Small refactor * Fix unused variable warning * Simplify deserialization code * Fix wrong error message * Fixup changelog entry * Add example to the config * Fix integration test framework * Fix typo in config file * Apply suggestions from code review Co-authored-by: Luca Joss <43531661+ljoss17@users.noreply.github.com> Signed-off-by: Romain Ruetschi * Use dynamic gas for Osmosis in auto-generated config * Small improvement to `config auto` command output and usage * Fix typo Co-authored-by: Luca Joss <43531661+ljoss17@users.noreply.github.com> Signed-off-by: Romain Ruetschi * Update guide template * Fix guide * Rename configuration 'dynamic_gas' to 'dynamic_gas_price' * Rename 'dynamic_gas_price' subconfigurations 'max_gas_price' to 'max' and 'gas_price_multiplier' to 'multiplier' --------- Signed-off-by: Simon Noetzlin Signed-off-by: Romain Ruetschi Signed-off-by: Luca Joss <43531661+ljoss17@users.noreply.github.com> Signed-off-by: Romain Ruetschi Co-authored-by: Romain Ruetschi Co-authored-by: Simon Noetzlin Co-authored-by: GoodDaisy <90915921+GoodDaisy@users.noreply.github.com> Co-authored-by: beer-1 <147697694+beer-1@users.noreply.github.com> Co-authored-by: Adam Tucker Co-authored-by: Nicolas Lara Co-authored-by: Romain Ruetschi <106849+romac@users.noreply.github.com> --- .../ibc-relayer/3738-dynamic-gas-fees.md | 12 + .../3738-dynamic-gas-fees-metrics.md | 8 + .github/workflows/integration.yaml | 2 +- Cargo.lock | 8 +- config.toml | 12 + crates/chain-registry/Cargo.toml | 2 +- crates/relayer-cli/src/chain_registry.rs | 9 + .../relayer-cli/src/commands/config/auto.rs | 39 +-- crates/relayer/Cargo.toml | 1 + crates/relayer/src/chain/cosmos.rs | 13 + crates/relayer/src/chain/cosmos/batch.rs | 72 ++++-- crates/relayer/src/chain/cosmos/config.rs | 4 + .../relayer/src/chain/cosmos/eip_base_fee.rs | 141 +++++++++++ crates/relayer/src/chain/cosmos/estimate.rs | 14 +- crates/relayer/src/chain/cosmos/gas.rs | 69 ++++- crates/relayer/src/chain/cosmos/types/gas.rs | 3 + crates/relayer/src/config.rs | 1 + crates/relayer/src/config/dynamic_gas.rs | 142 +++++++++++ crates/relayer/src/error.rs | 32 +++ crates/relayer/src/lib.rs | 1 - crates/telemetry/src/state.rs | 60 ++++- flake.lock | 238 +++++++++++++----- guide/src/SUMMARY.md | 3 +- guide/src/documentation/commands/config.md | 4 +- .../configuration/configure-hermes.md | 2 +- .../configuration/dynamic-gas-fees.md | 21 ++ .../src/documentation/telemetry/operators.md | 18 +- .../commands/hermes/config/auto_1.md | 2 +- .../templates/help_templates/config/auto.md | 6 +- .../src/tutorials/production/setup-hermes.md | 2 +- tools/check-guide/Cargo.lock | 212 +++++++++------- tools/integration-test/Cargo.toml | 1 + .../src/tests/dynamic_gas_fee.rs | 214 ++++++++++++++++ tools/integration-test/src/tests/mod.rs | 3 + tools/test-framework/src/relayer/tx.rs | 6 + tools/test-framework/src/types/single/node.rs | 2 + 36 files changed, 1166 insertions(+), 213 deletions(-) create mode 100644 .changelog/unreleased/features/ibc-relayer/3738-dynamic-gas-fees.md create mode 100644 .changelog/unreleased/features/ibc-telemetry/3738-dynamic-gas-fees-metrics.md create mode 100644 crates/relayer/src/chain/cosmos/eip_base_fee.rs create mode 100644 crates/relayer/src/config/dynamic_gas.rs create mode 100644 guide/src/documentation/configuration/dynamic-gas-fees.md create mode 100644 tools/integration-test/src/tests/dynamic_gas_fee.rs diff --git a/.changelog/unreleased/features/ibc-relayer/3738-dynamic-gas-fees.md b/.changelog/unreleased/features/ibc-relayer/3738-dynamic-gas-fees.md new file mode 100644 index 0000000000..578056b876 --- /dev/null +++ b/.changelog/unreleased/features/ibc-relayer/3738-dynamic-gas-fees.md @@ -0,0 +1,12 @@ +- Add a new per-chain configuration table `dynamic_gas_price` which enables + querying the current gas price from the chain instead of the static `gas_price`, + when the chain has [EIP-1559][eip]-like dynamic gas price. + The new configuration setting can be configured per-chain as follows: + ```toml + dynamic_gas_price = { enabled = true, multiplier = 1.1, max = 0.6 } + ``` + At the moment, only chains which support the `osmosis.txfees.v1beta1.Query/GetEipBaseFee` + query can be used with dynamic gas price enabled. + ([\#3738](https://github.com/informalsystems/hermes/issues/3738)) + +[eip]: https://metamask.io/1559/ diff --git a/.changelog/unreleased/features/ibc-telemetry/3738-dynamic-gas-fees-metrics.md b/.changelog/unreleased/features/ibc-telemetry/3738-dynamic-gas-fees-metrics.md new file mode 100644 index 0000000000..98a9555967 --- /dev/null +++ b/.changelog/unreleased/features/ibc-telemetry/3738-dynamic-gas-fees-metrics.md @@ -0,0 +1,8 @@ +- Add three metrics related to EIP gas price: + - `dynamic_gas_queried_fees` contains data on the queried values + before applying any filter + - `dynamic_gas_queried_success_fees` contains data on the queried + values if the query was successful and before applying any filter + - `dynamic_gas_paid_fees` contains data on the queried values after + applying the `max` filter + ([\#3738](https://github.com/informalsystems/hermes/issues/3738)) \ No newline at end of file diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml index 78ef604845..bc9f4a5427 100644 --- a/.github/workflows/integration.yaml +++ b/.github/workflows/integration.yaml @@ -79,7 +79,7 @@ jobs: command: osmosisd account_prefix: osmo native_token: stake - features: '' + features: dynamic-gas-fee - package: juno command: junod account_prefix: juno diff --git a/Cargo.lock b/Cargo.lock index f2a986eeca..b8ab401cbc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1430,6 +1430,7 @@ dependencies = [ "once_cell", "prost", "regex", + "reqwest", "retry", "ripemd", "secp256k1", @@ -2477,7 +2478,6 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", "winreg", ] @@ -4005,12 +4005,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki-roots" -version = "0.25.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" - [[package]] name = "winapi" version = "0.3.9" diff --git a/config.toml b/config.toml index 06dabdac13..f45e2289cf 100644 --- a/config.toml +++ b/config.toml @@ -303,6 +303,18 @@ gas_price = { price = 0.025, denom = 'stake' } # Minimum value: 1.0 gas_multiplier = 1.1 +# Query the current gas price from the chain instead of using the static `gas_price` from the config. +# Useful for chains which have [EIP-1559][eip]-like dynamic gas price. +# +# At the moment, only chains which support the `osmosis.txfees.v1beta1.Query/GetEipBaseFee` +# query can be used with dynamic gas price enabled. +# +# See this page in the Hermes guide for more information: +# https://hermes.informal.systems/documentation/configuration/dynamic-gas-fees.html +# +# Default: { enabled = false, multiplier = 1.1, max = 0.6 } +dynamic_gas_price = { enabled = false, multiplier = 1.1, max = 0.6 } + # Specify how many IBC messages at most to include in a single transaction. # Default: 30 max_msg_num = 30 diff --git a/crates/chain-registry/Cargo.toml b/crates/chain-registry/Cargo.toml index 5724404d1f..b28dc1de05 100644 --- a/crates/chain-registry/Cargo.toml +++ b/crates/chain-registry/Cargo.toml @@ -21,7 +21,7 @@ flex-error = { version = "0.4.4", default-features = false } futures = { version = "0.3.27", features = ["executor"] } http = "0.2" itertools = "0.10.5" -reqwest = { version = "0.11.13", features = ["rustls-tls", "json"], default-features = false } +reqwest = { version = "0.11.13", features = ["rustls-tls-native-roots", "json"], default-features = false } serde = "1.0.195" serde_json = "1" tokio = "1.17.0" diff --git a/crates/relayer-cli/src/chain_registry.rs b/crates/relayer-cli/src/chain_registry.rs index df63a513c1..cbaae53590 100644 --- a/crates/relayer-cli/src/chain_registry.rs +++ b/crates/relayer-cli/src/chain_registry.rs @@ -6,6 +6,7 @@ use std::marker::Send; use futures::future::join_all; use http::Uri; +use ibc_relayer::config::dynamic_gas::DynamicGasPrice; use tokio::task::{JoinError, JoinHandle}; use tracing::trace; @@ -120,6 +121,13 @@ where 0.1 }; + // Use EIP-1559 dynamic gas price for Osmosis + let dynamic_gas_price = if chain_data.chain_id.as_str() == "osmosis-1" { + DynamicGasPrice::unsafe_new(true, 1.1, 0.6) + } else { + DynamicGasPrice::disabled() + }; + Ok(ChainConfig::CosmosSdk(CosmosSdkConfig { id: chain_data.chain_id, rpc_addr: rpc_data.rpc_address, @@ -140,6 +148,7 @@ where max_gas: Some(400000), gas_adjustment: None, gas_multiplier: Some(GasMultiplier::new(1.1).unwrap()), + dynamic_gas_price, fee_granter: None, max_msg_num: MaxMsgNum::default(), max_tx_size: MaxTxSize::default(), diff --git a/crates/relayer-cli/src/commands/config/auto.rs b/crates/relayer-cli/src/commands/config/auto.rs index 66fbd0969c..64241d030d 100644 --- a/crates/relayer-cli/src/commands/config/auto.rs +++ b/crates/relayer-cli/src/commands/config/auto.rs @@ -1,6 +1,7 @@ use crate::chain_registry::get_configs; use abscissa_core::clap::Parser; use abscissa_core::{Command, Runnable}; +use itertools::Itertools; use crate::conclude::Output; @@ -25,7 +26,7 @@ fn find_key(chain_config: &ChainConfig) -> Option { /// If a is specified then it will be used without verifying that it exists. #[derive(Clone, Command, Debug, Parser, PartialEq, Eq)] #[clap( - override_usage = "hermes config auto [OPTIONS] --output --chains " + override_usage = "hermes config auto [OPTIONS] --output --chain --chain " )] pub struct AutoCmd { #[clap( @@ -39,11 +40,14 @@ pub struct AutoCmd { #[clap( long = "chains", + alias = "chain", required = true, multiple = true, value_name = "CHAIN_NAME:OPTIONAL_KEY_NAME", help_heading = "REQUIRED", - help = "Names of the chains to include in the config. Every chain must be in the chain registry." + help = "Names of the chains to include in the configuration, together with an optional key name. \ + Either repeat this argument for every chain or pass a space-separated list of chains. \ + Every chain must be found in the chain registry." )] chain_names: Vec, @@ -149,23 +153,22 @@ impl Runnable for AutoCmd { }; match store(&config, &self.path) { + Ok(_) if missing_chains_set.is_empty() => { + Output::success_msg(format!( + "Config file written successfully at '{}'", + self.path.display() + )) + .exit() + }, Ok(_) => { - if missing_chains_set.is_empty() { - Output::success_msg(format!( - "Config file written successfully at '{}'", - self.path.display() - )) - .exit() - } else { - Output::success_msg(format!( - "Config file written successfully at '{}'. - However, configurations for the following chains were not able to be generated: {:?}", - self.path.display(), - missing_chains_set, - )) - .exit() - } - } + Output::success_msg(format!( + "Config file written successfully at '{}'. \ + However, configurations for the following chains were not able to be generated: {}", + self.path.display(), + missing_chains_set.iter().join(", "), + )) + .exit() + }, Err(e) => Output::error(format!( "An error occurred while attempting to write the config file: {}", e diff --git a/crates/relayer/Cargo.toml b/crates/relayer/Cargo.toml index 80e7ee25d7..faf0d93c7c 100644 --- a/crates/relayer/Cargo.toml +++ b/crates/relayer/Cargo.toml @@ -51,6 +51,7 @@ dirs-next = "2.0.0" retry = { version = "2.0.0", default-features = false } async-stream = "0.3.5" http = "0.2.9" +reqwest = { version = "0.11", features = ["rustls-tls-native-roots", "json"], default-features = false } flex-error = { version = "0.4.4", default-features = false } signature = "2.1.0" anyhow = "1.0" diff --git a/crates/relayer/src/chain/cosmos.rs b/crates/relayer/src/chain/cosmos.rs index f1935d12a8..d5ccc13242 100644 --- a/crates/relayer/src/chain/cosmos.rs +++ b/crates/relayer/src/chain/cosmos.rs @@ -105,13 +105,16 @@ use crate::util::pretty::{ }; use crate::{chain::client::ClientSettings, config::Error as ConfigError}; +use self::gas::dynamic_gas_price; use self::types::app_state::GenesisAppState; +use self::types::gas::GasConfig; use self::version::Specs; pub mod batch; pub mod client; pub mod compatibility; pub mod config; +pub mod eip_base_fee; pub mod encode; pub mod estimate; pub mod fee; @@ -490,6 +493,16 @@ impl CosmosSdkChain { Ok(min_gas_price) } + pub fn dynamic_gas_price(&self) -> GasPrice { + let gas_config = GasConfig::from(self.config()); + + self.rt.block_on(dynamic_gas_price( + &gas_config, + &self.config.id, + &self.config.rpc_addr, + )) + } + /// The unbonding period of this chain pub fn unbonding_period(&self) -> Result { crate::time!( diff --git a/crates/relayer/src/chain/cosmos/batch.rs b/crates/relayer/src/chain/cosmos/batch.rs index ca82b2d5c7..3e52f52aec 100644 --- a/crates/relayer/src/chain/cosmos/batch.rs +++ b/crates/relayer/src/chain/cosmos/batch.rs @@ -102,7 +102,7 @@ pub async fn send_batched_messages_and_wait_check_tx( return Ok(Vec::new()); } - let batches = batch_messages(config, key_pair, account, tx_memo, messages)?; + let batches = batch_messages(config, key_pair, account, tx_memo, messages).await?; let mut responses = Vec::new(); @@ -132,7 +132,7 @@ async fn send_messages_as_batches( let message_count = messages.len(); - let batches = batch_messages(config, key_pair, account, tx_memo, messages)?; + let batches = batch_messages(config, key_pair, account, tx_memo, messages).await?; debug!( "sending {} messages as {} batches to chain {} in parallel", @@ -173,7 +173,7 @@ async fn sequential_send_messages_as_batches( let message_count = messages.len(); - let batches = batch_messages(config, key_pair, account, tx_memo, messages)?; + let batches = batch_messages(config, key_pair, account, tx_memo, messages).await?; debug!( "sending {} messages as {} batches to chain {} in serial", @@ -238,7 +238,7 @@ fn response_to_tx_sync_result( } } -fn batch_messages( +async fn batch_messages( config: &TxConfig, key_pair: &Secp256k1KeyPair, account: &Account, @@ -253,7 +253,14 @@ fn batch_messages( // Estimate the overhead of the transaction envelope's encoding, // by taking the encoded length of an empty tx with the same auth info and signatures. // Use the maximum possible fee to get an upper bound for varint encoding. - let max_fee = gas_amount_to_fee(&config.gas_config, config.gas_config.max_gas); + let max_fee = gas_amount_to_fee( + &config.gas_config, + config.gas_config.max_gas, + &config.chain_id, + &config.rpc_address, + ) + .await; + let tx_metrics = encoded_tx_metrics(config, key_pair, account, tx_memo, &[], &max_fee)?; let tx_envelope_len = tx_metrics.envelope_len; let empty_body_len = tx_metrics.body_bytes_len; @@ -364,10 +371,16 @@ mod tests { (tx_config, key_pair, account) } - #[test] - fn batch_does_not_exceed_max_tx_size() { + #[tokio::test] + async fn batch_does_not_exceed_max_tx_size() { let (config, key_pair, account) = test_fixture(); - let max_fee = gas_amount_to_fee(&config.gas_config, config.gas_config.max_gas); + let max_fee = gas_amount_to_fee( + &config.gas_config, + config.gas_config.max_gas, + &config.chain_id, + &config.rpc_address, + ) + .await; let mut messages = vec![Any { type_url: "/example.Baz".into(), value: vec![0; 2], @@ -404,6 +417,7 @@ mod tests { &memo, messages.clone(), ) + .await .unwrap(); assert_eq!(batches.len(), 2); @@ -420,8 +434,8 @@ mod tests { } } - #[test] - fn batch_error_on_oversized_message() { + #[tokio::test] + async fn batch_error_on_oversized_message() { const MAX_TX_SIZE: usize = 203; let (config, key_pair, account) = test_fixture(); @@ -442,25 +456,32 @@ mod tests { &memo, messages.clone(), ) + .await .unwrap(); assert_eq!(batches.len(), 1); assert_eq!(batches[0].len(), 1); - let max_fee = gas_amount_to_fee(&config.gas_config, config.gas_config.max_gas); + let max_fee = gas_amount_to_fee( + &config.gas_config, + config.gas_config.max_gas, + &config.chain_id, + &config.rpc_address, + ) + .await; let tx_bytes = sign_and_encode_tx(&config, &key_pair, &account, &memo, &batches[0], &max_fee).unwrap(); assert_eq!(tx_bytes.len(), MAX_TX_SIZE); limited_config.max_tx_size = MaxTxSize::new(MAX_TX_SIZE - 1).unwrap(); - let res = batch_messages(&limited_config, &key_pair, &account, &memo, messages); + let res = batch_messages(&limited_config, &key_pair, &account, &memo, messages).await; assert!(res.is_err()); } - #[test] - fn test_batches_are_structured_appropriately_per_max_msg_num() { + #[tokio::test] + async fn test_batches_are_structured_appropriately_per_max_msg_num() { let (config, key_pair, account) = test_fixture(); // Ensure that when MaxMsgNum is 1, the resulting batch @@ -499,6 +520,7 @@ mod tests { &Memo::new("").unwrap(), messages.clone(), ) + .await .unwrap(); assert_eq!(batches.len(), 5); @@ -517,14 +539,15 @@ mod tests { &Memo::new("").unwrap(), messages, ) + .await .unwrap(); assert_eq!(batches.len(), 1); assert_eq!(batches[0].len(), 5); } - #[test] - fn test_batches_are_structured_appropriately_per_max_tx_size() { + #[tokio::test] + async fn test_batches_are_structured_appropriately_per_max_tx_size() { const MAX_TX_SIZE: usize = 198; let (config, key_pair, account) = test_fixture(); @@ -565,11 +588,18 @@ mod tests { &memo, messages.clone(), ) + .await .unwrap(); assert_eq!(batches.len(), 5); - let max_fee = gas_amount_to_fee(&config.gas_config, config.gas_config.max_gas); + let max_fee = gas_amount_to_fee( + &config.gas_config, + config.gas_config.max_gas, + &config.chain_id, + &config.rpc_address, + ) + .await; for batch in batches { assert_eq!(batch.len(), 1); @@ -589,15 +619,16 @@ mod tests { &Memo::new("").unwrap(), messages, ) + .await .unwrap(); assert_eq!(batches.len(), 1); assert_eq!(batches[0].len(), 5); } - #[test] + #[tokio::test] #[should_panic(expected = "`max_msg_num` must be greater than or equal to 1, found 0")] - fn test_max_msg_num_of_zero_panics() { + async fn test_max_msg_num_of_zero_panics() { let (mut config, key_pair, account) = test_fixture(); config.max_msg_num = MaxMsgNum::new(0).unwrap(); let _batches = batch_messages( @@ -606,6 +637,7 @@ mod tests { &account, &Memo::new("").unwrap(), vec![], - ); + ) + .await; } } diff --git a/crates/relayer/src/chain/cosmos/config.rs b/crates/relayer/src/chain/cosmos/config.rs index 225b7aa039..57314bccf5 100644 --- a/crates/relayer/src/chain/cosmos/config.rs +++ b/crates/relayer/src/chain/cosmos/config.rs @@ -10,6 +10,7 @@ use ibc_relayer_types::core::ics24_host::identifier::ChainId; use crate::chain::cosmos::config::error::Error as ConfigError; use crate::config::compat_mode::CompatMode; +use crate::config::dynamic_gas::DynamicGasPrice; use crate::config::gas_multiplier::GasMultiplier; use crate::config::types::{MaxMsgNum, MaxTxSize, Memo, TrustThreshold}; use crate::config::{ @@ -133,6 +134,9 @@ pub struct CosmosSdkConfig { #[serde(default)] pub packet_filter: PacketFilter, + #[serde(default)] + pub dynamic_gas_price: DynamicGasPrice, + #[serde(default)] pub address_type: AddressType, #[serde(default = "Vec::new", skip_serializing_if = "Vec::is_empty")] diff --git a/crates/relayer/src/chain/cosmos/eip_base_fee.rs b/crates/relayer/src/chain/cosmos/eip_base_fee.rs new file mode 100644 index 0000000000..75cc9eedd4 --- /dev/null +++ b/crates/relayer/src/chain/cosmos/eip_base_fee.rs @@ -0,0 +1,141 @@ +use core::fmt; +use std::ops::Div; +use std::str::FromStr; + +use serde::Deserialize; +use subtle_encoding::base64; +use tendermint_rpc::Url; +use tracing::debug; + +use ibc_proto::cosmos::base::v1beta1::DecProto; + +use crate::error::Error; + +pub async fn query_eip_base_fee(rpc_address: &Url) -> Result { + debug!("Querying Omosis EIP-1559 base fee from {rpc_address}"); + + let url = + format!("{rpc_address}/abci_query?path=\"/osmosis.txfees.v1beta1.Query/GetEipBaseFee\""); + + let response = reqwest::get(&url).await.map_err(Error::http_request)?; + + if !response.status().is_success() { + return Err(Error::http_response(response.status())); + } + + #[derive(Deserialize)] + struct EipBaseFeeHTTPResult { + result: EipBaseFeeResult, + } + + #[derive(Deserialize)] + struct EipBaseFeeResult { + response: EipBaseFeeResponse, + } + + #[derive(Deserialize)] + struct EipBaseFeeResponse { + value: String, + } + + let result: EipBaseFeeHTTPResult = response.json().await.map_err(Error::http_response_body)?; + + let encoded = result.result.response.value; + let decoded = base64::decode(encoded).map_err(Error::base64_decode)?; + + let dec_proto: DecProto = prost::Message::decode(decoded.as_ref()) + .map_err(|e| Error::protobuf_decode("cosmos.base.v1beta1.DecProto".to_string(), e))?; + + let base_fee_uint128 = Uint128::from_str(&dec_proto.dec).map_err(Error::parse_int)?; + + let dec = Decimal::new(base_fee_uint128); + let base_fee = f64::from_str(dec.to_string().as_str()).map_err(Error::parse_float)?; + + debug!("Omosis EIP-1559 base fee is {}", base_fee); + + Ok(base_fee) +} + +/// Extracted from `cosmwasm-std` +/// +/// +#[derive(Clone, Copy)] +struct Uint128(u128); + +impl Uint128 { + pub const fn new(value: u128) -> Self { + Self(value) + } + + pub fn is_zero(&self) -> bool { + self.0 == 0 + } + + pub fn checked_rem(&self, rhs: Self) -> Option { + self.0.checked_rem(rhs.0).map(Self) + } +} + +impl FromStr for Uint128 { + type Err = std::num::ParseIntError; + + fn from_str(s: &str) -> Result { + s.parse::().map(Self) + } +} + +impl Div for Uint128 { + type Output = Self; + + fn div(self, rhs: Self) -> Self::Output { + Self( + self.0 + .checked_div(rhs.0) + .expect("attempt to divide by zero"), + ) + } +} + +impl fmt::Display for Uint128 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +/// Extracted from `cosmwasm-std` +/// +/// +#[derive(Clone, Copy)] +struct Decimal(Uint128); + +impl Decimal { + const DECIMAL_FRACTIONAL: Uint128 = Uint128::new(1_000_000_000_000_000_000u128); // 1*10**18 + pub const DECIMAL_PLACES: u32 = 18; + + pub const fn new(value: Uint128) -> Self { + Self(value) + } +} + +impl fmt::Display for Decimal { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use core::fmt::Write; + + let whole = (self.0) / Self::DECIMAL_FRACTIONAL; + let fractional = (self.0).checked_rem(Self::DECIMAL_FRACTIONAL).unwrap(); + + if fractional.is_zero() { + write!(f, "{whole}") + } else { + let fractional_string = format!( + "{:0>padding$}", + fractional, + padding = Self::DECIMAL_PLACES as usize + ); + f.write_str(&whole.to_string())?; + f.write_char('.')?; + f.write_str(fractional_string.trim_end_matches('0'))?; + Ok(()) + } + } +} diff --git a/crates/relayer/src/chain/cosmos/estimate.rs b/crates/relayer/src/chain/cosmos/estimate.rs index 35c76a92ad..87a18a26b4 100644 --- a/crates/relayer/src/chain/cosmos/estimate.rs +++ b/crates/relayer/src/chain/cosmos/estimate.rs @@ -1,6 +1,7 @@ use ibc_proto::cosmos::tx::v1beta1::{Fee, Tx}; use ibc_proto::google::protobuf::Any; use ibc_relayer_types::core::ics24_host::identifier::ChainId; +use tendermint_rpc::Url; use tonic::codegen::http::Uri; use tracing::{debug, error, span, warn, Level}; @@ -44,8 +45,14 @@ pub async fn estimate_tx_fees( signatures: signed_tx.signatures, }; - let estimated_fee = - estimate_fee_with_tx(gas_config, &config.grpc_address, &config.chain_id, tx).await?; + let estimated_fee = estimate_fee_with_tx( + gas_config, + &config.grpc_address, + &config.rpc_address, + &config.chain_id, + tx, + ) + .await?; Ok(estimated_fee) } @@ -53,6 +60,7 @@ pub async fn estimate_tx_fees( async fn estimate_fee_with_tx( gas_config: &GasConfig, grpc_address: &Uri, + rpc_address: &Url, chain_id: &ChainId, tx: Tx, ) -> Result { @@ -80,7 +88,7 @@ async fn estimate_fee_with_tx( )); } - let adjusted_fee = gas_amount_to_fee(gas_config, estimated_gas); + let adjusted_fee = gas_amount_to_fee(gas_config, estimated_gas, chain_id, rpc_address).await; debug!( id = %chain_id, diff --git a/crates/relayer/src/chain/cosmos/gas.rs b/crates/relayer/src/chain/cosmos/gas.rs index 6f27923af5..07b4b6a20f 100644 --- a/crates/relayer/src/chain/cosmos/gas.rs +++ b/crates/relayer/src/chain/cosmos/gas.rs @@ -1,13 +1,24 @@ use core::cmp::min; use ibc_proto::cosmos::base::v1beta1::Coin; use ibc_proto::cosmos::tx::v1beta1::Fee; +use ibc_relayer_types::core::ics24_host::identifier::ChainId; use num_bigint::BigInt; use num_rational::BigRational; +use tendermint_rpc::Url; +use tracing::warn; use crate::chain::cosmos::types::gas::GasConfig; use crate::config::GasPrice; +use crate::telemetry; -pub fn gas_amount_to_fee(config: &GasConfig, gas_amount: u64) -> Fee { +use super::eip_base_fee::query_eip_base_fee; + +pub async fn gas_amount_to_fee( + config: &GasConfig, + gas_amount: u64, + chain_id: &ChainId, + rpc_address: &Url, +) -> Fee { let adjusted_gas_limit = adjust_estimated_gas(AdjustGas { gas_multiplier: config.gas_multiplier, max_gas: config.max_gas, @@ -15,7 +26,8 @@ pub fn gas_amount_to_fee(config: &GasConfig, gas_amount: u64) -> Fee { }); // The fee in coins based on gas amount - let amount = calculate_fee(adjusted_gas_limit, &config.gas_price); + let dynamic_gas_price = dynamic_gas_price(config, chain_id, rpc_address).await; + let amount = calculate_fee(adjusted_gas_limit, &dynamic_gas_price); Fee { amount: vec![amount], @@ -25,6 +37,59 @@ pub fn gas_amount_to_fee(config: &GasConfig, gas_amount: u64) -> Fee { } } +pub async fn dynamic_gas_price( + config: &GasConfig, + chain_id: &ChainId, + rpc_address: &Url, +) -> GasPrice { + if config.dynamic_gas_price.enabled { + let dynamic_gas_price = query_eip_base_fee(rpc_address) + .await + .map(|base_fee| base_fee * config.dynamic_gas_price.multiplier) + .map(|new_price| GasPrice { + price: new_price, + denom: config.gas_price.denom.clone(), + }); + + let dynamic_gas_price = match dynamic_gas_price { + Ok(dynamic_gas_price) => { + telemetry!( + dynamic_gas_queried_success_fees, + chain_id, + dynamic_gas_price.price + ); + + dynamic_gas_price + } + Err(e) => { + warn!("failed to query EIP base fee, will fallback to configured `gas_price`: {e}"); + config.gas_price.clone() + } + }; + + { + telemetry!(dynamic_gas_queried_fees, chain_id, dynamic_gas_price.price); + let _ = chain_id; + } + + if dynamic_gas_price.price > config.dynamic_gas_price.max { + warn!( + "queried EIP gas price is higher than configured max gas price, \ + will fallback to configured `max`. Queried: {}, maximum: {}", + dynamic_gas_price.price, config.dynamic_gas_price.max + ); + + return GasPrice::new(config.dynamic_gas_price.max, dynamic_gas_price.denom); + } + + telemetry!(dynamic_gas_paid_fees, chain_id, dynamic_gas_price.price); + + dynamic_gas_price + } else { + config.gas_price.clone() + } +} + pub fn calculate_fee(adjusted_gas_amount: u64, gas_price: &GasPrice) -> Coin { let fee_amount = mul_ceil(adjusted_gas_amount, gas_price.price); diff --git a/crates/relayer/src/chain/cosmos/types/gas.rs b/crates/relayer/src/chain/cosmos/types/gas.rs index 80291faaab..e472eb91af 100644 --- a/crates/relayer/src/chain/cosmos/types/gas.rs +++ b/crates/relayer/src/chain/cosmos/types/gas.rs @@ -2,6 +2,7 @@ use ibc_proto::cosmos::tx::v1beta1::Fee; use crate::chain::cosmos::calculate_fee; use crate::chain::cosmos::config::CosmosSdkConfig; +use crate::config::dynamic_gas::DynamicGasPrice; use crate::config::GasPrice; /// Default gas limit when submitting a transaction. @@ -17,6 +18,7 @@ pub struct GasConfig { pub gas_price: GasPrice, pub max_fee: Fee, pub fee_granter: String, + pub dynamic_gas_price: DynamicGasPrice, } impl<'a> From<&'a CosmosSdkConfig> for GasConfig { @@ -28,6 +30,7 @@ impl<'a> From<&'a CosmosSdkConfig> for GasConfig { gas_price: config.gas_price.clone(), max_fee: max_fee_from_config(config), fee_granter: fee_granter_from_config(config), + dynamic_gas_price: config.dynamic_gas_price, } } } diff --git a/crates/relayer/src/config.rs b/crates/relayer/src/config.rs index 27c1fee2dc..2f335e13d0 100644 --- a/crates/relayer/src/config.rs +++ b/crates/relayer/src/config.rs @@ -1,6 +1,7 @@ //! Relayer configuration pub mod compat_mode; +pub mod dynamic_gas; pub mod error; pub mod filter; pub mod gas_multiplier; diff --git a/crates/relayer/src/config/dynamic_gas.rs b/crates/relayer/src/config/dynamic_gas.rs new file mode 100644 index 0000000000..f18246f7eb --- /dev/null +++ b/crates/relayer/src/config/dynamic_gas.rs @@ -0,0 +1,142 @@ +use serde::de::Error as DeserializeError; +use serde::de::Unexpected; +use serde::Deserialize; +use serde::Deserializer; +use serde_derive::Serialize; + +flex_error::define_error! { + Error { + MultiplierTooSmall + { value: f64 } + |e| { + format_args!("`multiplier` in dynamic_gas configuration must be greater than or equal to {}, found {}", + DynamicGasPrice::MIN_MULTIPLIER, e.value) + }, + } +} + +#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Serialize)] +pub struct DynamicGasPrice { + pub enabled: bool, + pub multiplier: f64, + pub max: f64, +} + +impl DynamicGasPrice { + const DEFAULT_MULTIPLIER: f64 = 1.1; + const DEFAULT_MAX: f64 = 0.6; + const MIN_MULTIPLIER: f64 = 1.0; + + pub fn enabled(multiplier: f64, max: f64) -> Result { + Self::new(true, multiplier, max) + } + + pub fn disabled() -> Self { + Self { + enabled: false, + multiplier: Self::DEFAULT_MULTIPLIER, + max: Self::DEFAULT_MAX, + } + } + + pub fn new(enabled: bool, multiplier: f64, max: f64) -> Result { + if multiplier < Self::MIN_MULTIPLIER { + return Err(Error::multiplier_too_small(multiplier)); + } + + Ok(Self { + enabled, + multiplier, + max, + }) + } + + // Unsafe GasMultiplier used for test cases only. + pub fn unsafe_new(enabled: bool, multiplier: f64, max: f64) -> Self { + Self { + enabled, + multiplier, + max, + } + } +} + +impl Default for DynamicGasPrice { + fn default() -> Self { + Self::disabled() + } +} + +impl<'de> Deserialize<'de> for DynamicGasPrice { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + #[derive(Deserialize)] + struct DynGas { + enabled: bool, + multiplier: f64, + max: f64, + } + + let DynGas { + enabled, + multiplier, + max, + } = DynGas::deserialize(deserializer)?; + + DynamicGasPrice::new(enabled, multiplier, max).map_err(|e| match e.detail() { + ErrorDetail::MultiplierTooSmall(_) => D::Error::invalid_value( + Unexpected::Float(multiplier), + &format!( + "a floating-point value greater than {}", + Self::MIN_MULTIPLIER + ) + .as_str(), + ), + }) + } +} + +#[cfg(test)] +#[allow(dead_code)] // the field of the struct `DummyConfig` defined below is never accessed +mod tests { + use super::*; + + use serde::Deserialize; + use test_log::test; + + #[test] + fn parse_invalid_gas_multiplier() { + #[derive(Debug, Deserialize)] + struct DummyConfig { + dynamic_gas: DynamicGasPrice, + } + + let err = toml::from_str::( + "dynamic_gas = { enabled = true, multiplier = 0.9, max = 0.6 }", + ) + .unwrap_err() + .to_string(); + + println!("err: {err}"); + + assert!(err.contains("expected a floating-point value greater than")); + } + + #[test] + fn safe_gas_multiplier() { + let dynamic_gas = DynamicGasPrice::new(true, 0.6, 0.6); + assert!( + dynamic_gas.is_err(), + "Gas multiplier should be an error if value is lower than 1.0: {dynamic_gas:?}" + ); + } + + #[test] + fn unsafe_gas_multiplier() { + let dynamic_gas = DynamicGasPrice::unsafe_new(true, 0.6, 0.4); + assert_eq!(dynamic_gas.multiplier, 0.6); + assert_eq!(dynamic_gas.max, 0.4); + } +} diff --git a/crates/relayer/src/error.rs b/crates/relayer/src/error.rs index e16a1c4e75..2f3a964547 100644 --- a/crates/relayer/src/error.rs +++ b/crates/relayer/src/error.rs @@ -586,6 +586,38 @@ define_error! { InvalidCompatMode [ TendermintRpcError ] |_| { "Invalid CompatMode queried from chain and no `compat_mode` configured in Hermes. This can be fixed by specifying a `compat_mode` in Hermes config.toml" }, + + HttpRequest + [ TraceError ] + |_| { "HTTP request error" }, + + HttpResponse + { status: reqwest::StatusCode } + |e| { format!("HTTP response error with status code {}", e.status) }, + + HttpResponseBody + [ TraceError ] + |_| { "HTTP response body error" }, + + JsonDeserialize + [ TraceError ] + |_| { "JSON deserialization error" }, + + JsonField + { field: String } + |e| { format!("Missing or invalid JSON field: {}", e.field) }, + + ParseFloat + [ TraceError ] + |_| { "Error parsing float" }, + + ParseInt + [ TraceError ] + |_| { "Error parsing integer" }, + + Base64Decode + [ TraceError ] + |_| { "Error decoding base64-encoded data" }, } } diff --git a/crates/relayer/src/lib.rs b/crates/relayer/src/lib.rs index 0bca2140c0..16744ad6aa 100644 --- a/crates/relayer/src/lib.rs +++ b/crates/relayer/src/lib.rs @@ -1,6 +1,5 @@ #![forbid(unsafe_code)] #![deny( - warnings, trivial_casts, trivial_numeric_casts, unused_import_braces, diff --git a/crates/telemetry/src/state.rs b/crates/telemetry/src/state.rs index ea05147321..bf48381d1f 100644 --- a/crates/telemetry/src/state.rs +++ b/crates/telemetry/src/state.rs @@ -201,6 +201,15 @@ pub struct TelemetryState { /// Number of errors observed by Hermes when broadcasting a Tx broadcast_errors: Counter, + /// The EIP-1559 base fee queried + dynamic_gas_queried_fees: ObservableGauge, + + /// The EIP-1559 base fee paid + dynamic_gas_paid_fees: ObservableGauge, + + /// The EIP-1559 base fee successfully queried + dynamic_gas_queried_success_fees: ObservableGauge, + /// Number of ICS-20 packets filtered because the memo and/or the receiver fields were exceeding the configured limits filtered_packets: Counter, } @@ -385,7 +394,22 @@ impl TelemetryState { ) .init(), - filtered_packets: meter + dynamic_gas_queried_fees: meter + .f64_observable_gauge("dynamic_gas_queried_fees") + .with_description("The EIP-1559 base fee queried") + .init(), + + dynamic_gas_paid_fees: meter + .f64_observable_gauge("dynamic_gas_paid_fees") + .with_description("The EIP-1559 base fee paid") + .init(), + + dynamic_gas_queried_success_fees: meter + .f64_observable_gauge("dynamic_gas_queried_fees") + .with_description("The EIP-1559 base fee successfully queried") + .init(), + + filtered_packets: meter .u64_counter("filtered_packets") .with_description("Number of ICS-20 packets filtered because the memo and/or the receiver fields were exceeding the configured limits") .init(), @@ -1136,6 +1160,31 @@ impl TelemetryState { self.broadcast_errors.add(&cx, 1, labels); } + pub fn dynamic_gas_queried_fees(&self, chain_id: &ChainId, amount: f64) { + let cx = Context::current(); + + let labels = &[KeyValue::new("identifier", chain_id.to_string())]; + + self.dynamic_gas_queried_fees.observe(&cx, amount, labels); + } + + pub fn dynamic_gas_paid_fees(&self, chain_id: &ChainId, amount: f64) { + let cx = Context::current(); + + let labels = &[KeyValue::new("identifier", chain_id.to_string())]; + + self.dynamic_gas_paid_fees.observe(&cx, amount, labels); + } + + pub fn dynamic_gas_queried_success_fees(&self, chain_id: &ChainId, amount: f64) { + let cx = Context::current(); + + let labels = &[KeyValue::new("identifier", chain_id.to_string())]; + + self.dynamic_gas_queried_success_fees + .observe(&cx, amount, labels); + } + /// Increment number of packets filtered because the memo field is too big #[allow(clippy::too_many_arguments)] pub fn filtered_packets( @@ -1232,6 +1281,15 @@ impl AggregatorSelector for CustomAggregatorSelector { // TODO: Once quantile sketches are supported, replace histograms with that. "tx_latency_submitted" => Some(Arc::new(histogram(&self.get_submitted_range()))), "tx_latency_confirmed" => Some(Arc::new(histogram(&self.get_confirmed_range()))), + "dynamic_gas_queried_fees" => Some(Arc::new(histogram(&[ + 0.0025, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0, + ]))), + "dynamic_gas_paid_fees" => Some(Arc::new(histogram(&[ + 0.0025, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0, + ]))), + "dynamic_gas_queried_success_fees" => Some(Arc::new(histogram(&[ + 0.0025, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0, + ]))), "ics29_period_fees" => Some(Arc::new(last_value())), _ => Some(Arc::new(sum())), } diff --git a/flake.lock b/flake.lock index 874e699bf9..a0dbfb5653 100644 --- a/flake.lock +++ b/flake.lock @@ -20,16 +20,16 @@ "apalache-src": { "flake": false, "locked": { - "lastModified": 1650241137, - "narHash": "sha256-15jzwbBc7ByxHJbpHmIukSNvih9oxTXeinNamgXirCU=", + "lastModified": 1692625213, + "narHash": "sha256-Z/tmBMv+QshFJLo2kBgBdkqfKwF93CgURVIbYF3dwJE=", "owner": "informalsystems", "repo": "apalache", - "rev": "40d9ec66b3defe8e72803ca9241a73366497eeee", + "rev": "ec979d4554360faf9d73ddf72dccf350614076d5", "type": "github" }, "original": { "owner": "informalsystems", - "ref": "v0.24.0", + "ref": "v0.42.0", "repo": "apalache", "type": "github" } @@ -114,6 +114,7 @@ "cosmwasm-src": "cosmwasm-src", "crescent-src": "crescent-src", "cw-plus-src": "cw-plus-src", + "dydx-src": "dydx-src", "evmos-src": "evmos-src", "flake-parts": "flake-parts", "gaia-main-src": "gaia-main-src", @@ -129,6 +130,7 @@ "gaia8-src": "gaia8-src", "gaia9-src": "gaia9-src", "gex-src": "gex-src", + "gomod2nix": "gomod2nix", "hermes-src": "hermes-src", "ibc-go-v2-src": "ibc-go-v2-src", "ibc-go-v3-src": "ibc-go-v3-src", @@ -146,9 +148,10 @@ "ixo-src": "ixo-src", "juno-src": "juno-src", "migaloo-src": "migaloo-src", + "namada-src": "namada-src", "neutron-src": "neutron-src", "nix-std": "nix-std", - "nixpkgs": "nixpkgs", + "nixpkgs": "nixpkgs_2", "osmosis-src": "osmosis-src", "provenance-src": "provenance-src", "regen-src": "regen-src", @@ -175,11 +178,11 @@ "wasmvm_1_beta7-src": "wasmvm_1_beta7-src" }, "locked": { - "lastModified": 1701457684, - "narHash": "sha256-Tx3WsOM9scTXDHFyL5vNcQnCmT7Mx0dYg1Nmz8cFwt4=", + "lastModified": 1705315275, + "narHash": "sha256-XnjvjdTdXkwWFWx1nRflbsDyazSBV09QOmr/aiAuZ1M=", "owner": "informalsystems", "repo": "cosmos.nix", - "rev": "c0bb979a518aa08ba064112a85e03fbc7a7d2869", + "rev": "04ef5159b4262b7dd445544838468a84a1d987cf", "type": "github" }, "original": { @@ -256,19 +259,36 @@ "type": "github" } }, + "dydx-src": { + "flake": false, + "locked": { + "lastModified": 1702405483, + "narHash": "sha256-NiC+Nol8Cye0z/U5cgQ+zhvlbDJX6DouaMo8oYsRGDQ=", + "owner": "dydxprotocol", + "repo": "v4-chain", + "rev": "35b87db422b0ef4138101ba73b0f00d16780ba89", + "type": "github" + }, + "original": { + "owner": "dydxprotocol", + "ref": "protocol/v3.0.0-dev0", + "repo": "v4-chain", + "type": "github" + } + }, "evmos-src": { "flake": false, "locked": { - "lastModified": 1666728289, - "narHash": "sha256-hMry1q+31jqSe0krg880LIMcz0xgftB3mwfywWoLX3w=", - "owner": "tharsis", + "lastModified": 1702504794, + "narHash": "sha256-ECXXQ0hx/MXascMP6aXf880zts/dNPpQM9jOCIHTLZQ=", + "owner": "evmos", "repo": "evmos", - "rev": "80c38f659a65a983b221e2a568c6172b8ac3bffc", + "rev": "6f94d2002c01b7f7908a69089ed6996ac2bb450c", "type": "github" }, "original": { - "owner": "tharsis", - "ref": "v9.1.0", + "owner": "evmos", + "ref": "v16.0.0-rc4", "repo": "evmos", "type": "github" } @@ -278,11 +298,11 @@ "nixpkgs-lib": "nixpkgs-lib" }, "locked": { - "lastModified": 1698882062, - "narHash": "sha256-HkhafUayIqxXyHH1X8d9RDl1M2CkFgZLjKD3MzabiEo=", + "lastModified": 1701473968, + "narHash": "sha256-YcVE5emp1qQ8ieHUnxt1wCZCC3ZfAS+SRRWZ2TMda7E=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "8c9fa2545007b49a5db5f650ae91f227672c3877", + "rev": "34fed993f1674c8d06d58b37ce1e0fe5eebcb9f5", "type": "github" }, "original": { @@ -295,6 +315,24 @@ "inputs": { "systems": "systems" }, + "locked": { + "lastModified": 1694529238, + "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, "locked": { "lastModified": 1681202837, "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", @@ -309,7 +347,7 @@ "type": "github" } }, - "flake-utils_2": { + "flake-utils_3": { "locked": { "lastModified": 1667395993, "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", @@ -324,16 +362,16 @@ "type": "github" } }, - "flake-utils_3": { + "flake-utils_4": { "inputs": { - "systems": "systems_2" + "systems": "systems_3" }, "locked": { - "lastModified": 1701680307, - "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", + "lastModified": 1705309234, + "narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=", "owner": "numtide", "repo": "flake-utils", - "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", + "rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26", "type": "github" }, "original": { @@ -345,11 +383,11 @@ "gaia-main-src": { "flake": false, "locked": { - "lastModified": 1697456548, - "narHash": "sha256-iXcwU0/kDAGzQKYrHKTMX6/ayB6Ns0KBYMOpi5uNYJk=", + "lastModified": 1702388853, + "narHash": "sha256-1O8ncSd0mUNEUHSTi2U9d21Dv1yszQKohjp/AS6IxcU=", "owner": "cosmos", "repo": "gaia", - "rev": "e6da2cc3d1602a6c64fc50c90ea60651177d911b", + "rev": "2dc2b82ea9da34b3c4823458919004f1a583a597", "type": "github" }, "original": { @@ -562,19 +600,39 @@ "type": "github" } }, + "gomod2nix": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1702956934, + "narHash": "sha256-f1NuMA2mZ3Chw2CjlUkRAzNgDw0TYyj1i5YZJRByDdo=", + "owner": "JonathanLorimer", + "repo": "gomod2nix", + "rev": "6d2fce6003d08eee42648f2931de8449d3de1f5f", + "type": "github" + }, + "original": { + "owner": "JonathanLorimer", + "ref": "jonathan/update-go", + "repo": "gomod2nix", + "type": "github" + } + }, "hermes-src": { "flake": false, "locked": { - "lastModified": 1689751768, - "narHash": "sha256-yq+jdHSwUejMA1hURSHWHJ8QSyhDdnhpKE+tejgWSSE=", + "lastModified": 1702629809, + "narHash": "sha256-JTZMp4By/pGsMdKzfi4H1LQS1RKYQHBq5NEju5ADX/s=", "owner": "informalsystems", "repo": "hermes", - "rev": "1c1cf02988db67507de7d484e1a7f317fe494d6c", + "rev": "ab732666fe35de129ada98731280d03411f6375f", "type": "github" }, "original": { "owner": "informalsystems", - "ref": "v1.6.0", + "ref": "v1.7.4", "repo": "hermes", "type": "github" } @@ -684,16 +742,16 @@ "ibc-go-v8-channel-upgrade-src": { "flake": false, "locked": { - "lastModified": 1695726576, - "narHash": "sha256-mM6h1KAi8lQUrJakxI6f8WI+vpmBhCnAysk3hTZBI7M=", + "lastModified": 1703189903, + "narHash": "sha256-vxzv+b40TKqCIN4FAkeIu+jmlPP5XRLR+P0uEIjr7AE=", "owner": "cosmos", "repo": "ibc-go", - "rev": "63c30108f0ecf954108cf51f50f3d36ec58c7e51", + "rev": "7a89e5d5b5ebb7643ce3992c34008c35373ecf34", "type": "github" }, "original": { "owner": "cosmos", - "ref": "04-channel-upgrades-alpha.0", + "ref": "04-channel-upgrades-rc.0", "repo": "ibc-go", "type": "github" } @@ -768,11 +826,11 @@ "interchain-security-src": { "flake": false, "locked": { - "lastModified": 1697113174, - "narHash": "sha256-J+duWnA9ipgHryO5+9sv6uwcPVN2ceL0PGoCyVvN5YQ=", + "lastModified": 1700577019, + "narHash": "sha256-adBzn51PKoRsCL9gIzC5Tcqmu7u3GjxTcDj2jpZ/da8=", "owner": "cosmos", "repo": "interchain-security", - "rev": "28e0c14b34d5d15ea0eb19b694c74513667afe09", + "rev": "03aada4af3243dbf739a12adfacc7b37232df694", "type": "github" }, "original": { @@ -850,6 +908,23 @@ "type": "github" } }, + "namada-src": { + "flake": false, + "locked": { + "lastModified": 1702488720, + "narHash": "sha256-WyIVffqszY3rz3ClQJlpDaexLGQk8pVK+Y3k/D9Lvxg=", + "owner": "anoma", + "repo": "namada", + "rev": "468d3d3bcadd2bd11760855d2bbfcc0b4ce27e14", + "type": "github" + }, + "original": { + "owner": "anoma", + "ref": "v0.28.1", + "repo": "namada", + "type": "github" + } + }, "neutron-src": { "flake": false, "locked": { @@ -869,11 +944,11 @@ }, "nix-std": { "locked": { - "lastModified": 1685917625, - "narHash": "sha256-2manVKofCZrCToVDnDYNvtYUFBYOM5JhdDoNGVY4fq4=", + "lastModified": 1701658249, + "narHash": "sha256-KIt1TUuBvldhaVRta010MI5FeQlB8WadjqljybjesN0=", "owner": "chessai", "repo": "nix-std", - "rev": "e20af8822b5739434b875643bfc61fe0195ea2fb", + "rev": "715db541ffff4194620e48d210b76f73a74b5b5d", "type": "github" }, "original": { @@ -884,16 +959,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1701040486, - "narHash": "sha256-vawYwoHA5CwvjfqaT3A5CT9V36Eq43gxdwpux32Qkjw=", + "lastModified": 1702272962, + "narHash": "sha256-D+zHwkwPc6oYQ4G3A1HuadopqRwUY/JkMwHz1YF7j4Q=", "owner": "nixos", "repo": "nixpkgs", - "rev": "45827faa2132b8eade424f6bdd48d8828754341a", + "rev": "e97b3e4186bcadf0ef1b6be22b8558eab1cdeb5d", "type": "github" }, "original": { - "owner": "nixos", - "ref": "nixpkgs-unstable", + "owner": "NixOS", + "ref": "master", "repo": "nixpkgs", "type": "github" } @@ -901,11 +976,11 @@ "nixpkgs-lib": { "locked": { "dir": "lib", - "lastModified": 1698611440, - "narHash": "sha256-jPjHjrerhYDy3q9+s5EAsuhyhuknNfowY6yt6pjn9pc=", + "lastModified": 1701253981, + "narHash": "sha256-ztaDIyZ7HrTAfEEUt9AtTDNoCYxUdSd6NrRHaYOIxtk=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "0cbe9f69c234a7700596e943bfae7ef27a31b735", + "rev": "e92039b55bcd58469325ded85d4f58dd5a4eaf58", "type": "github" }, "original": { @@ -917,6 +992,22 @@ } }, "nixpkgs_2": { + "locked": { + "lastModified": 1701040486, + "narHash": "sha256-vawYwoHA5CwvjfqaT3A5CT9V36Eq43gxdwpux32Qkjw=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "45827faa2132b8eade424f6bdd48d8828754341a", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_3": { "locked": { "lastModified": 1681358109, "narHash": "sha256-eKyxW4OohHQx9Urxi7TQlFBTDWII+F+x2hklDOQPB50=", @@ -932,7 +1023,7 @@ "type": "github" } }, - "nixpkgs_3": { + "nixpkgs_4": { "locked": { "lastModified": 1674990008, "narHash": "sha256-4zOyp+hFW2Y7imxIpZqZGT8CEqKmDjwgfD6BzRUE0mQ=", @@ -948,13 +1039,13 @@ "type": "github" } }, - "nixpkgs_4": { + "nixpkgs_5": { "locked": { - "lastModified": 1701693815, - "narHash": "sha256-7BkrXykVWfkn6+c1EhFA3ko4MLi3gVG0p9G96PNnKTM=", + "lastModified": 1705505490, + "narHash": "sha256-HS+Zg50Zm1Ehfat/OgGS2YJqU7/4ohsQhK+ClwcKmVA=", "owner": "nixos", "repo": "nixpkgs", - "rev": "09ec6a0881e1a36c29d67497693a67a16f4da573", + "rev": "f36047a5a4b5631f75210859abac7f97ba1ba7a7", "type": "github" }, "original": { @@ -967,16 +1058,16 @@ "osmosis-src": { "flake": false, "locked": { - "lastModified": 1700576443, - "narHash": "sha256-UE3XEgdSp8mlgIKQRrBfb4wiPEeagB/wNWfDvDq4up4=", + "lastModified": 1702398856, + "narHash": "sha256-4uLO7izIZ8JvKTfUXbYkxQFpIjwMEcO81WvhklrzI9E=", "owner": "osmosis-labs", "repo": "osmosis", - "rev": "d9965b09d3e8690c77050bb095bc5b69772ebdfb", + "rev": "b0aee0006ce55d0851773084bd7880db7e32ad70", "type": "github" }, "original": { "owner": "osmosis-labs", - "ref": "v20.4.0", + "ref": "v21.0.0", "repo": "osmosis", "type": "github" } @@ -1035,21 +1126,21 @@ "root": { "inputs": { "cosmos-nix": "cosmos-nix", - "flake-utils": "flake-utils_3", - "nixpkgs": "nixpkgs_4" + "flake-utils": "flake-utils_4", + "nixpkgs": "nixpkgs_5" } }, "rust-overlay": { "inputs": { - "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs_2" + "flake-utils": "flake-utils_2", + "nixpkgs": "nixpkgs_3" }, "locked": { - "lastModified": 1701310566, - "narHash": "sha256-CL9J3xUR2Ejni4LysrEGX0IdO+Y4BXCiH/By0lmF3eQ=", + "lastModified": 1702347444, + "narHash": "sha256-ueDw7aQf4Xyk69XnDD0YNWDlFdlOgJGPeWFa7uu/cfw=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "6d3c6e185198b8bf7ad639f22404a75aa9a09bff", + "rev": "bc13176f27cf3be724d18924b4f6aa47686ca2e3", "type": "github" }, "original": { @@ -1060,8 +1151,8 @@ }, "sbt-derivation": { "inputs": { - "flake-utils": "flake-utils_2", - "nixpkgs": "nixpkgs_3" + "flake-utils": "flake-utils_3", + "nixpkgs": "nixpkgs_4" }, "locked": { "lastModified": 1698464090, @@ -1224,6 +1315,21 @@ "type": "github" } }, + "systems_3": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, "umee-src": { "flake": false, "locked": { diff --git a/guide/src/SUMMARY.md b/guide/src/SUMMARY.md index e85b810e6b..fbef9c31b3 100644 --- a/guide/src/SUMMARY.md +++ b/guide/src/SUMMARY.md @@ -28,12 +28,13 @@ - [Start relaying](./tutorials/production/start-relaying.md) - [Configuration](./documentation/configuration/index.md) + - [CometBFT Compatibility modes](./documentation/configuration/comet-compat-mode.md) - [Configure Hermes](./documentation/configuration/configure-hermes.md) - [Description of the parameters](./documentation/configuration/description.md) + - [Dynamic gas fees](./documentation/configuration/dynamic-gas-fees.md) - [Filter incentivized packets](./documentation/configuration/filter-incentivized.md) - [Packet clearing](./documentation/configuration/packet-clearing.md) - [Performance tuning](./documentation/configuration/performance.md) - - [CometBFT Compatibility modes](./documentation/configuration/comet-compat-mode.md) - [Telemetry](./documentation/telemetry/index.md) - [Operators guide](./documentation/telemetry/operators.md) diff --git a/guide/src/documentation/commands/config.md b/guide/src/documentation/commands/config.md index 793a1a523c..40e6ab85a2 100644 --- a/guide/src/documentation/commands/config.md +++ b/guide/src/documentation/commands/config.md @@ -27,7 +27,7 @@ __Example__ Use `config auto` to generate a configuration file that is able to relay between `cosmoshub` and `osmosis`. This command assumes the existence of a key file for `cosmoshub-4` and `osmosis-1` in `$HOME/.hermes/keys`. ``` -{{#template ../../templates/commands/hermes/config/auto_1.md PATH=~/example_config.toml CHAIN_NAME:OPTIONAL_KEY_NAME=cosmoshub osmosis}} +{{#template ../../templates/commands/hermes/config/auto_1.md PATH=~/example_config.toml CHAIN1_NAME:OPTIONAL_KEY_NAME=cosmoshub osmosis}} 2022-08-16T17:27:26.966233Z INFO ThreadId(01) using default configuration from '~/.hermes/config.toml' 2022-08-16T17:27:27.800213Z INFO ThreadId(01) cosmoshub-4: uses key "key_cosmoshub" @@ -38,7 +38,7 @@ SUCCESS Config file written successfully at '~/example_config.toml' It is also possible to manually specify a key name for any chain. ``` -{{#template ../../templates/commands/hermes/config/auto_1.md PATH=~/example_config.toml CHAIN_NAME:OPTIONAL_KEY_NAME=cosmoshub:random_key osmosis}} +{{#template ../../templates/commands/hermes/config/auto_1.md PATH=~/example_config.toml CHAIN1_NAME:OPTIONAL_KEY_NAME=cosmoshub:random_key osmosis}} 2022-08-16T17:29:56.902499Z INFO ThreadId(01) using default configuration from '~/.hermes/config.toml' 2022-08-16T17:29:57.288874Z INFO ThreadId(01) cosmoshub-4: uses key "random_key" diff --git a/guide/src/documentation/configuration/configure-hermes.md b/guide/src/documentation/configuration/configure-hermes.md index cec76e4fb7..c63fab7200 100644 --- a/guide/src/documentation/configuration/configure-hermes.md +++ b/guide/src/documentation/configuration/configure-hermes.md @@ -27,7 +27,7 @@ hermes [--config CONFIG_FILE] COMMAND The simplest way to configure Hermes for a given chain is by running the command ```shell -{{#template ../../templates/commands/hermes/config/auto_1.md PATH=~//config.toml CHAIN_NAME:OPTIONAL_KEY_NAME= }} +{{#template ../../templates/commands/hermes/config/auto_1.md PATH=~//config.toml CHAIN1_NAME:OPTIONAL_KEY_NAME= }} ``` This will generate a `config.toml` file for some specified chains. Note, however, that the configuration is generated by pulling the chain data from the Cosmos [chain registry][chain-registry]. The specified chain(s) must exist in the registry for the command to work. Check out [this][config-auto-reference] section of the Hermes commands reference to find more information on the `config auto` command. diff --git a/guide/src/documentation/configuration/dynamic-gas-fees.md b/guide/src/documentation/configuration/dynamic-gas-fees.md new file mode 100644 index 0000000000..81762167ff --- /dev/null +++ b/guide/src/documentation/configuration/dynamic-gas-fees.md @@ -0,0 +1,21 @@ +# Dynamic Gas Fees + +Some chains use a dynamic gas price system instead of static gas price. By configuring the `dynamic_gas_price` for those chains, Hermes will query the gas price and apply the configured multiplier instead of using the configured static gas price: + +```toml +... +[.dynamic_gas_price] +enabled = true +multiplier = 1.1 +max = 0.6 +... +``` + +## Notes + +* If the query fails, Hermes will fallback to the configured static gas price. +* If the queried gas price is higher than the maximum configured gas price, Hermes will use the maximum gas price but this might cause the relaying of the packet to fail due to insufficient fees. + +## Monitoring + +As this feature can be delicate to handle, multiple metrics have been added in order to monitor the dynamic gas fees. Please consult the [Dynamic Gas Metrics](../telemetry/operators.md#dynamic-gas-fees) section for detailed information on these metrics. \ No newline at end of file diff --git a/guide/src/documentation/telemetry/operators.md b/guide/src/documentation/telemetry/operators.md index c990dfb01a..2496b6e91a 100644 --- a/guide/src/documentation/telemetry/operators.md +++ b/guide/src/documentation/telemetry/operators.md @@ -162,4 +162,20 @@ Note that this metrics is disabled if `misbehaviour = false` in your Hermes conf | Name | Description | OpenTelemetry type | Configuration Dependencies | | ------------------- | --------------------------------------------------------------------------- | ------------------- | -------------------------- | | `ics29_fee_amounts_total` | Total amount received from ICS29 fees  | `u64` Counter  | None | -| `ics29_period_fees` | Amount of ICS29 fees rewarded over the past 7 days type | `u64` ValueRecorder | None | \ No newline at end of file +| `ics29_period_fees` | Amount of ICS29 fees rewarded over the past 7 days type | `u64` ValueRecorder | None | + +## Dynamic gas fees + +The introduction of dynamic gas fees adds additional configuration which can be delicate to handle correctly. The following metrics can help correctly configure your relayer. + +| Name | Description | OpenTelemetry type | Configuration Dependencies | +| ---------------------------------- | -------------------------------------------------------------------- | ------------------- | -------------------------- | +| `dynamic_gas_queried_fees` | The EIP-1559 base fee queried  | `u64` ValueRecorder | None | +| `dynamic_gas_queried_success_fees` | The EIP-1559 base fee successfully queried   | `u64` ValueRecorder | None | +| `dynamic_gas_paid_fees` | The EIP-1559 base fee paid  | `u64` ValueRecorder | None | + +Notes: + +- The `dynamic_gas_queried_fees` contains the gas price used after the query but before filtering by configured `max`. This means that this metric might contain the static gas price if the query failed. +- The `dynamic_gas_queried_success_fees` will only contain the gas price when the query succeeds, if this metric doesn't contain values or less values that the `dynamic_gas_queried_fees` this could indicate an issue with the endpoint used to query the fees. +- `dynamic_gas_paid_fees` will contain the price used by the relayer, the maximum value for this metric is `max`. If there are multiple values in the same bucket as the `max` it could indicate that the gas price queried is often higher than the configured `max`. \ No newline at end of file diff --git a/guide/src/templates/commands/hermes/config/auto_1.md b/guide/src/templates/commands/hermes/config/auto_1.md index c7c4e932b0..e7bec76e08 100644 --- a/guide/src/templates/commands/hermes/config/auto_1.md +++ b/guide/src/templates/commands/hermes/config/auto_1.md @@ -1 +1 @@ -[[#BINARY hermes]][[#GLOBALOPTIONS]] config auto[[#OPTIONS]] --output [[#PATH]] --chains [[#CHAIN_NAME:OPTIONAL_KEY_NAME]] +[[#BINARY hermes]][[#GLOBALOPTIONS]] config auto[[#OPTIONS]] --output [[#PATH]] --chain [[#CHAIN1_NAME:OPTIONAL_KEY_NAME]] --chain [[#CHAIN2_NAME:OPTIONAL_KEY_NAME]] diff --git a/guide/src/templates/help_templates/config/auto.md b/guide/src/templates/help_templates/config/auto.md index b1b9e1773e..1c0f7bc7af 100644 --- a/guide/src/templates/help_templates/config/auto.md +++ b/guide/src/templates/help_templates/config/auto.md @@ -2,7 +2,7 @@ DESCRIPTION: Automatically generate a config.toml for the specified chain(s) USAGE: - hermes config auto [OPTIONS] --output --chains + hermes config auto [OPTIONS] --output --chain --chain OPTIONS: --commit Commit hash from which the chain configs will be generated. If @@ -11,7 +11,9 @@ OPTIONS: REQUIRED: --chains ... - Names of the chains to include in the config. Every chain must be in the chain registry. + Names of the chains to include in the configuration, together with an optional key name. + Either repeat this argument for every chain or pass a space-separated list of chains. + Every chain must be found in the chain registry. --output Path to the configuration file diff --git a/guide/src/tutorials/production/setup-hermes.md b/guide/src/tutorials/production/setup-hermes.md index 81c4509061..7f666b0372 100644 --- a/guide/src/tutorials/production/setup-hermes.md +++ b/guide/src/tutorials/production/setup-hermes.md @@ -36,7 +36,7 @@ Then, you need to create a configuration file for Hermes (more details in the [d The command `hermes config auto` provides a way to automatically generate a configuration file for chains in the [chain-registry](https://github.com/cosmos/chain-registry): ```shell -{{#template ../../templates/commands/hermes/config/auto_1.md PATH=$HOME/.hermes/config.toml CHAIN_NAME:OPTIONAL_KEY_NAME=cosmoshub:keyhub osmosis:keyosmosis}} +{{#template ../../templates/commands/hermes/config/auto_1.md PATH=$HOME/.hermes/config.toml CHAIN1_NAME:OPTIONAL_KEY_NAME=cosmoshub:keyhub osmosis:keyosmosis}} ``` >__NOTE__: This command also automatically finds IBC paths and generates packet filters from the [_IBC](https://github.com/cosmos/chain-registry/tree/master/_IBC) folder in the chain-registry. diff --git a/tools/check-guide/Cargo.lock b/tools/check-guide/Cargo.lock index 735f88c9a3..e5ab2c34a5 100644 --- a/tools/check-guide/Cargo.lock +++ b/tools/check-guide/Cargo.lock @@ -172,7 +172,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.48", ] [[package]] @@ -183,7 +183,7 @@ checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.48", ] [[package]] @@ -313,6 +313,12 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" +[[package]] +name = "bech32" +version = "0.10.0-beta" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98f7eed2b2781a6f0b5c903471d48e15f56fb4e1165df8a9a2337fd1a59d45ea" + [[package]] name = "bit-set" version = "0.5.3" @@ -330,18 +336,28 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitcoin" -version = "0.30.1" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e99ff7289b20a7385f66a0feda78af2fc119d28fb56aea8886a9cd0a4abdd75" +checksum = "fd00f3c09b5f21fb357abe32d29946eb8bb7a0862bae62c0b5e4a692acbbe73c" dependencies = [ - "bech32", - "bitcoin-private", - "bitcoin_hashes", + "bech32 0.10.0-beta", + "bitcoin-internals", + "bitcoin_hashes 0.13.0", + "hex-conservative", "hex_lit", "secp256k1", "serde", ] +[[package]] +name = "bitcoin-internals" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" +dependencies = [ + "serde", +] + [[package]] name = "bitcoin-private" version = "0.1.0" @@ -355,6 +371,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d7066118b13d4b20b23645932dfb3a81ce7e29f95726c2036fa33cd7b092501" dependencies = [ "bitcoin-private", +] + +[[package]] +name = "bitcoin_hashes" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" +dependencies = [ + "bitcoin-internals", + "hex-conservative", "serde", ] @@ -712,12 +738,11 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.8" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" dependencies = [ - "cfg-if 1.0.0", - "crossbeam-utils 0.8.16", + "crossbeam-utils 0.8.19", ] [[package]] @@ -728,7 +753,7 @@ checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" dependencies = [ "autocfg", "cfg-if 1.0.0", - "crossbeam-utils 0.8.16", + "crossbeam-utils 0.8.19", "memoffset", "scopeguard", ] @@ -746,12 +771,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if 1.0.0", -] +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "crunchy" @@ -806,7 +828,7 @@ checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.48", ] [[package]] @@ -1276,7 +1298,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.48", ] [[package]] @@ -1500,6 +1522,12 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hex-conservative" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2" + [[package]] name = "hex_lit" version = "0.1.1" @@ -1654,7 +1682,7 @@ dependencies = [ [[package]] name = "ibc-chain-registry" -version = "0.26.1" +version = "0.26.4" dependencies = [ "async-trait", "flex-error", @@ -1690,16 +1718,16 @@ dependencies = [ [[package]] name = "ibc-relayer" -version = "0.26.1" +version = "0.26.4" dependencies = [ "anyhow", "async-stream", - "bech32", + "bech32 0.9.1", "bitcoin", "bs58", "byte-unit", "bytes", - "crossbeam-channel 0.5.8", + "crossbeam-channel 0.5.11", "digest 0.10.7", "dirs-next", "ed25519", @@ -1718,11 +1746,13 @@ dependencies = [ "ibc-telemetry", "itertools 0.10.5", "moka", + "monostate", "num-bigint", "num-rational", "once_cell", "prost", "regex", + "reqwest", "retry", "ripemd", "secp256k1", @@ -1745,23 +1775,23 @@ dependencies = [ "tiny-keccak", "tokio", "tokio-stream", - "toml 0.7.8", + "toml 0.8.8", "tonic", "tracing", "tracing-subscriber", - "uuid 1.4.1", + "uuid 1.7.0", ] [[package]] name = "ibc-relayer-cli" -version = "1.7.1" +version = "1.7.4" dependencies = [ "abscissa_core", "clap 3.2.25", "clap_complete 3.2.5", "color-eyre", "console", - "crossbeam-channel 0.5.8", + "crossbeam-channel 0.5.11", "dialoguer", "dirs-next", "eyre", @@ -1793,10 +1823,10 @@ dependencies = [ [[package]] name = "ibc-relayer-rest" -version = "0.26.1" +version = "0.26.4" dependencies = [ "axum", - "crossbeam-channel 0.5.8", + "crossbeam-channel 0.5.11", "ibc-relayer", "ibc-relayer-types", "serde", @@ -1806,7 +1836,7 @@ dependencies = [ [[package]] name = "ibc-relayer-types" -version = "0.26.1" +version = "0.26.4" dependencies = [ "bytes", "derive_more", @@ -1832,7 +1862,7 @@ dependencies = [ [[package]] name = "ibc-telemetry" -version = "0.26.1" +version = "0.26.4" dependencies = [ "axum", "dashmap", @@ -2254,9 +2284,9 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8017ec3548ffe7d4cef7ac0e12b044c01164a74c0f3119420faeaf13490ad8b" dependencies = [ - "crossbeam-channel 0.5.8", + "crossbeam-channel 0.5.11", "crossbeam-epoch", - "crossbeam-utils 0.8.16", + "crossbeam-utils 0.8.19", "once_cell", "parking_lot", "quanta", @@ -2266,7 +2296,28 @@ dependencies = [ "tagptr", "thiserror", "triomphe", - "uuid 1.4.1", + "uuid 1.7.0", +] + +[[package]] +name = "monostate" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "878c2a1f1c70e5724fa28f101ca787b6a7e8ad5c5e4ae4ca3b0fa4a419fa9075" +dependencies = [ + "monostate-impl", + "serde", +] + +[[package]] +name = "monostate-impl" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f686d68a09079e63b1d2c64aa305095887ce50565f00a922ebfaeeee0d9ba6ce" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", ] [[package]] @@ -2291,7 +2342,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" dependencies = [ "bitflags 2.4.0", - "crossbeam-channel 0.5.8", + "crossbeam-channel 0.5.11", "filetime", "fsevent-sys", "inotify", @@ -2309,7 +2360,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e55ee272914f4563a2f8b8553eb6811f3c0caea81c756346bad15b7e3ef969f0" dependencies = [ - "crossbeam-channel 0.5.8", + "crossbeam-channel 0.5.11", "notify", ] @@ -2399,9 +2450,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "oneline-eyre" @@ -2479,7 +2530,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b3a2a91fdbfdd4d212c0dcc2ab540de2c2bcbbd90be17de7a7daf8822d010c1" dependencies = [ "async-trait", - "crossbeam-channel 0.5.8", + "crossbeam-channel 0.5.11", "dashmap", "fnv", "futures-channel", @@ -2612,7 +2663,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.48", ] [[package]] @@ -2681,7 +2732,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.48", ] [[package]] @@ -2761,9 +2812,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.67" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] @@ -2803,7 +2854,7 @@ dependencies = [ "itertools 0.11.0", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.48", ] [[package]] @@ -2838,7 +2889,7 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a17e662a7a8291a865152364c20c7abc5e60486ab2001e8ec10b24862de0b9ab" dependencies = [ - "crossbeam-utils 0.8.16", + "crossbeam-utils 0.8.19", "libc", "mach2", "once_cell", @@ -2850,9 +2901,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -3006,7 +3057,6 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", "winreg", ] @@ -3195,11 +3245,11 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.27.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" +checksum = "3f622567e3b4b38154fb8190bcf6b160d7a4301d70595a49195b48c116007a27" dependencies = [ - "bitcoin_hashes", + "bitcoin_hashes 0.12.0", "rand", "secp256k1-sys", "serde", @@ -3207,9 +3257,9 @@ dependencies = [ [[package]] name = "secp256k1-sys" -version = "0.8.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" +checksum = "e5d1746aae42c19d583c3c1a8c646bfad910498e2051c551a7f2e3c0c9fbb7eb" dependencies = [ "cc", ] @@ -3258,9 +3308,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.188" +version = "1.0.195" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" dependencies = [ "serde_derive", ] @@ -3286,13 +3336,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.188" +version = "1.0.195" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.48", ] [[package]] @@ -3324,14 +3374,14 @@ checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.48", ] [[package]] name = "serde_spanned" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" dependencies = [ "serde", ] @@ -3578,7 +3628,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.37", + "syn 2.0.48", ] [[package]] @@ -3615,9 +3665,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.37" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", @@ -3909,7 +3959,7 @@ checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.48", ] [[package]] @@ -4029,7 +4079,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.48", ] [[package]] @@ -4090,9 +4140,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.8" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" +checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" dependencies = [ "serde", "serde_spanned", @@ -4102,18 +4152,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.19.15" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" dependencies = [ "indexmap 2.0.2", "serde", @@ -4212,7 +4262,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.48", ] [[package]] @@ -4424,9 +4474,9 @@ checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" [[package]] name = "uuid" -version = "1.4.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" +checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" dependencies = [ "getrandom", ] @@ -4528,7 +4578,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.48", "wasm-bindgen-shared", ] @@ -4562,7 +4612,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -4583,12 +4633,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki-roots" -version = "0.25.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" - [[package]] name = "winapi" version = "0.3.9" @@ -4797,5 +4841,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.48", ] diff --git a/tools/integration-test/Cargo.toml b/tools/integration-test/Cargo.toml index 3b2327aff1..640b0871a9 100644 --- a/tools/integration-test/Cargo.toml +++ b/tools/integration-test/Cargo.toml @@ -42,6 +42,7 @@ interchain-security = [] celestia = [] async-icq = [] juno = [] +dynamic-gas-fee = [] [[bin]] name = "test_setup_with_binary_channel" diff --git a/tools/integration-test/src/tests/dynamic_gas_fee.rs b/tools/integration-test/src/tests/dynamic_gas_fee.rs new file mode 100644 index 0000000000..3e30ec468d --- /dev/null +++ b/tools/integration-test/src/tests/dynamic_gas_fee.rs @@ -0,0 +1,214 @@ +//! The [`DynamicGasTest`] test ensures that the [`DynamicGas`] +//! configuration works correctly. The test can enable or disable the dynamic +//! gas price for the second chain. +//! +//! To test dynamic gas configuration, it will enable dynamic gas price on the +//! second chain only. It will then create and relay a first IBC transfer with a +//! big memo. The gas fee paid is then recorded. +//! A second IBC transfer without memo will then be relayed. The gas fee paid +//! will also be recorded. The test will assert that the Tx with a big memo +//! and dynamic gas enabled is lower than the Tx without memo and dynamic gas +//! disabled. +//! +//! The second test disables the dynamic gas price on both chains in +//! order to ensure that the first IBC transfer will cost more if dynamic +//! gas is disabled. + +use ibc_relayer::config::dynamic_gas::DynamicGasPrice; +use ibc_relayer::config::ChainConfig; +use ibc_relayer::config::GasPrice; +use ibc_test_framework::prelude::*; + +#[test] +fn test_dynamic_gas_transfer() -> Result<(), Error> { + run_binary_channel_test(&DynamicGasTest { + dynamic_gas_enabled: true, + }) +} + +#[test] +fn test_static_gas_transfer() -> Result<(), Error> { + run_binary_channel_test(&DynamicGasTest { + dynamic_gas_enabled: false, + }) +} + +const MEMO_CHAR: &str = "a"; +const MEMO_SIZE: usize = 10000; + +pub struct DynamicGasTest { + dynamic_gas_enabled: bool, +} + +impl TestOverrides for DynamicGasTest { + fn modify_relayer_config(&self, config: &mut Config) { + config.mode.clients.misbehaviour = false; + config.mode.clients.refresh = false; + config.mode.packets.clear_interval = 0; + + match &mut config.chains[0] { + ChainConfig::CosmosSdk(chain_config_a) => { + chain_config_a.gas_price = + GasPrice::new(0.1, chain_config_a.gas_price.denom.clone()); + chain_config_a.dynamic_gas_price = DynamicGasPrice::unsafe_new(false, 1.1, 0.6); + } + } + + match &mut config.chains[1] { + ChainConfig::CosmosSdk(chain_config_b) => { + chain_config_b.gas_price = + GasPrice::new(0.1, chain_config_b.gas_price.denom.clone()); + chain_config_b.dynamic_gas_price = + DynamicGasPrice::unsafe_new(self.dynamic_gas_enabled, 1.1, 0.6); + } + } + } + + fn should_spawn_supervisor(&self) -> bool { + false + } +} + +impl BinaryChannelTest for DynamicGasTest { + fn run( + &self, + _config: &TestConfig, + relayer: RelayerDriver, + chains: ConnectedChains, + channel: ConnectedChannel, + ) -> Result<(), Error> { + let denom_a = chains.node_a.denom(); + let wallet_a = chains.node_a.wallets().user1().cloned(); + let wallet_b = chains.node_b.wallets().user1().cloned(); + + let a_to_b_amount = 12345u64; + + let denom_a_to_b = derive_ibc_denom( + &channel.port_b.as_ref(), + &channel.channel_id_b.as_ref(), + &denom_a, + )?; + + let gas_denom_a: MonoTagged = + MonoTagged::new(Denom::Base("stake".to_owned())); + let gas_denom_b: MonoTagged = + MonoTagged::new(Denom::Base("stake".to_owned())); + + let balance_relayer_b_before = chains.node_b.chain_driver().query_balance( + &chains.node_b.wallets().relayer().address(), + &gas_denom_b.as_ref(), + )?; + + let memo: String = MEMO_CHAR.repeat(MEMO_SIZE); + + chains + .node_a + .chain_driver() + .ibc_transfer_token_with_memo_and_timeout( + &channel.port_a.as_ref(), + &channel.channel_id_a.as_ref(), + &wallet_a.as_ref(), + &wallet_b.address(), + &denom_a.with_amount(a_to_b_amount).as_ref(), + Some(memo), + None, + )?; + + // Do a simple IBC transfer with the dynamic gas configuration + let tx1_paid_gas_relayer = relayer.with_supervisor(|| { + // Assert that user on chain B received the tokens + chains.node_b.chain_driver().assert_eventual_wallet_amount( + &wallet_b.address(), + &denom_a_to_b.with_amount(a_to_b_amount).as_ref(), + )?; + + // Wait for a bit before querying the new balance + sleep(Duration::from_secs(5)); + + let balance_relayer_b_after = chains.node_b.chain_driver().query_balance( + &chains.node_b.wallets().relayer().address(), + &gas_denom_b.as_ref(), + )?; + + let paid_fees_relayer_b = balance_relayer_b_before + .amount() + .checked_sub(balance_relayer_b_after.amount()); + + assert!( + paid_fees_relayer_b.is_some(), + "subtraction between queried amounts for relayer should be Some" + ); + + info!("IBC transfer with memo was successful"); + + Ok(paid_fees_relayer_b.unwrap()) + })?; + + let b_to_a_amount = 23456u64; + let denom_b = chains.node_b.denom(); + + let denom_b_to_a = derive_ibc_denom( + &channel.port_a.as_ref(), + &channel.channel_id_a.as_ref(), + &denom_b, + )?; + + let balance_relayer_a_before = chains.node_a.chain_driver().query_balance( + &chains.node_a.wallets().relayer().address(), + &gas_denom_a.as_ref(), + )?; + + chains.node_b.chain_driver().ibc_transfer_token( + &channel.port_b.as_ref(), + &channel.channel_id_b.as_ref(), + &chains.node_b.wallets().user1(), + &chains.node_a.wallets().user1().address(), + &denom_b.with_amount(b_to_a_amount).as_ref(), + )?; + + let tx2_paid_gas_relayer = relayer.with_supervisor(|| { + // Assert that user on chain B received the tokens + chains.node_a.chain_driver().assert_eventual_wallet_amount( + &chains.node_a.wallets().user1().address(), + &denom_b_to_a.with_amount(b_to_a_amount).as_ref(), + )?; + + // Wait for a bit before querying the new balance + sleep(Duration::from_secs(5)); + + let balance_relayer_a_after = chains.node_a.chain_driver().query_balance( + &chains.node_a.wallets().relayer().address(), + &gas_denom_a.as_ref(), + )?; + + let paid_fees_relayer_a = balance_relayer_a_before + .amount() + .checked_sub(balance_relayer_a_after.amount()); + + assert!( + paid_fees_relayer_a.is_some(), + "subtraction between queried amounts for relayer should be Some" + ); + + info!("IBC transfer without memo was successful"); + + Ok(paid_fees_relayer_a.unwrap()) + })?; + + info!("paid gas fees for Tx with memo `{tx1_paid_gas_relayer}`, without memo `{tx2_paid_gas_relayer}`"); + + if self.dynamic_gas_enabled { + assert!( + tx1_paid_gas_relayer < tx2_paid_gas_relayer, + "with dynamic gas enabled, gas paid for the first TX should be lower" + ); + } else { + assert!( + tx1_paid_gas_relayer > tx2_paid_gas_relayer, + "with dynamic gas disabled, gas paid for the second TX should be lower" + ); + } + + Ok(()) + } +} diff --git a/tools/integration-test/src/tests/mod.rs b/tools/integration-test/src/tests/mod.rs index b56c22b49d..373cf4d276 100644 --- a/tools/integration-test/src/tests/mod.rs +++ b/tools/integration-test/src/tests/mod.rs @@ -63,3 +63,6 @@ pub mod fee_grant; #[cfg(any(doc, feature = "interchain-security"))] pub mod interchain_security; + +#[cfg(any(doc, feature = "dynamic-gas-fee"))] +pub mod dynamic_gas_fee; diff --git a/tools/test-framework/src/relayer/tx.rs b/tools/test-framework/src/relayer/tx.rs index 94a8d8cf80..a2d4e41393 100644 --- a/tools/test-framework/src/relayer/tx.rs +++ b/tools/test-framework/src/relayer/tx.rs @@ -7,6 +7,7 @@ use ibc_proto::cosmos::tx::v1beta1::Fee; use ibc_relayer::chain::cosmos::gas::calculate_fee; use ibc_relayer::chain::cosmos::types::config::TxConfig; use ibc_relayer::chain::cosmos::types::gas::GasConfig; +use ibc_relayer::config::dynamic_gas::DynamicGasPrice; use ibc_relayer::config::{AddressType, GasPrice}; use ibc_relayer_types::core::ics24_host::identifier::ChainId; use tendermint_rpc::Url; @@ -43,6 +44,11 @@ pub fn gas_config_for_test(native_token: String) -> GasConfig { gas_price, max_fee, fee_granter, + dynamic_gas_price: DynamicGasPrice { + enabled: false, + multiplier: 1.0, + max: 0.6, + }, } } diff --git a/tools/test-framework/src/types/single/node.rs b/tools/test-framework/src/types/single/node.rs index 4fbc20b938..9d4e7ea280 100644 --- a/tools/test-framework/src/types/single/node.rs +++ b/tools/test-framework/src/types/single/node.rs @@ -9,6 +9,7 @@ use eyre::Report as Error; use ibc_relayer::chain::cosmos::config::CosmosSdkConfig; use ibc_relayer::config; use ibc_relayer::config::compat_mode::CompatMode; +use ibc_relayer::config::dynamic_gas::DynamicGasPrice; use ibc_relayer::config::gas_multiplier::GasMultiplier; use ibc_relayer::keyring::Store; use ibc_relayer_types::core::ics24_host::identifier::ChainId; @@ -174,6 +175,7 @@ impl FullNode { max_gas: Some(3000000), gas_adjustment: None, gas_multiplier: Some(GasMultiplier::unsafe_new(1.5)), + dynamic_gas_price: DynamicGasPrice::default(), fee_granter: None, max_msg_num: Default::default(), max_tx_size: Default::default(),