Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: ampd configs should contain a Vec of handler configs #77

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 80 additions & 47 deletions ampd/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use serde::Deserialize;

use crate::broadcaster;
use crate::evm::{deserialize_evm_chain_configs, EvmChainConfig};
use crate::handlers::multisig::MultisigConfig;
use crate::handlers::{self, config::deserialize_handler_configs};
use crate::tofnd::Config as TofndConfig;
use crate::url::Url;

Expand All @@ -12,11 +11,10 @@ pub struct Config {
pub tm_jsonrpc: Url,
pub tm_grpc: Url,
pub broadcast: broadcaster::Config,
#[serde(deserialize_with = "deserialize_evm_chain_configs")]
pub evm_chains: Vec<EvmChainConfig>,
#[serde(deserialize_with = "deserialize_handler_configs")]
pub handlers: Vec<handlers::config::Config>,
pub tofnd_config: TofndConfig,
pub event_buffer_cap: usize,
pub multisig: Option<MultisigConfig>,
}

impl Default for Config {
Expand All @@ -25,10 +23,9 @@ impl Default for Config {
tm_jsonrpc: "http://localhost:26657".parse().unwrap(),
tm_grpc: "tcp://localhost:9090".parse().unwrap(),
broadcast: broadcaster::Config::default(),
evm_chains: vec![],
handlers: vec![],
tofnd_config: TofndConfig::default(),
event_buffer_cap: 100000,
multisig: None,
}
}
}
Expand All @@ -39,56 +36,85 @@ mod tests {
use rand::rngs::OsRng;

use super::Config;
use crate::evm::ChainName;
use crate::types::PublicKey;
use crate::types::{PublicKey, TMAddress};

#[test]
fn deserialize_evm_configs() {
let rpc_url = "http://localhost:7545/";
let voting_verifier = PublicKey::from(SigningKey::random(&mut OsRng).verifying_key())
.account_id("axelar")
.unwrap()
.into();

fn deserialize_handlers() {
let config_str = format!(
"
[[evm_chains]]
[[handlers]]
type = 'EVMMsgVerifier'
cosmwasm_contract = '{}'

[handlers.chain]
name = 'Ethereum'
rpc_url = '{rpc_url}'
voting_verifier = '{voting_verifier}'
rpc_url = 'http://localhost:7545/'

[[handlers]]
type = 'EVMMsgVerifier'
cosmwasm_contract = '{}'

[[evm_chains]]
[handlers.chain]
name = 'Polygon'
rpc_url = '{rpc_url}'
voting_verifier = '{voting_verifier}'

[[evm_chains]]
name = 'Optimism'
rpc_url = '{rpc_url}'
voting_verifier = '{voting_verifier}'
l1_chain_name = 'Ethereum'
rpc_url = 'http://localhost:7546/'

[[handlers]]
type = 'MultisigSigner'
cosmwasm_contract = '{}'
",
rand_tm_address(),
rand_tm_address(),
rand_tm_address(),
);

let cfg: Config = toml::from_str(config_str.as_str()).unwrap();
assert_eq!(cfg.evm_chains.len(), 3);

let actual = cfg.evm_chains.get(0).unwrap();
assert_eq!(actual.name, ChainName::Ethereum);
assert_eq!(actual.rpc_url.as_str(), rpc_url);
assert_eq!(actual.l1_chain_name, None);
assert_eq!(actual.voting_verifier, voting_verifier);

let actual = cfg.evm_chains.get(1).unwrap();
assert_eq!(actual.name, ChainName::Other("Polygon".into()));
assert_eq!(actual.rpc_url.as_str(), rpc_url);
assert_eq!(actual.l1_chain_name, None);
assert_eq!(actual.voting_verifier, voting_verifier);

let actual = cfg.evm_chains.get(2).unwrap();
assert_eq!(actual.name, ChainName::Other("Optimism".into()));
assert_eq!(actual.rpc_url.as_str(), rpc_url);
assert_eq!(actual.l1_chain_name, Some(ChainName::Ethereum));
assert_eq!(actual.voting_verifier, voting_verifier);
assert_eq!(cfg.handlers.len(), 3);
}

#[test]
fn deserialize_handlers_evm_msg_verifiers_with_the_same_chain_name() {
let config_str = format!(
"
[[handlers]]
type = 'EVMMsgVerifier'
cosmwasm_contract = '{}'

[handlers.chain]
name = 'Ethereum'
rpc_url = 'http://localhost:7545/'

[[handlers]]
type = 'EVMMsgVerifier'
cosmwasm_contract = '{}'

[handlers.chain]
name = 'Ethereum'
rpc_url = 'http://localhost:7546/'
",
rand_tm_address(),
rand_tm_address(),
);

assert!(toml::from_str::<Config>(config_str.as_str()).is_err());
}

#[test]
fn deserialize_handlers_more_then_one_for_mulsitig_signer() {
let config_str = format!(
"
[[handlers]]
type = 'MultisigSigner'
cosmwasm_contract = '{}'

[[handlers]]
type = 'MultisigSigner'
cosmwasm_contract = '{}'
",
rand_tm_address(),
rand_tm_address(),
);

assert!(toml::from_str::<Config>(config_str.as_str()).is_err());
}

#[test]
Expand Down Expand Up @@ -130,4 +156,11 @@ mod tests {
assert_eq!(cfg.tofnd_config.party_uid.as_str(), party_uid);
assert_eq!(cfg.tofnd_config.key_uid.as_str(), key_uid);
}

fn rand_tm_address() -> TMAddress {
PublicKey::from(SigningKey::random(&mut OsRng).verifying_key())
.account_id("axelar")
.unwrap()
.into()
}
}
52 changes: 0 additions & 52 deletions ampd/src/evm/mod.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
use std::collections::HashSet;
use std::fmt::Display;

use enum_display_derive::Display;
use ethers::types::U64;
use serde::de::{self, Deserializer};
use serde::Deserialize;

use crate::types::TMAddress;
use crate::url::Url;

pub mod error;
pub mod finalizer;
pub mod json_rpc;
Expand Down Expand Up @@ -47,53 +42,6 @@ impl ChainName {
}
}

#[derive(Debug, Deserialize)]
pub struct EvmChainConfig {
pub name: ChainName,
pub rpc_url: Url,
pub l1_chain_name: Option<ChainName>,
pub voting_verifier: TMAddress,
}

pub fn deserialize_evm_chain_configs<'de, D>(
deserializer: D,
) -> core::result::Result<Vec<EvmChainConfig>, D::Error>
where
D: Deserializer<'de>,
{
let evm_configs: Vec<EvmChainConfig> = Deserialize::deserialize(deserializer)?;

// validate name being unique
let chain_names: HashSet<&ChainName> = evm_configs
.iter()
.map(|evm_config| &evm_config.name)
.collect();
if evm_configs.len() != chain_names.len() {
return Err(de::Error::custom(
"the evm_chain_configs must be unique by name",
));
}

for config in &evm_configs {
match &config.l1_chain_name {
None => continue,
Some(l1_chain_name) => {
if !chain_names.contains(&l1_chain_name) {
return Err(de::Error::custom(
"l1_chain_name must be one of the evm_chain_configs if set",
));
}

if *l1_chain_name == config.name {
return Err(de::Error::custom("l1_chain_name must not equal to name"));
}
}
}
}

Ok(evm_configs)
}

#[cfg(test)]
mod tests {
use std::str::FromStr;
Expand Down
84 changes: 84 additions & 0 deletions ampd/src/handlers/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use serde::de::{self, Deserializer};
use serde::Deserialize;
use std::collections::HashSet;

use crate::evm::ChainName;
use crate::types::TMAddress;
use crate::url::Url;

#[derive(Debug, Deserialize)]
pub struct Chain {
pub name: ChainName,
pub rpc_url: Url,
}

#[derive(Debug, Deserialize)]
#[serde(tag = "type")]
pub enum Config {
EVMMsgVerifier {
fish-sammy marked this conversation as resolved.
Show resolved Hide resolved
chain: Chain,
cosmwasm_contract: TMAddress,
},
MultisigSigner {
cosmwasm_contract: TMAddress,
},
}

fn validate_multisig_signer_config<'de, D>(configs: &[Config]) -> Result<(), D::Error>
where
D: Deserializer<'de>,
{
match configs
.iter()
.filter(|config| matches!(config, Config::MultisigSigner { .. }))
.count()
{
count if count > 1 => Err(de::Error::custom(
"only one multisig signer config is allowed",
)),
_ => Ok(()),
}
}

fn validate_evm_msg_verifier_configs<'de, D>(configs: &[Config]) -> Result<(), D::Error>
where
D: Deserializer<'de>,
{
let evm_msg_verifier_configs: Vec<_> = configs
.iter()
.filter(|config| matches!(config, Config::EVMMsgVerifier { .. }))
.collect();
fish-sammy marked this conversation as resolved.
Show resolved Hide resolved

// validate chain names being unique
let chain_names: HashSet<_> = evm_msg_verifier_configs
.iter()
.filter_map(|config| match config {
Config::EVMMsgVerifier {
chain: Chain { name, .. },
..
} => Some(name),
_ => None,
})
.collect();
if evm_msg_verifier_configs.len() != chain_names.len() {
return Err(de::Error::custom(
"the chain name EVM msg verifier configs must be unique",
));
}

Ok(())
}

pub fn deserialize_handler_configs<'de, D>(
deserializer: D,
) -> core::result::Result<Vec<Config>, D::Error>
where
D: Deserializer<'de>,
{
let configs: Vec<Config> = Deserialize::deserialize(deserializer)?;

validate_evm_msg_verifier_configs::<D>(&configs)?;
validate_multisig_signer_config::<D>(&configs)?;

Ok(configs)
}
fish-sammy marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions ampd/src/handlers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod chain;
pub mod config;
pub mod end_block;
mod errors;
pub mod evm_verify_msg;
Expand Down
5 changes: 0 additions & 5 deletions ampd/src/handlers/multisig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,6 @@ use crate::tofnd::MessageDigest;
use crate::types::PublicKey;
use crate::types::TMAddress;

#[derive(Debug, Deserialize)]
pub struct MultisigConfig {
pub address: TMAddress,
}

#[derive(Debug, Deserialize)]
#[try_from("wasm-signing_started")]
struct SigningStartedEvent {
Expand Down
Loading
Loading