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