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