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