cfx_config/
configuration.rs

1// Copyright 2019 Conflux Foundation. All rights reserved.
2// Conflux is free software and distributed under GNU General Public License.
3// See http://www.gnu.org/licenses/
4
5use std::{collections::BTreeMap, convert::TryInto, path::PathBuf, sync::Arc};
6
7use cfx_rpc_builder::RpcModuleSelection;
8use lazy_static::*;
9use log::{error, warn};
10use parking_lot::RwLock;
11use rand::Rng;
12
13use cfx_addr::{cfx_addr_decode, Network};
14use cfx_executor::{machine::Machine, spec::CommonParams};
15use cfx_internal_common::{
16    ChainIdParams, ChainIdParamsInner, ChainIdParamsOneChainInner,
17};
18use cfx_parameters::{
19    block::DEFAULT_TARGET_BLOCK_GAS_LIMIT, tx_pool::TXPOOL_DEFAULT_NONCE_BITS,
20};
21use cfx_rpc_cfx_types::{
22    address::USE_SIMPLE_RPC_ADDRESS, apis::ApiSet, RpcImplConfiguration,
23};
24use cfx_storage::{
25    defaults::DEFAULT_DEBUG_SNAPSHOT_CHECKER_THREADS, storage_dir,
26    ConsensusParam, ProvideExtraSnapshotSyncConfig, StorageConfiguration,
27};
28use cfx_types::{
29    parse_hex_string, Address, AllChainID, Space, SpaceMap, H256, U256,
30};
31use cfxcore::{
32    block_data_manager::{DataManagerConfiguration, DbType},
33    block_parameters::*,
34    cache_config::{
35        DEFAULT_INVALID_BLOCK_HASH_CACHE_SIZE_IN_COUNT,
36        DEFAULT_LEDGER_CACHE_SIZE,
37        DEFAULT_TARGET_DIFFICULTIES_CACHE_SIZE_IN_COUNT,
38    },
39    consensus::{
40        consensus_inner::consensus_executor::ConsensusExecutionConfiguration,
41        pivot_hint::PivotHintConfig, ConsensusConfig, ConsensusInnerConfig,
42    },
43    consensus_internal_parameters::*,
44    consensus_parameters::*,
45    light_protocol::LightNodeConfiguration,
46    sync::{ProtocolConfiguration, StateSyncConfiguration, SyncGraphConfig},
47    sync_parameters::*,
48    transaction_pool::TxPoolConfig,
49    NodeType,
50};
51use diem_types::term_state::{
52    pos_state_config::PosStateConfig, IN_QUEUE_LOCKED_VIEWS,
53    OUT_QUEUE_LOCKED_VIEWS, ROUND_PER_TERM, TERM_ELECTED_SIZE, TERM_MAX_SIZE,
54};
55use jsonrpsee::server::ServerConfigBuilder;
56use metrics::MetricsConfiguration;
57use network::DiscoveryConfiguration;
58use primitives::block_header::CIP112_TRANSITION_HEIGHT;
59use txgen::TransactionGeneratorConfig;
60
61use crate::{HttpConfiguration, TcpConfiguration, WsConfiguration};
62
63lazy_static! {
64    pub static ref CHAIN_ID: RwLock<Option<ChainIdParams>> = Default::default();
65}
66const BLOCK_DB_DIR_NAME: &str = "blockchain_db";
67const NET_CONFIG_DB_DIR_NAME: &str = "net_config";
68
69// usage:
70// ```
71// build_config! {
72//     {
73//         (name, (type), default_value)
74//         ...
75//     }
76//     {
77//         (name, (type), default_value, converter)
78//     }
79// }
80// ```
81// `converter` is a function used to convert a provided String to `Result<type,
82// String>`. For each entry, field `name` of type `type` will be created in
83// `RawConfiguration`, and it will be assigned to the value passed through
84// commandline argument or configuration file. Commandline argument will
85// override the configuration file if the parameter is given in both.
86build_config! {
87    {
88        // Configs are grouped by section. Within one section configs should
89        // be kept in alphabetical order for the sake of indexing and maintenance.
90        //
91        // Some preset configurations.
92        //
93        // For both `test` and `dev` modes, we will
94        //     * Set initial difficulty to 4
95        //     * Allow calling test and debug rpc from public port
96        //
97        // `test` mode is for Conflux testing and debugging, we will
98        //     * Add latency to peer connections
99        //     * Skip handshake encryption check
100        //     * Skip header timestamp verification
101        //     * Handle NewBlockHash even in catch-up mode
102        //     * Allow data propagation test
103        //     * Allow setting genesis accounts and generate tx from secrets
104        //
105        // `dev` mode is for users to run a single node that automatically
106        //     generates blocks with fixed intervals
107        //     * You are expected to also set `jsonrpc_ws_port`, `jsonrpc_tcp_port`,
108        //       and `jsonrpc_http_port` if you want RPC functionalities.
109        //     * generate blocks automatically without PoW.
110        //     * Skip catch-up mode even there is no peer
111        //
112        (mode, (Option<String>), None)
113        // Development related section.
114        (debug_invalid_state_root, (bool), false)
115        (debug_invalid_state_root_epoch, (Option<String>), None)
116        (debug_dump_dir_invalid_state_root, (String), "./storage_db/debug_dump_invalid_state_root/".to_string())
117        // Controls block generation speed.
118        // Only effective in `dev` mode
119        (dev_block_interval_ms, (Option<u64>), None)
120        (dev_pack_tx_immediately, (Option<bool>), None)
121        (enable_state_expose, (bool), false)
122        (generate_tx, (bool), false)
123        (generate_tx_period_us, (Option<u64>), Some(100_000))
124        (log_conf, (Option<String>), None)
125        (log_file, (Option<String>), None)
126        (max_block_size_in_bytes, (usize), MAX_BLOCK_SIZE_IN_BYTES)
127        (evm_transaction_block_ratio,(u64),EVM_TRANSACTION_BLOCK_RATIO)
128        (evm_transaction_gas_ratio,(u64),EVM_TRANSACTION_GAS_RATIO)
129        (metrics_enabled, (bool), false)
130        (metrics_influxdb_host, (Option<String>), None)
131        (metrics_influxdb_db, (String), "conflux".into())
132        (metrics_influxdb_username, (Option<String>), None)
133        (metrics_influxdb_password, (Option<String>), None)
134        (metrics_influxdb_node, (Option<String>), None)
135        (metrics_output_file, (Option<String>), None)
136        (metrics_report_interval_ms, (u64), 3_000)
137        (metrics_prometheus_listen_addr, (Option<String>), None)
138        (profiling_listen_addr, (Option<String>), None)
139        (rocksdb_disable_wal, (bool), false)
140        (txgen_account_count, (usize), 10)
141
142        // Genesis section.
143        (adaptive_weight_beta, (u64), ADAPTIVE_WEIGHT_DEFAULT_BETA)
144        (anticone_penalty_ratio, (u64), ANTICONE_PENALTY_RATIO)
145        (chain_id, (Option<u32>), None)
146        (evm_chain_id, (Option<u32>), None)
147        (execute_genesis, (bool), true)
148        (default_transition_time, (Option<u64>), None)
149        // Snapshot Epoch Count is a consensus parameter. This flag overrides
150        // the parameter, which only take effect in `dev` mode.
151        (dev_snapshot_epoch_count, (u32), SNAPSHOT_EPOCHS_CAPACITY)
152        (era_epoch_count, (u64), ERA_DEFAULT_EPOCH_COUNT)
153        (heavy_block_difficulty_ratio, (u64), HEAVY_BLOCK_DEFAULT_DIFFICULTY_RATIO)
154        (genesis_accounts, (Option<String>), None)
155        (genesis_evm_secrets, (Option<String>), None)
156        (genesis_secrets, (Option<String>), None)
157        (pivot_hint_path, (Option<String>), None)
158        (pivot_hint_checksum, (Option<String>), None)
159        (initial_difficulty, (Option<u64>), None)
160        (referee_bound, (usize), REFEREE_DEFAULT_BOUND)
161        (timer_chain_beta, (u64), TIMER_CHAIN_DEFAULT_BETA)
162        (timer_chain_block_difficulty_ratio, (u64), TIMER_CHAIN_BLOCK_DEFAULT_DIFFICULTY_RATIO)
163        // FIXME: this is part of spec.
164        (transaction_epoch_bound, (u64), TRANSACTION_DEFAULT_EPOCH_BOUND)
165
166
167        // Hardfork section
168        // V1.1
169        (tanzanite_transition_height, (u64), TANZANITE_HEIGHT)
170        // V2.0
171        (hydra_transition_number, (Option<u64>), None)
172        (hydra_transition_height, (Option<u64>), None)
173        (cip43_init_end_number, (Option<u64>), None)
174        (cip78_patch_transition_number,(Option<u64>),None)
175        (cip90_transition_height,(Option<u64>),None)
176        (cip90_transition_number,(Option<u64>),None)
177        // V2.1
178        (dao_vote_transition_number, (Option<u64>), None)
179        (dao_vote_transition_height, (Option<u64>), None)
180        (cip105_transition_number, (Option<u64>), None)
181        (params_dao_vote_period, (u64), DAO_PARAMETER_VOTE_PERIOD)
182        // V2.2
183        (sigma_fix_transition_number, (Option<u64>), None)
184        // V2.3
185        (cip107_transition_number, (Option<u64>), None)
186        (cip112_transition_height, (Option<u64>), None)
187        (cip118_transition_number, (Option<u64>), None)
188        (cip119_transition_number, (Option<u64>), None)
189        // V2.4
190        (base_fee_burn_transition_number, (Option<u64>), None)
191        (base_fee_burn_transition_height, (Option<u64>), None)
192        (cip1559_transition_height, (Option<u64>), None)
193        (cancun_opcodes_transition_number, (Option<u64>), None)
194        (min_native_base_price, (Option<u64>), None)
195        (min_eth_base_price, (Option<u64>), None)
196        // V2.5
197        (c2_fix_transition_height, (Option<u64>), None)
198        // V3.0
199        (eoa_code_transition_height, (Option<u64>), None)
200        (cip151_transition_height, (Option<u64>), None)
201        (cip645_transition_height, (Option<u64>), None)
202        (cip145_fix_transition_height, (Option<u64>), None)
203        // For test only
204        (align_evm_transition_height, (u64), u64::MAX)
205        // V3.1
206        (cip166_transition_height, (Option<u64>), None)
207        (osaka_opcode_transition_height, (Option<u64>), None)
208
209
210
211        // Mining section.
212        (mining_author, (Option<String>), None)
213        (mining_type, (Option<String>), None)
214        (stratum_listen_address, (String), "127.0.0.1".into())
215        (stratum_port, (u16), 32525)
216        (stratum_secret, (Option<String>), None)
217        (use_octopus_in_test_mode, (bool), false)
218        (pow_problem_window_size, (usize), 1)
219
220        // Network section.
221        (jsonrpc_local_tcp_port, (Option<u16>), None)
222        (jsonrpc_local_http_port, (Option<u16>), None)
223        (jsonrpc_local_ws_port, (Option<u16>), None)
224        (jsonrpc_ws_port, (Option<u16>), None)
225        (jsonrpc_tcp_port, (Option<u16>), None)
226        (jsonrpc_http_port, (Option<u16>), None)
227        (jsonrpc_http_threads, (Option<usize>), None)
228        (jsonrpc_cors, (Option<String>), None)
229        (jsonrpc_http_keep_alive, (bool), false)
230        (jsonrpc_ws_max_payload_bytes, (usize), 30 * 1024 * 1024)
231        (jsonrpc_http_eth_port, (Option<u16>), None)
232        (jsonrpc_ws_eth_port, (Option<u16>), None)
233        (jsonrpc_max_request_body_size, (u32), 10 * 1024 * 1024)
234        (jsonrpc_max_response_body_size, (u32), 10 * 1024 * 1024)
235        (jsonrpc_max_connections, (u32), 100)
236        (jsonrpc_max_subscriptions_per_connection, (u32), 1024)
237        (jsonrpc_message_buffer_capacity, (u32), 1024)
238        // The network_id, if unset, defaults to the chain_id.
239        // Only override the network_id for local experiments,
240        // when user would like to keep the existing blockchain data
241        // but disconnect from the public network.
242        (network_id, (Option<u64>), None)
243        (rpc_enable_metrics, (bool), false)
244        (tcp_port, (u16), 32323)
245        (public_tcp_port, (Option<u16>), None)
246        (public_address, (Option<String>), None)
247        (udp_port, (Option<u16>), Some(32323))
248        (max_estimation_gas_limit, (Option<u64>), None)
249        (rpc_address_simple_mode, (bool), false)
250
251        // Network parameters section.
252        (blocks_request_timeout_ms, (u64), 20_000)
253        (check_request_period_ms, (u64), 1_000)
254        (chunk_size_byte, (u64), DEFAULT_CHUNK_SIZE)
255        (demote_peer_for_timeout, (bool), false)
256        (dev_allow_phase_change_without_peer, (bool), false)
257        (egress_queue_capacity, (usize), 256)
258        (egress_min_throttle, (usize), 10)
259        (egress_max_throttle, (usize), 64)
260        (expire_block_gc_period_s, (u64), 900)
261        (headers_request_timeout_ms, (u64), 10_000)
262        (heartbeat_period_interval_ms, (u64), 30_000)
263        (heartbeat_timeout_ms, (u64), 180_000)
264        (inflight_pending_tx_index_maintain_timeout_ms, (u64), 30_000)
265        (max_allowed_timeout_in_observing_period, (u64), 10)
266        (max_chunk_number_in_manifest, (usize), 500)
267        (max_downloading_chunks, (usize), 8)
268        (max_downloading_chunk_attempts, (usize), 5)
269        (max_downloading_manifest_attempts, (usize), 5)
270        (max_handshakes, (usize), 64)
271        (max_incoming_peers, (usize), 64)
272        (max_inflight_request_count, (u64), 64)
273        (max_outgoing_peers, (usize), 8)
274        (max_outgoing_peers_archive, (Option<usize>), None)
275        (max_peers_tx_propagation, (usize), 128)
276        (max_unprocessed_block_size_mb, (usize), (128))
277        (min_peers_tx_propagation, (usize), 8)
278        (min_phase_change_normal_peer_count, (usize), 3)
279        (received_tx_index_maintain_timeout_ms, (u64), 300_000)
280        (request_block_with_public, (bool), false)
281        (send_tx_period_ms, (u64), 1300)
282        (snapshot_candidate_request_timeout_ms, (u64), 10_000)
283        (snapshot_chunk_request_timeout_ms, (u64), 30_000)
284        (snapshot_manifest_request_timeout_ms, (u64), 30_000)
285        (sync_expire_block_timeout_s, (u64), 7200)
286        (throttling_conf, (Option<String>), None)
287        (timeout_observing_period_s, (u64), 600)
288        (transaction_request_timeout_ms, (u64), 30_000)
289        (tx_maintained_for_peer_timeout_ms, (u64), 600_000)
290
291        // Peer management section.
292        (bootnodes, (Option<String>), None)
293        (discovery_discover_node_count, (u32), 16)
294        (discovery_expire_time_s, (u64), 20)
295        (discovery_fast_refresh_timeout_ms, (u64), 10_000)
296        (discovery_find_node_timeout_ms, (u64), 2_000)
297        (discovery_housekeeping_timeout_ms, (u64), 1_000)
298        (discovery_max_nodes_ping, (usize), 32)
299        (discovery_ping_timeout_ms, (u64), 2_000)
300        (discovery_round_timeout_ms, (u64), 500)
301        (discovery_throttling_interval_ms, (u64), 1_000)
302        (discovery_throttling_limit_ping, (usize), 20)
303        (discovery_throttling_limit_find_nodes, (usize), 10)
304        (enable_discovery, (bool), true)
305        (netconf_dir, (Option<String>), None)
306        (net_key, (Option<String>), None)
307        (node_table_timeout_s, (u64), 300)
308        (node_table_promotion_timeout_s, (u64), 3 * 24 * 3600)
309        (session_ip_limits, (String), "1,8,4,2".into())
310        (subnet_quota, (usize), 128)
311
312        // Transaction cache/transaction pool section.
313        (tx_cache_index_maintain_timeout_ms, (u64), 300_000)
314        (tx_pool_size, (usize), 50_000)
315        (tx_pool_min_native_tx_gas_price, (Option<u64>), None)
316        (tx_pool_min_eth_tx_gas_price, (Option<u64>), None)
317        (tx_pool_nonce_bits, (usize), TXPOOL_DEFAULT_NONCE_BITS)
318        (tx_pool_allow_gas_over_half_block, (bool), false)
319        (max_packing_batch_gas_limit, (u64), 3_000_000)
320        (max_packing_batch_size, (usize), 50)
321        (packing_pool_degree, (u8), 4)
322
323
324        // Storage Section.
325        (additional_maintained_snapshot_count, (u32), 1)
326        // `None` for `additional_maintained*` means the data is never garbage collected.
327        (additional_maintained_block_body_epoch_count, (Option<usize>), None)
328        (additional_maintained_execution_result_epoch_count, (Option<usize>), None)
329        (additional_maintained_reward_epoch_count, (Option<usize>), None)
330        (additional_maintained_trace_epoch_count, (Option<usize>), None)
331        (additional_maintained_transaction_index_epoch_count, (Option<usize>), None)
332        (block_cache_gc_period_ms, (u64), 5_000)
333        (block_db_dir, (Option<String>), None)
334        (block_db_type, (String), "rocksdb".to_string())
335        (checkpoint_gc_time_in_era_count, (f64), 0.5)
336        // The conflux data dir, if unspecified, is the workdir where conflux is started.
337        (conflux_data_dir, (String), "./blockchain_data".to_string())
338        (enable_single_mpt_storage, (bool), false)
339        (ledger_cache_size, (usize), DEFAULT_LEDGER_CACHE_SIZE)
340        (invalid_block_hash_cache_size_in_count, (usize), DEFAULT_INVALID_BLOCK_HASH_CACHE_SIZE_IN_COUNT)
341        (rocksdb_cache_size, (Option<usize>), Some(128))
342        (rocksdb_compaction_profile, (Option<String>), None)
343        (storage_delta_mpts_cache_recent_lfu_factor, (f64), cfx_storage::defaults::DEFAULT_DELTA_MPTS_CACHE_RECENT_LFU_FACTOR)
344        (storage_delta_mpts_cache_size, (u32), cfx_storage::defaults::DEFAULT_DELTA_MPTS_CACHE_SIZE)
345        (storage_delta_mpts_cache_start_size, (u32), cfx_storage::defaults::DEFAULT_DELTA_MPTS_CACHE_START_SIZE)
346        (storage_delta_mpts_node_map_vec_size, (u32), cfx_storage::defaults::MAX_CACHED_TRIE_NODES_R_LFU_COUNTER)
347        (storage_delta_mpts_slab_idle_size, (u32), cfx_storage::defaults::DEFAULT_DELTA_MPTS_SLAB_IDLE_SIZE)
348        (storage_single_mpt_cache_size, (u32), cfx_storage::defaults::DEFAULT_DELTA_MPTS_CACHE_SIZE * 2)
349        (storage_single_mpt_cache_start_size, (u32), cfx_storage::defaults::DEFAULT_DELTA_MPTS_CACHE_START_SIZE * 2)
350        (storage_single_mpt_slab_idle_size, (u32), cfx_storage::defaults::DEFAULT_DELTA_MPTS_SLAB_IDLE_SIZE * 2)
351        (storage_max_open_snapshots, (u16), cfx_storage::defaults::DEFAULT_MAX_OPEN_SNAPSHOTS)
352        (storage_max_open_mpt_count, (u32), cfx_storage::defaults::DEFAULT_MAX_OPEN_MPT)
353        (strict_tx_index_gc, (bool), true)
354        (sync_state_starting_epoch, (Option<u64>), None)
355        (sync_state_epoch_gap, (Option<u64>), None)
356        (target_difficulties_cache_size_in_count, (usize), DEFAULT_TARGET_DIFFICULTIES_CACHE_SIZE_IN_COUNT)
357
358        // General/Unclassified section.
359        (account_provider_refresh_time_ms, (u64), 1000)
360        (check_phase_change_period_ms, (u64), 1000)
361        (enable_optimistic_execution, (bool), true)
362        (future_block_buffer_capacity, (usize), 32768)
363        (get_logs_filter_max_limit, (Option<usize>), None)
364        (get_logs_filter_max_epoch_range, (Option<u64>), None)
365        (get_logs_filter_max_block_number_range, (Option<u64>), None)
366        (get_logs_epoch_batch_size, (usize), 32)
367        (max_trans_count_received_in_catch_up, (u64), 60_000)
368        (persist_tx_index, (bool), false)
369        (persist_block_number_index, (bool), true)
370        (print_memory_usage_period_s, (Option<u64>), None)
371        (target_block_gas_limit, (u64), DEFAULT_TARGET_BLOCK_GAS_LIMIT)
372        (executive_trace, (bool), false)
373        (check_status_genesis, (bool), true)
374        (packing_gas_limit_block_count, (u64), 10)
375        (poll_lifetime_in_seconds, (Option<u32>), None)
376
377        // TreeGraph Section.
378        (is_consortium, (bool), false)
379        (pos_config_path, (Option<String>), Some("./pos_config/pos_config.yaml".to_string()))
380        (pos_genesis_pivot_decision, (Option<H256>), None)
381        (vrf_proposal_threshold, (U256), U256::from_str("1111111111111100000000000000000000000000000000000000000000000000").unwrap())
382        // Deferred epoch count before a confirmed epoch.
383        (pos_pivot_decision_defer_epoch_count, (u64), 50)
384        (cip113_pivot_decision_defer_epoch_count, (u64), 20)
385        (cip113_transition_height, (u64), u64::MAX)
386        (pos_reference_enable_height, (u64), u64::MAX)
387        (pos_initial_nodes_path, (String), "./pos_config/initial_nodes.json".to_string())
388        (pos_private_key_path, (String), "./pos_config/pos_key".to_string())
389        (pos_round_per_term, (u64), ROUND_PER_TERM)
390        (pos_term_max_size, (usize), TERM_MAX_SIZE)
391        (pos_term_elected_size, (usize), TERM_ELECTED_SIZE)
392        (pos_in_queue_locked_views, (u64), IN_QUEUE_LOCKED_VIEWS)
393        (pos_out_queue_locked_views, (u64), OUT_QUEUE_LOCKED_VIEWS)
394        (pos_cip99_transition_view, (u64), u64::MAX)
395        (pos_cip99_in_queue_locked_views, (u64), IN_QUEUE_LOCKED_VIEWS)
396        (pos_cip99_out_queue_locked_views, (u64), OUT_QUEUE_LOCKED_VIEWS)
397        (nonce_limit_transition_view, (u64), u64::MAX)
398        (pos_cip136_transition_view, (u64), u64::MAX)
399        (pos_cip136_in_queue_locked_views, (u64), IN_QUEUE_LOCKED_VIEWS)
400        (pos_cip136_out_queue_locked_views, (u64), OUT_QUEUE_LOCKED_VIEWS)
401        (pos_cip136_round_per_term, (u64), ROUND_PER_TERM)
402        (pos_cip156_transition_view, (u64), u64::MAX)
403        // 6 months with 30s rounds
404        (pos_cip156_dispute_locked_views, (u64), 6 * 30 * 24 * 60 * 2)
405        (dev_pos_private_key_encryption_password, (Option<String>), None)
406        (pos_started_as_voter, (bool), true)
407
408        // Light node section
409        (ln_epoch_request_batch_size, (Option<usize>), None)
410        (ln_epoch_request_timeout_sec, (Option<u64>), None)
411        (ln_header_request_batch_size, (Option<usize>), None)
412        (ln_header_request_timeout_sec, (Option<u64>), None)
413        (ln_max_headers_in_flight, (Option<usize>), None)
414        (ln_max_parallel_epochs_to_request, (Option<usize>), None)
415        (ln_num_epochs_to_request, (Option<usize>), None)
416        (ln_num_waiting_headers_threshold, (Option<usize>), None)
417        (keep_snapshot_before_stable_checkpoint, (bool), true)
418        (force_recompute_height_during_construct_pivot, (Option<u64>), None)
419
420        // The snapshot database consists of two tables: snapshot_key_value and snapshot_mpt. However, the size of snapshot_mpt is significantly larger than that of snapshot_key_value.
421        // When the configuration parameter use_isolated_db_for_mpt_table is set to true, the snapshot_mpt table will be located in a separate database.
422        (use_isolated_db_for_mpt_table, (bool), false)
423        // The use_isolated_db_for_mpt_table_height parameter is utilized to determine when to enable the use_isolated_db_for_mpt_table option.
424        //  None: enabled since the next snapshot
425        //  u64: enabled since the specified height
426        (use_isolated_db_for_mpt_table_height, (Option<u64>), None)
427        // Recover the latest MPT snapshot from the era checkpoint
428        (recovery_latest_mpt_snapshot, (bool), false)
429        (keep_era_genesis_snapshot, (bool), true)
430
431        // This is designed for fast node catch-up but has not been thoroughly tested. Do not use it in production environments.
432        (backup_mpt_snapshot, (bool), true)
433    }
434    {
435        // Development related section.
436        (
437            log_level, (LevelFilter), LevelFilter::Info, |l| {
438                LevelFilter::from_str(l)
439                    .map_err(|_| format!("Invalid log level: {}", l))
440            }
441        )
442
443        // Genesis Section
444        // chain_id_params describes a complex setup where chain id can change over epochs.
445        // Usually this is needed to describe forks. This config overrides chain_id.
446        (chain_id_params, (Option<ChainIdParamsOneChainInner>), None,
447            ChainIdParamsOneChainInner::parse_config_str)
448
449        // Storage section.
450        (provide_more_snapshot_for_sync,
451            (Vec<ProvideExtraSnapshotSyncConfig>),
452            vec![ProvideExtraSnapshotSyncConfig::StableCheckpoint],
453            ProvideExtraSnapshotSyncConfig::parse_config_list)
454        (node_type, (Option<NodeType>), None, NodeType::from_str)
455        (public_rpc_apis, (ApiSet), ApiSet::Safe, ApiSet::from_str)
456        (public_evm_rpc_apis, (RpcModuleSelection), RpcModuleSelection::Evm, RpcModuleSelection::from_str)
457        (single_mpt_space, (Option<Space>), None, Space::from_str)
458    }
459}
460
461#[derive(Debug, Clone)]
462pub struct Configuration {
463    pub raw_conf: RawConfiguration,
464}
465
466impl Default for Configuration {
467    fn default() -> Self {
468        Configuration {
469            raw_conf: Default::default(),
470        }
471    }
472}
473
474impl Configuration {
475    pub fn parse(matches: &clap::ArgMatches) -> Result<Configuration, String> {
476        let mut config = Configuration::default();
477        config.raw_conf = RawConfiguration::parse(matches)?;
478
479        if matches.get_flag("archive") {
480            config.raw_conf.node_type = Some(NodeType::Archive);
481        } else if matches.get_flag("full") {
482            config.raw_conf.node_type = Some(NodeType::Full);
483        } else if matches.get_flag("light") {
484            config.raw_conf.node_type = Some(NodeType::Light);
485        }
486
487        CIP112_TRANSITION_HEIGHT
488            .set(config.raw_conf.cip112_transition_height.unwrap_or(u64::MAX))
489            .expect("called once");
490
491        USE_SIMPLE_RPC_ADDRESS
492            .set(config.raw_conf.rpc_address_simple_mode)
493            .expect("called once");
494
495        Ok(config)
496    }
497
498    pub fn from_file(config_path: &str) -> Result<Configuration, String> {
499        Ok(Configuration {
500            raw_conf: RawConfiguration::from_file(config_path)?,
501        })
502    }
503
504    fn network_id(&self) -> u64 {
505        match self.raw_conf.network_id {
506            Some(x) => x,
507            // If undefined, the network id is set to the native space chain_id
508            // at genesis.
509            None => {
510                self.chain_id_params()
511                    .read()
512                    .get_chain_id(/* epoch_number = */ 0)
513                    .in_native_space() as u64
514            }
515        }
516    }
517
518    pub fn net_config(&self) -> Result<NetworkConfiguration, String> {
519        let mut network_config = NetworkConfiguration::new_with_port(
520            self.network_id(),
521            self.raw_conf.tcp_port,
522            self.discovery_protocol(),
523        );
524
525        network_config.is_consortium = self.raw_conf.is_consortium;
526        network_config.discovery_enabled = self.raw_conf.enable_discovery;
527        network_config.boot_nodes = to_bootnodes(&self.raw_conf.bootnodes)
528            .map_err(|e| format!("failed to parse bootnodes: {}", e))?;
529        network_config.config_path = Some(match &self.raw_conf.netconf_dir {
530            Some(dir) => dir.clone(),
531            None => Path::new(&self.raw_conf.conflux_data_dir)
532                .join(NET_CONFIG_DB_DIR_NAME)
533                .into_os_string()
534                .into_string()
535                .unwrap(),
536        });
537        network_config.use_secret =
538            self.raw_conf.net_key.as_ref().map(|sec_str| {
539                parse_hex_string(sec_str)
540                    .expect("net_key is not a valid secret string")
541            });
542        if let Some(addr) = self.raw_conf.public_address.clone() {
543            let addr_ip = if let Some(idx) = addr.find(":") {
544                warn!("Public address configuration should not contain port! (val = {}). Content after ':' is ignored.", &addr);
545                (&addr[0..idx]).to_string()
546            } else {
547                addr
548            };
549            let addr_with_port = match self.raw_conf.public_tcp_port {
550                Some(port) => addr_ip + ":" + &port.to_string(),
551                None => addr_ip + ":" + &self.raw_conf.tcp_port.to_string(),
552            };
553            network_config.public_address =
554                match addr_with_port.to_socket_addrs().map(|mut i| i.next()) {
555                    Ok(sock_addr) => sock_addr,
556                    Err(_e) => {
557                        warn!("public_address in config is invalid");
558                        None
559                    }
560                };
561        }
562        network_config.node_table_timeout =
563            Duration::from_secs(self.raw_conf.node_table_timeout_s);
564        network_config.connection_lifetime_for_promotion =
565            Duration::from_secs(self.raw_conf.node_table_promotion_timeout_s);
566        network_config.test_mode = self.is_test_mode();
567        network_config.subnet_quota = self.raw_conf.subnet_quota;
568        network_config.session_ip_limit_config =
569            self.raw_conf.session_ip_limits.clone().try_into().map_err(
570                |e| format!("failed to parse session ip limit config: {}", e),
571            )?;
572        network_config.fast_discovery_refresh_timeout = Duration::from_millis(
573            self.raw_conf.discovery_fast_refresh_timeout_ms,
574        );
575        network_config.discovery_round_timeout =
576            Duration::from_millis(self.raw_conf.discovery_round_timeout_ms);
577        network_config.housekeeping_timeout = Duration::from_millis(
578            self.raw_conf.discovery_housekeeping_timeout_ms,
579        );
580        network_config.max_handshakes = self.raw_conf.max_handshakes;
581        network_config.max_incoming_peers = self.raw_conf.max_incoming_peers;
582        network_config.max_outgoing_peers = self.raw_conf.max_outgoing_peers;
583        network_config.max_outgoing_peers_archive =
584            self.raw_conf.max_outgoing_peers_archive.unwrap_or(0);
585        Ok(network_config)
586    }
587
588    pub fn cache_config(&self) -> CacheConfig {
589        let mut cache_config = CacheConfig::default();
590        cache_config.ledger = self.raw_conf.ledger_cache_size;
591        cache_config.invalid_block_hashes_cache_size_in_count =
592            self.raw_conf.invalid_block_hash_cache_size_in_count;
593        cache_config.target_difficulties_cache_size_in_count =
594            self.raw_conf.target_difficulties_cache_size_in_count;
595        cache_config
596    }
597
598    pub fn db_config(&self) -> (PathBuf, DatabaseConfig) {
599        let db_dir: PathBuf = match &self.raw_conf.block_db_dir {
600            Some(dir) => dir.into(),
601            None => Path::new(&self.raw_conf.conflux_data_dir)
602                .join(BLOCK_DB_DIR_NAME),
603        };
604        if let Err(e) = fs::create_dir_all(&db_dir) {
605            panic!("Error creating database directory: {:?}", e);
606        }
607
608        let compact_profile =
609            match self.raw_conf.rocksdb_compaction_profile.as_ref() {
610                Some(p) => db::DatabaseCompactionProfile::from_str(p).unwrap(),
611                None => db::DatabaseCompactionProfile::default(),
612            };
613        let db_config = db::db_config(
614            &db_dir,
615            self.raw_conf.rocksdb_cache_size.clone(),
616            compact_profile,
617            NUM_COLUMNS.clone(),
618            self.raw_conf.rocksdb_disable_wal,
619        );
620        (db_dir, db_config)
621    }
622
623    pub fn chain_id_params(&self) -> ChainIdParams {
624        if CHAIN_ID.read().is_none() {
625            let mut to_init = CHAIN_ID.write();
626            if to_init.is_none() {
627                if let Some(_chain_id_params) = &self.raw_conf.chain_id_params {
628                    unreachable!("Upgradable ChainId is not ready.")
629                // *to_init = Some(ChainIdParamsInner::new_from_inner(
630                //     chain_id_params,
631                // ))
632                } else {
633                    let chain_id = self
634                        .raw_conf
635                        .chain_id
636                        .unwrap_or_else(|| rand::rng().random());
637                    let evm_chain_id =
638                        self.raw_conf.evm_chain_id.unwrap_or(chain_id);
639                    *to_init = Some(ChainIdParamsInner::new_simple(
640                        AllChainID::new(chain_id, evm_chain_id),
641                    ));
642                }
643            }
644        }
645        CHAIN_ID.read().as_ref().unwrap().clone()
646    }
647
648    pub fn consensus_config(&self) -> ConsensusConfig {
649        let enable_optimistic_execution = if DEFERRED_STATE_EPOCH_COUNT <= 1 {
650            false
651        } else {
652            self.raw_conf.enable_optimistic_execution
653        };
654        let pivot_hint_conf = match (
655            &self.raw_conf.pivot_hint_path,
656            &self.raw_conf.pivot_hint_checksum,
657        ) {
658            (Some(path), Some(checksum)) => {
659                let checksum = H256::from_str(checksum)
660                    .expect("Cannot parse `pivot_hint_checksum` as hex string");
661                Some(PivotHintConfig::new(path, checksum))
662            }
663            (None, None) => None,
664            _ => {
665                panic!("`pivot_hint_path` and `pivot_hint_checksum` must be both set or both unset");
666            }
667        };
668        let mut conf = ConsensusConfig {
669            chain_id: self.chain_id_params(),
670            inner_conf: ConsensusInnerConfig {
671                adaptive_weight_beta: self.raw_conf.adaptive_weight_beta,
672                heavy_block_difficulty_ratio: self
673                    .raw_conf
674                    .heavy_block_difficulty_ratio,
675                timer_chain_block_difficulty_ratio: self
676                    .raw_conf
677                    .timer_chain_block_difficulty_ratio,
678                timer_chain_beta: self.raw_conf.timer_chain_beta,
679                era_epoch_count: self.raw_conf.era_epoch_count,
680                enable_optimistic_execution,
681                enable_state_expose: self.raw_conf.enable_state_expose,
682                pos_pivot_decision_defer_epoch_count: self.raw_conf.pos_pivot_decision_defer_epoch_count,
683                cip113_pivot_decision_defer_epoch_count: self.raw_conf.cip113_pivot_decision_defer_epoch_count,
684                cip113_transition_height: self.raw_conf.cip113_transition_height,
685                debug_dump_dir_invalid_state_root: if self
686                    .raw_conf
687                    .debug_invalid_state_root
688                {
689                    Some(
690                        self.raw_conf.debug_dump_dir_invalid_state_root.clone(),
691                    )
692                } else {
693                    None
694                },
695
696                debug_invalid_state_root_epoch: match &self
697                    .raw_conf
698                    .debug_invalid_state_root_epoch
699                {
700                    Some(epoch_hex) => {
701                        Some(H256::from_str(&epoch_hex).expect("debug_invalid_state_root_epoch byte length is incorrect."))
702                    }
703                    None => None,
704                },
705                force_recompute_height_during_construct_pivot: self.raw_conf.force_recompute_height_during_construct_pivot,
706                recovery_latest_mpt_snapshot: self.raw_conf.recovery_latest_mpt_snapshot,
707                use_isolated_db_for_mpt_table: self.raw_conf.use_isolated_db_for_mpt_table,
708            },
709            bench_mode: false,
710            transaction_epoch_bound: self.raw_conf.transaction_epoch_bound,
711            referee_bound: self.raw_conf.referee_bound,
712            get_logs_epoch_batch_size: self.raw_conf.get_logs_epoch_batch_size,
713            get_logs_filter_max_epoch_range: self.raw_conf.get_logs_filter_max_epoch_range,
714            get_logs_filter_max_block_number_range: self.raw_conf.get_logs_filter_max_block_number_range,
715            get_logs_filter_max_limit: self.raw_conf.get_logs_filter_max_limit,
716            sync_state_starting_epoch: self.raw_conf.sync_state_starting_epoch,
717            sync_state_epoch_gap: self.raw_conf.sync_state_epoch_gap,
718            pivot_hint_conf,
719        };
720        match self.raw_conf.node_type {
721            Some(NodeType::Archive) => {
722                if conf.sync_state_starting_epoch.is_none() {
723                    conf.sync_state_starting_epoch = Some(0);
724                }
725            }
726            _ => {
727                if conf.sync_state_epoch_gap.is_none() {
728                    conf.sync_state_epoch_gap =
729                        Some(CATCH_UP_EPOCH_LAG_THRESHOLD);
730                }
731            }
732        }
733        conf
734    }
735
736    pub fn pow_config(&self) -> ProofOfWorkConfig {
737        let stratum_secret =
738            self.raw_conf.stratum_secret.as_ref().map(|hex_str| {
739                parse_hex_string(hex_str)
740                    .expect("Stratum secret should be 64-digit hex string")
741            });
742
743        ProofOfWorkConfig::new(
744            self.is_test_or_dev_mode(),
745            self.raw_conf.use_octopus_in_test_mode,
746            self.raw_conf.mining_type.as_ref().map_or_else(
747                || {
748                    // Enable stratum implicitly if `mining_author` is set.
749                    if self.raw_conf.mining_author.is_some() {
750                        "stratum"
751                    } else {
752                        "disable"
753                    }
754                },
755                |s| s.as_str(),
756            ),
757            self.raw_conf.initial_difficulty,
758            self.raw_conf.stratum_listen_address.clone(),
759            self.raw_conf.stratum_port,
760            stratum_secret,
761            self.raw_conf.pow_problem_window_size,
762            self.common_params().transition_heights.cip86,
763        )
764    }
765
766    pub fn verification_config(
767        &self, machine: Arc<Machine>,
768    ) -> VerificationConfig {
769        VerificationConfig::new(
770            self.is_test_mode(),
771            self.raw_conf.referee_bound,
772            self.raw_conf.max_block_size_in_bytes,
773            self.raw_conf.transaction_epoch_bound,
774            self.raw_conf.tx_pool_nonce_bits,
775            self.raw_conf.pos_reference_enable_height,
776            machine,
777        )
778    }
779
780    pub fn tx_gen_config(&self) -> Option<TransactionGeneratorConfig> {
781        if self.is_test_or_dev_mode() &&
782            // FIXME: this is not a good condition to check.
783            self.raw_conf.genesis_secrets.is_some()
784        {
785            Some(TransactionGeneratorConfig::new(
786                self.raw_conf.generate_tx,
787                self.raw_conf.generate_tx_period_us.expect("has default"),
788                self.raw_conf.txgen_account_count,
789            ))
790        } else {
791            None
792        }
793    }
794
795    pub fn storage_config(&self, node_type: &NodeType) -> StorageConfiguration {
796        let conflux_data_path = Path::new(&self.raw_conf.conflux_data_dir);
797        StorageConfiguration {
798            additional_maintained_snapshot_count: self
799                .raw_conf
800                .additional_maintained_snapshot_count,
801            consensus_param: ConsensusParam {
802                snapshot_epoch_count: if self.is_test_mode() {
803                    self.raw_conf.dev_snapshot_epoch_count
804                } else {
805                    SNAPSHOT_EPOCHS_CAPACITY
806                },
807                era_epoch_count: self.raw_conf.era_epoch_count,
808            },
809            debug_snapshot_checker_threads:
810                DEFAULT_DEBUG_SNAPSHOT_CHECKER_THREADS,
811            delta_mpts_cache_recent_lfu_factor: self
812                .raw_conf
813                .storage_delta_mpts_cache_recent_lfu_factor,
814            delta_mpts_cache_size: self.raw_conf.storage_delta_mpts_cache_size,
815            delta_mpts_cache_start_size: self
816                .raw_conf
817                .storage_delta_mpts_cache_start_size,
818            delta_mpts_node_map_vec_size: self
819                .raw_conf
820                .storage_delta_mpts_node_map_vec_size,
821            delta_mpts_slab_idle_size: self
822                .raw_conf
823                .storage_delta_mpts_slab_idle_size,
824            single_mpt_cache_start_size: self
825                .raw_conf
826                .storage_single_mpt_cache_start_size,
827            single_mpt_cache_size: self.raw_conf.storage_single_mpt_cache_size,
828            single_mpt_slab_idle_size: self
829                .raw_conf
830                .storage_single_mpt_slab_idle_size,
831            max_open_snapshots: self.raw_conf.storage_max_open_snapshots,
832            path_delta_mpts_dir: conflux_data_path
833                .join(&*storage_dir::DELTA_MPTS_DIR),
834            path_snapshot_dir: conflux_data_path
835                .join(&*storage_dir::SNAPSHOT_DIR),
836            path_snapshot_info_db: conflux_data_path
837                .join(&*storage_dir::SNAPSHOT_INFO_DB_PATH),
838            path_storage_dir: conflux_data_path
839                .join(&*storage_dir::STORAGE_DIR),
840            provide_more_snapshot_for_sync: self
841                .raw_conf
842                .provide_more_snapshot_for_sync
843                .clone(),
844            max_open_mpt_count: self.raw_conf.storage_max_open_mpt_count,
845            enable_single_mpt_storage: match node_type {
846                NodeType::Archive => self.raw_conf.enable_single_mpt_storage,
847                _ => {
848                    if self.raw_conf.enable_single_mpt_storage {
849                        error!("enable_single_mpt_storage is only supported for Archive nodes!")
850                    }
851                    false
852                }
853            },
854            single_mpt_space: self.raw_conf.single_mpt_space.clone(),
855            cip90a: self
856                .raw_conf
857                .cip90_transition_height
858                .unwrap_or(self.raw_conf.hydra_transition_height.unwrap_or(0)),
859            keep_snapshot_before_stable_checkpoint: self
860                .raw_conf
861                .keep_snapshot_before_stable_checkpoint,
862            use_isolated_db_for_mpt_table: self
863                .raw_conf
864                .use_isolated_db_for_mpt_table,
865            use_isolated_db_for_mpt_table_height: self
866                .raw_conf
867                .use_isolated_db_for_mpt_table_height,
868            keep_era_genesis_snapshot: self.raw_conf.keep_era_genesis_snapshot,
869            backup_mpt_snapshot: self.raw_conf.backup_mpt_snapshot,
870        }
871    }
872
873    pub fn protocol_config(&self) -> ProtocolConfiguration {
874        ProtocolConfiguration {
875            is_consortium: self.raw_conf.is_consortium,
876            send_tx_period: Duration::from_millis(
877                self.raw_conf.send_tx_period_ms,
878            ),
879            check_request_period: Duration::from_millis(
880                self.raw_conf.check_request_period_ms,
881            ),
882            check_phase_change_period: Duration::from_millis(
883                self.raw_conf.check_phase_change_period_ms,
884            ),
885            heartbeat_period_interval: Duration::from_millis(
886                self.raw_conf.heartbeat_period_interval_ms,
887            ),
888            block_cache_gc_period: Duration::from_millis(
889                self.raw_conf.block_cache_gc_period_ms,
890            ),
891            expire_block_gc_period: Duration::from_secs(
892                self.raw_conf.expire_block_gc_period_s,
893            ),
894            headers_request_timeout: Duration::from_millis(
895                self.raw_conf.headers_request_timeout_ms,
896            ),
897            blocks_request_timeout: Duration::from_millis(
898                self.raw_conf.blocks_request_timeout_ms,
899            ),
900            transaction_request_timeout: Duration::from_millis(
901                self.raw_conf.transaction_request_timeout_ms,
902            ),
903            tx_maintained_for_peer_timeout: Duration::from_millis(
904                self.raw_conf.tx_maintained_for_peer_timeout_ms,
905            ),
906            max_inflight_request_count: self
907                .raw_conf
908                .max_inflight_request_count,
909            request_block_with_public: self.raw_conf.request_block_with_public,
910            received_tx_index_maintain_timeout: Duration::from_millis(
911                self.raw_conf.received_tx_index_maintain_timeout_ms,
912            ),
913            inflight_pending_tx_index_maintain_timeout: Duration::from_millis(
914                self.raw_conf.inflight_pending_tx_index_maintain_timeout_ms,
915            ),
916            max_trans_count_received_in_catch_up: self
917                .raw_conf
918                .max_trans_count_received_in_catch_up,
919            min_peers_tx_propagation: self.raw_conf.min_peers_tx_propagation,
920            max_peers_tx_propagation: self.raw_conf.max_peers_tx_propagation,
921            max_downloading_chunks: self.raw_conf.max_downloading_chunks,
922            max_downloading_chunk_attempts: self
923                .raw_conf
924                .max_downloading_chunk_attempts,
925            test_mode: self.is_test_mode(),
926            dev_mode: self.is_dev_mode(),
927            throttling_config_file: self.raw_conf.throttling_conf.clone(),
928            snapshot_candidate_request_timeout: Duration::from_millis(
929                self.raw_conf.snapshot_candidate_request_timeout_ms,
930            ),
931            snapshot_manifest_request_timeout: Duration::from_millis(
932                self.raw_conf.snapshot_manifest_request_timeout_ms,
933            ),
934            snapshot_chunk_request_timeout: Duration::from_millis(
935                self.raw_conf.snapshot_chunk_request_timeout_ms,
936            ),
937            chunk_size_byte: self.raw_conf.chunk_size_byte,
938            max_chunk_number_in_manifest: self
939                .raw_conf
940                .max_chunk_number_in_manifest,
941            timeout_observing_period_s: self
942                .raw_conf
943                .timeout_observing_period_s,
944            max_allowed_timeout_in_observing_period: self
945                .raw_conf
946                .max_allowed_timeout_in_observing_period,
947            demote_peer_for_timeout: self.raw_conf.demote_peer_for_timeout,
948            heartbeat_timeout: Duration::from_millis(
949                self.raw_conf.heartbeat_timeout_ms,
950            ),
951            max_unprocessed_block_size: self
952                .raw_conf
953                .max_unprocessed_block_size_mb
954                * 1_000_000,
955            sync_expire_block_timeout: Duration::from_secs(
956                self.raw_conf.sync_expire_block_timeout_s,
957            ),
958            allow_phase_change_without_peer: if self.is_dev_mode() {
959                true
960            } else {
961                self.raw_conf.dev_allow_phase_change_without_peer
962            },
963            min_phase_change_normal_peer_count: self
964                .raw_conf
965                .min_phase_change_normal_peer_count,
966            pos_genesis_pivot_decision: self
967                .raw_conf
968                .pos_genesis_pivot_decision
969                .expect("set to genesis if none"),
970            check_status_genesis: self.raw_conf.check_status_genesis,
971            pos_started_as_voter: self.raw_conf.pos_started_as_voter,
972        }
973    }
974
975    pub fn state_sync_config(&self) -> StateSyncConfiguration {
976        StateSyncConfiguration {
977            max_downloading_chunks: self.raw_conf.max_downloading_chunks,
978            candidate_request_timeout: Duration::from_millis(
979                self.raw_conf.snapshot_candidate_request_timeout_ms,
980            ),
981            chunk_request_timeout: Duration::from_millis(
982                self.raw_conf.snapshot_chunk_request_timeout_ms,
983            ),
984            manifest_request_timeout: Duration::from_millis(
985                self.raw_conf.snapshot_manifest_request_timeout_ms,
986            ),
987            max_downloading_manifest_attempts: self
988                .raw_conf
989                .max_downloading_manifest_attempts,
990        }
991    }
992
993    pub fn data_mananger_config(&self) -> DataManagerConfiguration {
994        let mut conf = DataManagerConfiguration {
995            persist_tx_index: self.raw_conf.persist_tx_index,
996            persist_block_number_index: self
997                .raw_conf
998                .persist_block_number_index,
999            tx_cache_index_maintain_timeout: Duration::from_millis(
1000                self.raw_conf.tx_cache_index_maintain_timeout_ms,
1001            ),
1002            db_type: match self.raw_conf.block_db_type.as_str() {
1003                "rocksdb" => DbType::Rocksdb,
1004                "sqlite" => DbType::Sqlite,
1005                _ => panic!("Invalid block_db_type parameter!"),
1006            },
1007            additional_maintained_block_body_epoch_count: self
1008                .raw_conf
1009                .additional_maintained_block_body_epoch_count,
1010            additional_maintained_execution_result_epoch_count: self
1011                .raw_conf
1012                .additional_maintained_execution_result_epoch_count,
1013            additional_maintained_reward_epoch_count: self
1014                .raw_conf
1015                .additional_maintained_reward_epoch_count,
1016            additional_maintained_trace_epoch_count: self
1017                .raw_conf
1018                .additional_maintained_trace_epoch_count,
1019            additional_maintained_transaction_index_epoch_count: self
1020                .raw_conf
1021                .additional_maintained_transaction_index_epoch_count,
1022            checkpoint_gc_time_in_epoch_count: (self
1023                .raw_conf
1024                .checkpoint_gc_time_in_era_count
1025                * self.raw_conf.era_epoch_count as f64)
1026                as usize,
1027            strict_tx_index_gc: self.raw_conf.strict_tx_index_gc,
1028        };
1029
1030        // By default, we do not keep the block data for additional period,
1031        // but `node_type = "archive"` is a shortcut for keeping all them.
1032        if !matches!(self.raw_conf.node_type, Some(NodeType::Archive)) {
1033            if conf.additional_maintained_block_body_epoch_count.is_none() {
1034                conf.additional_maintained_block_body_epoch_count = Some(0);
1035            }
1036            if conf
1037                .additional_maintained_execution_result_epoch_count
1038                .is_none()
1039            {
1040                conf.additional_maintained_execution_result_epoch_count =
1041                    Some(0);
1042            }
1043            if conf
1044                .additional_maintained_transaction_index_epoch_count
1045                .is_none()
1046            {
1047                conf.additional_maintained_transaction_index_epoch_count =
1048                    Some(0);
1049            }
1050            if conf.additional_maintained_reward_epoch_count.is_none() {
1051                conf.additional_maintained_reward_epoch_count = Some(0);
1052            }
1053            if conf.additional_maintained_trace_epoch_count.is_none() {
1054                conf.additional_maintained_trace_epoch_count = Some(0);
1055            }
1056        }
1057        if conf.additional_maintained_transaction_index_epoch_count != Some(0) {
1058            conf.persist_tx_index = true;
1059        }
1060        conf
1061    }
1062
1063    pub fn sync_graph_config(&self) -> SyncGraphConfig {
1064        SyncGraphConfig {
1065            future_block_buffer_capacity: self
1066                .raw_conf
1067                .future_block_buffer_capacity,
1068            enable_state_expose: self.raw_conf.enable_state_expose,
1069            is_consortium: self.raw_conf.is_consortium,
1070        }
1071    }
1072
1073    pub fn metrics_config(&self) -> MetricsConfiguration {
1074        MetricsConfiguration {
1075            enabled: self.raw_conf.metrics_enabled,
1076            report_interval: Duration::from_millis(
1077                self.raw_conf.metrics_report_interval_ms,
1078            ),
1079            file_report_output: self.raw_conf.metrics_output_file.clone(),
1080            influxdb_report_host: self.raw_conf.metrics_influxdb_host.clone(),
1081            influxdb_report_db: self.raw_conf.metrics_influxdb_db.clone(),
1082            influxdb_report_username: self
1083                .raw_conf
1084                .metrics_influxdb_username
1085                .clone(),
1086            influxdb_report_password: self
1087                .raw_conf
1088                .metrics_influxdb_password
1089                .clone(),
1090            influxdb_report_node: self.raw_conf.metrics_influxdb_node.clone(),
1091            prometheus_listen_addr: self
1092                .raw_conf
1093                .metrics_prometheus_listen_addr
1094                .clone(),
1095        }
1096    }
1097
1098    pub fn txpool_config(&self) -> TxPoolConfig {
1099        let (min_native_tx_price_default, min_eth_tx_price_default) =
1100            if self.is_test_or_dev_mode() {
1101                (1, 1)
1102            } else {
1103                (ONE_GDRIP_IN_DRIP, 20 * ONE_GDRIP_IN_DRIP)
1104            };
1105        TxPoolConfig {
1106            capacity: self.raw_conf.tx_pool_size,
1107            half_block_gas_limit: RwLock::new(U256::from(
1108                DEFAULT_TARGET_BLOCK_GAS_LIMIT / 2,
1109            )),
1110            min_native_tx_price: self
1111                .raw_conf
1112                .tx_pool_min_native_tx_gas_price
1113                .unwrap_or(min_native_tx_price_default),
1114            allow_gas_over_half_block: self
1115                .raw_conf
1116                .tx_pool_allow_gas_over_half_block,
1117            target_block_gas_limit: self.raw_conf.target_block_gas_limit,
1118            min_eth_tx_price: self
1119                .raw_conf
1120                .tx_pool_min_eth_tx_gas_price
1121                .unwrap_or(min_eth_tx_price_default),
1122            max_packing_batch_gas_limit: self
1123                .raw_conf
1124                .max_packing_batch_gas_limit,
1125            max_packing_batch_size: self.raw_conf.max_packing_batch_size,
1126            packing_pool_degree: self.raw_conf.packing_pool_degree,
1127        }
1128    }
1129
1130    pub fn rpc_impl_config(&self) -> RpcImplConfiguration {
1131        RpcImplConfiguration {
1132            get_logs_filter_max_limit: self.raw_conf.get_logs_filter_max_limit,
1133            dev_pack_tx_immediately: self
1134                .raw_conf
1135                .dev_pack_tx_immediately
1136                .unwrap_or_else(|| {
1137                    self.is_dev_mode()
1138                        && self.raw_conf.dev_block_interval_ms.is_none()
1139                }),
1140            max_payload_bytes: self.raw_conf.jsonrpc_ws_max_payload_bytes,
1141            enable_metrics: self.raw_conf.rpc_enable_metrics,
1142            poll_lifetime_in_seconds: self.raw_conf.poll_lifetime_in_seconds,
1143            max_estimation_gas_limit: self
1144                .raw_conf
1145                .max_estimation_gas_limit
1146                .map(U256::from),
1147        }
1148    }
1149
1150    pub fn local_http_config(&self) -> HttpConfiguration {
1151        HttpConfiguration::new(
1152            Some((127, 0, 0, 1)),
1153            self.raw_conf.jsonrpc_local_http_port,
1154            self.raw_conf.jsonrpc_cors.clone(),
1155            self.raw_conf.jsonrpc_http_keep_alive,
1156            self.raw_conf.jsonrpc_http_threads,
1157        )
1158    }
1159
1160    pub fn http_config(&self) -> HttpConfiguration {
1161        HttpConfiguration::new(
1162            None,
1163            self.raw_conf.jsonrpc_http_port,
1164            self.raw_conf.jsonrpc_cors.clone(),
1165            self.raw_conf.jsonrpc_http_keep_alive,
1166            self.raw_conf.jsonrpc_http_threads,
1167        )
1168    }
1169
1170    pub fn eth_http_config(&self) -> HttpConfiguration {
1171        HttpConfiguration::new(
1172            None,
1173            self.raw_conf.jsonrpc_http_eth_port,
1174            self.raw_conf.jsonrpc_cors.clone(),
1175            self.raw_conf.jsonrpc_http_keep_alive,
1176            self.raw_conf.jsonrpc_http_threads,
1177        )
1178    }
1179
1180    pub fn eth_ws_config(&self) -> WsConfiguration {
1181        WsConfiguration::new(
1182            None,
1183            self.raw_conf.jsonrpc_ws_eth_port,
1184            self.raw_conf.jsonrpc_ws_max_payload_bytes,
1185        )
1186    }
1187
1188    pub fn local_tcp_config(&self) -> TcpConfiguration {
1189        TcpConfiguration::new(
1190            Some((127, 0, 0, 1)),
1191            self.raw_conf.jsonrpc_local_tcp_port,
1192        )
1193    }
1194
1195    pub fn tcp_config(&self) -> TcpConfiguration {
1196        TcpConfiguration::new(None, self.raw_conf.jsonrpc_tcp_port)
1197    }
1198
1199    pub fn jsonrpsee_server_builder(&self) -> ServerConfigBuilder {
1200        let builder = ServerConfigBuilder::default()
1201            .max_request_body_size(self.raw_conf.jsonrpc_max_request_body_size)
1202            .max_response_body_size(
1203                self.raw_conf.jsonrpc_max_response_body_size,
1204            )
1205            .max_connections(self.raw_conf.jsonrpc_max_connections)
1206            .max_subscriptions_per_connection(
1207                self.raw_conf.jsonrpc_max_subscriptions_per_connection,
1208            )
1209            .set_message_buffer_capacity(
1210                self.raw_conf.jsonrpc_message_buffer_capacity,
1211            );
1212
1213        builder
1214    }
1215
1216    pub fn local_ws_config(&self) -> WsConfiguration {
1217        WsConfiguration::new(
1218            Some((127, 0, 0, 1)),
1219            self.raw_conf.jsonrpc_local_ws_port,
1220            self.raw_conf.jsonrpc_ws_max_payload_bytes,
1221        )
1222    }
1223
1224    pub fn ws_config(&self) -> WsConfiguration {
1225        WsConfiguration::new(
1226            None,
1227            self.raw_conf.jsonrpc_ws_port,
1228            self.raw_conf.jsonrpc_ws_max_payload_bytes,
1229        )
1230    }
1231
1232    pub fn execution_config(&self) -> ConsensusExecutionConfiguration {
1233        ConsensusExecutionConfiguration {
1234            executive_trace: self.raw_conf.executive_trace,
1235        }
1236    }
1237
1238    pub fn discovery_protocol(&self) -> DiscoveryConfiguration {
1239        DiscoveryConfiguration {
1240            discover_node_count: self.raw_conf.discovery_discover_node_count,
1241            expire_time: Duration::from_secs(
1242                self.raw_conf.discovery_expire_time_s,
1243            ),
1244            find_node_timeout: Duration::from_millis(
1245                self.raw_conf.discovery_find_node_timeout_ms,
1246            ),
1247            max_nodes_ping: self.raw_conf.discovery_max_nodes_ping,
1248            ping_timeout: Duration::from_millis(
1249                self.raw_conf.discovery_ping_timeout_ms,
1250            ),
1251            throttling_interval: Duration::from_millis(
1252                self.raw_conf.discovery_throttling_interval_ms,
1253            ),
1254            throttling_limit_ping: self
1255                .raw_conf
1256                .discovery_throttling_limit_ping,
1257            throttling_limit_find_nodes: self
1258                .raw_conf
1259                .discovery_throttling_limit_find_nodes,
1260        }
1261    }
1262
1263    pub fn is_test_mode(&self) -> bool {
1264        match self.raw_conf.mode.as_ref().map(|s| s.as_str()) {
1265            Some("test") => true,
1266            _ => false,
1267        }
1268    }
1269
1270    pub fn is_dev_mode(&self) -> bool {
1271        match self.raw_conf.mode.as_ref().map(|s| s.as_str()) {
1272            Some("dev") => true,
1273            _ => false,
1274        }
1275    }
1276
1277    pub fn is_test_or_dev_mode(&self) -> bool {
1278        match self.raw_conf.mode.as_ref().map(|s| s.as_str()) {
1279            Some("dev") | Some("test") => true,
1280            _ => false,
1281        }
1282    }
1283
1284    pub fn is_consortium(&self) -> bool { self.raw_conf.is_consortium }
1285
1286    pub fn light_node_config(&self) -> LightNodeConfiguration {
1287        LightNodeConfiguration {
1288            epoch_request_batch_size: self.raw_conf.ln_epoch_request_batch_size,
1289            epoch_request_timeout: self
1290                .raw_conf
1291                .ln_epoch_request_timeout_sec
1292                .map(Duration::from_secs),
1293            header_request_batch_size: self
1294                .raw_conf
1295                .ln_header_request_batch_size,
1296            header_request_timeout: self
1297                .raw_conf
1298                .ln_header_request_timeout_sec
1299                .map(Duration::from_secs),
1300            max_headers_in_flight: self.raw_conf.ln_max_headers_in_flight,
1301            max_parallel_epochs_to_request: self
1302                .raw_conf
1303                .ln_max_parallel_epochs_to_request,
1304            num_epochs_to_request: self.raw_conf.ln_num_epochs_to_request,
1305            num_waiting_headers_threshold: self
1306                .raw_conf
1307                .ln_num_waiting_headers_threshold,
1308        }
1309    }
1310
1311    pub fn common_params(&self) -> CommonParams {
1312        let mut params = CommonParams::default();
1313
1314        if self.is_test_or_dev_mode() {
1315            params.early_set_internal_contracts_states = true;
1316        }
1317
1318        let non_test_default = SpaceMap::new(
1319            INITIAL_1559_CORE_BASE_PRICE,
1320            INITIAL_1559_ETH_BASE_PRICE,
1321        );
1322        let test_default = SpaceMap::new(1u64, 1);
1323        let config = SpaceMap::new(
1324            self.raw_conf.min_native_base_price,
1325            self.raw_conf.min_eth_base_price,
1326        );
1327        let base_price = SpaceMap::zip3(non_test_default, test_default, config)
1328            .map_all(|(non_test, test, config)| {
1329                if let Some(x) = config {
1330                    x
1331                } else if self.is_test_or_dev_mode() {
1332                    test
1333                } else {
1334                    non_test
1335                }
1336            });
1337        params.min_base_price = base_price.map_all(U256::from);
1338
1339        params.chain_id = self.chain_id_params();
1340        params.anticone_penalty_ratio = self.raw_conf.anticone_penalty_ratio;
1341        params.evm_transaction_block_ratio =
1342            self.raw_conf.evm_transaction_block_ratio;
1343        params.evm_transaction_gas_ratio =
1344            self.raw_conf.evm_transaction_gas_ratio;
1345
1346        params.params_dao_vote_period = self.raw_conf.params_dao_vote_period;
1347
1348        self.set_cips(&mut params);
1349
1350        params
1351    }
1352
1353    pub fn node_type(&self) -> NodeType {
1354        self.raw_conf.node_type.unwrap_or(NodeType::Full)
1355    }
1356
1357    pub fn pos_state_config(&self) -> PosStateConfig {
1358        // The current implementation requires the round number to be an even
1359        // number.
1360        assert_eq!(self.raw_conf.pos_round_per_term % 2, 0);
1361        PosStateConfig::new(
1362            self.raw_conf.pos_round_per_term,
1363            self.raw_conf.pos_term_max_size,
1364            self.raw_conf.pos_term_elected_size,
1365            self.raw_conf.pos_in_queue_locked_views,
1366            self.raw_conf.pos_out_queue_locked_views,
1367            self.raw_conf.pos_cip99_transition_view,
1368            self.raw_conf.pos_cip99_in_queue_locked_views,
1369            self.raw_conf.pos_cip99_out_queue_locked_views,
1370            self.raw_conf.nonce_limit_transition_view,
1371            20_000, // 2 * 10^7 CFX
1372            self.raw_conf.pos_cip136_transition_view,
1373            self.raw_conf.pos_cip136_in_queue_locked_views,
1374            self.raw_conf.pos_cip136_out_queue_locked_views,
1375            self.raw_conf.pos_cip136_round_per_term,
1376            self.raw_conf.pos_cip156_transition_view,
1377            self.raw_conf.pos_cip156_dispute_locked_views,
1378        )
1379    }
1380
1381    fn set_cips(&self, params: &mut CommonParams) {
1382        let default_transition_time =
1383            if let Some(num) = self.raw_conf.default_transition_time {
1384                num
1385            } else if self.is_test_or_dev_mode() {
1386                0u64
1387            } else {
1388                u64::MAX
1389            };
1390
1391        // This is to set the default transition time for the CIPs that cannot
1392        // be enabled in the genesis.
1393        let non_genesis_default_transition_time =
1394            match self.raw_conf.default_transition_time {
1395                Some(num) if num > 0 => num,
1396                _ => {
1397                    if self.is_test_or_dev_mode() {
1398                        1u64
1399                    } else {
1400                        u64::MAX
1401                    }
1402                }
1403            };
1404
1405        //
1406        // Tanzanite hardfork
1407        //
1408        params.transition_heights.cip40 =
1409            self.raw_conf.tanzanite_transition_height;
1410        let mut base_block_rewards = BTreeMap::new();
1411        base_block_rewards.insert(0, INITIAL_BASE_MINING_REWARD_IN_UCFX.into());
1412        base_block_rewards.insert(
1413            params.transition_heights.cip40,
1414            MINING_REWARD_TANZANITE_IN_UCFX.into(),
1415        );
1416        params.base_block_rewards = base_block_rewards;
1417
1418        //
1419        // Hydra hardfork (V2.0)
1420        //
1421        set_conf!(
1422            self.raw_conf.hydra_transition_number.unwrap_or(default_transition_time);
1423            params.transition_numbers => { cip43a, cip64, cip71, cip78a, cip92 }
1424        );
1425        set_conf!(
1426            self.raw_conf.hydra_transition_height.unwrap_or(default_transition_time);
1427            params.transition_heights => { cip76, cip86 }
1428        );
1429        params.transition_numbers.cip43b =
1430            self.raw_conf.cip43_init_end_number.unwrap_or(
1431                if self.is_test_or_dev_mode() {
1432                    u64::MAX
1433                } else {
1434                    params.transition_numbers.cip43a
1435                },
1436            );
1437        params.transition_numbers.cip62 = if self.is_test_or_dev_mode() {
1438            0u64
1439        } else {
1440            BN128_ENABLE_NUMBER
1441        };
1442        params.transition_numbers.cip78b = self
1443            .raw_conf
1444            .cip78_patch_transition_number
1445            .unwrap_or(params.transition_numbers.cip78a);
1446        params.transition_heights.cip90a = self
1447            .raw_conf
1448            .cip90_transition_height
1449            .or(self.raw_conf.hydra_transition_height)
1450            .unwrap_or(default_transition_time);
1451        params.transition_numbers.cip90b = self
1452            .raw_conf
1453            .cip90_transition_number
1454            .or(self.raw_conf.hydra_transition_number)
1455            .unwrap_or(default_transition_time);
1456
1457        //
1458        // DAO vote hardfork (V2.1)
1459        //
1460        set_conf!(
1461            self.raw_conf.dao_vote_transition_number.unwrap_or(default_transition_time);
1462            params.transition_numbers => { cip97, cip98 }
1463        );
1464        params.transition_numbers.cip94n = self
1465            .raw_conf
1466            .dao_vote_transition_number
1467            .unwrap_or(non_genesis_default_transition_time);
1468        params.transition_heights.cip94h = self
1469            .raw_conf
1470            .dao_vote_transition_height
1471            .unwrap_or(non_genesis_default_transition_time);
1472        params.transition_numbers.cip105 = self
1473            .raw_conf
1474            .cip105_transition_number
1475            .or(self.raw_conf.dao_vote_transition_number)
1476            .unwrap_or(default_transition_time);
1477
1478        //
1479        // Sigma protocol fix hardfork (V2.2)
1480        //
1481        params.transition_numbers.cip_sigma_fix = self
1482            .raw_conf
1483            .sigma_fix_transition_number
1484            .unwrap_or(default_transition_time);
1485
1486        //
1487        // Burn collateral hardfork (V2.3)
1488        //
1489        params.transition_numbers.cip107 = self
1490            .raw_conf
1491            .cip107_transition_number
1492            .unwrap_or(default_transition_time);
1493        params.transition_heights.cip112 =
1494            *CIP112_TRANSITION_HEIGHT.get().expect("initialized");
1495        params.transition_numbers.cip118 = self
1496            .raw_conf
1497            .cip118_transition_number
1498            .unwrap_or(default_transition_time);
1499        params.transition_numbers.cip119 = self
1500            .raw_conf
1501            .cip119_transition_number
1502            .unwrap_or(default_transition_time);
1503
1504        //
1505        // 1559 hardfork (V2.4)
1506        //
1507        set_conf!(
1508            self.raw_conf.base_fee_burn_transition_number.unwrap_or(default_transition_time);
1509            params.transition_numbers => { cip131, cip132, cip133b, cip137, cip144, cip145 }
1510        );
1511        set_conf!(
1512            self.raw_conf.base_fee_burn_transition_height.unwrap_or(default_transition_time);
1513            params.transition_heights => { cip130, cip133e }
1514        );
1515        // TODO: disable 1559 test during dev
1516        params.transition_heights.cip1559 = self
1517            .raw_conf
1518            .cip1559_transition_height
1519            .or(self.raw_conf.base_fee_burn_transition_height)
1520            .unwrap_or(non_genesis_default_transition_time);
1521        params.transition_numbers.cancun_opcodes = self
1522            .raw_conf
1523            .cancun_opcodes_transition_number
1524            .or(self.raw_conf.base_fee_burn_transition_number)
1525            .unwrap_or(default_transition_time);
1526
1527        if params.transition_heights.cip1559
1528            < self.raw_conf.pos_reference_enable_height
1529        {
1530            panic!("1559 can not be activated earlier than pos reference: 1559 (epoch {}), pos (epoch {})", params.transition_heights.cip1559, self.raw_conf.pos_reference_enable_height);
1531        }
1532
1533        //
1534        // hardfork (V2.5)
1535        //
1536        params.transition_heights.cip_c2_fix = self
1537            .raw_conf
1538            .c2_fix_transition_height
1539            .unwrap_or(default_transition_time);
1540
1541        //
1542        // 7702 hardfork (V3.0)
1543        //
1544        set_conf!(
1545            self.raw_conf.eoa_code_transition_height.unwrap_or(default_transition_time);
1546            params.transition_heights => { cip150, cip151, cip152, cip154, cip7702, cip645, eip2537, eip2935, eip7623, cip145_fix }
1547        );
1548        if let Some(x) = self.raw_conf.cip151_transition_height {
1549            params.transition_heights.cip151 = x;
1550        }
1551        if let Some(x) = self.raw_conf.cip645_transition_height {
1552            params.transition_heights.cip645 = x;
1553        }
1554        if let Some(x) = self.raw_conf.cip145_fix_transition_height {
1555            params.transition_heights.cip145_fix = x;
1556        }
1557        params.transition_heights.align_evm =
1558            self.raw_conf.align_evm_transition_height;
1559
1560        // hardfork (V3.1)
1561        set_conf!(
1562            self.raw_conf.osaka_opcode_transition_height.unwrap_or(default_transition_time);
1563            params.transition_heights => { cip166 }
1564        );
1565        if let Some(x) = self.raw_conf.cip166_transition_height {
1566            params.transition_heights.cip166 = x;
1567        }
1568    }
1569}
1570
1571/// Validates and formats bootnodes option.
1572pub fn to_bootnodes(bootnodes: &Option<String>) -> Result<Vec<String>, String> {
1573    match *bootnodes {
1574        Some(ref x) if !x.is_empty() => x
1575            .split(',')
1576            // ignore empty strings
1577            .filter(|s| !s.is_empty())
1578            .map(|s| match validate_node_url(s).map(Into::into) {
1579                None => Ok(s.to_owned()),
1580                Some(network::Error::AddressResolve(_)) => Err(format!(
1581                    "Failed to resolve hostname of a boot node: {}",
1582                    s
1583                )),
1584                Some(e) => Err(format!(
1585                    "Invalid node address format given for a boot node: {} err={:?}",
1586                    s, e
1587                )),
1588            })
1589            .collect(),
1590        Some(_) => Ok(vec![]),
1591        None => Ok(vec![]),
1592    }
1593}
1594
1595pub fn parse_config_address_string(
1596    addr: &str, network: &Network,
1597) -> Result<Address, String> {
1598    let base32_err = match cfx_addr_decode(addr) {
1599        Ok(address) => {
1600            return if address.network != *network {
1601                Err(format!(
1602                    "address in configuration has unmatching network id: expected network={},\
1603                     address.network={}",
1604                    network,
1605                    address.network
1606                ))
1607            } else {
1608                address
1609                    .hex_address
1610                    .ok_or("decoded address has wrong byte length".into())
1611            };
1612        }
1613        Err(e) => e,
1614    };
1615    let hex_err = match parse_hex_string(addr) {
1616        Ok(address) => return Ok(address),
1617        Err(e) => e,
1618    };
1619    // An address from config must be valid.
1620    Err(format!("Address from configuration should be a valid base32 address or a 40-digit hex string!
1621            base32_err={:?}
1622            hex_err={:?}",
1623                base32_err, hex_err))
1624}
1625
1626#[cfg(test)]
1627mod tests {
1628    use cfx_addr::Network;
1629
1630    use crate::configuration::parse_config_address_string;
1631
1632    #[test]
1633    fn test_config_address_string() {
1634        let addr = parse_config_address_string(
1635            "0x1a2f80341409639ea6a35bbcab8299066109aa55",
1636            &Network::Main,
1637        )
1638        .unwrap();
1639        // Allow omitting the leading "0x" prefix.
1640        assert_eq!(
1641            addr,
1642            parse_config_address_string(
1643                "1a2f80341409639ea6a35bbcab8299066109aa55",
1644                &Network::Main,
1645            )
1646            .unwrap()
1647        );
1648        // Allow CIP-37 base32 address.
1649        assert_eq!(
1650            addr,
1651            parse_config_address_string(
1652                "cfx:aarc9abycue0hhzgyrr53m6cxedgccrmmyybjgh4xg",
1653                &Network::Main,
1654            )
1655            .unwrap()
1656        );
1657        // Allow optional fields in CIP-37 base32 address.
1658        assert_eq!(
1659            addr,
1660            parse_config_address_string(
1661                "cfx:type.user:aarc9abycue0hhzgyrr53m6cxedgccrmmyybjgh4xg",
1662                &Network::Main,
1663            )
1664            .unwrap()
1665        );
1666    }
1667}