Skip to content

Commit

Permalink
Allow deserializing a trust threshold as a string or a struct
Browse files Browse the repository at this point in the history
All these formats are allowed and equivalent:

- trust_threshold = '2/3'
- trust_threshold = { numerator = 2, denominator = 3 }
- trust_threshold = { numerator = '2', denominator = '3' } (for backward compat)
  • Loading branch information
romac committed Jan 3, 2024
1 parent 8393c8f commit b55ce20
Show file tree
Hide file tree
Showing 13 changed files with 160 additions and 79 deletions.
2 changes: 1 addition & 1 deletion config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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' }
3 changes: 1 addition & 2 deletions crates/relayer-cli/src/chain_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion crates/relayer-cli/src/commands/config/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
}
}
Expand Down
122 changes: 104 additions & 18 deletions crates/relayer-types/src/core/ics02_client/trust_threshold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -121,23 +122,32 @@ impl Display for TrustThreshold {
}
}

impl FromStr for TrustThreshold {
type Err = String;

fn from_str(s: &str) -> Result<Self, Self::Err> {
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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
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()))
}
}

Expand All @@ -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<E>(self, value: &str) -> Result<TrustThreshold, E>
where
E: de::Error,
{
Ok(FromStr::from_str(value).unwrap())
}

fn visit_map<M>(self, map: M) -> Result<TrustThreshold, M::Error>
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<u64, D::Error>
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<E>(self, value: &str) -> Result<u64, E>
where
E: de::Error,
{
FromStr::from_str(value).map_err(de::Error::custom)
}

fn visit_i64<E>(self, value: i64) -> Result<u64, E>
where
E: de::Error,
{
Ok(value as u64)
}

fn visit_u64<E>(self, value: u64) -> Result<u64, E>
where
E: de::Error,
{
Ok(value)
}
}

deserializer.deserialize_any(StringOrInt)
}
2 changes: 1 addition & 1 deletion crates/relayer/src/chain/cosmos/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
21 changes: 11 additions & 10 deletions crates/relayer/src/chain/cosmos/config.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
50 changes: 24 additions & 26 deletions crates/relayer/src/chain/cosmos/config/error.rs
Original file line number Diff line number Diff line change
@@ -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
)
},
}
}
1 change: 0 additions & 1 deletion crates/relayer/src/client_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
22 changes: 10 additions & 12 deletions crates/relayer/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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 {
Expand Down
2 changes: 2 additions & 0 deletions crates/relayer/src/config/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion crates/relayer/src/supervisor/client_state_filter.rs
Original file line number Diff line number Diff line change
@@ -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::{
Expand Down
5 changes: 2 additions & 3 deletions tools/integration-test/src/tests/client_refresh.rs
Original file line number Diff line number Diff line change
@@ -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::*;

Expand Down
5 changes: 2 additions & 3 deletions tools/integration-test/src/tests/client_settings.rs
Original file line number Diff line number Diff line change
@@ -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::*;

Expand Down

0 comments on commit b55ce20

Please sign in to comment.