use crate::{
combined_database::CombinedDatabaseConfig,
graphql_api::ServiceConfig as GraphQLConfig,
};
use clap::ValueEnum;
use fuel_core_chain_config::SnapshotReader;
pub use fuel_core_consensus_module::RelayerConsensusConfig;
pub use fuel_core_importer;
pub use fuel_core_poa::Trigger;
use fuel_core_tx_status_manager::config::Config as TxStatusManagerConfig;
use fuel_core_txpool::config::Config as TxPoolConfig;
use fuel_core_types::{
blockchain::header::StateTransitionBytecodeVersion,
fuel_types::{
AssetId,
ChainId,
},
signer::SignMode,
};
use std::{
num::{
NonZeroU32,
NonZeroU64,
},
path::PathBuf,
time::Duration,
};
use strum_macros::{
Display,
EnumString,
VariantNames,
};
#[cfg(feature = "parallel-executor")]
use std::num::NonZeroUsize;
#[cfg(feature = "relayer")]
use fuel_core_relayer::Config as RelayerConfig;
#[cfg(feature = "p2p")]
use fuel_core_p2p::config::{
Config as P2PConfig,
NotInitialized,
};
#[cfg(feature = "test-helpers")]
#[cfg(feature = "rpc")]
use fuel_core_block_aggregator_api::service::StorageMethod;
#[cfg(feature = "test-helpers")]
use fuel_core_chain_config::{
ChainConfig,
StateConfig,
};
#[cfg(feature = "test-helpers")]
#[cfg(feature = "rpc")]
use fuel_core_types::fuel_types::BlockHeight;
#[cfg(feature = "test-helpers")]
use std::net::{
SocketAddr,
TcpListener,
};
#[derive(Clone, Debug)]
pub struct RedisLeaderLockConfig {
pub redis_urls: Vec<String>,
pub lease_key: String,
pub lease_ttl: Duration,
pub node_timeout: Duration,
pub retry_delay: Duration,
pub max_retry_delay_offset: Duration,
pub max_attempts: u32,
pub stream_max_len: u32,
pub quorum_disruption_budget: u32,
}
#[derive(Clone, Debug)]
pub struct Config {
pub graphql_config: GraphQLConfig,
pub combined_db_config: CombinedDatabaseConfig,
pub snapshot_reader: SnapshotReader,
pub continue_on_error: bool,
pub debug: bool,
pub historical_execution: bool,
pub expensive_subscriptions: bool,
pub utxo_validation: bool,
pub allow_syscall: bool,
pub native_executor_version: Option<StateTransitionBytecodeVersion>,
#[cfg(feature = "parallel-executor")]
pub executor_number_of_cores: NonZeroUsize,
pub block_production: Trigger,
pub leader_lock: Option<RedisLeaderLockConfig>,
pub predefined_blocks_path: Option<PathBuf>,
pub txpool: TxPoolConfig,
pub tx_status_manager: TxStatusManagerConfig,
pub block_producer: fuel_core_producer::Config,
pub gas_price_config: GasPriceConfig,
#[cfg(feature = "rpc")]
pub rpc_config: Option<fuel_core_block_aggregator_api::service::Config>,
pub da_compression: DaCompressionMode,
pub block_importer: fuel_core_importer::Config,
#[cfg(feature = "relayer")]
pub relayer: Option<RelayerConfig>,
#[cfg(feature = "p2p")]
pub p2p: Option<P2PConfig<NotInitialized>>,
#[cfg(feature = "p2p")]
pub sync: fuel_core_sync::Config,
#[cfg(feature = "p2p")]
pub pre_confirmation_signature_service:
fuel_core_poa::pre_confirmation_signature_service::config::Config,
#[cfg(feature = "shared-sequencer")]
pub shared_sequencer: fuel_core_shared_sequencer::Config,
pub consensus_signer: SignMode,
pub name: String,
pub relayer_consensus_config: fuel_core_consensus_module::RelayerConsensusConfig,
pub min_connected_reserved_peers: usize,
pub time_until_synced: Duration,
pub production_timeout: Duration,
pub memory_pool_size: usize,
}
#[cfg(feature = "test-helpers")]
pub fn free_local_addr() -> SocketAddr {
let listener = TcpListener::bind("[::1]:0").unwrap();
listener.local_addr().unwrap() }
impl Config {
#[cfg(feature = "test-helpers")]
pub fn local_node() -> Self {
Self::local_node_with_state_config(StateConfig::local_testnet())
}
#[cfg(feature = "test-helpers")]
#[cfg(feature = "rpc")]
pub fn local_node_with_rpc() -> Self {
let mut config = Self::local_node_with_state_config(StateConfig::local_testnet());
let rpc_config = fuel_core_block_aggregator_api::service::Config {
addr: free_local_addr(),
sync_from: Some(BlockHeight::new(0)),
storage_method: StorageMethod::Local,
api_buffer_size: 100,
};
config.rpc_config = Some(rpc_config);
config
}
#[cfg(feature = "test-helpers")]
#[cfg(feature = "rpc")]
pub fn local_node_with_rpc_and_storage_method(storage_method: StorageMethod) -> Self {
let mut config = Self::local_node_with_state_config(StateConfig::local_testnet());
let rpc_config = fuel_core_block_aggregator_api::service::Config {
addr: free_local_addr(),
sync_from: Some(BlockHeight::new(0)),
storage_method,
api_buffer_size: 100,
};
config.rpc_config = Some(rpc_config);
config
}
#[cfg(feature = "test-helpers")]
pub fn local_node_with_state_config(state_config: StateConfig) -> Self {
Self::local_node_with_configs(ChainConfig::local_testnet(), state_config)
}
#[cfg(feature = "test-helpers")]
pub fn local_node_with_configs(
chain_config: ChainConfig,
state_config: StateConfig,
) -> Self {
Self::local_node_with_reader(SnapshotReader::new_in_memory(
chain_config,
state_config,
))
}
#[cfg(feature = "test-helpers")]
pub fn local_node_with_reader(snapshot_reader: SnapshotReader) -> Self {
let block_importer = fuel_core_importer::Config::new(false);
let latest_block = snapshot_reader.last_block_config();
let native_executor_version = latest_block
.map(|last_block| last_block.state_transition_version.saturating_add(1))
.unwrap_or(
fuel_core_types::blockchain::header::LATEST_STATE_TRANSITION_VERSION,
);
let utxo_validation = false;
let combined_db_config = CombinedDatabaseConfig {
#[cfg(feature = "rocksdb")]
database_config: crate::state::rocks_db::DatabaseConfig::config_for_tests(),
database_path: Default::default(),
#[cfg(feature = "rocksdb")]
database_type: DbType::RocksDb,
#[cfg(not(feature = "rocksdb"))]
database_type: DbType::InMemory,
#[cfg(feature = "rocksdb")]
state_rewind_policy:
crate::state::historical_rocksdb::StateRewindPolicy::RewindFullRange,
};
#[cfg(feature = "p2p")]
let network_name = snapshot_reader.chain_config().chain_name.clone();
let gas_price_config = GasPriceConfig::local_node();
const MAX_TXS_TTL: Duration = Duration::from_secs(60 * 100000000);
#[cfg(feature = "rpc")]
let rpc_config = None;
Self {
graphql_config: GraphQLConfig {
addr: std::net::SocketAddr::new(
std::net::Ipv4Addr::new(127, 0, 0, 1).into(),
0,
),
number_of_threads: 0,
database_batch_size: 100,
block_subscriptions_queue: 1000,
max_queries_depth: 16,
max_queries_complexity: 80000,
max_queries_recursive_depth: 16,
max_queries_resolver_recursive_depth: 1,
max_queries_directives: 10,
max_concurrent_queries: 1024,
request_body_bytes_limit: 16 * 1024 * 1024,
query_log_threshold_time: Duration::from_secs(2),
api_request_timeout: Duration::from_secs(60),
assemble_tx_dry_run_limit: 3,
assemble_tx_estimate_predicates_limit: 5,
costs: Default::default(),
required_fuel_block_height_tolerance: 10,
required_fuel_block_height_timeout: Duration::from_secs(30),
},
combined_db_config,
continue_on_error: false,
debug: true,
historical_execution: true,
allow_syscall: true,
expensive_subscriptions: true,
utxo_validation,
native_executor_version: Some(native_executor_version),
#[cfg(feature = "parallel-executor")]
executor_number_of_cores: NonZeroUsize::new(1).expect("1 is not zero"),
snapshot_reader,
block_production: Trigger::Instant,
leader_lock: None,
predefined_blocks_path: None,
txpool: TxPoolConfig {
utxo_validation,
max_txs_ttl: MAX_TXS_TTL,
..Default::default()
},
tx_status_manager: TxStatusManagerConfig {
subscription_ttl: MAX_TXS_TTL,
..Default::default()
},
block_producer: fuel_core_producer::Config {
..Default::default()
},
da_compression: DaCompressionMode::Disabled,
gas_price_config,
block_importer,
#[cfg(feature = "relayer")]
relayer: None,
#[cfg(feature = "p2p")]
p2p: Some(P2PConfig::<NotInitialized>::default(network_name.as_str())),
#[cfg(feature = "p2p")]
sync: fuel_core_sync::Config::default(),
#[cfg(feature = "p2p")]
pre_confirmation_signature_service:
fuel_core_poa::pre_confirmation_signature_service::config::Config::default(
),
#[cfg(feature = "shared-sequencer")]
shared_sequencer: fuel_core_shared_sequencer::Config::local_node(),
consensus_signer: SignMode::Key(fuel_core_types::secrecy::Secret::new(
fuel_core_chain_config::default_consensus_dev_key().into(),
)),
name: String::default(),
relayer_consensus_config: Default::default(),
min_connected_reserved_peers: 0,
time_until_synced: Duration::ZERO,
production_timeout: Duration::from_secs(20),
memory_pool_size: 4,
#[cfg(feature = "rpc")]
rpc_config,
}
}
pub fn make_config_consistent(mut self) -> Config {
if !self.debug && !self.utxo_validation {
tracing::warn!(
"The `utxo_validation` should be `true` with disabled `debug`"
);
self.utxo_validation = true;
}
if self.txpool.utxo_validation != self.utxo_validation {
tracing::warn!("The `utxo_validation` of `TxPool` was inconsistent");
self.txpool.utxo_validation = self.utxo_validation;
}
self
}
pub fn base_asset_id(&self) -> AssetId {
*self
.snapshot_reader
.chain_config()
.consensus_parameters
.base_asset_id()
}
pub fn chain_id(&self) -> ChainId {
self.snapshot_reader
.chain_config()
.consensus_parameters
.chain_id()
}
}
impl From<&Config> for fuel_core_poa::Config {
fn from(config: &Config) -> Self {
fuel_core_poa::Config {
trigger: config.block_production,
signer: config.consensus_signer.clone(),
metrics: false,
min_connected_reserved_peers: config.min_connected_reserved_peers,
time_until_synced: config.time_until_synced,
production_timeout: config.production_timeout,
chain_id: config
.snapshot_reader
.chain_config()
.consensus_parameters
.chain_id(),
}
}
}
#[cfg(feature = "p2p")]
impl From<&Config> for fuel_core_poa::pre_confirmation_signature_service::config::Config {
fn from(value: &Config) -> Self {
fuel_core_poa::pre_confirmation_signature_service::config::Config {
echo_delegation_interval: value
.pre_confirmation_signature_service
.echo_delegation_interval,
key_expiration_interval: value
.pre_confirmation_signature_service
.key_expiration_interval,
key_rotation_interval: value
.pre_confirmation_signature_service
.key_rotation_interval,
}
}
}
#[derive(
Clone, Copy, Debug, Display, Eq, PartialEq, EnumString, VariantNames, ValueEnum,
)]
#[strum(serialize_all = "kebab_case")]
pub enum DbType {
InMemory,
RocksDb,
}
#[derive(Clone, Debug)]
pub struct GasPriceConfig {
pub starting_exec_gas_price: u64,
pub exec_gas_price_change_percent: u16,
pub min_exec_gas_price: u64,
pub exec_gas_price_threshold_percent: u8,
pub da_committer_url: Option<url::Url>,
pub da_poll_interval: Option<Duration>,
pub da_gas_price_factor: NonZeroU64,
pub starting_recorded_height: Option<u32>,
pub min_da_gas_price: u64,
pub max_da_gas_price: u64,
pub max_da_gas_price_change_percent: u16,
pub da_gas_price_p_component: i64,
pub da_gas_price_d_component: i64,
pub gas_price_metrics: bool,
pub activity_normal_range_size: u16,
pub activity_capped_range_size: u16,
pub activity_decrease_range_size: u16,
pub block_activity_threshold: u8,
}
impl GasPriceConfig {
#[cfg(feature = "test-helpers")]
pub fn local_node() -> GasPriceConfig {
let starting_gas_price = 0;
let gas_price_change_percent = 0;
let min_gas_price = 0;
let gas_price_threshold_percent = 50;
let gas_price_metrics = false;
GasPriceConfig {
starting_exec_gas_price: starting_gas_price,
exec_gas_price_change_percent: gas_price_change_percent,
min_exec_gas_price: min_gas_price,
exec_gas_price_threshold_percent: gas_price_threshold_percent,
da_gas_price_factor: NonZeroU64::new(100).expect("100 is not zero"),
starting_recorded_height: None,
min_da_gas_price: 0,
max_da_gas_price: 1,
max_da_gas_price_change_percent: 0,
da_gas_price_p_component: 0,
da_gas_price_d_component: 0,
gas_price_metrics,
activity_normal_range_size: 0,
activity_capped_range_size: 0,
activity_decrease_range_size: 0,
da_committer_url: None,
block_activity_threshold: 0,
da_poll_interval: Some(Duration::from_secs(1)),
}
}
}
#[derive(Debug, Clone)]
pub struct DaCompressionConfig {
pub retention_duration: Duration,
pub metrics: bool,
pub starting_height: Option<NonZeroU32>,
}
#[derive(Debug, Clone)]
pub enum DaCompressionMode {
Disabled,
Enabled(DaCompressionConfig),
}