1use std::{
6 net::{Ipv4Addr, SocketAddr},
7 num::NonZeroUsize,
8 path::PathBuf,
9};
10
11use anyhow::anyhow;
12use fastcrypto::{
13 encoding::{Encoding, Hex},
14 traits::KeyPair,
15};
16use iota_config::{
17 AUTHORITIES_DB_NAME, CONSENSUS_DB_NAME, ConsensusConfig, FULL_NODE_DB_PATH,
18 IOTA_GENESIS_MIGRATION_TX_DATA_FILENAME, NodeConfig, local_ip_utils,
19 node::{
20 AuthorityKeyPairWithPath, AuthorityOverloadConfig, AuthorityStorePruningConfig,
21 CheckpointExecutorConfig, ExecutionCacheConfig, ExpensiveSafetyCheckConfig, Genesis,
22 GrpcApiConfig, KeyPairWithPath, RunWithRange, StateSnapshotConfig,
23 default_enable_jsonrpc_api, default_end_of_epoch_broadcast_channel_capacity,
24 default_full_checkpoint_contents_cache_size_mb,
25 },
26 p2p::{DiscoveryConfig, P2pConfig, SeedPeer, StateSyncConfig},
27 transaction_deny_config::TransactionDenyConfig,
28 verifier_signing_config::VerifierSigningConfig,
29};
30use iota_multiaddr::Multiaddr;
31use iota_names::config::IotaNamesConfig;
32use iota_protocol_config::Chain;
33use iota_types::{
34 crypto::{AuthorityKeyPair, AuthorityPublicKeyBytes, NetworkPrivateKey},
35 supported_protocol_versions::SupportedProtocolVersions,
36 traffic_control::PolicyConfig,
37};
38
39use crate::{
40 genesis_config::{ValidatorGenesisConfig, ValidatorGenesisConfigBuilder},
41 network_config::NetworkConfig,
42};
43
44#[derive(Clone, Default)]
48pub struct ValidatorConfigBuilder {
49 config_directory: Option<PathBuf>,
50 supported_protocol_versions: Option<SupportedProtocolVersions>,
51 force_unpruned_checkpoints: bool,
52 authority_overload_config: Option<AuthorityOverloadConfig>,
53 transaction_deny_config: Option<TransactionDenyConfig>,
54 execution_cache_config: Option<ExecutionCacheConfig>,
55 data_ingestion_dir: Option<PathBuf>,
56 policy_config: Option<PolicyConfig>,
57 max_submit_position: Option<usize>,
58 submit_delay_step_override_millis: Option<u64>,
59 discovery_config: Option<DiscoveryConfig>,
60 chain_override: Option<Chain>,
61}
62
63impl ValidatorConfigBuilder {
64 pub fn new() -> Self {
65 Self {
66 ..Default::default()
67 }
68 }
69
70 pub fn with_chain_override(mut self, chain: Chain) -> Self {
71 assert!(self.chain_override.is_none(), "Chain override already set");
72 self.chain_override = Some(chain);
73 self
74 }
75
76 pub fn with_config_directory(mut self, config_directory: PathBuf) -> Self {
77 assert!(self.config_directory.is_none());
78 self.config_directory = Some(config_directory);
79 self
80 }
81
82 pub fn with_supported_protocol_versions(
83 mut self,
84 supported_protocol_versions: SupportedProtocolVersions,
85 ) -> Self {
86 assert!(self.supported_protocol_versions.is_none());
87 self.supported_protocol_versions = Some(supported_protocol_versions);
88 self
89 }
90
91 pub fn with_unpruned_checkpoints(mut self) -> Self {
92 self.force_unpruned_checkpoints = true;
93 self
94 }
95
96 pub fn with_authority_overload_config(mut self, config: AuthorityOverloadConfig) -> Self {
97 self.authority_overload_config = Some(config);
98 self
99 }
100
101 pub fn with_transaction_deny_config(mut self, config: TransactionDenyConfig) -> Self {
102 self.transaction_deny_config = Some(config);
103 self
104 }
105
106 pub fn with_execution_cache_config(mut self, config: ExecutionCacheConfig) -> Self {
107 self.execution_cache_config = Some(config);
108 self
109 }
110
111 pub fn with_data_ingestion_dir(mut self, path: PathBuf) -> Self {
112 self.data_ingestion_dir = Some(path);
113 self
114 }
115
116 pub fn with_policy_config(mut self, config: Option<PolicyConfig>) -> Self {
117 self.policy_config = config;
118 self
119 }
120
121 pub fn with_max_submit_position(mut self, max_submit_position: usize) -> Self {
122 self.max_submit_position = Some(max_submit_position);
123 self
124 }
125
126 pub fn with_submit_delay_step_override_millis(
127 mut self,
128 submit_delay_step_override_millis: u64,
129 ) -> Self {
130 self.submit_delay_step_override_millis = Some(submit_delay_step_override_millis);
131 self
132 }
133
134 pub fn with_discovery_config(mut self, discovery_config: DiscoveryConfig) -> Self {
135 self.discovery_config = Some(discovery_config);
136 self
137 }
138
139 pub fn build_without_genesis(self, validator: ValidatorGenesisConfig) -> NodeConfig {
140 let key_path = get_key_path(&validator.authority_key_pair);
141 let config_directory = self
142 .config_directory
143 .unwrap_or_else(|| iota_common::tempdir().keep());
144 let migration_tx_data_path =
145 Some(config_directory.join(IOTA_GENESIS_MIGRATION_TX_DATA_FILENAME));
146 let db_path = config_directory
147 .join(AUTHORITIES_DB_NAME)
148 .join(key_path.clone());
149 let network_address = validator.network_address;
150 let consensus_db_path = config_directory.join(CONSENSUS_DB_NAME).join(key_path);
151 let consensus_config = ConsensusConfig {
152 db_path: consensus_db_path,
153 db_retention_epochs: None,
154 db_pruner_period_secs: None,
155 max_pending_transactions: None,
156 max_submit_position: self.max_submit_position,
157 submit_delay_step_override_millis: self.submit_delay_step_override_millis,
158 parameters: Default::default(),
159 graduated_load_shedding_soft_limit_pct: Default::default(),
160 };
161
162 let p2p_config = P2pConfig {
163 listen_address: validator.p2p_listen_address.unwrap_or_else(|| {
164 validator
165 .p2p_address
166 .udp_multiaddr_to_listen_address()
167 .unwrap()
168 }),
169 external_address: Some(validator.p2p_address),
170 state_sync: Some(StateSyncConfig {
173 checkpoint_content_timeout_ms: Some(10_000),
174 ..Default::default()
175 }),
176 discovery: self.discovery_config,
178 ..Default::default()
179 };
180
181 let mut pruning_config = local_network_pruning_config();
182 if self.force_unpruned_checkpoints {
183 pruning_config.set_num_epochs_to_retain_for_checkpoints(Some(u64::MAX));
184 }
185 let pruning_config = pruning_config;
186 let checkpoint_executor_config = CheckpointExecutorConfig {
187 data_ingestion_dir: self.data_ingestion_dir,
188 ..Default::default()
189 };
190
191 NodeConfig {
192 authority_key_pair: AuthorityKeyPairWithPath::new(validator.authority_key_pair),
193 network_key_pair: KeyPairWithPath::new(validator.network_key_pair.into()),
194 account_key_pair: KeyPairWithPath::new(validator.account_key_pair),
195 protocol_key_pair: KeyPairWithPath::new(validator.protocol_key_pair.into()),
196 json_rpc_address: SocketAddr::new(
201 network_address
202 .to_socket_addr()
203 .map(|address| address.ip())
204 .unwrap_or_else(|_| Ipv4Addr::LOCALHOST.into()),
205 network_address.port().unwrap_or_default().saturating_add(5),
206 ),
207 db_path,
208 network_address,
209 metrics_address: validator.metrics_address,
210 admin_interface_address: validator.admin_interface_address,
211 consensus_config: Some(consensus_config),
212 enable_jsonrpc_api: default_enable_jsonrpc_api(),
213 enable_index_processing: None,
214 genesis: Genesis::new_empty(),
215 migration_tx_data_path,
216 grpc_load_shed: None,
217 grpc_concurrency_limit_per_core: NonZeroUsize::new(500_000_000).unwrap(),
220 p2p_config,
221 authority_store_pruning_config: pruning_config,
222 end_of_epoch_broadcast_channel_capacity:
223 default_end_of_epoch_broadcast_channel_capacity(),
224 checkpoint_executor_config,
225 metrics: None,
226 supported_protocol_versions: self.supported_protocol_versions,
227 expensive_safety_check_config: ExpensiveSafetyCheckConfig::default(),
230 transaction_deny_config: self.transaction_deny_config.unwrap_or_default(),
231 certificate_deny_config: Default::default(),
232 state_debug_dump_config: Default::default(),
233 checkpoint_archive_config: None,
234 state_snapshot_write_config: StateSnapshotConfig::default(),
235 transaction_kv_store_read_config: Default::default(),
236 transaction_kv_store_write_config: None,
237 authority_overload_config: self.authority_overload_config.unwrap_or_default(),
238 execution_cache_config: self.execution_cache_config.unwrap_or_default(),
239 full_checkpoint_contents_cache_size_mb: default_full_checkpoint_contents_cache_size_mb(
240 ),
241 run_with_range: None,
242 policy_config: self.policy_config,
243 enable_validator_tx_finalizer: true,
244 enable_soft_locking: true,
245 verifier_signing_config: VerifierSigningConfig::default(),
246 enable_db_write_stall: None,
247 iota_names_config: None,
248 enable_grpc_api: false,
249 grpc_api_config: None,
250 chain_override_for_testing: self.chain_override,
251 validator_client_monitor_config: None,
252 validator_grpc_listener_limits: Default::default(),
253 json_rpc_listener_limits: Default::default(),
254 grpc_api_listener_limits: Default::default(),
255 }
256 }
257
258 pub fn build(
259 self,
260 validator: ValidatorGenesisConfig,
261 genesis: iota_config::genesis::Genesis,
262 ) -> NodeConfig {
263 let mut config = self.build_without_genesis(validator);
264 config.genesis = iota_config::node::Genesis::new(genesis);
265 config
266 }
267
268 pub fn build_new_validator<R: rand::CryptoRng>(
269 self,
270 rng: &mut R,
271 network_config: &NetworkConfig,
272 ) -> NodeConfig {
273 let validator_config = ValidatorGenesisConfigBuilder::new().build(rng);
274 self.build(validator_config, network_config.genesis.clone())
275 }
276}
277
278#[derive(Clone, Debug, Default)]
279pub struct FullnodeConfigBuilder {
280 config_directory: Option<PathBuf>,
281 rpc_port: Option<u16>,
283 rpc_addr: Option<SocketAddr>,
284 supported_protocol_versions: Option<SupportedProtocolVersions>,
285 expensive_safety_check_config: Option<ExpensiveSafetyCheckConfig>,
286 db_path: Option<PathBuf>,
287 network_address: Option<Multiaddr>,
288 json_rpc_address: Option<SocketAddr>,
289 metrics_address: Option<SocketAddr>,
290 admin_interface_address: Option<SocketAddr>,
291 genesis: Option<Genesis>,
292 p2p_external_address: Option<Multiaddr>,
293 p2p_listen_address: Option<SocketAddr>,
294 network_key_pair: Option<KeyPairWithPath>,
295 run_with_range: Option<RunWithRange>,
296 policy_config: Option<PolicyConfig>,
297 data_ingestion_dir: Option<PathBuf>,
298 disable_pruning: bool,
299 num_epochs_to_retain_for_indexes: Option<u64>,
300 iota_names_config: Option<IotaNamesConfig>,
301 enable_jsonrpc_api: Option<bool>,
303 enable_grpc_api: bool,
304 grpc_api_config: Option<GrpcApiConfig>,
305 discovery_config: Option<DiscoveryConfig>,
306 chain_override: Option<Chain>,
307 state_snapshot_write_config: Option<StateSnapshotConfig>,
308}
309
310impl FullnodeConfigBuilder {
311 pub fn new() -> Self {
312 Self::default()
313 }
314
315 pub fn with_state_snapshot_config(mut self, config: StateSnapshotConfig) -> Self {
317 self.state_snapshot_write_config = Some(config);
318 self
319 }
320
321 pub fn with_chain_override(mut self, chain: Chain) -> Self {
322 assert!(self.chain_override.is_none(), "Chain override already set");
323 self.chain_override = Some(chain);
324 self
325 }
326
327 pub fn with_config_directory(mut self, config_directory: PathBuf) -> Self {
328 self.config_directory = Some(config_directory);
329 self
330 }
331
332 pub fn with_rpc_port(mut self, port: u16) -> Self {
333 assert!(self.rpc_addr.is_none() && self.rpc_port.is_none());
334 self.rpc_port = Some(port);
335 self
336 }
337
338 pub fn with_rpc_addr(mut self, addr: impl Into<SocketAddr>) -> Self {
339 assert!(self.rpc_addr.is_none() && self.rpc_port.is_none());
340 self.rpc_addr = Some(addr.into());
341 self
342 }
343
344 pub fn with_supported_protocol_versions(mut self, versions: SupportedProtocolVersions) -> Self {
345 self.supported_protocol_versions = Some(versions);
346 self
347 }
348
349 pub fn with_disable_pruning(mut self, disable_pruning: bool) -> Self {
350 self.disable_pruning = disable_pruning;
351 self
352 }
353
354 pub fn with_expensive_safety_check_config(
355 mut self,
356 expensive_safety_check_config: ExpensiveSafetyCheckConfig,
357 ) -> Self {
358 self.expensive_safety_check_config = Some(expensive_safety_check_config);
359 self
360 }
361
362 pub fn with_db_path(mut self, db_path: PathBuf) -> Self {
363 self.db_path = Some(db_path);
364 self
365 }
366
367 pub fn with_network_address(mut self, network_address: Multiaddr) -> Self {
368 self.network_address = Some(network_address);
369 self
370 }
371
372 pub fn with_json_rpc_address(mut self, json_rpc_address: impl Into<SocketAddr>) -> Self {
373 self.json_rpc_address = Some(json_rpc_address.into());
374 self
375 }
376
377 pub fn with_metrics_address(mut self, metrics_address: impl Into<SocketAddr>) -> Self {
378 self.metrics_address = Some(metrics_address.into());
379 self
380 }
381
382 pub fn with_admin_interface_address(
383 mut self,
384 admin_interface_address: Option<impl Into<SocketAddr>>,
385 ) -> Self {
386 self.admin_interface_address = admin_interface_address.map(|addr| addr.into());
387 self
388 }
389
390 pub fn with_genesis(mut self, genesis: Genesis) -> Self {
391 self.genesis = Some(genesis);
392 self
393 }
394
395 pub fn with_p2p_external_address(mut self, p2p_external_address: Multiaddr) -> Self {
396 self.p2p_external_address = Some(p2p_external_address);
397 self
398 }
399
400 pub fn with_p2p_listen_address(mut self, p2p_listen_address: impl Into<SocketAddr>) -> Self {
401 self.p2p_listen_address = Some(p2p_listen_address.into());
402 self
403 }
404
405 pub fn with_network_private_key(
406 mut self,
407 network_private_key: Option<NetworkPrivateKey>,
408 ) -> Self {
409 if let Some(network_private_key) = network_private_key {
410 self.network_key_pair = Some(KeyPairWithPath::new(network_private_key.into()));
411 }
412 self
413 }
414
415 pub fn with_num_epochs_to_retain_for_indexes(mut self, epochs: Option<u64>) -> Self {
416 self.num_epochs_to_retain_for_indexes = epochs;
417 self
418 }
419
420 pub fn with_run_with_range(mut self, run_with_range: Option<RunWithRange>) -> Self {
421 if let Some(run_with_range) = run_with_range {
422 self.run_with_range = Some(run_with_range);
423 }
424 self
425 }
426
427 pub fn with_policy_config(mut self, config: Option<PolicyConfig>) -> Self {
428 self.policy_config = config;
429 self
430 }
431
432 pub fn with_data_ingestion_dir(mut self, path: Option<PathBuf>) -> Self {
433 self.data_ingestion_dir = path;
434 self
435 }
436
437 pub fn with_iota_names_config(mut self, config: Option<IotaNamesConfig>) -> Self {
438 self.iota_names_config = config;
439 self
440 }
441
442 pub fn with_enable_jsonrpc_api(mut self, enable_jsonrpc_api: bool) -> Self {
445 self.enable_jsonrpc_api = Some(enable_jsonrpc_api);
446 self
447 }
448
449 pub fn with_enable_grpc_api(mut self, enable_grpc_api: bool) -> Self {
450 self.enable_grpc_api = enable_grpc_api;
451 self
452 }
453
454 pub fn with_grpc_api_config(mut self, config: GrpcApiConfig) -> Self {
455 self.grpc_api_config = Some(config);
456 self
457 }
458
459 pub fn with_discovery_config(mut self, discovery_config: DiscoveryConfig) -> Self {
460 self.discovery_config = Some(discovery_config);
461 self
462 }
463
464 pub fn build_from_parts<R: rand::CryptoRng>(
470 self,
471 rng: &mut R,
472 validator_configs: &[NodeConfig],
473 genesis: iota_config::node::Genesis,
474 ) -> NodeConfig {
475 self.try_build_from_parts(rng, validator_configs, genesis)
476 .unwrap_or_else(|err| panic!("{err:#}"))
477 }
478
479 pub fn try_build_from_parts<R: rand::CryptoRng>(
484 self,
485 rng: &mut R,
486 validator_configs: &[NodeConfig],
487 genesis: iota_config::node::Genesis,
488 ) -> anyhow::Result<NodeConfig> {
489 let genesis_config = ValidatorGenesisConfigBuilder::new().build(rng);
492 self.try_build_from_genesis_config(genesis_config, validator_configs, genesis)
493 }
494
495 pub fn try_build_from_genesis_config(
511 self,
512 genesis_config: ValidatorGenesisConfig,
513 validator_configs: &[NodeConfig],
514 genesis: iota_config::node::Genesis,
515 ) -> anyhow::Result<NodeConfig> {
516 let ip = genesis_config
517 .network_address
518 .to_socket_addr()
519 .unwrap()
520 .ip()
521 .to_string();
522
523 let key_path = get_key_path(&genesis_config.authority_key_pair);
524 let config_directory = self
525 .config_directory
526 .unwrap_or_else(|| iota_common::tempdir().keep());
527
528 let migration_tx_data_path =
529 Some(config_directory.join(IOTA_GENESIS_MIGRATION_TX_DATA_FILENAME));
530
531 let p2p_config = {
532 let seed_peers = validator_configs
533 .iter()
534 .enumerate()
535 .map(|(index, config)| {
536 let address = config.p2p_config.external_address.clone().ok_or_else(|| {
537 anyhow!(
538 "validator {index} has no `p2p-config.external-address`, which the \
539 fullnode needs to derive its seed peers: either its config never set \
540 one or it was cleared"
541 )
542 })?;
543 Ok(SeedPeer {
544 peer_id: Some(anemo::PeerId(
545 config.network_private_key().public_key().into_bytes(),
546 )),
547 address,
548 })
549 })
550 .collect::<anyhow::Result<Vec<_>>>()?;
551
552 P2pConfig {
553 listen_address: self.p2p_listen_address.unwrap_or_else(|| {
554 genesis_config.p2p_listen_address.unwrap_or_else(|| {
555 genesis_config
556 .p2p_address
557 .udp_multiaddr_to_listen_address()
558 .unwrap()
559 })
560 }),
561 external_address: self
562 .p2p_external_address
563 .or(Some(genesis_config.p2p_address.clone())),
564 seed_peers,
565 state_sync: Some(StateSyncConfig {
568 checkpoint_content_timeout_ms: Some(10_000),
569 ..Default::default()
570 }),
571 discovery: self.discovery_config,
573 ..Default::default()
574 }
575 };
576
577 let json_rpc_address = self.json_rpc_address.unwrap_or_else(|| {
578 self.rpc_addr.unwrap_or_else(|| {
579 let rpc_port = self
580 .rpc_port
581 .unwrap_or_else(|| local_ip_utils::get_available_port(&ip));
582 format!("{ip}:{rpc_port}").parse().unwrap()
583 })
584 });
585
586 let grpc_api_config = self.grpc_api_config.or_else(|| {
587 if self.enable_grpc_api {
588 Some(GrpcApiConfig {
589 address: format!("{ip}:{}", local_ip_utils::get_available_port(&ip))
590 .parse()
591 .unwrap(),
592 ..Default::default()
593 })
594 } else {
595 Some(GrpcApiConfig::default())
599 }
600 });
601
602 let checkpoint_executor_config = CheckpointExecutorConfig {
603 data_ingestion_dir: self.data_ingestion_dir,
604 ..Default::default()
605 };
606
607 let mut pruning_config = local_network_pruning_config();
608 if let Some(epochs) = self.num_epochs_to_retain_for_indexes {
609 pruning_config.num_epochs_to_retain_for_indexes = Some(epochs);
610 }
611 if self.disable_pruning {
612 pruning_config.set_num_epochs_to_retain_for_checkpoints(Some(u64::MAX));
613 pruning_config.set_num_epochs_to_retain(u64::MAX);
614 };
615
616 Ok(NodeConfig {
617 authority_key_pair: AuthorityKeyPairWithPath::new(genesis_config.authority_key_pair),
618 account_key_pair: KeyPairWithPath::new(genesis_config.account_key_pair),
619 protocol_key_pair: KeyPairWithPath::new(genesis_config.protocol_key_pair.into()),
620 network_key_pair: self
621 .network_key_pair
622 .unwrap_or(KeyPairWithPath::new(genesis_config.network_key_pair.into())),
623 db_path: self
624 .db_path
625 .unwrap_or(config_directory.join(FULL_NODE_DB_PATH).join(key_path)),
626 network_address: self
627 .network_address
628 .unwrap_or(genesis_config.network_address),
629 metrics_address: self
630 .metrics_address
631 .unwrap_or(genesis_config.metrics_address),
632 admin_interface_address: self
633 .admin_interface_address
634 .unwrap_or(genesis_config.admin_interface_address),
635 json_rpc_address,
636 consensus_config: None,
637 enable_jsonrpc_api: self
638 .enable_jsonrpc_api
639 .unwrap_or_else(default_enable_jsonrpc_api),
640 enable_index_processing: None,
641 genesis,
642 migration_tx_data_path,
643 grpc_load_shed: None,
644 grpc_concurrency_limit_per_core: NonZeroUsize::new(500_000_000).unwrap(),
647 p2p_config,
648 authority_store_pruning_config: pruning_config,
649 end_of_epoch_broadcast_channel_capacity:
650 default_end_of_epoch_broadcast_channel_capacity(),
651 checkpoint_executor_config,
652 metrics: None,
653 supported_protocol_versions: self.supported_protocol_versions,
654 expensive_safety_check_config: self
655 .expensive_safety_check_config
656 .unwrap_or_else(ExpensiveSafetyCheckConfig::new_enable_all),
657 transaction_deny_config: Default::default(),
658 certificate_deny_config: Default::default(),
659 state_debug_dump_config: Default::default(),
660 checkpoint_archive_config: None,
661 state_snapshot_write_config: self.state_snapshot_write_config.unwrap_or_default(),
662 transaction_kv_store_read_config: Default::default(),
663 transaction_kv_store_write_config: Default::default(),
664 authority_overload_config: Default::default(),
665 run_with_range: self.run_with_range,
666 policy_config: self.policy_config,
667 execution_cache_config: ExecutionCacheConfig::default(),
668 full_checkpoint_contents_cache_size_mb: default_full_checkpoint_contents_cache_size_mb(
669 ),
670 enable_validator_tx_finalizer: false,
672 enable_soft_locking: true,
675 verifier_signing_config: VerifierSigningConfig::default(),
676 enable_db_write_stall: None,
677 iota_names_config: self.iota_names_config,
678 enable_grpc_api: self.enable_grpc_api,
679 grpc_api_config,
680 chain_override_for_testing: self.chain_override,
681 validator_client_monitor_config: None,
682 validator_grpc_listener_limits: Default::default(),
683 json_rpc_listener_limits: Default::default(),
684 grpc_api_listener_limits: Default::default(),
685 })
686 }
687
688 pub fn build<R: rand::CryptoRng>(
694 self,
695 rng: &mut R,
696 network_config: &NetworkConfig,
697 ) -> NodeConfig {
698 self.try_build(rng, network_config)
699 .unwrap_or_else(|err| panic!("{err:#}"))
700 }
701
702 pub fn try_build<R: rand::CryptoRng>(
706 self,
707 rng: &mut R,
708 network_config: &NetworkConfig,
709 ) -> anyhow::Result<NodeConfig> {
710 let genesis = self.genesis_for(network_config);
711 self.try_build_from_parts(rng, network_config.validator_configs(), genesis)
712 }
713
714 pub fn try_build_with_genesis_config(
719 self,
720 genesis_config: ValidatorGenesisConfig,
721 network_config: &NetworkConfig,
722 ) -> anyhow::Result<NodeConfig> {
723 let genesis = self.genesis_for(network_config);
724 self.try_build_from_genesis_config(
725 genesis_config,
726 network_config.validator_configs(),
727 genesis,
728 )
729 }
730
731 fn genesis_for(&self, network_config: &NetworkConfig) -> Genesis {
732 self.genesis
733 .as_ref()
734 .or_else(|| network_config.get_validator_genesis())
735 .cloned()
736 .unwrap_or_else(|| Genesis::new(network_config.genesis.clone()))
737 }
738}
739
740fn get_key_path(key_pair: &AuthorityKeyPair) -> String {
743 let public_key: AuthorityPublicKeyBytes = key_pair.public().into();
744 let mut key_path = Hex::encode(public_key);
745 key_path.truncate(12);
748 key_path
749}
750
751fn local_network_pruning_config() -> AuthorityStorePruningConfig {
756 let mut pruning_config = AuthorityStorePruningConfig::default();
757 if !cfg!(msim) {
758 pruning_config.set_num_epochs_to_retain_for_checkpoints(Some(u64::MAX));
759 }
760 pruning_config
761}
762
763#[cfg(test)]
764mod tests {
765 use rand::{rand_core::UnwrapErr, rngs::SysRng};
766
767 use super::{FullnodeConfigBuilder, Genesis, ValidatorGenesisConfigBuilder};
768
769 #[test]
772 fn a_fullnode_takes_its_addresses_from_its_genesis_config() {
773 let dir = tempfile::TempDir::new().unwrap();
774 let mut genesis_config = ValidatorGenesisConfigBuilder::new()
775 .with_ip("127.0.0.1".to_owned())
776 .build(&mut UnwrapErr(SysRng));
777 genesis_config.metrics_address = ([127, 0, 0, 1], 9184).into();
778 genesis_config.admin_interface_address = ([127, 0, 0, 1], 9185).into();
779 genesis_config.p2p_address = "/ip4/127.0.0.1/udp/9186/http".parse().unwrap();
780
781 let config = FullnodeConfigBuilder::new()
782 .with_config_directory(dir.path().to_path_buf())
783 .try_build_from_genesis_config(
784 genesis_config.copy_with_private_keys(),
785 &[],
786 Genesis::new_empty(),
787 )
788 .unwrap();
789
790 assert_eq!(config.metrics_address.to_string(), "127.0.0.1:9184");
791 assert_eq!(config.admin_interface_address.to_string(), "127.0.0.1:9185");
792 assert_eq!(
793 config.p2p_config.external_address.as_ref().unwrap(),
794 &genesis_config.p2p_address
795 );
796 assert_eq!(
797 config.p2p_config.listen_address.to_string(),
798 "127.0.0.1:9186"
799 );
800
801 let same = FullnodeConfigBuilder::new()
803 .with_config_directory(dir.path().to_path_buf())
804 .try_build_from_genesis_config(genesis_config, &[], Genesis::new_empty())
805 .unwrap();
806 assert_eq!(config.db_path, same.db_path);
807 assert_eq!(
808 config.authority_public_key(),
809 same.authority_public_key(),
810 "the fullnode's identity is not the one its genesis config gives it"
811 );
812 }
813
814 #[test]
815 fn an_address_set_on_the_builder_wins_over_the_genesis_config() {
816 let mut genesis_config = ValidatorGenesisConfigBuilder::new()
817 .with_ip("127.0.0.1".to_owned())
818 .build(&mut UnwrapErr(SysRng));
819 genesis_config.metrics_address = ([127, 0, 0, 1], 9184).into();
820 genesis_config.admin_interface_address = ([127, 0, 0, 1], 9185).into();
821
822 let config = FullnodeConfigBuilder::new()
823 .with_admin_interface_address(Some(([127, 0, 0, 1], 1337)))
824 .try_build_from_genesis_config(genesis_config, &[], Genesis::new_empty())
825 .unwrap();
826
827 assert_eq!(config.admin_interface_address.to_string(), "127.0.0.1:1337");
828 assert_eq!(config.metrics_address.to_string(), "127.0.0.1:9184");
829 }
830 #[test]
833 fn every_builder_constructor_serves_json_rpc_unless_told_otherwise() {
834 let build = |builder: FullnodeConfigBuilder| {
835 let genesis_config = ValidatorGenesisConfigBuilder::new()
836 .with_ip("127.0.0.1".to_owned())
837 .build(&mut UnwrapErr(SysRng));
838 builder
839 .try_build_from_genesis_config(genesis_config, &[], Genesis::new_empty())
840 .unwrap()
841 .enable_jsonrpc_api
842 };
843 assert!(build(FullnodeConfigBuilder::default()));
844 assert!(build(FullnodeConfigBuilder::new()));
845 assert!(!build(
846 FullnodeConfigBuilder::new().with_enable_jsonrpc_api(false)
847 ));
848 }
849}