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