Skip to content

Commit

Permalink
Merge branch 'master' into romac/handshake-bounded-retries
Browse files Browse the repository at this point in the history
  • Loading branch information
romac authored Mar 7, 2024
2 parents 96f948e + cac00ee commit 31019d9
Show file tree
Hide file tree
Showing 27 changed files with 885 additions and 76 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
- Add a per-chain configuration `excluded_sequences` allowing
users to specify a list of packet sequences which will not be
cleared.
This configuration has no impact on standard packet relaying.
([\#3754](https://github.com/informalsystems/hermes/issues/3754))
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- Improve the log diagnostic when an out of gas error is thrown.
And a new entry related to gas error has been added to the Hermes
guide.
([\#3530](https://github.com/informalsystems/hermes/issues/3530))
2 changes: 1 addition & 1 deletion .github/workflows/cargo-doc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions-rs/toolchain@v1
with:
toolchain: nightly
toolchain: nightly-2024-03-03
override: true

- name: Build API documentation
Expand Down
12 changes: 12 additions & 0 deletions config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,18 @@ memo_prefix = ''
# This will override the global clear interval for this chain only, allowing different intervals for each chain.
# clear_interval = 50

# Specify packet sequences which should not be cleared, per channel.
#
# For each channel, specify a list of sequences which should not be cleared, eg.
#
# excluded_sequences = [
# ['channel-0', [1, 2, 3]],
# ['channel-1', [4, 5, 6]]
# ]
#
# Default: No filter
# excluded_sequences = []

[[chains]]
id = 'ibc-1'
rpc_addr = 'http://127.0.0.1:26557'
Expand Down
9 changes: 5 additions & 4 deletions crates/relayer-cli/src/chain_registry.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
//! Contains functions to generate a relayer config for a given chain

use std::collections::HashMap;
use std::fmt::Display;
use std::marker::Send;

use futures::future::join_all;
use http::Uri;
use ibc_relayer::config::dynamic_gas::DynamicGasPrice;
use std::collections::BTreeMap;
use std::collections::HashMap;
use std::fmt::Display;
use std::marker::Send;
use tokio::task::{JoinError, JoinHandle};
use tracing::{error, trace};

Expand Down Expand Up @@ -173,6 +173,7 @@ where
extension_options: Vec::new(),
compat_mode: None,
clear_interval: None,
excluded_sequences: BTreeMap::new(),
}))
}

Expand Down
58 changes: 53 additions & 5 deletions crates/relayer-cli/src/commands/clear.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use abscissa_core::config::Override;
use abscissa_core::{Command, FrameworkErrorKind, Runnable};

use ibc_relayer::chain::handle::{BaseChainHandle, ChainHandle};
use ibc_relayer::chain::requests::{IncludeProof, QueryChannelRequest, QueryHeight};
use ibc_relayer::config::Config;
use ibc_relayer::link::error::LinkError;
use ibc_relayer::link::{Link, LinkParameters};
Expand Down Expand Up @@ -146,27 +147,74 @@ impl Runnable for ClearPacketsCmd {
}
}

let mut ev_list = vec![];
let (channel, _) = match chains.src.query_channel(
QueryChannelRequest {
port_id: self.port_id.clone(),
channel_id: self.channel_id.clone(),
height: QueryHeight::Latest,
},
IncludeProof::No,
) {
Ok(channel) => channel,
Err(e) => Output::error(e).exit(),
};

let exclude_src_sequences = config
.find_chain(&chains.src.id())
.map(|chain_config| chain_config.excluded_sequences(&self.channel_id).to_vec())
.unwrap_or_default();

let exclude_dst_sequences =
if let Some(counterparty_channel_id) = channel.counterparty().channel_id() {
config
.find_chain(&chains.dst.id())
.map(|chain_config| {
chain_config
.excluded_sequences(counterparty_channel_id)
.to_vec()
})
.unwrap_or_default()
} else {
Vec::new()
};

// Construct links in both directions.
let opts = LinkParameters {
let fwd_opts = LinkParameters {
src_port_id: self.port_id.clone(),
src_channel_id: self.channel_id.clone(),
max_memo_size: config.mode.packets.ics20_max_memo_size,
max_receiver_size: config.mode.packets.ics20_max_receiver_size,
exclude_src_sequences,
};

let fwd_link = match Link::new_from_opts(chains.src.clone(), chains.dst, opts, false, false)
{
// Construct links in both directions.
let reverse_opts = LinkParameters {
src_port_id: self.port_id.clone(),
src_channel_id: self.channel_id.clone(),
max_memo_size: config.mode.packets.ics20_max_memo_size,
max_receiver_size: config.mode.packets.ics20_max_receiver_size,
exclude_src_sequences: exclude_dst_sequences,
};

let fwd_link = match Link::new_from_opts(
chains.src.clone(),
chains.dst.clone(),
fwd_opts,
false,
false,
) {
Ok(link) => link,
Err(e) => Output::error(e).exit(),
};

let rev_link = match fwd_link.reverse(false, false) {
let rev_link = match Link::new_from_opts(chains.dst, chains.src, reverse_opts, false, false)
{
Ok(link) => link,
Err(e) => Output::error(e).exit(),
};

let mut ev_list = vec![];

// Schedule RecvPacket messages for pending packets in both directions or,
// if packet sequences are provided, only on the specified chain.
// This may produce pending acks which will be processed in the next phase.
Expand Down
8 changes: 8 additions & 0 deletions crates/relayer-cli/src/commands/tx/packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,11 @@ impl Runnable for TxPacketRecvCmd {
src_channel_id: self.src_channel_id.clone(),
max_memo_size: config.mode.packets.ics20_max_memo_size,
max_receiver_size: config.mode.packets.ics20_max_receiver_size,

// Packets are only excluded when clearing
exclude_src_sequences: vec![],
};

let link = match Link::new_from_opts(chains.src, chains.dst, opts, false, false) {
Ok(link) => link,
Err(e) => Output::error(e).exit(),
Expand Down Expand Up @@ -185,7 +189,11 @@ impl Runnable for TxPacketAckCmd {
src_channel_id: self.src_channel_id.clone(),
max_memo_size: config.mode.packets.ics20_max_memo_size,
max_receiver_size: config.mode.packets.ics20_max_receiver_size,

// Packets are only excluded when clearing
exclude_src_sequences: vec![],
};

let link = match Link::new_from_opts(chains.src, chains.dst, opts, false, false) {
Ok(link) => link,
Err(e) => Output::error(e).exit(),
Expand Down
18 changes: 15 additions & 3 deletions crates/relayer/src/chain/cosmos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ use tendermint_rpc::endpoint::status;
use tendermint_rpc::{Client, HttpClient, Order};

use crate::account::Balance;
use crate::chain::client::ClientSettings;
use crate::chain::cosmos::batch::{
send_batched_messages_and_wait_check_tx, send_batched_messages_and_wait_commit,
sequential_send_batched_messages_and_wait_commit,
Expand Down Expand Up @@ -91,6 +92,7 @@ use crate::chain::handle::Subscription;
use crate::chain::requests::*;
use crate::chain::tracking::TrackedMsgs;
use crate::client_state::{AnyClientState, IdentifiedAnyClientState};
use crate::config::Error as ConfigError;
use crate::config::{parse_gas_prices, ChainConfig, GasPrice};
use crate::consensus_state::AnyConsensusState;
use crate::denom::DenomTrace;
Expand All @@ -102,10 +104,10 @@ use crate::light_client::tendermint::LightClient as TmLightClient;
use crate::light_client::{LightClient, Verified};
use crate::misbehaviour::MisbehaviourEvidence;
use crate::util::compat_mode::compat_mode_from_version;
use crate::util::pretty::PrettySlice;
use crate::util::pretty::{
PrettyIdentifiedChannel, PrettyIdentifiedClientState, PrettyIdentifiedConnection,
};
use crate::{chain::client::ClientSettings, config::Error as ConfigError};

use self::gas::dynamic_gas_price;
use self::types::app_state::GenesisAppState;
Expand Down Expand Up @@ -671,8 +673,7 @@ impl CosmosSdkChain {

let mut client = self
.block_on(ServiceClient::connect(grpc_addr.clone()))
.map_err(Error::grpc_transport)
.unwrap();
.map_err(Error::grpc_transport)?;

let request = tonic::Request::new(GetSyncingRequest {});

Expand Down Expand Up @@ -2430,6 +2431,17 @@ fn do_health_check(chain: &CosmosSdkChain) -> Result<(), Error> {
let grpc_address = chain.grpc_addr.to_string();
let rpc_address = chain.config.rpc_addr.to_string();

if !chain.config.excluded_sequences.is_empty() {
for (channel_id, seqs) in chain.config.excluded_sequences.iter() {
if !seqs.is_empty() {
warn!(
"chain '{chain_id}' will not clear packets on channel '{channel_id}' with sequences: {}. \
Ignore this warning if this configuration is correct.", PrettySlice(seqs)
);
}
}
}

chain.block_on(chain.rpc_client.health()).map_err(|e| {
Error::health_check_json_rpc(
chain_id.clone(),
Expand Down
6 changes: 5 additions & 1 deletion crates/relayer/src/chain/cosmos/config.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use core::time::Duration;
use std::collections::BTreeMap;
use std::path::PathBuf;

use byte_unit::Byte;
use ibc_relayer_types::core::ics04_channel::packet::Sequence;
use serde_derive::{Deserialize, Serialize};
use tendermint_rpc::Url;

use ibc_relayer_types::core::ics23_commitment::specs::ProofSpecs;
use ibc_relayer_types::core::ics24_host::identifier::ChainId;
use ibc_relayer_types::core::ics24_host::identifier::{ChainId, ChannelId};

use crate::chain::cosmos::config::error::Error as ConfigError;
use crate::config::compat_mode::CompatMode;
Expand Down Expand Up @@ -146,6 +148,8 @@ pub struct CosmosSdkConfig {
pub extension_options: Vec<ExtensionOption>,
pub compat_mode: Option<CompatMode>,
pub clear_interval: Option<u64>,
#[serde(default)]
pub excluded_sequences: BTreeMap<ChannelId, Vec<Sequence>>,
}

impl CosmosSdkConfig {
Expand Down
44 changes: 30 additions & 14 deletions crates/relayer/src/chain/cosmos/estimate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,26 @@ use crate::keyring::Secp256k1KeyPair;
use crate::telemetry;
use crate::util::pretty::PrettyFee;

pub enum EstimatedGas {
Simulated(u64),
Default(u64),
}

impl EstimatedGas {
pub fn get_amount(&self) -> u64 {
match self {
Self::Simulated(amount) | Self::Default(amount) => *amount,
}
}
}

pub async fn estimate_tx_fees(
config: &TxConfig,
key_pair: &Secp256k1KeyPair,
account: &Account,
tx_memo: &Memo,
messages: &[Any],
) -> Result<Fee, Error> {
) -> Result<(Fee, EstimatedGas), Error> {
let gas_config = &config.gas_config;

debug!(
Expand All @@ -46,7 +59,7 @@ pub async fn estimate_tx_fees(
signatures: signed_tx.signatures,
};

let estimated_fee = estimate_fee_with_tx(
let estimated_fee_and_gas = estimate_fee_with_tx(
gas_config,
&config.grpc_address,
&config.rpc_address,
Expand All @@ -56,7 +69,7 @@ pub async fn estimate_tx_fees(
)
.await?;

Ok(estimated_fee)
Ok(estimated_fee_and_gas)
}

async fn estimate_fee_with_tx(
Expand All @@ -66,7 +79,7 @@ async fn estimate_fee_with_tx(
chain_id: &ChainId,
tx: Tx,
account: &Account,
) -> Result<Fee, Error> {
) -> Result<(Fee, EstimatedGas), Error> {
let estimated_gas = {
crate::time!(
"estimate_gas_with_tx",
Expand All @@ -78,29 +91,32 @@ async fn estimate_fee_with_tx(
estimate_gas_with_tx(gas_config, grpc_address, tx, account).await
}?;

if estimated_gas > gas_config.max_gas {
let estimated_gas_amount = estimated_gas.get_amount();

if estimated_gas_amount > gas_config.max_gas {
debug!(
id = %chain_id, estimated = ?estimated_gas, max = ?gas_config.max_gas,
id = %chain_id, estimated = ?estimated_gas_amount, max = ?gas_config.max_gas,
"send_tx: estimated gas is higher than max gas"
);

return Err(Error::tx_simulate_gas_estimate_exceeded(
chain_id.clone(),
estimated_gas,
estimated_gas_amount,
gas_config.max_gas,
));
}

let adjusted_fee = gas_amount_to_fee(gas_config, estimated_gas, chain_id, rpc_address).await;
let adjusted_fee =
gas_amount_to_fee(gas_config, estimated_gas_amount, chain_id, rpc_address).await;

debug!(
id = %chain_id,
"send_tx: using {} gas, fee {}",
estimated_gas,
estimated_gas_amount,
PrettyFee(&adjusted_fee)
);

Ok(adjusted_fee)
Ok((adjusted_fee, estimated_gas))
}

/// Try to simulate the given tx in order to estimate how much gas will be needed to submit it.
Expand All @@ -116,7 +132,7 @@ async fn estimate_gas_with_tx(
grpc_address: &Uri,
tx: Tx,
account: &Account,
) -> Result<u64, Error> {
) -> Result<EstimatedGas, Error> {
let simulated_gas = send_tx_simulate(grpc_address, tx)
.await
.map(|sr| sr.gas_info);
Expand All @@ -130,7 +146,7 @@ async fn estimate_gas_with_tx(
gas_info.gas_used
);

Ok(gas_info.gas_used)
Ok(EstimatedGas::Simulated(gas_info.gas_used))
}

Ok(None) => {
Expand All @@ -139,7 +155,7 @@ async fn estimate_gas_with_tx(
gas_config.default_gas
);

Ok(gas_config.default_gas)
Ok(EstimatedGas::Default(gas_config.default_gas))
}

// If there is a chance that the tx will be accepted once actually submitted, we fall
Expand All @@ -158,7 +174,7 @@ async fn estimate_gas_with_tx(
get_error_text(&e),
);

Ok(gas_config.default_gas)
Ok(EstimatedGas::Default(gas_config.default_gas))
}

Err(e) => {
Expand Down
Loading

0 comments on commit 31019d9

Please sign in to comment.