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