Skip to content

Commit cc671b9

Browse files
committed
refactor: use enum proxy pattern to improve extendability of main (#34)
* refactor: use enum pattern * chore: lint f64 comparison * chore: fmt stuff
1 parent 370a301 commit cc671b9

6 files changed

Lines changed: 270 additions & 117 deletions

File tree

apps/ibc-attestor/src/adapter/mod.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ use thiserror::Error;
22

33
use crate::rpc::api::CommitmentType;
44

5+
use cosmos::CosmosAdapter;
6+
use evm::EvmAdapter;
7+
use solana::SolanaAdapter;
8+
59
/// Cosmos adapter
610
pub mod cosmos;
711
/// EVM adapter
@@ -47,6 +51,89 @@ pub trait AdapterBuilder {
4751
fn build(config: Self::Config) -> Result<Self::Adapter, AttestationAdapterError>;
4852
}
4953

54+
/// Enum wrapping all concrete adapter implementations.
55+
pub enum AdapterEnum {
56+
/// EVM adapter
57+
Evm(EvmAdapter),
58+
/// Solana adapter
59+
Solana(SolanaAdapter),
60+
/// Cosmos adapter
61+
Cosmos(CosmosAdapter),
62+
}
63+
64+
impl AdapterEnum {
65+
/// Returns the name of the adapter for logging.
66+
#[must_use]
67+
pub const fn adapter_name(&self) -> &'static str {
68+
match self {
69+
Self::Evm(_) => "evm",
70+
Self::Solana(_) => "solana",
71+
Self::Cosmos(_) => "cosmos",
72+
}
73+
}
74+
}
75+
76+
#[async_trait::async_trait]
77+
impl AttestationAdapter for AdapterEnum {
78+
async fn get_last_height_at_configured_finality(&self) -> Result<u64, AttestationAdapterError> {
79+
match self {
80+
Self::Evm(a) => a.get_last_height_at_configured_finality().await,
81+
Self::Solana(a) => a.get_last_height_at_configured_finality().await,
82+
Self::Cosmos(a) => a.get_last_height_at_configured_finality().await,
83+
}
84+
}
85+
86+
async fn get_block_timestamp(&self, height: u64) -> Result<u64, AttestationAdapterError> {
87+
match self {
88+
Self::Evm(a) => a.get_block_timestamp(height).await,
89+
Self::Solana(a) => a.get_block_timestamp(height).await,
90+
Self::Cosmos(a) => a.get_block_timestamp(height).await,
91+
}
92+
}
93+
94+
async fn get_commitment(
95+
&self,
96+
client_id: String,
97+
height: u64,
98+
sequence: u64,
99+
commitment_path: &[u8],
100+
commitment_type: CommitmentType,
101+
) -> Result<Option<[u8; 32]>, AttestationAdapterError> {
102+
match self {
103+
Self::Evm(a) => {
104+
a.get_commitment(
105+
client_id,
106+
height,
107+
sequence,
108+
commitment_path,
109+
commitment_type,
110+
)
111+
.await
112+
}
113+
Self::Solana(a) => {
114+
a.get_commitment(
115+
client_id,
116+
height,
117+
sequence,
118+
commitment_path,
119+
commitment_type,
120+
)
121+
.await
122+
}
123+
Self::Cosmos(a) => {
124+
a.get_commitment(
125+
client_id,
126+
height,
127+
sequence,
128+
commitment_path,
129+
commitment_type,
130+
)
131+
.await
132+
}
133+
}
134+
}
135+
}
136+
50137
/// Attestation adapter methods needed to provide attestations for a given chain
51138
#[async_trait::async_trait]
52139
pub trait AttestationAdapter: Sync + Send + 'static {

apps/ibc-attestor/src/bin/ibc_attestor/cli.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Defines the client interface for the attestor server.
22
use clap::{Parser, ValueEnum};
3+
use ibc_attestor::config;
34

45
/// The type of blockchain adapter to use
56
#[derive(Clone, Debug, ValueEnum)]
@@ -12,6 +13,16 @@ pub enum ChainType {
1213
Cosmos,
1314
}
1415

16+
impl From<ChainType> for config::ChainType {
17+
fn from(ct: ChainType) -> Self {
18+
match ct {
19+
ChainType::Evm => Self::Evm,
20+
ChainType::Solana => Self::Solana,
21+
ChainType::Cosmos => Self::Cosmos,
22+
}
23+
}
24+
}
25+
1526
/// The type of signer to use
1627
#[derive(Clone, Debug, ValueEnum)]
1728
pub enum SignerType {
@@ -21,6 +32,15 @@ pub enum SignerType {
2132
Remote,
2233
}
2334

35+
impl From<SignerType> for config::SignerType {
36+
fn from(st: SignerType) -> Self {
37+
match st {
38+
SignerType::Local => Self::Local,
39+
SignerType::Remote => Self::Remote,
40+
}
41+
}
42+
}
43+
2444
#[derive(Clone, Debug, Parser)]
2545
#[command(
2646
name = "ibc_attestor",

apps/ibc-attestor/src/bin/ibc_attestor/main.rs

Lines changed: 21 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,10 @@ use alloy_signer_local::PrivateKeySigner;
44
use clap::Parser;
55
use ethereum_keys::signer_local::{read_from_keystore, write_to_keystore};
66
use ibc_attestor::{
7-
adapter::{
8-
AdapterBuilder,
9-
cosmos::{CosmosAdapterBuilder, CosmosAdapterConfig},
10-
evm::{EvmAdapterBuilder, EvmAdapterConfig},
11-
solana::{SolanaAdapterBuilder, SolanaAdapterConfig},
12-
},
13-
config::{AttestorConfig, TracingConfig},
7+
config::RuntimeConfig,
148
logging::init_logging,
159
rpc::{RpcError, health, server},
16-
signer::{
17-
SignerBuilder,
18-
local::{DEFAULT_KEYSTORE_NAME, LocalSigner, LocalSignerConfig},
19-
remote::{RemoteSigner, RemoteSignerConfig},
20-
},
10+
signer::local::DEFAULT_KEYSTORE_NAME,
2111
};
2212

2313
use tokio::{
@@ -27,7 +17,7 @@ use tokio::{
2717
};
2818
use tracing::info;
2919

30-
use crate::cli::{AttestorCli, ChainType, Commands, SignerType, key::KeyCommands};
20+
use crate::cli::{AttestorCli, Commands, key::KeyCommands};
3121

3222
mod cli;
3323

@@ -43,12 +33,14 @@ fn default_attestor_dir() -> Result<PathBuf, anyhow::Error> {
4333
Ok(PathBuf::from(home).join(".ibc-attestor"))
4434
}
4535

46-
fn run_servers<B: AdapterBuilder + 'static, S: SignerBuilder + 'static>(
47-
config: AttestorConfig<B::Config, S::Config>,
36+
type ServerHandles = (JoinHandle<Result<(), RpcError>>, JoinHandle<()>);
37+
38+
fn run_servers(
39+
config: RuntimeConfig,
4840
shutdown_tx: &broadcast::Sender<()>,
49-
) -> Result<(JoinHandle<Result<(), RpcError>>, JoinHandle<()>), anyhow::Error> {
50-
let adapter = B::build(config.adapter)?;
51-
let signer = S::build(config.signer)?;
41+
) -> Result<ServerHandles, anyhow::Error> {
42+
let adapter_name = config.adapter.adapter_name();
43+
let signer_name = config.signer.signer_name();
5244
let server_config = config.server;
5345

5446
let grpc_shutdown_rx = shutdown_tx.subscribe();
@@ -60,10 +52,10 @@ fn run_servers<B: AdapterBuilder + 'static, S: SignerBuilder + 'static>(
6052
let grpc_handle = tokio::spawn(async move {
6153
server::start(
6254
grpc_addr,
63-
adapter,
64-
B::adapter_name(),
65-
signer,
66-
S::signer_name(),
55+
config.adapter,
56+
adapter_name,
57+
config.signer,
58+
signer_name,
6759
grpc_shutdown_rx,
6860
)
6961
.await
@@ -82,55 +74,17 @@ async fn main() -> Result<(), anyhow::Error> {
8274

8375
match cli.command {
8476
Commands::Server(args) => {
85-
// Load tracing config first to initialize logging before parsing full config
86-
let tracing_config = TracingConfig::from_file(&args.config)?;
87-
let _tracing_guard = init_logging(tracing_config);
77+
let config = RuntimeConfig::from_file(
78+
&args.config,
79+
&args.chain_type.into(),
80+
&args.signer_type.into(),
81+
)?;
82+
let _tracing_guard = init_logging(config.tracing.clone());
8883

8984
// Create shutdown broadcast channel
9085
let (shutdown_tx, _shutdown_rx) = broadcast::channel(1);
9186

92-
let (grpc_handle, health_handle) = match (args.chain_type, args.signer_type) {
93-
(ChainType::Evm, SignerType::Local) => {
94-
let config = AttestorConfig::<EvmAdapterConfig, LocalSignerConfig>::from_file(
95-
&args.config,
96-
)?;
97-
run_servers::<EvmAdapterBuilder, LocalSigner>(config, &shutdown_tx)?
98-
}
99-
(ChainType::Evm, SignerType::Remote) => {
100-
let config = AttestorConfig::<EvmAdapterConfig, RemoteSignerConfig>::from_file(
101-
&args.config,
102-
)?;
103-
run_servers::<EvmAdapterBuilder, RemoteSigner>(config, &shutdown_tx)?
104-
}
105-
(ChainType::Solana, SignerType::Local) => {
106-
let config =
107-
AttestorConfig::<SolanaAdapterConfig, LocalSignerConfig>::from_file(
108-
&args.config,
109-
)?;
110-
run_servers::<SolanaAdapterBuilder, LocalSigner>(config, &shutdown_tx)?
111-
}
112-
(ChainType::Solana, SignerType::Remote) => {
113-
let config =
114-
AttestorConfig::<SolanaAdapterConfig, RemoteSignerConfig>::from_file(
115-
&args.config,
116-
)?;
117-
run_servers::<SolanaAdapterBuilder, RemoteSigner>(config, &shutdown_tx)?
118-
}
119-
(ChainType::Cosmos, SignerType::Local) => {
120-
let config =
121-
AttestorConfig::<CosmosAdapterConfig, LocalSignerConfig>::from_file(
122-
&args.config,
123-
)?;
124-
run_servers::<CosmosAdapterBuilder, LocalSigner>(config, &shutdown_tx)?
125-
}
126-
(ChainType::Cosmos, SignerType::Remote) => {
127-
let config =
128-
AttestorConfig::<CosmosAdapterConfig, RemoteSignerConfig>::from_file(
129-
&args.config,
130-
)?;
131-
run_servers::<CosmosAdapterBuilder, RemoteSigner>(config, &shutdown_tx)?
132-
}
133-
};
87+
let (grpc_handle, health_handle) = run_servers(config, &shutdown_tx)?;
13488

13589
_ = wait_for_shutdown_signal().await;
13690
info!("shutdown signal received, starting graceful shutdown");

0 commit comments

Comments
 (0)