diff --git a/config.toml b/config.toml index 88801a955c..5bb0f6acb4 100644 --- a/config.toml +++ b/config.toml @@ -422,5 +422,5 @@ max_tx_size = 2097152 clock_drift = '5s' max_block_time = '30s' trusting_period = '14days' -trust_threshold = { numerator = '2', denominator = '3' } +trust_threshold = '2/3' address_type = { derivation = 'cosmos' } diff --git a/crates/relayer-cli/src/chain_registry.rs b/crates/relayer-cli/src/chain_registry.rs index f7952c6981..27c3b1bad0 100644 --- a/crates/relayer-cli/src/chain_registry.rs +++ b/crates/relayer-cli/src/chain_registry.rs @@ -19,11 +19,10 @@ use ibc_chain_registry::querier::*; use ibc_relayer::chain::cosmos::config::CosmosSdkConfig; use ibc_relayer::config::filter::{FilterPattern, PacketFilter}; use ibc_relayer::config::gas_multiplier::GasMultiplier; -use ibc_relayer::config::types::{MaxMsgNum, MaxTxSize, Memo}; +use ibc_relayer::config::types::{MaxMsgNum, MaxTxSize, Memo, TrustThreshold}; use ibc_relayer::config::{default, AddressType, ChainConfig, EventSourceMode, GasPrice}; use ibc_relayer::keyring::Store; -use tendermint_light_client_verifier::types::TrustThreshold; use tendermint_rpc::Url; const MAX_HEALTHY_QUERY_RETRIES: u8 = 5; diff --git a/crates/relayer-cli/src/commands/config/validate.rs b/crates/relayer-cli/src/commands/config/validate.rs index 4414bba2ab..03efaf018c 100644 --- a/crates/relayer-cli/src/commands/config/validate.rs +++ b/crates/relayer-cli/src/commands/config/validate.rs @@ -41,7 +41,7 @@ impl Runnable for ValidateCmd { // No need to output the underlying error, this is done already when the application boots. // See `application::CliApp::after_config`. match config.validate_config() { - Ok(_) => Output::success("configuration is valid").exit(), + Ok(_) => Output::success_msg("configuration is valid").exit(), Err(_) => Output::error("configuration is invalid").exit(), } } diff --git a/crates/relayer-types/src/core/ics02_client/trust_threshold.rs b/crates/relayer-types/src/core/ics02_client/trust_threshold.rs index b2183c6f98..158a05a9a9 100644 --- a/crates/relayer-types/src/core/ics02_client/trust_threshold.rs +++ b/crates/relayer-types/src/core/ics02_client/trust_threshold.rs @@ -4,6 +4,7 @@ use std::convert::TryFrom; use std::fmt::{Display, Error as FmtError, Formatter}; +use std::str::FromStr; use ibc_proto::Protobuf; use num_rational::Ratio; @@ -121,23 +122,32 @@ impl Display for TrustThreshold { } } +impl FromStr for TrustThreshold { + type Err = String; + + fn from_str(s: &str) -> Result { + let parts: Vec<&str> = s.split('/').collect(); + + if parts.len() != 2 { + return Err(format!("invalid trust threshold, must be a fraction: {s}")); + } + + let (num, denom) = (parts[0].parse(), parts[1].parse()); + + if let (Ok(num), Ok(denom)) = (num, denom) { + TrustThreshold::new(num, denom).map_err(|e| e.to_string()) + } else { + Err(format!("invalid trust threshold, must be a fraction: {s}",)) + } + } +} + impl Serialize for TrustThreshold { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { - #[derive(Serialize)] - struct TrustThreshold { - numerator: u64, - denominator: u64, - } - - let tt = TrustThreshold { - numerator: self.numerator(), - denominator: self.denominator(), - }; - - tt.serialize(serializer) + serializer.serialize_str(&format!("{}/{}", self.numerator(), self.denominator())) } } @@ -146,13 +156,89 @@ impl<'de> Deserialize<'de> for TrustThreshold { where D: serde::Deserializer<'de>, { - #[derive(Deserialize)] - struct TrustThreshold { - numerator: u64, - denominator: u64, + use serde::de::{self, Visitor}; + use std::fmt; + + // This is a Visitor that forwards string types to T's `FromStr` impl and + // forwards map types to T's `Deserialize` impl. The `PhantomData` is to + // keep the compiler from complaining about T being an unused generic type + // parameter. We need T in order to know the Value type for the Visitor + // impl. + struct StringOrStruct; + + impl<'de> Visitor<'de> for StringOrStruct { + type Value = TrustThreshold; + + fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { + formatter.write_str("string or map") + } + + fn visit_str(self, value: &str) -> Result + where + E: de::Error, + { + Ok(FromStr::from_str(value).unwrap()) + } + + fn visit_map(self, map: M) -> Result + where + M: de::MapAccess<'de>, + { + #[derive(Deserialize)] + struct TT { + #[serde(deserialize_with = "string_or_int")] + numerator: u64, + #[serde(deserialize_with = "string_or_int")] + denominator: u64, + } + + let tt = TT::deserialize(de::value::MapAccessDeserializer::new(map))?; + + TrustThreshold::new(tt.numerator, tt.denominator).map_err(de::Error::custom) + } + } + + deserializer.deserialize_any(StringOrStruct) + } +} + +fn string_or_int<'de, D>(deserializer: D) -> Result +where + D: serde::Deserializer<'de>, +{ + use serde::de::{self, Visitor}; + use std::fmt; + + struct StringOrInt; + + impl<'de> Visitor<'de> for StringOrInt { + type Value = u64; + + fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { + formatter.write_str("string or int") } - let tt = TrustThreshold::deserialize(deserializer)?; - Self::new(tt.numerator, tt.denominator).map_err(serde::de::Error::custom) + fn visit_str(self, value: &str) -> Result + where + E: de::Error, + { + FromStr::from_str(value).map_err(de::Error::custom) + } + + fn visit_i64(self, value: i64) -> Result + where + E: de::Error, + { + Ok(value as u64) + } + + fn visit_u64(self, value: u64) -> Result + where + E: de::Error, + { + Ok(value) + } } + + deserializer.deserialize_any(StringOrInt) } diff --git a/crates/relayer/src/chain/cosmos/client.rs b/crates/relayer/src/chain/cosmos/client.rs index 0d3b69cdbc..cc8235c2e3 100644 --- a/crates/relayer/src/chain/cosmos/client.rs +++ b/crates/relayer/src/chain/cosmos/client.rs @@ -42,7 +42,7 @@ impl Settings { let trust_threshold = options .trust_threshold - .unwrap_or_else(|| src_chain_config.trust_threshold.into()); + .unwrap_or(src_chain_config.trust_threshold); Settings { max_clock_drift, diff --git a/crates/relayer/src/chain/cosmos/config.rs b/crates/relayer/src/chain/cosmos/config.rs index 0c73faef25..147f714229 100644 --- a/crates/relayer/src/chain/cosmos/config.rs +++ b/crates/relayer/src/chain/cosmos/config.rs @@ -1,20 +1,21 @@ +use core::time::Duration; +use std::path::PathBuf; + +use byte_unit::Byte; +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 crate::chain::cosmos::config::error::Error as ConfigError; use crate::config::compat_mode::CompatMode; use crate::config::gas_multiplier::GasMultiplier; -use crate::config::types::{MaxMsgNum, MaxTxSize, Memo}; +use crate::config::types::{MaxMsgNum, MaxTxSize, Memo, TrustThreshold}; use crate::config::{ self, AddressType, EventSourceMode, ExtensionOption, GasPrice, GenesisRestart, PacketFilter, }; use crate::config::{default, RefreshRate}; -use byte_unit::Byte; -use core::time::Duration; -use ibc_relayer_types::core::ics23_commitment::specs::ProofSpecs; -use ibc_relayer_types::core::ics24_host::identifier::ChainId; -use serde_derive::{Deserialize, Serialize}; -use std::path::PathBuf; -use tendermint_light_client::verifier::types::TrustThreshold; -use tendermint_rpc::Url; - use crate::keyring::Store; pub mod error; diff --git a/crates/relayer/src/chain/cosmos/config/error.rs b/crates/relayer/src/chain/cosmos/config/error.rs index 41ee500266..5980ad9ac4 100644 --- a/crates/relayer/src/chain/cosmos/config/error.rs +++ b/crates/relayer/src/chain/cosmos/config/error.rs @@ -1,34 +1,32 @@ use flex_error::define_error; +use ibc_relayer_types::core::ics02_client::trust_threshold::TrustThreshold; use ibc_relayer_types::core::ics24_host::identifier::ChainId; -use tendermint_light_client_verifier::types::TrustThreshold; define_error! { - Error { - InvalidTrustThreshold - { - threshold: TrustThreshold, - chain_id: ChainId, - reason: String - } - |e| { - format!("config file specifies an invalid `trust_threshold` ({0}) for the chain '{1}', caused by: {2}", - e.threshold, e.chain_id, e.reason) - }, - -DeprecatedGasAdjustment - { - gas_adjustment: f64, - gas_multiplier: f64, - chain_id: ChainId, - } - |e| { - format!( - "config file specifies deprecated setting `gas_adjustment = {1}` for the chain '{0}'; \ - to get the same behavior, use `gas_multiplier = {2}", - e.chain_id, e.gas_adjustment, e.gas_multiplier - ) - }, + InvalidTrustThreshold + { + threshold: TrustThreshold, + chain_id: ChainId, + reason: String + } + |e| { + format!("config file specifies an invalid `trust_threshold` ({0}) for the chain '{1}', caused by: {2}", + e.threshold, e.chain_id, e.reason) + }, + DeprecatedGasAdjustment + { + gas_adjustment: f64, + gas_multiplier: f64, + chain_id: ChainId, + } + |e| { + format!( + "config file specifies deprecated setting `gas_adjustment = {1}` for the chain '{0}'; \ + to get the same behavior, use `gas_multiplier = {2}", + e.chain_id, e.gas_adjustment, e.gas_multiplier + ) + }, } } diff --git a/crates/relayer/src/client_state.rs b/crates/relayer/src/client_state.rs index 352106cf5d..814abddff6 100644 --- a/crates/relayer/src/client_state.rs +++ b/crates/relayer/src/client_state.rs @@ -14,7 +14,6 @@ use ibc_relayer_types::core::ics02_client::client_state::ClientState; use ibc_relayer_types::core::ics02_client::client_type::ClientType; use ibc_relayer_types::core::ics02_client::error::Error; use ibc_relayer_types::core::ics02_client::trust_threshold::TrustThreshold; - use ibc_relayer_types::core::ics24_host::error::ValidationError; use ibc_relayer_types::core::ics24_host::identifier::{ChainId, ClientId}; use ibc_relayer_types::Height; diff --git a/crates/relayer/src/config.rs b/crates/relayer/src/config.rs index d0e1d83ab9..a3e94e814f 100644 --- a/crates/relayer/src/config.rs +++ b/crates/relayer/src/config.rs @@ -10,15 +10,14 @@ pub mod trust_threshold; pub mod types; use alloc::collections::BTreeMap; +use core::cmp::Ordering; +use core::fmt::{Display, Error as FmtError, Formatter}; +use core::str::FromStr; +use core::time::Duration; +use std::{fs, fs::File, io::Write, ops::Range, path::Path}; + use byte_unit::Byte; -use core::{ - cmp::Ordering, - fmt::{Display, Error as FmtError, Formatter}, - str::FromStr, - time::Duration, -}; use serde_derive::{Deserialize, Serialize}; -use std::{fs, fs::File, io::Write, ops::Range, path::Path}; use tendermint::block::Height as BlockHeight; use tendermint_rpc::Url; use tendermint_rpc::WebSocketClientUrl; @@ -27,10 +26,11 @@ use ibc_proto::google::protobuf::Any; use ibc_relayer_types::core::ics24_host::identifier::{ChainId, ChannelId, PortId}; use ibc_relayer_types::timestamp::ZERO_DURATION; +use crate::chain::cosmos::config::CosmosSdkConfig; +use crate::config::types::TrustThreshold; +use crate::error::Error as RelayerError; use crate::extension_options::ExtensionOptionDynamicFeeTx; -use crate::keyring::Store; -use crate::keyring::{AnySigningKeyPair, KeyRing}; -use crate::{chain::cosmos::config::CosmosSdkConfig, error::Error as RelayerError}; +use crate::keyring::{AnySigningKeyPair, KeyRing, Store}; use crate::keyring; @@ -145,8 +145,6 @@ impl Display for ExtensionOption { /// Defaults for various fields pub mod default { - use ibc_relayer_types::core::ics02_client::trust_threshold::TrustThreshold; - use super::*; pub fn ccv_consumer_chain() -> bool { diff --git a/crates/relayer/src/config/types.rs b/crates/relayer/src/config/types.rs index def6765f0a..c79e0bd2ad 100644 --- a/crates/relayer/src/config/types.rs +++ b/crates/relayer/src/config/types.rs @@ -3,6 +3,8 @@ //! Implements defaults, as well as serializing and //! deserializing with upper-bound verification. +pub use ibc_relayer_types::core::ics02_client::trust_threshold::TrustThreshold; + pub use max_msg_num::MaxMsgNum; pub mod max_msg_num { diff --git a/crates/relayer/src/supervisor/client_state_filter.rs b/crates/relayer/src/supervisor/client_state_filter.rs index 87133e89b7..646d628710 100644 --- a/crates/relayer/src/supervisor/client_state_filter.rs +++ b/crates/relayer/src/supervisor/client_state_filter.rs @@ -1,9 +1,9 @@ use alloc::collections::BTreeMap as HashMap; use flex_error::define_error; -use ibc_relayer_types::core::ics02_client::trust_threshold::TrustThreshold; use tracing::{debug, trace}; +use ibc_relayer_types::core::ics02_client::trust_threshold::TrustThreshold; use ibc_relayer_types::core::ics03_connection::connection::ConnectionEnd; use ibc_relayer_types::core::ics04_channel::error::Error as ChannelError; use ibc_relayer_types::core::ics24_host::identifier::{ diff --git a/tools/integration-test/src/tests/client_refresh.rs b/tools/integration-test/src/tests/client_refresh.rs index 24df985574..8871cab801 100644 --- a/tools/integration-test/src/tests/client_refresh.rs +++ b/tools/integration-test/src/tests/client_refresh.rs @@ -1,10 +1,9 @@ use std::time::Duration; -use ibc_relayer::config::ChainConfig; -use ibc_relayer_types::core::ics02_client::trust_threshold::TrustThreshold; - use ibc_relayer::config::gas_multiplier::GasMultiplier; +use ibc_relayer::config::ChainConfig; use ibc_relayer::foreign_client::CreateOptions; +use ibc_relayer_types::core::ics02_client::trust_threshold::TrustThreshold; use ibc_test_framework::prelude::*; diff --git a/tools/integration-test/src/tests/client_settings.rs b/tools/integration-test/src/tests/client_settings.rs index bfd18ae66d..c5b5b4fa11 100644 --- a/tools/integration-test/src/tests/client_settings.rs +++ b/tools/integration-test/src/tests/client_settings.rs @@ -1,12 +1,11 @@ use std::time::Duration; -use ibc_relayer::config::ChainConfig; -use ibc_relayer_types::core::ics02_client::trust_threshold::TrustThreshold; - use ibc_relayer::chain::requests::{IncludeProof, QueryClientStateRequest, QueryHeight}; use ibc_relayer::client_state::AnyClientState; +use ibc_relayer::config::ChainConfig; use ibc_relayer::foreign_client::CreateOptions; use ibc_relayer_types::clients::ics07_tendermint::client_state::ClientState as TmClientState; +use ibc_relayer_types::core::ics02_client::trust_threshold::TrustThreshold; use ibc_test_framework::prelude::*;