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::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 state_snapshot_write_config: Option<StateSnapshotConfig>,
317}
318
319impl FullnodeConfigBuilder {
320 pub fn new() -> Self {
321 Self::default()
322 }
323
324 pub fn with_state_snapshot_config(mut self, config: StateSnapshotConfig) -> Self {
326 self.state_snapshot_write_config = Some(config);
327 self
328 }
329
330 pub fn with_chain_override(mut self, chain: Chain) -> Self {
331 assert!(self.chain_override.is_none(), "Chain override already set");
332 self.chain_override = Some(chain);
333 self
334 }
335
336 pub fn with_config_directory(mut self, config_directory: PathBuf) -> Self {
337 self.config_directory = Some(config_directory);
338 self
339 }
340
341 pub fn with_rpc_port(mut self, port: u16) -> Self {
342 assert!(self.rpc_addr.is_none() && self.rpc_port.is_none());
343 self.rpc_port = Some(port);
344 self
345 }
346
347 pub fn with_rpc_addr(mut self, addr: impl Into<SocketAddr>) -> Self {
348 assert!(self.rpc_addr.is_none() && self.rpc_port.is_none());
349 self.rpc_addr = Some(addr.into());
350 self
351 }
352
353 pub fn with_supported_protocol_versions(mut self, versions: SupportedProtocolVersions) -> Self {
354 self.supported_protocol_versions = Some(versions);
355 self
356 }
357
358 pub fn with_disable_pruning(mut self, disable_pruning: bool) -> Self {
359 self.disable_pruning = disable_pruning;
360 self
361 }
362
363 pub fn with_expensive_safety_check_config(
364 mut self,
365 expensive_safety_check_config: ExpensiveSafetyCheckConfig,
366 ) -> Self {
367 self.expensive_safety_check_config = Some(expensive_safety_check_config);
368 self
369 }
370
371 pub fn with_db_path(mut self, db_path: PathBuf) -> Self {
372 self.db_path = Some(db_path);
373 self
374 }
375
376 pub fn with_network_address(mut self, network_address: Multiaddr) -> Self {
377 self.network_address = Some(network_address);
378 self
379 }
380
381 pub fn with_json_rpc_address(mut self, json_rpc_address: impl Into<SocketAddr>) -> Self {
382 self.json_rpc_address = Some(json_rpc_address.into());
383 self
384 }
385
386 pub fn with_metrics_address(mut self, metrics_address: impl Into<SocketAddr>) -> Self {
387 self.metrics_address = Some(metrics_address.into());
388 self
389 }
390
391 pub fn with_admin_interface_address(
392 mut self,
393 admin_interface_address: Option<impl Into<SocketAddr>>,
394 ) -> Self {
395 self.admin_interface_address = admin_interface_address.map(|addr| addr.into());
396 self
397 }
398
399 pub fn with_genesis(mut self, genesis: Genesis) -> Self {
400 self.genesis = Some(genesis);
401 self
402 }
403
404 pub fn with_p2p_external_address(mut self, p2p_external_address: Multiaddr) -> Self {
405 self.p2p_external_address = Some(p2p_external_address);
406 self
407 }
408
409 pub fn with_p2p_listen_address(mut self, p2p_listen_address: impl Into<SocketAddr>) -> Self {
410 self.p2p_listen_address = Some(p2p_listen_address.into());
411 self
412 }
413
414 pub fn with_network_key_pair(mut self, network_key_pair: Option<NetworkKeyPair>) -> Self {
415 if let Some(network_key_pair) = network_key_pair {
416 self.network_key_pair = Some(KeyPairWithPath::new(network_to_simple_keypair(
417 &network_key_pair,
418 )));
419 }
420 self
421 }
422
423 pub fn with_run_with_range(mut self, run_with_range: Option<RunWithRange>) -> Self {
424 if let Some(run_with_range) = run_with_range {
425 self.run_with_range = Some(run_with_range);
426 }
427 self
428 }
429
430 pub fn with_policy_config(mut self, config: Option<PolicyConfig>) -> Self {
431 self.policy_config = config;
432 self
433 }
434
435 pub fn with_fw_config(mut self, config: Option<RemoteFirewallConfig>) -> Self {
436 self.fw_config = config;
437 self
438 }
439
440 pub fn with_data_ingestion_dir(mut self, path: Option<PathBuf>) -> Self {
441 self.data_ingestion_dir = path;
442 self
443 }
444
445 pub fn with_iota_names_config(mut self, config: Option<IotaNamesConfig>) -> Self {
446 self.iota_names_config = config;
447 self
448 }
449
450 pub fn with_enable_grpc_api(mut self, enable_grpc_api: bool) -> Self {
451 self.enable_grpc_api = enable_grpc_api;
452 self
453 }
454
455 pub fn with_grpc_api_config(mut self, config: GrpcApiConfig) -> Self {
456 self.grpc_api_config = Some(config);
457 self
458 }
459
460 pub fn with_discovery_config(mut self, discovery_config: DiscoveryConfig) -> Self {
461 self.discovery_config = Some(discovery_config);
462 self
463 }
464
465 pub fn build_from_parts<R: rand::CryptoRng>(
471 self,
472 rng: &mut R,
473 validator_configs: &[NodeConfig],
474 genesis: iota_config::node::Genesis,
475 ) -> NodeConfig {
476 self.try_build_from_parts(rng, validator_configs, genesis)
477 .unwrap_or_else(|err| panic!("{err:#}"))
478 }
479
480 pub fn try_build_from_parts<R: rand::CryptoRng>(
485 self,
486 rng: &mut R,
487 validator_configs: &[NodeConfig],
488 genesis: iota_config::node::Genesis,
489 ) -> anyhow::Result<NodeConfig> {
490 let genesis_config = ValidatorGenesisConfigBuilder::new().build(rng);
493 self.try_build_from_genesis_config(genesis_config, validator_configs, genesis)
494 }
495
496 pub fn try_build_from_genesis_config(
512 self,
513 genesis_config: ValidatorGenesisConfig,
514 validator_configs: &[NodeConfig],
515 genesis: iota_config::node::Genesis,
516 ) -> anyhow::Result<NodeConfig> {
517 let ip = genesis_config
518 .network_address
519 .to_socket_addr()
520 .unwrap()
521 .ip()
522 .to_string();
523
524 let key_path = get_key_path(&genesis_config.authority_key_pair);
525 let config_directory = self
526 .config_directory
527 .unwrap_or_else(|| iota_common::tempdir().keep());
528
529 let migration_tx_data_path =
530 Some(config_directory.join(IOTA_GENESIS_MIGRATION_TX_DATA_FILENAME));
531
532 let p2p_config = {
533 let seed_peers = validator_configs
534 .iter()
535 .enumerate()
536 .map(|(index, config)| {
537 let address = config.p2p_config.external_address.clone().ok_or_else(|| {
538 anyhow!(
539 "validator {index} has no `p2p-config.external-address`, which the \
540 fullnode needs to derive its seed peers: either its config never set \
541 one or it was cleared"
542 )
543 })?;
544 Ok(SeedPeer {
545 peer_id: Some(anemo::PeerId(
546 config.network_key_pair().public().0.to_bytes(),
547 )),
548 address,
549 })
550 })
551 .collect::<anyhow::Result<Vec<_>>>()?;
552
553 P2pConfig {
554 listen_address: self.p2p_listen_address.unwrap_or_else(|| {
555 genesis_config.p2p_listen_address.unwrap_or_else(|| {
556 genesis_config
557 .p2p_address
558 .udp_multiaddr_to_listen_address()
559 .unwrap()
560 })
561 }),
562 external_address: self
563 .p2p_external_address
564 .or(Some(genesis_config.p2p_address.clone())),
565 seed_peers,
566 state_sync: Some(StateSyncConfig {
569 checkpoint_content_timeout_ms: Some(10_000),
570 ..Default::default()
571 }),
572 discovery: self.discovery_config,
574 ..Default::default()
575 }
576 };
577
578 let json_rpc_address = self.json_rpc_address.unwrap_or_else(|| {
579 self.rpc_addr.unwrap_or_else(|| {
580 let rpc_port = self
581 .rpc_port
582 .unwrap_or_else(|| local_ip_utils::get_available_port(&ip));
583 format!("{ip}:{rpc_port}").parse().unwrap()
584 })
585 });
586
587 let grpc_api_config = self.grpc_api_config.or_else(|| {
588 if self.enable_grpc_api {
589 Some(GrpcApiConfig {
590 address: format!("{ip}:{}", local_ip_utils::get_available_port(&ip))
591 .parse()
592 .unwrap(),
593 ..Default::default()
594 })
595 } else {
596 Some(GrpcApiConfig::default())
600 }
601 });
602
603 let checkpoint_executor_config = CheckpointExecutorConfig {
604 data_ingestion_dir: self.data_ingestion_dir,
605 ..Default::default()
606 };
607
608 let mut pruning_config = AuthorityStorePruningConfig::default();
609 if self.disable_pruning {
610 pruning_config.set_num_epochs_to_retain_for_checkpoints(None);
611 pruning_config.set_num_epochs_to_retain(u64::MAX);
612 };
613
614 Ok(NodeConfig {
615 authority_key_pair: AuthorityKeyPairWithPath::new(genesis_config.authority_key_pair),
616 account_key_pair: KeyPairWithPath::new(genesis_config.account_key_pair),
617 protocol_key_pair: KeyPairWithPath::new(network_to_simple_keypair(
618 &genesis_config.protocol_key_pair,
619 )),
620 network_key_pair: self.network_key_pair.unwrap_or(KeyPairWithPath::new(
621 network_to_simple_keypair(&genesis_config.network_key_pair),
622 )),
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_index_processing: default_enable_index_processing(),
638 genesis,
639 migration_tx_data_path,
640 grpc_load_shed: None,
641 grpc_concurrency_limit_per_core: NonZeroUsize::new(500_000_000).unwrap(),
644 p2p_config,
645 authority_store_pruning_config: pruning_config,
646 end_of_epoch_broadcast_channel_capacity:
647 default_end_of_epoch_broadcast_channel_capacity(),
648 checkpoint_executor_config,
649 metrics: None,
650 supported_protocol_versions: self.supported_protocol_versions,
651 expensive_safety_check_config: self
652 .expensive_safety_check_config
653 .unwrap_or_else(ExpensiveSafetyCheckConfig::new_enable_all),
654 transaction_deny_config: Default::default(),
655 certificate_deny_config: Default::default(),
656 state_debug_dump_config: Default::default(),
657 checkpoint_archive_config: None,
658 state_snapshot_write_config: self.state_snapshot_write_config.unwrap_or_default(),
659 indexer_max_subscriptions: Default::default(),
660 transaction_kv_store_read_config: Default::default(),
661 transaction_kv_store_write_config: Default::default(),
662 authority_overload_config: Default::default(),
663 run_with_range: self.run_with_range,
664 jsonrpc_server_type: None,
665 policy_config: self.policy_config,
666 firewall_config: self.fw_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 })
683 }
684
685 pub fn build<R: rand::CryptoRng>(
691 self,
692 rng: &mut R,
693 network_config: &NetworkConfig,
694 ) -> NodeConfig {
695 self.try_build(rng, network_config)
696 .unwrap_or_else(|err| panic!("{err:#}"))
697 }
698
699 pub fn try_build<R: rand::CryptoRng>(
703 self,
704 rng: &mut R,
705 network_config: &NetworkConfig,
706 ) -> anyhow::Result<NodeConfig> {
707 let genesis = self.genesis_for(network_config);
708 self.try_build_from_parts(rng, network_config.validator_configs(), genesis)
709 }
710
711 pub fn try_build_with_genesis_config(
716 self,
717 genesis_config: ValidatorGenesisConfig,
718 network_config: &NetworkConfig,
719 ) -> anyhow::Result<NodeConfig> {
720 let genesis = self.genesis_for(network_config);
721 self.try_build_from_genesis_config(
722 genesis_config,
723 network_config.validator_configs(),
724 genesis,
725 )
726 }
727
728 fn genesis_for(&self, network_config: &NetworkConfig) -> Genesis {
729 self.genesis
730 .as_ref()
731 .or_else(|| network_config.get_validator_genesis())
732 .cloned()
733 .unwrap_or_else(|| Genesis::new(network_config.genesis.clone()))
734 }
735}
736
737fn get_key_path(key_pair: &AuthorityKeyPair) -> String {
740 let public_key: AuthorityPublicKeyBytes = key_pair.public().into();
741 let mut key_path = Hex::encode(public_key);
742 key_path.truncate(12);
745 key_path
746}
747
748#[cfg(test)]
749mod tests {
750 use rand::{rand_core::UnwrapErr, rngs::SysRng};
751
752 use super::{FullnodeConfigBuilder, Genesis, ValidatorGenesisConfigBuilder};
753
754 #[test]
757 fn a_fullnode_takes_its_addresses_from_its_genesis_config() {
758 let dir = tempfile::TempDir::new().unwrap();
759 let mut genesis_config = ValidatorGenesisConfigBuilder::new()
760 .with_ip("127.0.0.1".to_owned())
761 .build(&mut UnwrapErr(SysRng));
762 genesis_config.metrics_address = ([127, 0, 0, 1], 9184).into();
763 genesis_config.admin_interface_address = ([127, 0, 0, 1], 9185).into();
764 genesis_config.p2p_address = "/ip4/127.0.0.1/udp/9186/http".parse().unwrap();
765
766 let config = FullnodeConfigBuilder::new()
767 .with_config_directory(dir.path().to_path_buf())
768 .try_build_from_genesis_config(
769 genesis_config.copy_with_private_keys(),
770 &[],
771 Genesis::new_empty(),
772 )
773 .unwrap();
774
775 assert_eq!(config.metrics_address.to_string(), "127.0.0.1:9184");
776 assert_eq!(config.admin_interface_address.to_string(), "127.0.0.1:9185");
777 assert_eq!(
778 config.p2p_config.external_address.as_ref().unwrap(),
779 &genesis_config.p2p_address
780 );
781 assert_eq!(
782 config.p2p_config.listen_address.to_string(),
783 "127.0.0.1:9186"
784 );
785
786 let same = FullnodeConfigBuilder::new()
788 .with_config_directory(dir.path().to_path_buf())
789 .try_build_from_genesis_config(genesis_config, &[], Genesis::new_empty())
790 .unwrap();
791 assert_eq!(config.db_path, same.db_path);
792 assert_eq!(
793 config.authority_public_key(),
794 same.authority_public_key(),
795 "the fullnode's identity is not the one its genesis config gives it"
796 );
797 }
798
799 #[test]
800 fn an_address_set_on_the_builder_wins_over_the_genesis_config() {
801 let mut genesis_config = ValidatorGenesisConfigBuilder::new()
802 .with_ip("127.0.0.1".to_owned())
803 .build(&mut UnwrapErr(SysRng));
804 genesis_config.metrics_address = ([127, 0, 0, 1], 9184).into();
805 genesis_config.admin_interface_address = ([127, 0, 0, 1], 9185).into();
806
807 let config = FullnodeConfigBuilder::new()
808 .with_admin_interface_address(Some(([127, 0, 0, 1], 1337)))
809 .try_build_from_genesis_config(genesis_config, &[], Genesis::new_empty())
810 .unwrap();
811
812 assert_eq!(config.admin_interface_address.to_string(), "127.0.0.1:1337");
813 assert_eq!(config.metrics_address.to_string(), "127.0.0.1:9184");
814 }
815}