Skip to content

Commit

Permalink
Improve error message when deserializing an invalid chain config
Browse files Browse the repository at this point in the history
Error messages when deserializing an invalid chain config have gotten a lot worse since #3787.

For example, when mistyping the `gas_multiplier` field as `gas_multiplie` in the per-chain config:

```
data did not match any variant of untagged enum ChainConfig for key `chains` at line 424 column 1
```

After this commit (same message as before #3787):

```
invalid CosmosSdk config: unknown field `gas_multiplie`, expected one of `id`, `rpc_addr`, `grpc_addr`, `event_source`,
`rpc_timeout`, `trusted_node`, `account_prefix`, `key_name`, `key_store_type`, `key_store_folder`, `store_prefix`,
`default_gas`, `max_gas`, `genesis_restart`, `gas_adjustment`, `gas_multiplier`, `fee_granter`, `max_msg_num`,
`max_tx_size`, `max_grpc_decoding_size`, `query_packets_chunk_size`, `clock_drift`, `max_block_time`, `trusting_period`,
`client_refresh_rate`, `ccv_consumer_chain`, `memo_prefix`, `sequential_batch_tx`, `proof_specs`, `trust_threshold`,
`gas_price`, `packet_filter`, `address_type`, `extension_options`, `compat_mode`, `clear_interval`
for key `chains` at line 424 column 1
```

For this, we now use a custom deserializer for ChainConfig instead of relying on an untagged enum.
  • Loading branch information
romac committed Jan 22, 2024
1 parent 90ebd6b commit d06151d
Showing 1 changed file with 36 additions and 10 deletions.
46 changes: 36 additions & 10 deletions crates/relayer/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -618,18 +618,16 @@ pub enum EventSourceMode {
},
}

// NOTE:
// To work around a limitation of serde, which does not allow
// NOTE: To work around a limitation of serde, which does not allow
// to specify a default variant if not tag is present,
// every underlying chain config MUST have a field `r#type` of
// type `monotstate::MustBe!("VariantName")`.
// every underlying chain config struct MUST have a field `r#type` with
// type `monotstate::MustBe!("VariantName")`, eg. the `CosmosSdkConfig`
// struct has a field `r#type: MustBe!("CosmosSdk")`.
//
// For chains other than CosmosSdk, this field MUST NOT be annotated
// with `#[serde(default)]`.
//
// See https://github.com/serde-rs/serde/issues/2231
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
#[serde(untagged)]
// IMPORTANT: Do not forget to update the `Deserializer` instance
// below when adding a new chain type.
#[derive(Clone, Debug, PartialEq, Serialize)]
#[serde(tag = "type")]
pub enum ChainConfig {
CosmosSdk(CosmosSdkConfig),
}
Expand Down Expand Up @@ -704,6 +702,34 @@ impl ChainConfig {
}
}

impl<'de> Deserialize<'de> for ChainConfig {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let value = toml::Value::deserialize(deserializer)?;

let type_value = value
.get("type")
.cloned()
.unwrap_or_else(|| toml::Value::String("CosmosSdk".to_string()));

let type_str = type_value
.as_str()
.ok_or_else(|| serde::de::Error::custom("invalid chain type, must be a string"))?;

match type_str {
"CosmosSdk" => CosmosSdkConfig::deserialize(value)
.map(Self::CosmosSdk)
.map_err(|e| serde::de::Error::custom(format!("invalid CosmosSdk config: {e}"))),

chain_type => Err(serde::de::Error::custom(format!(
"unknown chain type: {chain_type}",
))),
}
}
}

/// 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

0 comments on commit d06151d

Please sign in to comment.