Skip to main content

phos_data_network/
builder.rs

1use std::{marker::PhantomData, sync::Arc};
2#[cfg(not(target_arch = "wasm32"))]
3use std::{net::SocketAddr, path::PathBuf};
4
5use eyre::{eyre, Result};
6use reqwest::{IntoUrl, Url};
7
8use helios_core::execution::{
9    cache::CachingProvider,
10    providers::{
11        block::block_cache::BlockCache, historical::eip2935::Eip2935Provider,
12        rpc::RpcExecutionProvider, verifiable_api::VerifiableApiExecutionProvider,
13    },
14};
15
16#[cfg(not(target_arch = "wasm32"))]
17use crate::database::FileDB;
18use crate::{
19    config::{networks::Network, Config, TrustOptions},
20    consensus::ConsensusClient,
21    database::{ConfigDB, Database},
22    spec::DataNetwork,
23    DataNetworkClient,
24};
25
26pub struct DataNetworkClientBuilder<DB: Database> {
27    network: Option<Network>,
28    consensus_rpc: Option<Url>,
29    execution_rpc: Option<Url>,
30    verifiable_api: Option<Url>,
31    trust_options: Option<TrustOptions>,
32    #[cfg(not(target_arch = "wasm32"))]
33    rpc_address: Option<SocketAddr>,
34    #[cfg(not(target_arch = "wasm32"))]
35    data_dir: Option<PathBuf>,
36    config: Option<Config>,
37    phantom: PhantomData<DB>,
38}
39
40impl<DB: Database> Default for DataNetworkClientBuilder<DB> {
41    fn default() -> Self {
42        Self {
43            network: None,
44            consensus_rpc: None,
45            execution_rpc: None,
46            verifiable_api: None,
47            trust_options: None,
48            #[cfg(not(target_arch = "wasm32"))]
49            rpc_address: None,
50            #[cfg(not(target_arch = "wasm32"))]
51            data_dir: None,
52            config: None,
53            phantom: PhantomData,
54        }
55    }
56}
57
58impl<DB: Database> DataNetworkClientBuilder<DB> {
59    pub fn new() -> Self {
60        Self::default()
61    }
62
63    pub fn network(mut self, network: Network) -> Self {
64        self.network = Some(network);
65        self
66    }
67
68    pub fn consensus_rpc<T: IntoUrl>(mut self, consensus_rpc: T) -> Result<Self> {
69        self.consensus_rpc = Some(
70            consensus_rpc
71                .into_url()
72                .map_err(|_| eyre!("Invalid consensus RPC URL"))?,
73        );
74        Ok(self)
75    }
76
77    pub fn execution_rpc<T: IntoUrl>(mut self, execution_rpc: T) -> Result<Self> {
78        self.execution_rpc = Some(
79            execution_rpc
80                .into_url()
81                .map_err(|_| eyre!("Invalid execution RPC URL"))?,
82        );
83        Ok(self)
84    }
85
86    pub fn verifiable_api<T: IntoUrl>(mut self, verifiable_api: T) -> Result<Self> {
87        self.verifiable_api = Some(
88            verifiable_api
89                .into_url()
90                .map_err(|_| eyre!("Invalid verifiable API URL"))?,
91        );
92        Ok(self)
93    }
94
95    pub fn trust_options(mut self, trust_options: TrustOptions) -> Self {
96        self.trust_options = Some(trust_options);
97        self
98    }
99
100    #[cfg(not(target_arch = "wasm32"))]
101    pub fn rpc_address(mut self, rpc_address: SocketAddr) -> Self {
102        self.rpc_address = Some(rpc_address);
103        self
104    }
105
106    #[cfg(not(target_arch = "wasm32"))]
107    pub fn data_dir(mut self, data_dir: PathBuf) -> Self {
108        self.data_dir = Some(data_dir);
109        self
110    }
111
112    pub fn config(mut self, config: Config) -> Self {
113        self.config = Some(config);
114        self
115    }
116
117    pub fn build(self) -> Result<DataNetworkClient> {
118        let base_config = if let Some(network) = self.network {
119            network.to_base_config()
120        } else {
121            let config = self
122                .config
123                .as_ref()
124                .ok_or(eyre!("missing network config"))?;
125            config.to_base_config()
126        };
127
128        let consensus_rpc = self
129            .consensus_rpc
130            .or_else(|| {
131                self.config
132                    .as_ref()
133                    .map(|config| config.consensus_rpc.clone())
134            })
135            .or_else(|| base_config.consensus_rpc.clone())
136            .ok_or_else(|| eyre!("missing consensus rpc"))?;
137
138        let execution_rpc = self
139            .execution_rpc
140            .or_else(|| {
141                self.config
142                    .as_ref()
143                    .and_then(|config| config.execution_rpc.clone())
144            })
145            .or_else(|| base_config.execution_rpc.clone());
146
147        let verifiable_api = self.verifiable_api.or_else(|| {
148            self.config
149                .as_ref()
150                .and_then(|config| config.verifiable_api.clone())
151        });
152
153        let trust_options = self.trust_options.or_else(|| {
154            self.config
155                .as_ref()
156                .and_then(|config| config.trust_options.clone())
157        });
158
159        #[cfg(not(target_arch = "wasm32"))]
160        let data_dir = if self.data_dir.is_some() {
161            self.data_dir
162        } else if let Some(config) = &self.config {
163            config.data_dir.clone()
164        } else {
165            base_config.data_dir.clone()
166        };
167
168        #[cfg(not(target_arch = "wasm32"))]
169        let rpc_address = if let Some(address) = self.rpc_address {
170            Some(address)
171        } else if let Some(config) = &self.config {
172            config
173                .rpc_bind_ip
174                .zip(config.rpc_port)
175                .map(|(ip, port)| SocketAddr::new(ip, port))
176        } else {
177            Some(SocketAddr::new(
178                base_config.rpc_bind_ip,
179                base_config.rpc_port,
180            ))
181        };
182
183        let database_type = self
184            .config
185            .as_ref()
186            .and_then(|config| config.database_type.clone());
187
188        let config = Config {
189            consensus_rpc,
190            execution_rpc,
191            verifiable_api,
192            rpc_bind_ip: None,
193            rpc_port: None,
194            trust_options,
195            #[cfg(not(target_arch = "wasm32"))]
196            data_dir,
197            #[cfg(target_arch = "wasm32")]
198            data_dir: None,
199            chain: base_config.chain,
200            verifier_options: base_config.verifier_options,
201            execution_forks: base_config.execution_forks,
202            database_type,
203        };
204
205        let config = Arc::new(config);
206        let consensus = ConsensusClient::<DB>::new(config.clone())?;
207
208        if let Some(verifiable_api) = &config.verifiable_api {
209            let block_provider = BlockCache::<DataNetwork>::new();
210            let historical_provider = Eip2935Provider::new();
211            let execution = VerifiableApiExecutionProvider::with_historical_provider(
212                verifiable_api,
213                block_provider,
214                historical_provider,
215            );
216            let execution = CachingProvider::new(execution);
217
218            Ok(DataNetworkClient::new(
219                consensus,
220                execution,
221                config.execution_forks,
222                #[cfg(not(target_arch = "wasm32"))]
223                rpc_address,
224            ))
225        } else {
226            let block_provider = BlockCache::<DataNetwork>::new();
227            let rpc_url = config
228                .execution_rpc
229                .as_ref()
230                .ok_or_else(|| eyre!("missing execution rpc"))?
231                .clone();
232            let historical_provider = Eip2935Provider::new();
233            let execution = RpcExecutionProvider::with_historical_provider(
234                rpc_url,
235                block_provider,
236                historical_provider,
237            );
238            let execution = CachingProvider::new(execution);
239
240            Ok(DataNetworkClient::new(
241                consensus,
242                execution,
243                config.execution_forks,
244                #[cfg(not(target_arch = "wasm32"))]
245                rpc_address,
246            ))
247        }
248    }
249}
250
251#[cfg(not(target_arch = "wasm32"))]
252impl DataNetworkClientBuilder<FileDB> {
253    pub fn with_file_db(self) -> Self {
254        self
255    }
256}
257
258impl DataNetworkClientBuilder<ConfigDB> {
259    pub fn with_config_db(self) -> Self {
260        self
261    }
262}