1use crate::{
2 combined_database::CombinedDatabaseConfig,
3 graphql_api::ServiceConfig as GraphQLConfig,
4};
5use clap::ValueEnum;
6use fuel_core_chain_config::SnapshotReader;
7pub use fuel_core_consensus_module::RelayerConsensusConfig;
8pub use fuel_core_importer;
9pub use fuel_core_poa::Trigger;
10use fuel_core_tx_status_manager::config::Config as TxStatusManagerConfig;
11use fuel_core_txpool::config::Config as TxPoolConfig;
12use fuel_core_types::{
13 blockchain::header::StateTransitionBytecodeVersion,
14 fuel_types::{
15 AssetId,
16 ChainId,
17 },
18 signer::SignMode,
19};
20use std::{
21 num::{
22 NonZeroU32,
23 NonZeroU64,
24 },
25 path::PathBuf,
26 time::Duration,
27};
28use strum_macros::{
29 Display,
30 EnumString,
31 VariantNames,
32};
33
34#[cfg(feature = "parallel-executor")]
35use std::num::NonZeroUsize;
36
37#[cfg(feature = "relayer")]
38use fuel_core_relayer::Config as RelayerConfig;
39
40#[cfg(feature = "p2p")]
41use fuel_core_p2p::config::{
42 Config as P2PConfig,
43 NotInitialized,
44};
45
46#[cfg(feature = "test-helpers")]
47#[cfg(feature = "rpc")]
48use fuel_core_block_aggregator_api::service::StorageMethod;
49#[cfg(feature = "test-helpers")]
50use fuel_core_chain_config::{
51 ChainConfig,
52 StateConfig,
53};
54#[cfg(feature = "test-helpers")]
55#[cfg(feature = "rpc")]
56use fuel_core_types::fuel_types::BlockHeight;
57#[cfg(feature = "test-helpers")]
58use std::net::{
59 SocketAddr,
60 TcpListener,
61};
62
63#[derive(Clone, Debug)]
64pub struct RedisLeaderLockConfig {
65 pub redis_urls: Vec<String>,
66 pub lease_key: String,
67 pub lease_ttl: Duration,
68 pub node_timeout: Duration,
69 pub retry_delay: Duration,
70 pub max_retry_delay_offset: Duration,
71 pub max_attempts: u32,
72 pub stream_max_len: u32,
73 pub quorum_disruption_budget: u32,
74}
75
76#[derive(Clone, Debug)]
77pub struct Config {
78 pub graphql_config: GraphQLConfig,
79 pub combined_db_config: CombinedDatabaseConfig,
80 pub snapshot_reader: SnapshotReader,
81 pub continue_on_error: bool,
82 pub debug: bool,
87 pub historical_execution: bool,
92 pub expensive_subscriptions: bool,
93 pub utxo_validation: bool,
94 pub allow_syscall: bool,
95 pub native_executor_version: Option<StateTransitionBytecodeVersion>,
96 #[cfg(feature = "parallel-executor")]
97 pub executor_number_of_cores: NonZeroUsize,
98 pub block_production: Trigger,
99 pub leader_lock: Option<RedisLeaderLockConfig>,
100 pub predefined_blocks_path: Option<PathBuf>,
101 pub txpool: TxPoolConfig,
102 pub tx_status_manager: TxStatusManagerConfig,
103 pub block_producer: fuel_core_producer::Config,
104 pub gas_price_config: GasPriceConfig,
105 #[cfg(feature = "rpc")]
106 pub rpc_config: Option<fuel_core_block_aggregator_api::service::Config>,
107 pub da_compression: DaCompressionMode,
108 pub block_importer: fuel_core_importer::Config,
109 #[cfg(feature = "relayer")]
110 pub relayer: Option<RelayerConfig>,
111 #[cfg(feature = "p2p")]
112 pub p2p: Option<P2PConfig<NotInitialized>>,
113 #[cfg(feature = "p2p")]
114 pub sync: fuel_core_sync::Config,
115 #[cfg(feature = "p2p")]
116 pub pre_confirmation_signature_service:
117 fuel_core_poa::pre_confirmation_signature_service::config::Config,
118 #[cfg(feature = "shared-sequencer")]
119 pub shared_sequencer: fuel_core_shared_sequencer::Config,
120 pub consensus_signer: SignMode,
121 pub name: String,
122 pub relayer_consensus_config: fuel_core_consensus_module::RelayerConsensusConfig,
123 pub min_connected_reserved_peers: usize,
125 pub time_until_synced: Duration,
127 pub production_timeout: Duration,
129 pub memory_pool_size: usize,
131}
132
133#[cfg(feature = "test-helpers")]
134pub fn free_local_addr() -> SocketAddr {
135 let listener = TcpListener::bind("[::1]:0").unwrap();
136 listener.local_addr().unwrap() }
138
139impl Config {
140 #[cfg(feature = "test-helpers")]
141 pub fn local_node() -> Self {
142 Self::local_node_with_state_config(StateConfig::local_testnet())
143 }
144
145 #[cfg(feature = "test-helpers")]
146 #[cfg(feature = "rpc")]
147 pub fn local_node_with_rpc() -> Self {
148 let mut config = Self::local_node_with_state_config(StateConfig::local_testnet());
149 let rpc_config = fuel_core_block_aggregator_api::service::Config {
150 addr: free_local_addr(),
151 sync_from: Some(BlockHeight::new(0)),
152 storage_method: StorageMethod::Local,
153 api_buffer_size: 100,
154 };
155 config.rpc_config = Some(rpc_config);
156 config
157 }
158
159 #[cfg(feature = "test-helpers")]
160 #[cfg(feature = "rpc")]
161 pub fn local_node_with_rpc_and_storage_method(storage_method: StorageMethod) -> Self {
162 let mut config = Self::local_node_with_state_config(StateConfig::local_testnet());
163 let rpc_config = fuel_core_block_aggregator_api::service::Config {
164 addr: free_local_addr(),
165 sync_from: Some(BlockHeight::new(0)),
166 storage_method,
167 api_buffer_size: 100,
168 };
169 config.rpc_config = Some(rpc_config);
170 config
171 }
172
173 #[cfg(feature = "test-helpers")]
174 pub fn local_node_with_state_config(state_config: StateConfig) -> Self {
175 Self::local_node_with_configs(ChainConfig::local_testnet(), state_config)
176 }
177
178 #[cfg(feature = "test-helpers")]
179 pub fn local_node_with_configs(
180 chain_config: ChainConfig,
181 state_config: StateConfig,
182 ) -> Self {
183 Self::local_node_with_reader(SnapshotReader::new_in_memory(
184 chain_config,
185 state_config,
186 ))
187 }
188
189 #[cfg(feature = "test-helpers")]
190 pub fn local_node_with_reader(snapshot_reader: SnapshotReader) -> Self {
191 let block_importer = fuel_core_importer::Config::new(false);
192 let latest_block = snapshot_reader.last_block_config();
193 let native_executor_version = latest_block
195 .map(|last_block| last_block.state_transition_version.saturating_add(1))
196 .unwrap_or(
197 fuel_core_types::blockchain::header::LATEST_STATE_TRANSITION_VERSION,
198 );
199
200 let utxo_validation = false;
201
202 let combined_db_config = CombinedDatabaseConfig {
203 #[cfg(feature = "rocksdb")]
204 database_config: crate::state::rocks_db::DatabaseConfig::config_for_tests(),
205 database_path: Default::default(),
206 #[cfg(feature = "rocksdb")]
207 database_type: DbType::RocksDb,
208 #[cfg(not(feature = "rocksdb"))]
209 database_type: DbType::InMemory,
210 #[cfg(feature = "rocksdb")]
211 state_rewind_policy:
212 crate::state::historical_rocksdb::StateRewindPolicy::RewindFullRange,
213 };
214
215 #[cfg(feature = "p2p")]
216 let network_name = snapshot_reader.chain_config().chain_name.clone();
217 let gas_price_config = GasPriceConfig::local_node();
218
219 const MAX_TXS_TTL: Duration = Duration::from_secs(60 * 100000000);
220
221 #[cfg(feature = "rpc")]
222 let rpc_config = None;
223
224 Self {
225 graphql_config: GraphQLConfig {
226 addr: std::net::SocketAddr::new(
227 std::net::Ipv4Addr::new(127, 0, 0, 1).into(),
228 0,
229 ),
230 number_of_threads: 0,
231 database_batch_size: 100,
232 block_subscriptions_queue: 1000,
233 max_queries_depth: 16,
234 max_queries_complexity: 80000,
235 max_queries_recursive_depth: 16,
236 max_queries_resolver_recursive_depth: 1,
237 max_queries_directives: 10,
238 max_concurrent_queries: 1024,
239 request_body_bytes_limit: 16 * 1024 * 1024,
240 query_log_threshold_time: Duration::from_secs(2),
241 api_request_timeout: Duration::from_secs(60),
242 assemble_tx_dry_run_limit: 3,
243 assemble_tx_estimate_predicates_limit: 5,
244 costs: Default::default(),
245 required_fuel_block_height_tolerance: 10,
246 required_fuel_block_height_timeout: Duration::from_secs(30),
247 },
248 combined_db_config,
249 continue_on_error: false,
250 debug: true,
251 historical_execution: true,
252 allow_syscall: true,
253 expensive_subscriptions: true,
254 utxo_validation,
255 native_executor_version: Some(native_executor_version),
256 #[cfg(feature = "parallel-executor")]
257 executor_number_of_cores: NonZeroUsize::new(1).expect("1 is not zero"),
258 snapshot_reader,
259 block_production: Trigger::Instant,
260 leader_lock: None,
261 predefined_blocks_path: None,
262 txpool: TxPoolConfig {
263 utxo_validation,
264 max_txs_ttl: MAX_TXS_TTL,
265 ..Default::default()
266 },
267 tx_status_manager: TxStatusManagerConfig {
268 subscription_ttl: MAX_TXS_TTL,
269 ..Default::default()
270 },
271 block_producer: fuel_core_producer::Config {
272 ..Default::default()
273 },
274 da_compression: DaCompressionMode::Disabled,
275 gas_price_config,
276 block_importer,
277 #[cfg(feature = "relayer")]
278 relayer: None,
279 #[cfg(feature = "p2p")]
280 p2p: Some(P2PConfig::<NotInitialized>::default(network_name.as_str())),
281 #[cfg(feature = "p2p")]
282 sync: fuel_core_sync::Config::default(),
283 #[cfg(feature = "p2p")]
284 pre_confirmation_signature_service:
285 fuel_core_poa::pre_confirmation_signature_service::config::Config::default(
286 ),
287 #[cfg(feature = "shared-sequencer")]
288 shared_sequencer: fuel_core_shared_sequencer::Config::local_node(),
289 consensus_signer: SignMode::Key(fuel_core_types::secrecy::Secret::new(
290 fuel_core_chain_config::default_consensus_dev_key().into(),
291 )),
292 name: String::default(),
293 relayer_consensus_config: Default::default(),
294 min_connected_reserved_peers: 0,
295 time_until_synced: Duration::ZERO,
296 production_timeout: Duration::from_secs(20),
297 memory_pool_size: 4,
298 #[cfg(feature = "rpc")]
299 rpc_config,
300 }
301 }
302
303 pub fn make_config_consistent(mut self) -> Config {
305 if !self.debug && !self.utxo_validation {
306 tracing::warn!(
307 "The `utxo_validation` should be `true` with disabled `debug`"
308 );
309 self.utxo_validation = true;
310 }
311
312 if self.txpool.utxo_validation != self.utxo_validation {
313 tracing::warn!("The `utxo_validation` of `TxPool` was inconsistent");
314 self.txpool.utxo_validation = self.utxo_validation;
315 }
316
317 self
318 }
319
320 pub fn base_asset_id(&self) -> AssetId {
321 *self
322 .snapshot_reader
323 .chain_config()
324 .consensus_parameters
325 .base_asset_id()
326 }
327
328 pub fn chain_id(&self) -> ChainId {
329 self.snapshot_reader
330 .chain_config()
331 .consensus_parameters
332 .chain_id()
333 }
334}
335
336impl From<&Config> for fuel_core_poa::Config {
337 fn from(config: &Config) -> Self {
338 fuel_core_poa::Config {
339 trigger: config.block_production,
340 signer: config.consensus_signer.clone(),
341 metrics: false,
342 min_connected_reserved_peers: config.min_connected_reserved_peers,
343 time_until_synced: config.time_until_synced,
344 production_timeout: config.production_timeout,
345 chain_id: config
346 .snapshot_reader
347 .chain_config()
348 .consensus_parameters
349 .chain_id(),
350 }
351 }
352}
353
354#[cfg(feature = "p2p")]
355impl From<&Config> for fuel_core_poa::pre_confirmation_signature_service::config::Config {
356 fn from(value: &Config) -> Self {
357 fuel_core_poa::pre_confirmation_signature_service::config::Config {
358 echo_delegation_interval: value
359 .pre_confirmation_signature_service
360 .echo_delegation_interval,
361 key_expiration_interval: value
362 .pre_confirmation_signature_service
363 .key_expiration_interval,
364 key_rotation_interval: value
365 .pre_confirmation_signature_service
366 .key_rotation_interval,
367 }
368 }
369}
370
371#[derive(
372 Clone, Copy, Debug, Display, Eq, PartialEq, EnumString, VariantNames, ValueEnum,
373)]
374#[strum(serialize_all = "kebab_case")]
375pub enum DbType {
376 InMemory,
377 RocksDb,
378}
379
380#[derive(Clone, Debug)]
381pub struct GasPriceConfig {
382 pub starting_exec_gas_price: u64,
383 pub exec_gas_price_change_percent: u16,
384 pub min_exec_gas_price: u64,
385 pub exec_gas_price_threshold_percent: u8,
386 pub da_committer_url: Option<url::Url>,
387 pub da_poll_interval: Option<Duration>,
388 pub da_gas_price_factor: NonZeroU64,
389 pub starting_recorded_height: Option<u32>,
390 pub min_da_gas_price: u64,
391 pub max_da_gas_price: u64,
392 pub max_da_gas_price_change_percent: u16,
393 pub da_gas_price_p_component: i64,
394 pub da_gas_price_d_component: i64,
395 pub gas_price_metrics: bool,
396 pub activity_normal_range_size: u16,
397 pub activity_capped_range_size: u16,
398 pub activity_decrease_range_size: u16,
399 pub block_activity_threshold: u8,
400}
401
402impl GasPriceConfig {
403 #[cfg(feature = "test-helpers")]
404 pub fn local_node() -> GasPriceConfig {
405 let starting_gas_price = 0;
406 let gas_price_change_percent = 0;
407 let min_gas_price = 0;
408 let gas_price_threshold_percent = 50;
409 let gas_price_metrics = false;
410
411 GasPriceConfig {
412 starting_exec_gas_price: starting_gas_price,
413 exec_gas_price_change_percent: gas_price_change_percent,
414 min_exec_gas_price: min_gas_price,
415 exec_gas_price_threshold_percent: gas_price_threshold_percent,
416 da_gas_price_factor: NonZeroU64::new(100).expect("100 is not zero"),
417 starting_recorded_height: None,
418 min_da_gas_price: 0,
419 max_da_gas_price: 1,
420 max_da_gas_price_change_percent: 0,
421 da_gas_price_p_component: 0,
422 da_gas_price_d_component: 0,
423 gas_price_metrics,
424 activity_normal_range_size: 0,
425 activity_capped_range_size: 0,
426 activity_decrease_range_size: 0,
427 da_committer_url: None,
428 block_activity_threshold: 0,
429 da_poll_interval: Some(Duration::from_secs(1)),
430 }
431 }
432}
433
434#[derive(Debug, Clone)]
435pub struct DaCompressionConfig {
436 pub retention_duration: Duration,
437 pub metrics: bool,
438 pub starting_height: Option<NonZeroU32>,
439}
440
441#[derive(Debug, Clone)]
442pub enum DaCompressionMode {
443 Disabled,
444 Enabled(DaCompressionConfig),
445}