1use std::{net::SocketAddr, num::NonZeroUsize, path::PathBuf};
6
7use anyhow::anyhow;
8use fastcrypto::{
9 encoding::{Encoding, Hex},
10 traits::KeyPair,
11};
12use iota_config::{
13 AUTHORITIES_DB_NAME, CONSENSUS_DB_NAME, ConsensusConfig, FULL_NODE_DB_PATH,
14 IOTA_GENESIS_MIGRATION_TX_DATA_FILENAME, NodeConfig, local_ip_utils,
15 node::{
16 AuthorityKeyPairWithPath, AuthorityOverloadConfig, AuthorityStorePruningConfig,
17 CheckpointExecutorConfig, ExecutionCacheConfig, ExpensiveSafetyCheckConfig, Genesis,
18 GrpcApiConfig, KeyPairWithPath, RunWithRange, StateSnapshotConfig,
19 default_enable_index_processing, default_end_of_epoch_broadcast_channel_capacity,
20 default_full_checkpoint_contents_cache_size_mb,
21 },
22 p2p::{DiscoveryConfig, P2pConfig, SeedPeer, StateSyncConfig},
23 transaction_deny_config::TransactionDenyConfig,
24 verifier_signing_config::VerifierSigningConfig,
25};
26use iota_multiaddr::Multiaddr;
27use iota_names::config::IotaNamesConfig;
28use iota_protocol_config::Chain;
29use iota_types::{
30 crypto::{
31 AuthorityKeyPair, AuthorityPublicKeyBytes, NetworkKeyPair, network_to_simple_keypair,
32 },
33 supported_protocol_versions::SupportedProtocolVersions,
34 traffic_control::{PolicyConfig, RemoteFirewallConfig},
35};
36
37use crate::{
38 genesis_config::{ValidatorGenesisConfig, ValidatorGenesisConfigBuilder},
39 network_config::NetworkConfig,
40};
41
42#[derive(Clone, Default)]
46pub struct ValidatorConfigBuilder {
47 config_directory: Option<PathBuf>,
48 supported_protocol_versions: Option<SupportedProtocolVersions>,
49 force_unpruned_checkpoints: bool,
50 authority_overload_config: Option<AuthorityOverloadConfig>,
51 transaction_deny_config: Option<TransactionDenyConfig>,
52 execution_cache_config: Option<ExecutionCacheConfig>,
53 data_ingestion_dir: Option<PathBuf>,
54 policy_config: Option<PolicyConfig>,
55 firewall_config: Option<RemoteFirewallConfig>,
56 max_submit_position: Option<usize>,
57 submit_delay_step_override_millis: Option<u64>,
58 discovery_config: Option<DiscoveryConfig>,
59 chain_override: Option<Chain>,
60}
61
62impl ValidatorConfigBuilder {
63 pub fn new() -> Self {
64 Self {
65 ..Default::default()
66 }
67 }
68
69 pub fn with_chain_override(mut self, chain: Chain) -> Self {
70 assert!(self.chain_override.is_none(), "Chain override already set");
71 self.chain_override = Some(chain);
72 self
73 }
74
75 pub fn with_config_directory(mut self, config_directory: PathBuf) -> Self {
76 assert!(self.config_directory.is_none());
77 self.config_directory = Some(config_directory);
78 self
79 }
80
81 pub fn with_supported_protocol_versions(
82 mut self,
83 supported_protocol_versions: SupportedProtocolVersions,
84 ) -> Self {
85 assert!(self.supported_protocol_versions.is_none());
86 self.supported_protocol_versions = Some(supported_protocol_versions);
87 self
88 }
89
90 pub fn with_unpruned_checkpoints(mut self) -> Self {
91 self.force_unpruned_checkpoints = true;
92 self
93 }
94
95 pub fn with_authority_overload_config(mut self, config: AuthorityOverloadConfig) -> Self {
96 self.authority_overload_config = Some(config);
97 self
98 }
99
100 pub fn with_transaction_deny_config(mut self, config: TransactionDenyConfig) -> Self {
101 self.transaction_deny_config = Some(config);
102 self
103 }
104
105 pub fn with_execution_cache_config(mut self, config: ExecutionCacheConfig) -> Self {
106 self.execution_cache_config = Some(config);
107 self
108 }
109
110 pub fn with_data_ingestion_dir(mut self, path: PathBuf) -> Self {
111 self.data_ingestion_dir = Some(path);
112 self
113 }
114
115 pub fn with_policy_config(mut self, config: Option<PolicyConfig>) -> Self {
116 self.policy_config = config;
117 self
118 }
119
120 pub fn with_firewall_config(mut self, config: Option<RemoteFirewallConfig>) -> Self {
121 self.firewall_config = config;
122 self
123 }
124
125 pub fn with_max_submit_position(mut self, max_submit_position: usize) -> Self {
126 self.max_submit_position = Some(max_submit_position);
127 self
128 }
129
130 pub fn with_submit_delay_step_override_millis(
131 mut self,
132 submit_delay_step_override_millis: u64,
133 ) -> Self {
134 self.submit_delay_step_override_millis = Some(submit_delay_step_override_millis);
135 self
136 }
137
138 pub fn with_discovery_config(mut self, discovery_config: DiscoveryConfig) -> Self {
139 self.discovery_config = Some(discovery_config);
140 self
141 }
142
143 pub fn build_without_genesis(self, validator: ValidatorGenesisConfig) -> NodeConfig {
144 let key_path = get_key_path(&validator.authority_key_pair);
145 let config_directory = self
146 .config_directory
147 .unwrap_or_else(|| iota_common::tempdir().keep());
148 let migration_tx_data_path =
149 Some(config_directory.join(IOTA_GENESIS_MIGRATION_TX_DATA_FILENAME));
150 let db_path = config_directory
151 .join(AUTHORITIES_DB_NAME)
152 .join(key_path.clone());
153 let network_address = validator.network_address;
154 let consensus_db_path = config_directory.join(CONSENSUS_DB_NAME).join(key_path);
155 let localhost = local_ip_utils::localhost_for_testing();
156 let consensus_config = ConsensusConfig {
157 db_path: consensus_db_path,
158 db_retention_epochs: None,
159 db_pruner_period_secs: None,
160 max_pending_transactions: None,
161 max_submit_position: self.max_submit_position,
162 submit_delay_step_override_millis: self.submit_delay_step_override_millis,
163 parameters: Default::default(),
164 graduated_load_shedding_soft_limit_pct: Default::default(),
165 };
166
167 let p2p_config = P2pConfig {
168 listen_address: validator.p2p_listen_address.unwrap_or_else(|| {
169 validator
170 .p2p_address
171 .udp_multiaddr_to_listen_address()
172 .unwrap()
173 }),
174 external_address: Some(validator.p2p_address),
175 state_sync: Some(StateSyncConfig {
178 checkpoint_content_timeout_ms: Some(10_000),
179 ..Default::default()
180 }),
181 discovery: self.discovery_config,
183 ..Default::default()
184 };
185
186 let mut pruning_config = AuthorityStorePruningConfig::default();
187 if self.force_unpruned_checkpoints {
188 pruning_config.set_num_epochs_to_retain_for_checkpoints(None);
189 }
190 let pruning_config = pruning_config;
191 let checkpoint_executor_config = CheckpointExecutorConfig {
192 data_ingestion_dir: self.data_ingestion_dir,
193 ..Default::default()
194 };
195
196 NodeConfig {
197 authority_key_pair: AuthorityKeyPairWithPath::new(validator.authority_key_pair),
198 network_key_pair: KeyPairWithPath::new(network_to_simple_keypair(
199 &validator.network_key_pair,
200 )),
201 account_key_pair: KeyPairWithPath::new(validator.account_key_pair),
202 protocol_key_pair: KeyPairWithPath::new(network_to_simple_keypair(
203 &validator.protocol_key_pair,
204 )),
205 db_path,
206 network_address,
207 metrics_address: validator.metrics_address,
208 admin_interface_address: validator.admin_interface_address,
209 json_rpc_address: local_ip_utils::new_tcp_address_for_testing(&localhost)
210 .to_socket_addr()
211 .unwrap(),
212 consensus_config: Some(consensus_config),
213 enable_index_processing: default_enable_index_processing(),
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 indexer_max_subscriptions: Default::default(),
236 transaction_kv_store_read_config: Default::default(),
237 transaction_kv_store_write_config: None,
238 authority_overload_config: self.authority_overload_config.unwrap_or_default(),
239 execution_cache_config: self.execution_cache_config.unwrap_or_default(),
240 full_checkpoint_contents_cache_size_mb: default_full_checkpoint_contents_cache_size_mb(
241 ),
242 run_with_range: None,
243 jsonrpc_server_type: None,
244 policy_config: self.policy_config,
245 firewall_config: self.firewall_config,
246 enable_validator_tx_finalizer: true,
247 enable_soft_locking: true,
248 verifier_signing_config: VerifierSigningConfig::default(),
249 enable_db_write_stall: None,
250 iota_names_config: None,
251 enable_grpc_api: false,
252 grpc_api_config: None,
253 chain_override_for_testing: self.chain_override,
254 validator_client_monitor_config: None,
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::RngCore + 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 fw_config: Option<RemoteFirewallConfig>,
298 data_ingestion_dir: Option<PathBuf>,
299 disable_pruning: bool,
300 iota_names_config: Option<IotaNamesConfig>,
301 enable_grpc_api: bool,
302 grpc_api_config: Option<GrpcApiConfig>,
303 discovery_config: Option<DiscoveryConfig>,
304 chain_override: Option<Chain>,
305 deterministic_port_base: Option<u16>,
306}
307
308impl FullnodeConfigBuilder {
309 pub fn new() -> Self {
310 Self::default()
311 }
312
313 pub fn with_chain_override(mut self, chain: Chain) -> Self {
314 assert!(self.chain_override.is_none(), "Chain override already set");
315 self.chain_override = Some(chain);
316 self
317 }
318
319 pub fn with_config_directory(mut self, config_directory: PathBuf) -> Self {
320 self.config_directory = Some(config_directory);
321 self
322 }
323
324 pub fn with_rpc_port(mut self, port: u16) -> Self {
325 assert!(self.rpc_addr.is_none() && self.rpc_port.is_none());
326 self.rpc_port = Some(port);
327 self
328 }
329
330 pub fn with_rpc_addr(mut self, addr: impl Into<SocketAddr>) -> Self {
331 assert!(self.rpc_addr.is_none() && self.rpc_port.is_none());
332 self.rpc_addr = Some(addr.into());
333 self
334 }
335
336 pub fn with_supported_protocol_versions(mut self, versions: SupportedProtocolVersions) -> Self {
337 self.supported_protocol_versions = Some(versions);
338 self
339 }
340
341 pub fn with_disable_pruning(mut self, disable_pruning: bool) -> Self {
342 self.disable_pruning = disable_pruning;
343 self
344 }
345
346 pub fn with_expensive_safety_check_config(
347 mut self,
348 expensive_safety_check_config: ExpensiveSafetyCheckConfig,
349 ) -> Self {
350 self.expensive_safety_check_config = Some(expensive_safety_check_config);
351 self
352 }
353
354 pub fn with_db_path(mut self, db_path: PathBuf) -> Self {
355 self.db_path = Some(db_path);
356 self
357 }
358
359 pub fn with_network_address(mut self, network_address: Multiaddr) -> Self {
360 self.network_address = Some(network_address);
361 self
362 }
363
364 pub fn with_json_rpc_address(mut self, json_rpc_address: impl Into<SocketAddr>) -> Self {
365 self.json_rpc_address = Some(json_rpc_address.into());
366 self
367 }
368
369 pub fn with_metrics_address(mut self, metrics_address: impl Into<SocketAddr>) -> Self {
370 self.metrics_address = Some(metrics_address.into());
371 self
372 }
373
374 pub fn with_admin_interface_address(
375 mut self,
376 admin_interface_address: Option<impl Into<SocketAddr>>,
377 ) -> Self {
378 self.admin_interface_address = admin_interface_address.map(|addr| addr.into());
379 self
380 }
381
382 pub fn with_genesis(mut self, genesis: Genesis) -> Self {
383 self.genesis = Some(genesis);
384 self
385 }
386
387 pub fn with_p2p_external_address(mut self, p2p_external_address: Multiaddr) -> Self {
388 self.p2p_external_address = Some(p2p_external_address);
389 self
390 }
391
392 pub fn with_p2p_listen_address(mut self, p2p_listen_address: impl Into<SocketAddr>) -> Self {
393 self.p2p_listen_address = Some(p2p_listen_address.into());
394 self
395 }
396
397 pub fn with_network_key_pair(mut self, network_key_pair: Option<NetworkKeyPair>) -> Self {
398 if let Some(network_key_pair) = network_key_pair {
399 self.network_key_pair = Some(KeyPairWithPath::new(network_to_simple_keypair(
400 &network_key_pair,
401 )));
402 }
403 self
404 }
405
406 pub fn with_run_with_range(mut self, run_with_range: Option<RunWithRange>) -> Self {
407 if let Some(run_with_range) = run_with_range {
408 self.run_with_range = Some(run_with_range);
409 }
410 self
411 }
412
413 pub fn with_policy_config(mut self, config: Option<PolicyConfig>) -> Self {
414 self.policy_config = config;
415 self
416 }
417
418 pub fn with_fw_config(mut self, config: Option<RemoteFirewallConfig>) -> Self {
419 self.fw_config = config;
420 self
421 }
422
423 pub fn with_data_ingestion_dir(mut self, path: Option<PathBuf>) -> Self {
424 self.data_ingestion_dir = path;
425 self
426 }
427
428 pub fn with_iota_names_config(mut self, config: Option<IotaNamesConfig>) -> Self {
429 self.iota_names_config = config;
430 self
431 }
432
433 pub fn with_enable_grpc_api(mut self, enable_grpc_api: bool) -> Self {
434 self.enable_grpc_api = enable_grpc_api;
435 self
436 }
437
438 pub fn with_grpc_api_config(mut self, config: GrpcApiConfig) -> Self {
439 self.grpc_api_config = Some(config);
440 self
441 }
442
443 pub fn with_discovery_config(mut self, discovery_config: DiscoveryConfig) -> Self {
444 self.discovery_config = Some(discovery_config);
445 self
446 }
447
448 pub fn with_deterministic_ports(mut self, port_base: u16) -> Self {
455 self.deterministic_port_base = Some(port_base);
456 self
457 }
458
459 pub fn build_from_parts<R: rand::RngCore + rand::CryptoRng>(
465 self,
466 rng: &mut R,
467 validator_configs: &[NodeConfig],
468 genesis: iota_config::node::Genesis,
469 ) -> NodeConfig {
470 self.try_build_from_parts(rng, validator_configs, genesis)
471 .unwrap_or_else(|err| panic!("{err:#}"))
472 }
473
474 pub fn try_build_from_parts<R: rand::RngCore + rand::CryptoRng>(
485 self,
486 rng: &mut R,
487 validator_configs: &[NodeConfig],
488 genesis: iota_config::node::Genesis,
489 ) -> anyhow::Result<NodeConfig> {
490 let validator_config = ValidatorGenesisConfigBuilder::new().build(rng);
493 let node_ip = validator_config
494 .network_address
495 .to_socket_addr()
496 .unwrap()
497 .ip();
498 let ip = node_ip.to_string();
499
500 let key_path = get_key_path(&validator_config.authority_key_pair);
501 let config_directory = self
502 .config_directory
503 .unwrap_or_else(|| iota_common::tempdir().keep());
504
505 let migration_tx_data_path =
506 Some(config_directory.join(IOTA_GENESIS_MIGRATION_TX_DATA_FILENAME));
507
508 let deterministic_port = |offset: u16| {
509 self.deterministic_port_base.map(|port_base| {
510 port_base.checked_add(offset).unwrap_or_else(|| {
511 panic!("the fullnode port layout does not fit above port {port_base}")
512 })
513 })
514 };
515 let deterministic_metrics_address =
516 deterministic_port(0).map(|port| SocketAddr::new(node_ip, port));
517 let deterministic_admin_interface_address =
518 deterministic_port(1).map(|port| SocketAddr::new(node_ip, port));
519 let deterministic_p2p_address = deterministic_port(2)
520 .map(|port| local_ip_utils::new_deterministic_udp_address_for_testing(&ip, port));
521
522 let p2p_config = {
523 let seed_peers = validator_configs
524 .iter()
525 .enumerate()
526 .map(|(index, config)| {
527 let address = config.p2p_config.external_address.clone().ok_or_else(|| {
528 anyhow!(
529 "validator {index} has no `p2p-config.external-address`, which the \
530 fullnode needs to derive its seed peers: either its config never set \
531 one or it was cleared"
532 )
533 })?;
534 Ok(SeedPeer {
535 peer_id: Some(anemo::PeerId(
536 config.network_key_pair().public().0.to_bytes(),
537 )),
538 address,
539 })
540 })
541 .collect::<anyhow::Result<Vec<_>>>()?;
542
543 P2pConfig {
544 listen_address: self
545 .p2p_listen_address
546 .or_else(|| {
547 deterministic_p2p_address
548 .as_ref()
549 .and_then(|address| address.udp_multiaddr_to_listen_address())
550 })
551 .unwrap_or_else(|| {
552 validator_config.p2p_listen_address.unwrap_or_else(|| {
553 validator_config
554 .p2p_address
555 .udp_multiaddr_to_listen_address()
556 .unwrap()
557 })
558 }),
559 external_address: self
560 .p2p_external_address
561 .or(deterministic_p2p_address)
562 .or(Some(validator_config.p2p_address.clone())),
563 seed_peers,
564 state_sync: Some(StateSyncConfig {
567 checkpoint_content_timeout_ms: Some(10_000),
568 ..Default::default()
569 }),
570 discovery: self.discovery_config,
572 ..Default::default()
573 }
574 };
575
576 let json_rpc_address = self.json_rpc_address.unwrap_or_else(|| {
577 self.rpc_addr.unwrap_or_else(|| {
578 let rpc_port = self
579 .rpc_port
580 .unwrap_or_else(|| local_ip_utils::get_available_port(&ip));
581 format!("{ip}:{rpc_port}").parse().unwrap()
582 })
583 });
584
585 let grpc_api_config = self.grpc_api_config.or_else(|| {
586 if self.enable_grpc_api {
587 Some(GrpcApiConfig {
588 address: format!("{ip}:{}", local_ip_utils::get_available_port(&ip))
589 .parse()
590 .unwrap(),
591 ..Default::default()
592 })
593 } else {
594 None
595 }
596 });
597
598 let checkpoint_executor_config = CheckpointExecutorConfig {
599 data_ingestion_dir: self.data_ingestion_dir,
600 ..Default::default()
601 };
602
603 let mut pruning_config = AuthorityStorePruningConfig::default();
604 if self.disable_pruning {
605 pruning_config.set_num_epochs_to_retain_for_checkpoints(None);
606 pruning_config.set_num_epochs_to_retain(u64::MAX);
607 };
608
609 Ok(NodeConfig {
610 authority_key_pair: AuthorityKeyPairWithPath::new(validator_config.authority_key_pair),
611 account_key_pair: KeyPairWithPath::new(validator_config.account_key_pair),
612 protocol_key_pair: KeyPairWithPath::new(network_to_simple_keypair(
613 &validator_config.protocol_key_pair,
614 )),
615 network_key_pair: self.network_key_pair.unwrap_or(KeyPairWithPath::new(
616 network_to_simple_keypair(&validator_config.network_key_pair),
617 )),
618 db_path: self
619 .db_path
620 .unwrap_or(config_directory.join(FULL_NODE_DB_PATH).join(key_path)),
621 network_address: self
622 .network_address
623 .unwrap_or(validator_config.network_address),
624 metrics_address: self
625 .metrics_address
626 .or(deterministic_metrics_address)
627 .unwrap_or_else(local_ip_utils::new_local_tcp_socket_for_testing),
628 admin_interface_address: self
629 .admin_interface_address
630 .or(deterministic_admin_interface_address)
631 .unwrap_or_else(local_ip_utils::new_local_tcp_socket_for_testing),
632 json_rpc_address,
633 consensus_config: None,
634 enable_index_processing: default_enable_index_processing(),
635 genesis,
636 migration_tx_data_path,
637 grpc_load_shed: None,
638 grpc_concurrency_limit_per_core: NonZeroUsize::new(500_000_000).unwrap(),
641 p2p_config,
642 authority_store_pruning_config: pruning_config,
643 end_of_epoch_broadcast_channel_capacity:
644 default_end_of_epoch_broadcast_channel_capacity(),
645 checkpoint_executor_config,
646 metrics: None,
647 supported_protocol_versions: self.supported_protocol_versions,
648 expensive_safety_check_config: self
649 .expensive_safety_check_config
650 .unwrap_or_else(ExpensiveSafetyCheckConfig::new_enable_all),
651 transaction_deny_config: Default::default(),
652 certificate_deny_config: Default::default(),
653 state_debug_dump_config: Default::default(),
654 checkpoint_archive_config: None,
655 state_snapshot_write_config: StateSnapshotConfig::default(),
656 indexer_max_subscriptions: Default::default(),
657 transaction_kv_store_read_config: Default::default(),
658 transaction_kv_store_write_config: Default::default(),
659 authority_overload_config: Default::default(),
660 run_with_range: self.run_with_range,
661 jsonrpc_server_type: None,
662 policy_config: self.policy_config,
663 firewall_config: self.fw_config,
664 execution_cache_config: ExecutionCacheConfig::default(),
665 full_checkpoint_contents_cache_size_mb: default_full_checkpoint_contents_cache_size_mb(
666 ),
667 enable_validator_tx_finalizer: false,
669 enable_soft_locking: true,
672 verifier_signing_config: VerifierSigningConfig::default(),
673 enable_db_write_stall: None,
674 iota_names_config: self.iota_names_config,
675 enable_grpc_api: self.enable_grpc_api,
676 grpc_api_config,
677 chain_override_for_testing: self.chain_override,
678 validator_client_monitor_config: None,
679 })
680 }
681
682 pub fn build<R: rand::RngCore + rand::CryptoRng>(
688 self,
689 rng: &mut R,
690 network_config: &NetworkConfig,
691 ) -> NodeConfig {
692 self.try_build(rng, network_config)
693 .unwrap_or_else(|err| panic!("{err:#}"))
694 }
695
696 pub fn try_build<R: rand::RngCore + rand::CryptoRng>(
707 self,
708 rng: &mut R,
709 network_config: &NetworkConfig,
710 ) -> anyhow::Result<NodeConfig> {
711 let genesis = self
712 .genesis
713 .as_ref()
714 .or_else(|| network_config.get_validator_genesis())
715 .cloned()
716 .unwrap_or_else(|| iota_config::node::Genesis::new(network_config.genesis.clone()));
717 self.try_build_from_parts(rng, network_config.validator_configs(), genesis)
718 }
719}
720
721fn get_key_path(key_pair: &AuthorityKeyPair) -> String {
724 let public_key: AuthorityPublicKeyBytes = key_pair.public().into();
725 let mut key_path = Hex::encode(public_key);
726 key_path.truncate(12);
729 key_path
730}
731
732#[cfg(test)]
733mod tests {
734 use std::net::SocketAddr;
735
736 use rand::rngs::OsRng;
737
738 use super::{FullnodeConfigBuilder, Genesis};
739
740 #[test]
741 fn deterministic_ports_fill_the_three_slots_of_a_fullnode() {
742 let config = FullnodeConfigBuilder::new()
743 .with_deterministic_ports(9184)
744 .build_from_parts(&mut OsRng, &[], Genesis::new_empty());
745 let ip = config.network_address.to_socket_addr().unwrap().ip();
746
747 assert_eq!(config.metrics_address, SocketAddr::new(ip, 9184));
748 assert_eq!(config.admin_interface_address, SocketAddr::new(ip, 9185));
749 assert_eq!(
750 config.p2p_config.external_address.unwrap().to_string(),
751 format!("/ip4/{ip}/udp/9186/http")
752 );
753 assert_eq!(config.p2p_config.listen_address, SocketAddr::new(ip, 9186));
754 }
755
756 #[test]
757 fn an_address_set_on_the_builder_wins_over_the_deterministic_ports() {
758 let config = FullnodeConfigBuilder::new()
759 .with_deterministic_ports(9184)
760 .with_admin_interface_address(Some(([127, 0, 0, 1], 1337)))
761 .build_from_parts(&mut OsRng, &[], Genesis::new_empty());
762 let ip = config.network_address.to_socket_addr().unwrap().ip();
763
764 assert_eq!(config.admin_interface_address.to_string(), "127.0.0.1:1337");
765 assert_eq!(config.metrics_address, SocketAddr::new(ip, 9184));
766 }
767}