Skip to content

Commit

Permalink
relayer(cosmos): refactor cosmos-specific config validation
Browse files Browse the repository at this point in the history
  • Loading branch information
erwanor committed Oct 23, 2023
1 parent e588311 commit 979cef4
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 101 deletions.
70 changes: 70 additions & 0 deletions crates/relayer/src/chain/cosmos/config.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::chain::cosmos::config::error::Error as ConfigError;
use crate::config::default;
use crate::config::gas_multiplier::GasMultiplier;
use crate::config::types::{MaxMsgNum, MaxTxSize, Memo};
Expand All @@ -15,6 +16,8 @@ use tendermint_rpc::Url;

use crate::keyring::Store;

pub mod error;

#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct CosmosSdkConfig {
Expand Down Expand Up @@ -121,3 +124,70 @@ pub struct CosmosSdkConfig {
#[serde(default = "Vec::new", skip_serializing_if = "Vec::is_empty")]
pub extension_options: Vec<ExtensionOption>,
}

impl CosmosSdkConfig {
pub fn validate(&self) -> Result<(), Diagnostic<ConfigError>> {
validate_trust_threshold(&self.id, self.trust_threshold)?;
validate_gas_settings(&self.id, self.gas_adjustment)?;
Ok(())
}
}

/// Check that the trust threshold is:
///
/// a) non-zero
/// b) greater or equal to 1/3
/// c) strictly less than 1
fn validate_trust_threshold(
id: &ChainId,
trust_threshold: TrustThreshold,
) -> Result<(), Diagnostic<ConfigError>> {
if trust_threshold.denominator() == 0 {
return Err(Diagnostic::Error(ConfigError::invalid_trust_threshold(
trust_threshold,
id.clone(),
"trust threshold denominator cannot be zero".to_string(),
)));
}

if trust_threshold.numerator() * 3 < trust_threshold.denominator() {
return Err(Diagnostic::Error(ConfigError::invalid_trust_threshold(
trust_threshold,
id.clone(),
"trust threshold cannot be < 1/3".to_string(),
)));
}

if trust_threshold.numerator() >= trust_threshold.denominator() {
return Err(Diagnostic::Error(ConfigError::invalid_trust_threshold(
trust_threshold,
id.clone(),
"trust threshold cannot be >= 1".to_string(),
)));
}

Ok(())
}

fn validate_gas_settings(
id: &ChainId,
gas_adjustment: Option<f64>,
) -> Result<(), Diagnostic<ConfigError>> {
// Check that the gas_adjustment option is not set
if let Some(gas_adjustment) = gas_adjustment {
let gas_multiplier = gas_adjustment + 1.0;

return Err(Diagnostic::Error(ConfigError::deprecated_gas_adjustment(
gas_adjustment,
gas_multiplier,
id.clone(),
)));
}

Ok(())
}
#[derive(Clone, Debug)]
pub enum Diagnostic<E> {
Warning(E),
Error(E),
}
34 changes: 34 additions & 0 deletions crates/relayer/src/chain/cosmos/config/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use flex_error::define_error;
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
)
},

}
}
102 changes: 30 additions & 72 deletions crates/relayer/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ use core::{
use serde_derive::{Deserialize, Serialize};
use std::{fs, fs::File, io::Write, ops::Range, path::Path};
use tendermint::block::Height as BlockHeight;
use tendermint_light_client::verifier::types::TrustThreshold;
use tendermint_rpc::{Url, WebSocketClientUrl};

use ibc_proto::google::protobuf::Any;
Expand Down Expand Up @@ -270,6 +269,7 @@ impl Config {

/// Method for syntactic validation of the input configuration file.
pub fn validate_config(&self) -> Result<(), Diagnostic<Error>> {
use alloc::collections::BTreeSet;
// Check for duplicate chain configuration and invalid trust thresholds
let mut unique_chain_ids = BTreeSet::new();
for chain_config in self.chains.iter() {
Expand All @@ -280,11 +280,12 @@ impl Config {
)));
}

#[allow(irrefutable_let_patterns)]
if let ChainConfig::CosmosSdk(cosmos_c) = chain_config {
validate_trust_threshold(&cosmos_c.id, cosmos_c.trust_threshold)?;
// Validate gas-related settings
validate_gas_settings(&cosmos_c.id, cosmos_c)?;
match chain_config {
ChainConfig::CosmosSdk(cosmos_config) => {
cosmos_config
.validate()
.map_err(Into::<Diagnostic<Error>>::into)?;
}
}
}

Expand Down Expand Up @@ -643,72 +644,6 @@ impl ChainConfig {
}
}

/* config validation */

use alloc::collections::BTreeSet;

#[derive(Clone, Debug)]
pub enum Diagnostic<E> {
Warning(E),
Error(E),
}

/* tm/cosmos sdk specific config validation */
/// Check that the trust threshold is:
///
/// a) non-zero
/// b) greater or equal to 1/3
/// c) strictly less than 1
fn validate_trust_threshold(
id: &ChainId,
trust_threshold: TrustThreshold,
) -> Result<(), Diagnostic<Error>> {
if trust_threshold.denominator() == 0 {
return Err(Diagnostic::Error(Error::invalid_trust_threshold(
trust_threshold,
id.clone(),
"trust threshold denominator cannot be zero".to_string(),
)));
}

if trust_threshold.numerator() * 3 < trust_threshold.denominator() {
return Err(Diagnostic::Error(Error::invalid_trust_threshold(
trust_threshold,
id.clone(),
"trust threshold cannot be < 1/3".to_string(),
)));
}

if trust_threshold.numerator() >= trust_threshold.denominator() {
return Err(Diagnostic::Error(Error::invalid_trust_threshold(
trust_threshold,
id.clone(),
"trust threshold cannot be >= 1".to_string(),
)));
}

Ok(())
}

fn validate_gas_settings(id: &ChainId, config: &CosmosSdkConfig) -> Result<(), Diagnostic<Error>> {
// Check that the gas_adjustment option is not set
if let Some(gas_adjustment) = config.gas_adjustment {
let gas_multiplier = gas_adjustment + 1.0;

return Err(Diagnostic::Error(Error::deprecated_gas_adjustment(
gas_adjustment,
gas_multiplier,
id.clone(),
)));
}

Ok(())
}

/* cosmos sdk */

/* general config handling code */

/// Attempt to load and parse the TOML config file as a `Config`.
pub fn load(path: impl AsRef<Path>) -> Result<Config, Error> {
let config_toml = std::fs::read_to_string(&path).map_err(Error::io)?;
Expand Down Expand Up @@ -754,6 +689,29 @@ impl Default for TracingServerConfig {
}
}

#[derive(Clone, Debug)]
pub enum Diagnostic<E> {
Warning(E),
Error(E),
}

use crate::chain::cosmos::config::Diagnostic as CosmosConfigDiagnostic;
impl<E: Into<Error>> From<CosmosConfigDiagnostic<E>> for Diagnostic<Error> {
fn from(value: CosmosConfigDiagnostic<E>) -> Self {
match value {
CosmosConfigDiagnostic::Warning(e) => Diagnostic::Warning(e.into()),
CosmosConfigDiagnostic::Error(e) => Diagnostic::Error(e.into()),
}
}
}

use crate::chain::cosmos::config::error::Error as CosmosConfigError;
impl From<CosmosConfigError> for Error {
fn from(error: CosmosConfigError) -> Error {
Error::cosmos_config_error(error.to_string())
}
}

#[cfg(test)]
mod tests {
use core::str::FromStr;
Expand Down
40 changes: 11 additions & 29 deletions crates/relayer/src/config/error.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use ibc_relayer_types::core::ics24_host::identifier::ChainId;
use tendermint_light_client_verifier::types::TrustThreshold;

use flex_error::{define_error, TraceError};
use tracing_subscriber::filter::ParseError;
Expand Down Expand Up @@ -31,30 +30,6 @@ define_error! {
e.chain_id)
},

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
)
},
Io
[ TraceError<std::io::Error> ]
|_| { "config I/O error" },
Expand All @@ -67,11 +42,18 @@ define_error! {
[ TraceError<toml::ser::Error> ]
|_| { "invalid configuration" },

InvalidGasPrice
{ price: String }
|e| { format!("invalid gas price: {}", e.price) },

WrongType
|_| { "wrong configuration type" },

InvalidGasPrice
{ price: String }
|e| {
format!("invalid gas price: {}", e.price)
},

CosmosConfigError { reason: String }
|e| {
format!("invalid cosmos config: {}", e.reason)
},
}
}

0 comments on commit 979cef4

Please sign in to comment.