use std::collections::HashMap;
use tracing::info;
use super::{
contracts::ContractsConfig, data_provider::DataProviderConfig, ipfs::IpfsConfig, loader::ConfigLoader,
rpc::ChainRpcProviderConfig, NewtonAvsConfig,
};
#[derive(Debug, Clone)]
pub struct ChainContext {
pub chain_id: u64,
pub contracts: ContractsConfig,
pub is_destination_chain: bool,
}
#[derive(Debug, Clone)]
pub struct MultiChainConfig<T: ConfigLoader> {
pub env: String,
pub source_chain_id: u64,
pub chains: HashMap<u64, ChainContext>,
pub rpc: ChainRpcProviderConfig,
pub service: T,
pub ipfs: IpfsConfig,
pub data_provider: DataProviderConfig,
}
impl<T: ConfigLoader + PartialEq + Eq + Clone> From<super::NewtonAvsConfig<T>> for MultiChainConfig<T> {
fn from(config: super::NewtonAvsConfig<T>) -> Self {
let source_chain_id = config.source_chain_id.unwrap_or(config.chain_id);
let is_destination = source_chain_id != config.chain_id;
let mut chains = HashMap::new();
chains.insert(
config.chain_id,
ChainContext {
chain_id: config.chain_id,
contracts: config.contracts,
is_destination_chain: is_destination,
},
);
Self {
env: config.env,
source_chain_id,
chains,
rpc: config.rpc,
service: config.service,
ipfs: config.ipfs,
data_provider: config.data_provider,
}
}
}
impl<T: ConfigLoader> MultiChainConfig<T> {
pub fn get_chain(&self, chain_id: u64) -> Option<&ChainContext> {
self.chains.get(&chain_id)
}
pub fn chain_ids(&self) -> Vec<u64> {
self.chains.keys().copied().collect()
}
pub fn chain_count(&self) -> usize {
self.chains.len()
}
pub fn is_multi_chain(&self) -> bool {
self.chains.len() > 1
}
pub fn add_chain(&mut self, chain_id: u64) -> eyre::Result<()> {
use crate::common::chain;
info!(chain_id, "adding chain to multi-chain config");
let is_destination = chain::is_destination_chain(chain_id);
let contracts = if is_destination {
let src_id = chain::get_source_chain_id(chain_id)
.ok_or_else(|| eyre::eyre!("no source chain mapping for destination chain {}", chain_id))?;
ContractsConfig::load(src_id, self.env.clone())?.with_destination_chain_id(chain_id, &self.env)?
} else {
ContractsConfig::load(chain_id, self.env.clone())?
};
self.chains.insert(
chain_id,
ChainContext {
chain_id,
contracts,
is_destination_chain: is_destination,
},
);
Ok(())
}
}
impl<T: ConfigLoader + PartialEq + Eq + Clone> MultiChainConfig<T> {
pub fn from_network(
network: crate::common::NetworkMode,
service_config_path: Option<&std::path::Path>,
data_provider_path: Option<&std::path::Path>,
) -> eyre::Result<Self> {
let source_chain_id = network.source_chain_id();
info!(
network = %network,
source_chain_id,
"building multi-chain config from network mode"
);
let mut builder = super::NewtonAvsConfigBuilder::new(source_chain_id);
if let Some(p) = service_config_path {
builder = builder.with_service_path(p.to_path_buf());
}
if let Some(p) = data_provider_path {
builder = builder.with_data_provider_path(p.to_path_buf());
}
let primary_config = builder.build::<T>()?;
let mut multi: MultiChainConfig<T> = primary_config.into();
for dest_id in network.destination_chain_ids() {
multi.add_chain(dest_id)?;
}
info!(
network = %network,
chains = ?multi.chain_ids(),
"multi-chain config loaded for {} chain(s)",
multi.chain_count()
);
Ok(multi)
}
pub fn to_single_chain_config(&self, chain_id: u64) -> Option<NewtonAvsConfig<T>> {
let ctx = self.chains.get(&chain_id)?;
Some(NewtonAvsConfig {
env: self.env.clone(),
chain_id,
source_chain_id: if ctx.is_destination_chain {
Some(self.source_chain_id)
} else {
None
},
rpc: self.rpc.clone(),
ipfs: self.ipfs.clone(),
contracts: ctx.contracts.clone(),
service: self.service.clone(),
data_provider: self.data_provider.clone(),
})
}
}