1use std::{
6 net::{IpAddr, Ipv4Addr, SocketAddr},
7 num::NonZeroUsize,
8 path::{Path, PathBuf},
9 sync::Arc,
10 time::Duration,
11};
12
13use anyhow::Result;
14use fastcrypto::ed25519::Ed25519KeyPair;
15use iota_keys::keypair_file::{read_authority_keypair_from_file, read_keypair_from_file};
16use iota_metrics::MetricGroups;
17use iota_multiaddr::Multiaddr;
18use iota_names::config::IotaNamesConfig;
19use iota_sdk_crypto::simple::SimpleKeypair;
20use iota_sdk_types::Address;
21use iota_types::{
22 committee::EpochId,
23 crypto::{
24 AccountKeyPair, AuthorityKeyPair, AuthorityPublicKeyBytes, KeypairTraits, NetworkKeyPair,
25 get_key_pair_from_rng, simple_to_network_keypair,
26 },
27 messages_checkpoint::CheckpointSequenceNumber,
28 supported_protocol_versions::{Chain, SupportedProtocolVersions},
29 traffic_control::{PolicyConfig, RemoteFirewallConfig},
30};
31use once_cell::sync::OnceCell;
32use rand::rngs::OsRng;
33use serde::{Deserialize, Serialize};
34use starfish_config::Parameters as StarfishParameters;
35use tracing::info;
36
37use crate::{
38 Config, certificate_deny_config::CertificateDenyConfig, genesis,
39 migration_tx_data::MigrationTxData, object_storage_config::ObjectStoreConfig, p2p::P2pConfig,
40 transaction_deny_config::TransactionDenyConfig, verifier_signing_config::VerifierSigningConfig,
41};
42
43pub const DEFAULT_VALIDATOR_GAS_PRICE: u64 = iota_types::transaction::DEFAULT_VALIDATOR_GAS_PRICE;
45
46pub const DEFAULT_COMMISSION_RATE: u64 = 200;
48
49pub const DEFAULT_FULL_CHECKPOINT_CONTENTS_CACHE_SIZE_MB: usize = 1024;
51
52#[derive(Clone, Debug, Deserialize, Serialize)]
53#[serde(rename_all = "kebab-case")]
54pub struct NodeConfig {
55 #[serde(default = "default_authority_key_pair")]
58 pub authority_key_pair: AuthorityKeyPairWithPath,
59 #[serde(default = "default_key_pair")]
62 pub protocol_key_pair: KeyPairWithPath,
63 #[serde(default = "default_key_pair")]
64 pub account_key_pair: KeyPairWithPath,
65 #[serde(default = "default_key_pair")]
68 pub network_key_pair: KeyPairWithPath,
69 pub db_path: PathBuf,
70
71 #[serde(default = "default_grpc_address")]
75 pub network_address: Multiaddr,
76 #[serde(default = "default_json_rpc_address")]
77 pub json_rpc_address: SocketAddr,
78
79 #[serde(default = "default_metrics_address")]
81 pub metrics_address: SocketAddr,
82
83 #[serde(default = "default_admin_interface_address")]
87 pub admin_interface_address: SocketAddr,
88
89 #[serde(skip_serializing_if = "Option::is_none")]
91 pub consensus_config: Option<ConsensusConfig>,
92
93 #[serde(default = "default_enable_index_processing")]
98 pub enable_index_processing: bool,
99
100 #[serde(default)]
102 pub jsonrpc_server_type: Option<ServerType>,
107
108 #[serde(default)]
112 pub grpc_load_shed: Option<bool>,
113
114 #[serde(default = "default_grpc_concurrency_limit_per_core")]
131 pub grpc_concurrency_limit_per_core: NonZeroUsize,
132
133 #[serde(default)]
135 pub p2p_config: P2pConfig,
136
137 pub genesis: Genesis,
141
142 pub migration_tx_data_path: Option<PathBuf>,
144
145 #[serde(default = "default_authority_store_pruning_config")]
148 pub authority_store_pruning_config: AuthorityStorePruningConfig,
149
150 #[serde(default = "default_end_of_epoch_broadcast_channel_capacity")]
155 pub end_of_epoch_broadcast_channel_capacity: usize,
156
157 #[serde(default)]
161 pub checkpoint_executor_config: CheckpointExecutorConfig,
162
163 #[serde(skip_serializing_if = "Option::is_none")]
164 pub metrics: Option<MetricsConfig>,
165
166 #[serde(skip)]
171 pub supported_protocol_versions: Option<SupportedProtocolVersions>,
172
173 #[serde(default)]
175 pub expensive_safety_check_config: ExpensiveSafetyCheckConfig,
176
177 #[serde(default)]
181 pub transaction_deny_config: TransactionDenyConfig,
182
183 #[serde(default)]
189 pub certificate_deny_config: CertificateDenyConfig,
190
191 #[serde(default)]
194 pub state_debug_dump_config: StateDebugDumpConfig,
195
196 #[serde(default)]
197 pub checkpoint_archive_config: Option<CheckpointArchiveConfig>,
198
199 #[serde(default)]
201 pub state_snapshot_write_config: StateSnapshotConfig,
202
203 #[serde(default)]
204 pub indexer_max_subscriptions: Option<usize>,
205
206 #[serde(default = "default_transaction_kv_store_config")]
207 pub transaction_kv_store_read_config: TransactionKeyValueStoreReadConfig,
208
209 #[serde(skip_serializing_if = "Option::is_none")]
211 pub transaction_kv_store_write_config: Option<TransactionKeyValueStoreWriteConfig>,
212
213 #[serde(default = "default_authority_overload_config")]
216 pub authority_overload_config: AuthorityOverloadConfig,
217
218 #[serde(skip_serializing_if = "Option::is_none")]
222 pub run_with_range: Option<RunWithRange>,
223
224 #[serde(
230 skip_serializing_if = "is_default_traffic_controller_policy_config",
231 default = "default_traffic_controller_policy_config"
232 )]
233 pub policy_config: Option<PolicyConfig>,
234
235 #[serde(skip_serializing_if = "Option::is_none")]
236 pub firewall_config: Option<RemoteFirewallConfig>,
237
238 #[serde(default)]
239 pub execution_cache_config: ExecutionCacheConfig,
240
241 #[serde(default = "default_full_checkpoint_contents_cache_size_mb")]
252 pub full_checkpoint_contents_cache_size_mb: usize,
253
254 #[serde(default = "bool_true")]
255 pub enable_validator_tx_finalizer: bool,
256
257 #[serde(default = "bool_true")]
263 pub enable_soft_locking: bool,
264
265 #[serde(default)]
266 pub verifier_signing_config: VerifierSigningConfig,
267
268 #[serde(skip_serializing_if = "Option::is_none")]
272 pub enable_db_write_stall: Option<bool>,
273
274 #[serde(default, skip_serializing_if = "Option::is_none")]
275 pub iota_names_config: Option<IotaNamesConfig>,
276
277 #[serde(default)]
279 pub enable_grpc_api: bool,
280 #[serde(
286 default = "default_grpc_api_config",
287 skip_serializing_if = "is_default_grpc_api_config"
288 )]
289 pub grpc_api_config: Option<GrpcApiConfig>,
290
291 #[serde(skip_serializing_if = "Option::is_none")]
296 pub chain_override_for_testing: Option<Chain>,
297
298 #[serde(default, skip_serializing_if = "Option::is_none")]
301 pub validator_client_monitor_config:
302 Option<crate::validator_client_monitor_config::ValidatorClientMonitorConfig>,
303}
304
305#[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize)]
306#[serde(rename_all = "kebab-case")]
307pub struct TlsConfig {
308 cert: String,
310 key: String,
312}
313
314impl TlsConfig {
315 pub fn cert(&self) -> &str {
316 &self.cert
317 }
318
319 pub fn key(&self) -> &str {
320 &self.key
321 }
322}
323
324#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
326#[serde(rename_all = "kebab-case")]
327pub struct GrpcApiConfig {
328 #[serde(default = "default_grpc_api_address")]
330 pub address: SocketAddr,
331
332 #[serde(skip_serializing_if = "Option::is_none")]
336 pub tls: Option<TlsConfig>,
337
338 #[serde(default = "default_grpc_api_max_message_size_bytes")]
340 pub max_message_size_bytes: u32,
341
342 #[serde(default = "default_grpc_api_broadcast_buffer_size")]
344 pub broadcast_buffer_size: u32,
345
346 #[serde(default = "default_grpc_api_max_concurrent_stream_subscribers")]
352 pub max_concurrent_stream_subscribers: u32,
353
354 #[serde(default = "default_grpc_api_max_json_move_value_size")]
357 pub max_json_move_value_size: usize,
358
359 #[serde(default = "default_grpc_api_max_execute_transaction_batch_size")]
362 pub max_execute_transaction_batch_size: u32,
363
364 #[serde(default = "default_grpc_api_max_simulate_transaction_batch_size")]
367 pub max_simulate_transaction_batch_size: u32,
368
369 #[serde(default = "default_grpc_api_max_get_objects_batch_size")]
371 pub max_get_objects_batch_size: u32,
372
373 #[serde(default = "default_grpc_api_max_get_transactions_batch_size")]
376 pub max_get_transactions_batch_size: u32,
377
378 #[serde(default = "default_grpc_api_max_checkpoint_inclusion_timeout_ms")]
382 pub max_checkpoint_inclusion_timeout_ms: u64,
383}
384
385fn default_grpc_api_address() -> SocketAddr {
386 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 50051)
387}
388
389fn default_grpc_api_broadcast_buffer_size() -> u32 {
390 100
391}
392
393fn default_grpc_api_max_concurrent_stream_subscribers() -> u32 {
394 1024
395}
396
397fn default_grpc_api_max_message_size_bytes() -> u32 {
398 128 * 1024 * 1024 }
400
401fn default_grpc_api_max_json_move_value_size() -> usize {
402 1024 * 1024 }
404
405fn default_grpc_api_max_execute_transaction_batch_size() -> u32 {
406 20
407}
408
409fn default_grpc_api_max_simulate_transaction_batch_size() -> u32 {
410 20
411}
412
413fn default_grpc_api_max_get_objects_batch_size() -> u32 {
414 1000
415}
416
417fn default_grpc_api_max_get_transactions_batch_size() -> u32 {
418 1000
419}
420
421fn default_grpc_api_max_checkpoint_inclusion_timeout_ms() -> u64 {
422 60_000 }
424
425impl Default for GrpcApiConfig {
426 fn default() -> Self {
427 Self {
428 address: default_grpc_api_address(),
429 tls: None,
430 max_message_size_bytes: default_grpc_api_max_message_size_bytes(),
431 broadcast_buffer_size: default_grpc_api_broadcast_buffer_size(),
432 max_concurrent_stream_subscribers: default_grpc_api_max_concurrent_stream_subscribers(),
433 max_json_move_value_size: default_grpc_api_max_json_move_value_size(),
434 max_execute_transaction_batch_size: default_grpc_api_max_execute_transaction_batch_size(
435 ),
436 max_simulate_transaction_batch_size:
437 default_grpc_api_max_simulate_transaction_batch_size(),
438 max_get_objects_batch_size: default_grpc_api_max_get_objects_batch_size(),
439 max_get_transactions_batch_size: default_grpc_api_max_get_transactions_batch_size(),
440 max_checkpoint_inclusion_timeout_ms:
441 default_grpc_api_max_checkpoint_inclusion_timeout_ms(),
442 }
443 }
444}
445
446impl GrpcApiConfig {
447 const GRPC_TONIC_DEFAULT_MAX_RECV_MESSAGE_SIZE: u32 = 4 * 1024 * 1024; const GRPC_MIN_CLIENT_MAX_MESSAGE_SIZE_BYTES: u32 =
451 Self::GRPC_TONIC_DEFAULT_MAX_RECV_MESSAGE_SIZE;
452
453 pub fn tls_config(&self) -> Option<&TlsConfig> {
454 self.tls.as_ref()
455 }
456
457 pub fn max_message_size_bytes(&self) -> u32 {
458 self.max_message_size_bytes
460 .max(Self::GRPC_MIN_CLIENT_MAX_MESSAGE_SIZE_BYTES)
461 }
462
463 pub fn max_message_size_client_bytes(&self, client_max_message_size_bytes: Option<u32>) -> u32 {
467 client_max_message_size_bytes
468 .unwrap_or(Self::GRPC_TONIC_DEFAULT_MAX_RECV_MESSAGE_SIZE)
471 .clamp(
473 Self::GRPC_MIN_CLIENT_MAX_MESSAGE_SIZE_BYTES,
474 self.max_message_size_bytes(),
475 )
476 }
477}
478
479#[derive(Clone, Debug, Default, Deserialize, Serialize)]
480#[serde(rename_all = "kebab-case")]
481pub struct ExecutionCacheConfig {
482 #[serde(default)]
483 pub writeback_cache: WritebackCacheConfig,
484}
485
486#[derive(Clone, Debug, Default, Deserialize, Serialize)]
487#[serde(rename_all = "kebab-case")]
488pub struct WritebackCacheConfig {
489 #[serde(default, skip_serializing_if = "Option::is_none")]
492 pub max_cache_size: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
495 pub package_cache_size: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
498 pub object_cache_size: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
500 pub marker_cache_size: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
502 pub object_by_id_cache_size: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
505 pub transaction_cache_size: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
507 pub executed_effect_cache_size: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
509 pub effect_cache_size: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
512 pub events_cache_size: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
515 pub transaction_objects_cache_size: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
520 pub backpressure_threshold: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
526 pub backpressure_threshold_for_rpc: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
536 pub backpressure_soft_limit_pct: Option<u32>,
537}
538
539impl WritebackCacheConfig {
540 pub fn max_cache_size(&self) -> u64 {
541 std::env::var("IOTA_CACHE_WRITEBACK_SIZE_MAX")
542 .ok()
543 .and_then(|s| s.parse().ok())
544 .or(self.max_cache_size)
545 .unwrap_or(100000)
546 }
547
548 pub fn package_cache_size(&self) -> u64 {
549 std::env::var("IOTA_CACHE_WRITEBACK_SIZE_PACKAGE")
550 .ok()
551 .and_then(|s| s.parse().ok())
552 .or(self.package_cache_size)
553 .unwrap_or(1000)
554 }
555
556 pub fn object_cache_size(&self) -> u64 {
557 std::env::var("IOTA_CACHE_WRITEBACK_SIZE_OBJECT")
558 .ok()
559 .and_then(|s| s.parse().ok())
560 .or(self.object_cache_size)
561 .unwrap_or_else(|| self.max_cache_size())
562 }
563
564 pub fn marker_cache_size(&self) -> u64 {
565 std::env::var("IOTA_CACHE_WRITEBACK_SIZE_MARKER")
566 .ok()
567 .and_then(|s| s.parse().ok())
568 .or(self.marker_cache_size)
569 .unwrap_or_else(|| self.object_cache_size())
570 }
571
572 pub fn object_by_id_cache_size(&self) -> u64 {
573 std::env::var("IOTA_CACHE_WRITEBACK_SIZE_OBJECT_BY_ID")
574 .ok()
575 .and_then(|s| s.parse().ok())
576 .or(self.object_by_id_cache_size)
577 .unwrap_or_else(|| self.object_cache_size())
578 }
579
580 pub fn transaction_cache_size(&self) -> u64 {
581 std::env::var("IOTA_CACHE_WRITEBACK_SIZE_TRANSACTION")
582 .ok()
583 .and_then(|s| s.parse().ok())
584 .or(self.transaction_cache_size)
585 .unwrap_or_else(|| self.max_cache_size())
586 }
587
588 pub fn executed_effect_cache_size(&self) -> u64 {
589 std::env::var("IOTA_CACHE_WRITEBACK_SIZE_EXECUTED_EFFECT")
590 .ok()
591 .and_then(|s| s.parse().ok())
592 .or(self.executed_effect_cache_size)
593 .unwrap_or_else(|| self.transaction_cache_size())
594 }
595
596 pub fn effect_cache_size(&self) -> u64 {
597 std::env::var("IOTA_CACHE_WRITEBACK_SIZE_EFFECT")
598 .ok()
599 .and_then(|s| s.parse().ok())
600 .or(self.effect_cache_size)
601 .unwrap_or_else(|| self.executed_effect_cache_size())
602 }
603
604 pub fn events_cache_size(&self) -> u64 {
605 std::env::var("IOTA_CACHE_WRITEBACK_SIZE_EVENTS")
606 .ok()
607 .and_then(|s| s.parse().ok())
608 .or(self.events_cache_size)
609 .unwrap_or_else(|| self.transaction_cache_size())
610 }
611
612 pub fn transaction_objects_cache_size(&self) -> u64 {
613 std::env::var("IOTA_CACHE_WRITEBACK_SIZE_TRANSACTION_OBJECTS")
614 .ok()
615 .and_then(|s| s.parse().ok())
616 .or(self.transaction_objects_cache_size)
617 .unwrap_or(1000)
618 }
619
620 pub fn backpressure_threshold(&self) -> u64 {
621 std::env::var("IOTA_CACHE_WRITEBACK_BACKPRESSURE_THRESHOLD")
622 .ok()
623 .and_then(|s| s.parse().ok())
624 .or(self.backpressure_threshold)
625 .unwrap_or(100_000)
626 }
627
628 pub fn backpressure_threshold_for_rpc(&self) -> u64 {
629 std::env::var("IOTA_CACHE_WRITEBACK_BACKPRESSURE_THRESHOLD_FOR_RPC")
630 .ok()
631 .and_then(|s| s.parse().ok())
632 .or(self.backpressure_threshold_for_rpc)
633 .unwrap_or(self.backpressure_threshold())
634 }
635
636 pub fn backpressure_soft_limit_pct(&self) -> u32 {
637 std::env::var("IOTA_CACHE_WRITEBACK_BACKPRESSURE_SOFT_LIMIT_PCT")
638 .ok()
639 .and_then(|s| s.parse().ok())
640 .or(self.backpressure_soft_limit_pct)
641 .unwrap_or(50)
642 .min(100)
643 }
644}
645
646#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
647#[serde(rename_all = "lowercase")]
648pub enum ServerType {
649 WebSocket,
650 Http,
651 Both,
652}
653
654#[derive(Clone, Debug, Deserialize, Serialize)]
655#[serde(rename_all = "kebab-case")]
656pub struct TransactionKeyValueStoreReadConfig {
657 #[serde(default = "default_base_url")]
658 pub base_url: String,
659
660 #[serde(default = "default_cache_size")]
661 pub cache_size: u64,
662}
663
664impl Default for TransactionKeyValueStoreReadConfig {
665 fn default() -> Self {
666 Self {
667 base_url: default_base_url(),
668 cache_size: default_cache_size(),
669 }
670 }
671}
672
673fn default_base_url() -> String {
674 "".to_string()
675}
676
677fn default_cache_size() -> u64 {
678 100_000
679}
680
681fn default_transaction_kv_store_config() -> TransactionKeyValueStoreReadConfig {
682 TransactionKeyValueStoreReadConfig::default()
683}
684
685fn default_authority_store_pruning_config() -> AuthorityStorePruningConfig {
686 AuthorityStorePruningConfig::default()
687}
688
689pub fn default_enable_index_processing() -> bool {
690 true
691}
692
693fn default_grpc_address() -> Multiaddr {
694 "/ip4/0.0.0.0/tcp/8080".parse().unwrap()
695}
696fn default_authority_key_pair() -> AuthorityKeyPairWithPath {
697 AuthorityKeyPairWithPath::new(get_key_pair_from_rng::<AuthorityKeyPair, _>(&mut OsRng).1)
698}
699
700fn default_key_pair() -> KeyPairWithPath {
701 KeyPairWithPath::new(AccountKeyPair::random().into())
702}
703
704fn default_metrics_address() -> SocketAddr {
705 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9184)
706}
707
708pub fn default_admin_interface_address() -> SocketAddr {
709 SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 1337)
710}
711
712pub fn default_json_rpc_address() -> SocketAddr {
713 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9000)
714}
715
716pub fn default_grpc_api_config() -> Option<GrpcApiConfig> {
717 Some(GrpcApiConfig::default())
718}
719
720fn is_default_grpc_api_config(grpc_api_config: &Option<GrpcApiConfig>) -> bool {
721 serializes_like(grpc_api_config, &default_grpc_api_config())
722}
723
724fn serializes_like<T: Serialize>(value: &T, default: &T) -> bool {
730 match (serde_yaml::to_string(value), serde_yaml::to_string(default)) {
731 (Ok(value), Ok(default)) => value == default,
732 _ => false,
733 }
734}
735
736pub fn default_grpc_concurrency_limit_per_core() -> NonZeroUsize {
737 NonZeroUsize::new(1000).unwrap()
738}
739
740pub fn default_end_of_epoch_broadcast_channel_capacity() -> usize {
741 128
742}
743
744pub fn default_full_checkpoint_contents_cache_size_mb() -> usize {
745 DEFAULT_FULL_CHECKPOINT_CONTENTS_CACHE_SIZE_MB
746}
747
748pub fn bool_true() -> bool {
749 true
750}
751
752impl Config for NodeConfig {}
753
754impl NodeConfig {
755 pub fn authority_key_pair(&self) -> &AuthorityKeyPair {
756 self.authority_key_pair.authority_keypair()
757 }
758
759 pub fn protocol_key_pair(&self) -> &NetworkKeyPair {
760 self.protocol_key_pair.ed25519_keypair()
761 }
762
763 pub fn network_key_pair(&self) -> &NetworkKeyPair {
764 self.network_key_pair.ed25519_keypair()
765 }
766
767 pub fn authority_public_key(&self) -> AuthorityPublicKeyBytes {
768 self.authority_key_pair().public().into()
769 }
770
771 pub fn db_path(&self) -> PathBuf {
772 self.db_path.join("live")
773 }
774
775 pub fn db_checkpoint_path(&self) -> PathBuf {
776 self.db_path.join("db_checkpoints")
777 }
778
779 pub fn snapshot_path(&self) -> PathBuf {
780 self.db_path.join("snapshot")
781 }
782
783 pub fn network_address(&self) -> &Multiaddr {
784 &self.network_address
785 }
786
787 pub fn consensus_config(&self) -> Option<&ConsensusConfig> {
788 self.consensus_config.as_ref()
789 }
790
791 pub fn genesis(&self) -> Result<&genesis::Genesis> {
792 self.genesis.genesis()
793 }
794
795 pub fn load_migration_tx_data(&self) -> Result<MigrationTxData> {
796 let Some(location) = &self.migration_tx_data_path else {
797 anyhow::bail!("no file location set");
798 };
799
800 let migration_tx_data = MigrationTxData::load(location)?;
802
803 migration_tx_data.validate_from_genesis(self.genesis.genesis()?)?;
805 Ok(migration_tx_data)
806 }
807
808 pub fn iota_address(&self) -> Address {
809 self.account_key_pair
810 .keypair()
811 .public_key()
812 .derive_address()
813 }
814
815 pub fn checkpoint_archive_config(&self) -> Option<&CheckpointArchiveConfig> {
816 self.checkpoint_archive_config.as_ref()
817 }
818
819 pub fn jsonrpc_server_type(&self) -> ServerType {
820 self.jsonrpc_server_type.unwrap_or(ServerType::Http)
821 }
822}
823
824#[derive(Debug, Clone, Deserialize, Serialize)]
825#[serde(rename_all = "kebab-case")]
826pub struct ConsensusConfig {
827 pub db_path: PathBuf,
829
830 pub db_retention_epochs: Option<u64>,
834
835 pub db_pruner_period_secs: Option<u64>,
839
840 pub max_pending_transactions: Option<usize>,
851
852 pub max_submit_position: Option<usize>,
858
859 pub submit_delay_step_override_millis: Option<u64>,
865
866 #[serde(skip_serializing_if = "Option::is_none", alias = "starfish_parameters")]
868 pub parameters: Option<StarfishParameters>,
869
870 #[serde(skip_serializing_if = "Option::is_none")]
876 pub graduated_load_shedding_soft_limit_pct: Option<u32>,
877}
878
879impl ConsensusConfig {
880 pub fn db_path(&self) -> &Path {
881 &self.db_path
882 }
883
884 pub fn max_pending_transactions(&self) -> usize {
888 self.max_pending_transactions.unwrap_or(20_000)
889 }
890
891 pub fn graduated_load_shedding_soft_limit_pct(&self) -> u32 {
896 self.graduated_load_shedding_soft_limit_pct
897 .unwrap_or(50)
898 .min(100)
899 }
900
901 pub fn submit_delay_step_override(&self) -> Option<Duration> {
902 self.submit_delay_step_override_millis
903 .map(Duration::from_millis)
904 }
905
906 pub fn db_retention_epochs(&self) -> u64 {
907 self.db_retention_epochs.unwrap_or(0)
908 }
909
910 pub fn db_pruner_period(&self) -> Duration {
911 self.db_pruner_period_secs
913 .map(Duration::from_secs)
914 .unwrap_or(Duration::from_secs(3_600))
915 }
916}
917
918#[derive(Clone, Debug, Deserialize, Serialize)]
919#[serde(rename_all = "kebab-case")]
920pub struct CheckpointExecutorConfig {
921 #[serde(default = "default_checkpoint_execution_max_concurrency")]
926 pub checkpoint_execution_max_concurrency: usize,
927
928 #[serde(default = "default_local_execution_timeout_sec")]
934 pub local_execution_timeout_sec: u64,
935
936 #[serde(default, skip_serializing_if = "Option::is_none")]
941 pub data_ingestion_dir: Option<PathBuf>,
942}
943
944#[derive(Clone, Debug, Default, Deserialize, Serialize)]
945#[serde(rename_all = "kebab-case")]
946pub struct ExpensiveSafetyCheckConfig {
947 #[serde(default)]
952 enable_epoch_iota_conservation_check: bool,
953
954 #[serde(default)]
958 enable_deep_per_tx_iota_conservation_check: bool,
959
960 #[serde(default)]
963 force_disable_epoch_iota_conservation_check: bool,
964
965 #[serde(default)]
968 enable_state_consistency_check: bool,
969
970 #[serde(default)]
972 force_disable_state_consistency_check: bool,
973
974 #[serde(default)]
975 enable_secondary_index_checks: bool,
976 }
978
979impl ExpensiveSafetyCheckConfig {
980 pub fn new_enable_all() -> Self {
981 Self {
982 enable_epoch_iota_conservation_check: true,
983 enable_deep_per_tx_iota_conservation_check: true,
984 force_disable_epoch_iota_conservation_check: false,
985 enable_state_consistency_check: true,
986 force_disable_state_consistency_check: false,
987 enable_secondary_index_checks: false, }
989 }
990
991 pub fn new_disable_all() -> Self {
992 Self {
993 enable_epoch_iota_conservation_check: false,
994 enable_deep_per_tx_iota_conservation_check: false,
995 force_disable_epoch_iota_conservation_check: true,
996 enable_state_consistency_check: false,
997 force_disable_state_consistency_check: true,
998 enable_secondary_index_checks: false,
999 }
1000 }
1001
1002 pub fn force_disable_epoch_iota_conservation_check(&mut self) {
1003 self.force_disable_epoch_iota_conservation_check = true;
1004 }
1005
1006 pub fn enable_epoch_iota_conservation_check(&self) -> bool {
1007 (self.enable_epoch_iota_conservation_check || cfg!(debug_assertions))
1008 && !self.force_disable_epoch_iota_conservation_check
1009 }
1010
1011 pub fn force_disable_state_consistency_check(&mut self) {
1012 self.force_disable_state_consistency_check = true;
1013 }
1014
1015 pub fn enable_state_consistency_check(&self) -> bool {
1016 (self.enable_state_consistency_check || cfg!(debug_assertions))
1017 && !self.force_disable_state_consistency_check
1018 }
1019
1020 pub fn enable_deep_per_tx_iota_conservation_check(&self) -> bool {
1021 self.enable_deep_per_tx_iota_conservation_check || cfg!(debug_assertions)
1022 }
1023
1024 pub fn enable_secondary_index_checks(&self) -> bool {
1025 self.enable_secondary_index_checks
1026 }
1027}
1028
1029fn default_checkpoint_execution_max_concurrency() -> usize {
1030 4
1031}
1032
1033fn default_local_execution_timeout_sec() -> u64 {
1034 30
1035}
1036
1037impl Default for CheckpointExecutorConfig {
1038 fn default() -> Self {
1039 Self {
1040 checkpoint_execution_max_concurrency: default_checkpoint_execution_max_concurrency(),
1041 local_execution_timeout_sec: default_local_execution_timeout_sec(),
1042 data_ingestion_dir: None,
1043 }
1044 }
1045}
1046
1047#[derive(Debug, Clone, Deserialize, Serialize)]
1048#[serde(rename_all = "kebab-case")]
1049pub struct AuthorityStorePruningConfig {
1050 #[serde(default = "default_num_latest_epoch_dbs_to_retain")]
1052 pub num_latest_epoch_dbs_to_retain: usize,
1053 #[serde(default)]
1058 pub num_epochs_to_retain: u64,
1059 #[serde(
1068 default = "default_periodic_compaction_threshold_days",
1069 skip_serializing_if = "is_default_periodic_compaction_threshold_days"
1070 )]
1071 pub periodic_compaction_threshold_days: Option<usize>,
1072 #[serde(skip_serializing_if = "Option::is_none")]
1075 pub num_epochs_to_retain_for_checkpoints: Option<u64>,
1076 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1082 pub enable_compaction_filter: bool,
1083 #[serde(skip_serializing_if = "Option::is_none")]
1084 pub num_epochs_to_retain_for_indexes: Option<u64>,
1085}
1086
1087fn default_num_latest_epoch_dbs_to_retain() -> usize {
1088 3
1089}
1090
1091fn default_periodic_compaction_threshold_days() -> Option<usize> {
1092 Some(1)
1093}
1094
1095fn is_default_periodic_compaction_threshold_days(days: &Option<usize>) -> bool {
1096 *days == default_periodic_compaction_threshold_days()
1097}
1098
1099impl Default for AuthorityStorePruningConfig {
1100 fn default() -> Self {
1101 Self {
1102 num_latest_epoch_dbs_to_retain: default_num_latest_epoch_dbs_to_retain(),
1103 num_epochs_to_retain: 0,
1104 periodic_compaction_threshold_days: default_periodic_compaction_threshold_days(),
1105 num_epochs_to_retain_for_checkpoints: if cfg!(msim) { Some(2) } else { None },
1106 enable_compaction_filter: cfg!(test) || cfg!(msim),
1107 num_epochs_to_retain_for_indexes: None,
1108 }
1109 }
1110}
1111
1112impl AuthorityStorePruningConfig {
1113 pub fn set_num_epochs_to_retain(&mut self, num_epochs_to_retain: u64) {
1114 self.num_epochs_to_retain = num_epochs_to_retain;
1115 }
1116
1117 pub fn set_num_epochs_to_retain_for_checkpoints(&mut self, num_epochs_to_retain: Option<u64>) {
1118 self.num_epochs_to_retain_for_checkpoints = num_epochs_to_retain;
1119 }
1120
1121 pub fn num_epochs_to_retain_for_checkpoints(&self) -> Option<u64> {
1122 self.num_epochs_to_retain_for_checkpoints
1123 .map(|n| {
1125 if n < 2 {
1126 info!("num_epochs_to_retain_for_checkpoints must be at least 2, rounding up from {}", n);
1127 2
1128 } else {
1129 n
1130 }
1131 })
1132 }
1133}
1134
1135#[derive(Debug, Clone, Deserialize, Serialize)]
1136#[serde(rename_all = "kebab-case")]
1137pub struct MetricsConfig {
1138 #[serde(skip_serializing_if = "Option::is_none")]
1139 pub push_interval_seconds: Option<u64>,
1140 #[serde(skip_serializing_if = "Option::is_none")]
1141 pub push_url: Option<String>,
1142 #[serde(skip_serializing_if = "Option::is_none")]
1143 pub groups: Option<MetricGroups>,
1144}
1145
1146fn default_checkpoint_archive_download_concurrency() -> NonZeroUsize {
1147 NonZeroUsize::new(10).unwrap()
1148}
1149
1150fn default_checkpoint_archive_verify_concurrency() -> NonZeroUsize {
1151 std::thread::available_parallelism().unwrap_or(NonZeroUsize::new(4).unwrap())
1152}
1153
1154fn default_checkpoint_archive_max_checkpoints_ahead_of_execution() -> NonZeroUsize {
1155 NonZeroUsize::new(100_000).unwrap()
1156}
1157
1158#[derive(Debug, Clone, Deserialize, Serialize)]
1161#[serde(rename_all = "kebab-case")]
1162pub struct CheckpointArchiveConfig {
1163 pub url: String,
1165 #[serde(default = "default_checkpoint_archive_download_concurrency")]
1167 pub download_concurrency: NonZeroUsize,
1168 #[serde(default = "default_checkpoint_archive_verify_concurrency")]
1171 pub verify_concurrency: NonZeroUsize,
1172 #[serde(default = "default_checkpoint_archive_max_checkpoints_ahead_of_execution")]
1178 pub max_checkpoints_ahead_of_execution: NonZeroUsize,
1179}
1180
1181#[derive(Default, Debug, Clone, Deserialize, Serialize)]
1189#[serde(rename_all = "kebab-case")]
1190pub struct StateSnapshotConfig {
1191 #[serde(skip_serializing_if = "Option::is_none")]
1192 pub object_store_config: Option<ObjectStoreConfig>,
1193 pub concurrency: usize,
1194}
1195
1196#[derive(Default, Debug, Clone, Deserialize, Serialize)]
1197#[serde(rename_all = "kebab-case")]
1198pub struct TransactionKeyValueStoreWriteConfig {
1199 pub aws_access_key_id: String,
1200 pub aws_secret_access_key: String,
1201 pub aws_region: String,
1202 pub table_name: String,
1203 pub bucket_name: String,
1204 pub concurrency: usize,
1205}
1206
1207#[derive(Clone, Debug, Deserialize, Serialize)]
1212#[serde(rename_all = "kebab-case")]
1213pub struct AuthorityOverloadConfig {
1214 #[serde(default = "default_max_txn_age_in_queue")]
1218 pub max_txn_age_in_queue: Duration,
1219
1220 #[serde(default = "default_overload_monitor_interval")]
1222 pub overload_monitor_interval: Duration,
1223
1224 #[serde(default = "default_execution_queue_latency_soft_limit")]
1226 pub execution_queue_latency_soft_limit: Duration,
1227
1228 #[serde(default = "default_execution_queue_latency_hard_limit")]
1231 pub execution_queue_latency_hard_limit: Duration,
1232
1233 #[serde(default = "default_max_load_shedding_percentage")]
1235 pub max_load_shedding_percentage: u32,
1236
1237 #[serde(default = "default_min_load_shedding_percentage_above_hard_limit")]
1240 pub min_load_shedding_percentage_above_hard_limit: u32,
1241
1242 #[serde(default = "default_safe_transaction_ready_rate")]
1245 pub safe_transaction_ready_rate: u32,
1246
1247 #[serde(default = "default_check_system_overload_at_signing")]
1250 pub check_system_overload_at_signing: bool,
1251
1252 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1255 pub check_system_overload_at_execution: bool,
1256
1257 #[serde(default = "default_max_transaction_manager_queue_length")]
1261 pub max_transaction_manager_queue_length: usize,
1262
1263 #[serde(default = "default_max_transaction_manager_per_object_queue_length")]
1266 pub max_transaction_manager_per_object_queue_length: usize,
1267
1268 #[serde(default = "default_max_transaction_manager_queue_length_soft_limit_pct")]
1272 pub max_transaction_manager_queue_length_soft_limit_pct: u32,
1273}
1274
1275impl AuthorityOverloadConfig {
1276 pub fn max_transaction_manager_queue_length_soft_limit_pct(&self) -> u32 {
1279 self.max_transaction_manager_queue_length_soft_limit_pct
1280 .min(100)
1281 }
1282}
1283
1284fn default_max_txn_age_in_queue() -> Duration {
1285 Duration::from_millis(500)
1286}
1287
1288fn default_overload_monitor_interval() -> Duration {
1289 Duration::from_secs(10)
1290}
1291
1292fn default_execution_queue_latency_soft_limit() -> Duration {
1293 Duration::from_secs(1)
1294}
1295
1296fn default_execution_queue_latency_hard_limit() -> Duration {
1297 Duration::from_secs(10)
1298}
1299
1300fn default_max_load_shedding_percentage() -> u32 {
1301 95
1302}
1303
1304fn default_min_load_shedding_percentage_above_hard_limit() -> u32 {
1305 50
1306}
1307
1308fn default_safe_transaction_ready_rate() -> u32 {
1309 100
1310}
1311
1312fn default_check_system_overload_at_signing() -> bool {
1313 true
1314}
1315
1316fn default_max_transaction_manager_queue_length() -> usize {
1317 100_000
1318}
1319
1320fn default_max_transaction_manager_queue_length_soft_limit_pct() -> u32 {
1321 50
1322}
1323
1324fn default_max_transaction_manager_per_object_queue_length() -> usize {
1325 20
1326}
1327
1328impl Default for AuthorityOverloadConfig {
1329 fn default() -> Self {
1330 Self {
1331 max_txn_age_in_queue: default_max_txn_age_in_queue(),
1332 overload_monitor_interval: default_overload_monitor_interval(),
1333 execution_queue_latency_soft_limit: default_execution_queue_latency_soft_limit(),
1334 execution_queue_latency_hard_limit: default_execution_queue_latency_hard_limit(),
1335 max_load_shedding_percentage: default_max_load_shedding_percentage(),
1336 min_load_shedding_percentage_above_hard_limit:
1337 default_min_load_shedding_percentage_above_hard_limit(),
1338 safe_transaction_ready_rate: default_safe_transaction_ready_rate(),
1339 check_system_overload_at_signing: true,
1340 check_system_overload_at_execution: false,
1341 max_transaction_manager_queue_length: default_max_transaction_manager_queue_length(),
1342 max_transaction_manager_queue_length_soft_limit_pct:
1343 default_max_transaction_manager_queue_length_soft_limit_pct(),
1344 max_transaction_manager_per_object_queue_length:
1345 default_max_transaction_manager_per_object_queue_length(),
1346 }
1347 }
1348}
1349
1350fn default_authority_overload_config() -> AuthorityOverloadConfig {
1351 AuthorityOverloadConfig::default()
1352}
1353
1354fn default_traffic_controller_policy_config() -> Option<PolicyConfig> {
1355 Some(PolicyConfig::default_dos_protection_policy())
1356}
1357
1358fn is_default_traffic_controller_policy_config(policy_config: &Option<PolicyConfig>) -> bool {
1359 serializes_like(policy_config, &default_traffic_controller_policy_config())
1360}
1361
1362#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq)]
1363pub struct Genesis {
1364 #[serde(flatten)]
1365 location: Option<GenesisLocation>,
1366
1367 #[serde(skip)]
1368 genesis: once_cell::sync::OnceCell<genesis::Genesis>,
1369}
1370
1371impl Genesis {
1372 pub fn new(genesis: genesis::Genesis) -> Self {
1373 Self {
1374 location: Some(GenesisLocation::InPlace {
1375 genesis: Box::new(genesis),
1376 }),
1377 genesis: Default::default(),
1378 }
1379 }
1380
1381 pub fn new_from_file<P: Into<PathBuf>>(path: P) -> Self {
1382 Self {
1383 location: Some(GenesisLocation::File {
1384 genesis_file_location: path.into(),
1385 }),
1386 genesis: Default::default(),
1387 }
1388 }
1389
1390 pub fn new_empty() -> Self {
1391 Self {
1392 location: None,
1393 genesis: Default::default(),
1394 }
1395 }
1396
1397 pub fn genesis(&self) -> Result<&genesis::Genesis> {
1398 match &self.location {
1399 Some(GenesisLocation::InPlace { genesis }) => Ok(genesis),
1400 Some(GenesisLocation::File {
1401 genesis_file_location,
1402 }) => self
1403 .genesis
1404 .get_or_try_init(|| genesis::Genesis::load(genesis_file_location)),
1405 None => anyhow::bail!("no genesis location set"),
1406 }
1407 }
1408}
1409
1410#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq)]
1411#[serde(untagged)]
1412enum GenesisLocation {
1413 InPlace {
1414 genesis: Box<genesis::Genesis>,
1415 },
1416 File {
1417 #[serde(rename = "genesis-file-location")]
1418 genesis_file_location: PathBuf,
1419 },
1420}
1421
1422#[derive(Clone, Debug, Deserialize, Serialize)]
1425pub struct KeyPairWithPath {
1426 #[serde(flatten)]
1427 location: KeyPairLocation,
1428
1429 #[serde(skip)]
1430 keypair: OnceCell<Arc<SimpleKeypair>>,
1431
1432 #[serde(skip)]
1438 ed25519_keypair: OnceCell<Arc<Ed25519KeyPair>>,
1439}
1440
1441impl PartialEq for KeyPairWithPath {
1442 fn eq(&self, other: &Self) -> bool {
1443 self.location == other.location
1444 }
1445}
1446
1447impl Eq for KeyPairWithPath {}
1448
1449#[derive(Debug, Clone, Deserialize, Serialize)]
1450#[serde(untagged)]
1451enum KeyPairLocation {
1452 InPlace {
1453 #[serde(with = "bech32_formatted_keypair")]
1454 value: Arc<SimpleKeypair>,
1455 },
1456 File {
1457 path: PathBuf,
1458 },
1459}
1460
1461impl PartialEq for KeyPairLocation {
1462 fn eq(&self, other: &Self) -> bool {
1463 match (self, other) {
1464 (Self::InPlace { value: a }, Self::InPlace { value: b }) => {
1465 a.to_bytes() == b.to_bytes()
1466 }
1467 (Self::File { path: a }, Self::File { path: b }) => a == b,
1468 _ => false,
1469 }
1470 }
1471}
1472
1473impl Eq for KeyPairLocation {}
1474
1475impl KeyPairWithPath {
1476 pub fn new(kp: SimpleKeypair) -> Self {
1477 let cell: OnceCell<Arc<SimpleKeypair>> = OnceCell::new();
1478 let arc_kp = Arc::new(kp);
1479 cell.set(arc_kp.clone()).expect("failed to set keypair");
1482 Self {
1483 location: KeyPairLocation::InPlace { value: arc_kp },
1484 keypair: cell,
1485 ed25519_keypair: OnceCell::new(),
1486 }
1487 }
1488
1489 pub fn new_from_path(path: PathBuf) -> Self {
1490 let cell: OnceCell<Arc<SimpleKeypair>> = OnceCell::new();
1491 cell.set(Arc::new(read_keypair_from_file(&path).unwrap_or_else(
1494 |e| panic!("invalid keypair file at path {path:?}: {e}"),
1495 )))
1496 .expect("failed to set keypair");
1497 Self {
1498 location: KeyPairLocation::File { path },
1499 keypair: cell,
1500 ed25519_keypair: OnceCell::new(),
1501 }
1502 }
1503
1504 pub fn keypair(&self) -> &SimpleKeypair {
1505 self.keypair
1506 .get_or_init(|| match &self.location {
1507 KeyPairLocation::InPlace { value } => value.clone(),
1508 KeyPairLocation::File { path } => {
1509 Arc::new(
1512 read_keypair_from_file(path).unwrap_or_else(|e| {
1513 panic!("invalid keypair file at path {path:?}: {e}")
1514 }),
1515 )
1516 }
1517 })
1518 .as_ref()
1519 }
1520
1521 pub fn ed25519_keypair(&self) -> &Ed25519KeyPair {
1525 self.ed25519_keypair
1526 .get_or_init(|| {
1527 Arc::new(
1528 simple_to_network_keypair(self.keypair())
1529 .expect("only Ed25519 network keys are allowed"),
1530 )
1531 })
1532 .as_ref()
1533 }
1534}
1535
1536#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
1539pub struct AuthorityKeyPairWithPath {
1540 #[serde(flatten)]
1541 location: AuthorityKeyPairLocation,
1542
1543 #[serde(skip)]
1544 keypair: OnceCell<Arc<AuthorityKeyPair>>,
1545}
1546
1547#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq)]
1548#[serde(untagged)]
1549enum AuthorityKeyPairLocation {
1550 InPlace { value: Arc<AuthorityKeyPair> },
1551 File { path: PathBuf },
1552}
1553
1554impl AuthorityKeyPairWithPath {
1555 pub fn new(kp: AuthorityKeyPair) -> Self {
1556 let cell: OnceCell<Arc<AuthorityKeyPair>> = OnceCell::new();
1557 let arc_kp = Arc::new(kp);
1558 cell.set(arc_kp.clone())
1561 .expect("failed to set authority keypair");
1562 Self {
1563 location: AuthorityKeyPairLocation::InPlace { value: arc_kp },
1564 keypair: cell,
1565 }
1566 }
1567
1568 pub fn new_from_path(path: PathBuf) -> Self {
1569 let cell: OnceCell<Arc<AuthorityKeyPair>> = OnceCell::new();
1570 cell.set(Arc::new(
1573 read_authority_keypair_from_file(&path)
1574 .unwrap_or_else(|_| panic!("invalid authority keypair file at path {path:?}")),
1575 ))
1576 .expect("failed to set authority keypair");
1577 Self {
1578 location: AuthorityKeyPairLocation::File { path },
1579 keypair: cell,
1580 }
1581 }
1582
1583 pub fn authority_keypair(&self) -> &AuthorityKeyPair {
1584 self.keypair
1585 .get_or_init(|| match &self.location {
1586 AuthorityKeyPairLocation::InPlace { value } => value.clone(),
1587 AuthorityKeyPairLocation::File { path } => {
1588 Arc::new(
1591 read_authority_keypair_from_file(path)
1592 .unwrap_or_else(|_| panic!("invalid authority keypair file {path:?}")),
1593 )
1594 }
1595 })
1596 .as_ref()
1597 }
1598}
1599
1600#[derive(Clone, Debug, Deserialize, Serialize, Default)]
1603#[serde(rename_all = "kebab-case")]
1604pub struct StateDebugDumpConfig {
1605 #[serde(skip_serializing_if = "Option::is_none")]
1606 pub dump_file_directory: Option<PathBuf>,
1607}
1608
1609#[cfg(test)]
1610mod tests {
1611 use std::path::PathBuf;
1612
1613 use fastcrypto::traits::KeyPair;
1614 use iota_keys::keypair_file::{write_authority_keypair_to_file, write_keypair_to_file};
1615 use iota_types::{
1616 crypto::{
1617 AuthorityKeyPair, NetworkKeyPair, get_key_pair_from_rng, network_to_simple_keypair,
1618 },
1619 traffic_control::PolicyConfig,
1620 };
1621 use rand::{SeedableRng, rngs::StdRng};
1622 use serde::Serialize;
1623 use serde_yaml::Value;
1624
1625 use super::{
1626 Genesis, GrpcApiConfig, default_grpc_api_config,
1627 default_periodic_compaction_threshold_days, default_traffic_controller_policy_config,
1628 };
1629 use crate::NodeConfig;
1630
1631 const TEMPLATE: &str = include_str!("../data/fullnode-template.yaml");
1632
1633 const POLICY_CONFIG: &[&str] = &["policy-config"];
1634 const GRPC_API_CONFIG: &[&str] = &["grpc-api-config"];
1635 const COMPACTION_THRESHOLD: &[&str] = &[
1636 "authority-store-pruning-config",
1637 "periodic-compaction-threshold-days",
1638 ];
1639
1640 fn template_config() -> NodeConfig {
1641 serde_yaml::from_str(TEMPLATE).unwrap()
1642 }
1643
1644 fn round_trip(config: &NodeConfig) -> NodeConfig {
1645 serde_yaml::from_str(&serde_yaml::to_string(config).unwrap()).unwrap()
1646 }
1647
1648 fn as_yaml<T: Serialize>(value: &T) -> String {
1649 serde_yaml::to_string(value).unwrap()
1650 }
1651
1652 fn written_at(value: &Value, path: &[&str]) -> Option<Value> {
1655 let (last, parents) = path.split_last().unwrap();
1656 let mut current = value;
1657 for name in parents {
1658 current = current
1659 .as_mapping()
1660 .unwrap()
1661 .get(&Value::String((*name).to_owned()))
1662 .unwrap();
1663 }
1664 current
1665 .as_mapping()
1666 .unwrap()
1667 .get(&Value::String((*last).to_owned()))
1668 .cloned()
1669 }
1670
1671 #[test]
1672 fn serialize_genesis_from_file() {
1673 let g = Genesis::new_from_file("path/to/file");
1674
1675 let s = serde_yaml::to_string(&g).unwrap();
1676 assert_eq!("---\ngenesis-file-location: path/to/file\n", s);
1677 let loaded_genesis: Genesis = serde_yaml::from_str(&s).unwrap();
1678 assert_eq!(g, loaded_genesis);
1679 }
1680
1681 #[test]
1682 fn fullnode_template() {
1683 const TEMPLATE: &str = include_str!("../data/fullnode-template.yaml");
1684
1685 let _template: NodeConfig = serde_yaml::from_str(TEMPLATE).unwrap();
1686 }
1687
1688 #[test]
1689 fn enable_soft_locking_defaults_to_enabled() {
1690 const TEMPLATE: &str = include_str!("../data/fullnode-template.yaml");
1693
1694 let config: NodeConfig = serde_yaml::from_str(TEMPLATE).unwrap();
1695 assert!(config.enable_soft_locking);
1696 }
1697
1698 #[test]
1699 fn load_key_pairs_to_node_config() {
1700 let authority_key_pair: AuthorityKeyPair =
1701 get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1;
1702 let protocol_key_pair: NetworkKeyPair =
1703 get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1;
1704 let network_key_pair: NetworkKeyPair =
1705 get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1;
1706
1707 write_authority_keypair_to_file(&authority_key_pair, PathBuf::from("authority.key"))
1708 .unwrap();
1709 write_keypair_to_file(
1710 &network_to_simple_keypair(&protocol_key_pair),
1711 PathBuf::from("protocol.key"),
1712 )
1713 .unwrap();
1714 write_keypair_to_file(
1715 &network_to_simple_keypair(&network_key_pair),
1716 PathBuf::from("network.key"),
1717 )
1718 .unwrap();
1719
1720 const TEMPLATE: &str = include_str!("../data/fullnode-template-with-path.yaml");
1721 let template: NodeConfig = serde_yaml::from_str(TEMPLATE).unwrap();
1722 assert_eq!(
1723 template.authority_key_pair().public(),
1724 authority_key_pair.public()
1725 );
1726 assert_eq!(
1727 template.network_key_pair().public(),
1728 network_key_pair.public()
1729 );
1730 assert_eq!(
1731 template.protocol_key_pair().public(),
1732 protocol_key_pair.public()
1733 );
1734 }
1735
1736 #[test]
1737 fn a_policy_config_survives_a_round_trip_in_all_three_states() {
1738 let mut config = template_config();
1739
1740 config.policy_config = None;
1741 assert!(round_trip(&config).policy_config.is_none());
1742
1743 config.policy_config = default_traffic_controller_policy_config();
1744 assert_eq!(
1745 as_yaml(&round_trip(&config).policy_config),
1746 as_yaml(&default_traffic_controller_policy_config())
1747 );
1748
1749 let configured = PolicyConfig {
1750 dry_run: !PolicyConfig::default_dos_protection_policy().dry_run,
1751 ..PolicyConfig::default_dos_protection_policy()
1752 };
1753 config.policy_config = Some(configured.clone());
1754 assert_eq!(
1755 as_yaml(&round_trip(&config).policy_config),
1756 as_yaml(&Some(configured))
1757 );
1758 }
1759
1760 #[test]
1761 fn a_grpc_api_config_survives_a_round_trip_in_all_three_states() {
1762 let mut config = template_config();
1763
1764 config.grpc_api_config = None;
1765 assert!(round_trip(&config).grpc_api_config.is_none());
1766
1767 config.grpc_api_config = default_grpc_api_config();
1768 assert_eq!(
1769 as_yaml(&round_trip(&config).grpc_api_config),
1770 as_yaml(&default_grpc_api_config())
1771 );
1772
1773 let configured = GrpcApiConfig {
1774 max_message_size_bytes: 1234,
1775 ..GrpcApiConfig::default()
1776 };
1777 config.grpc_api_config = Some(configured.clone());
1778 assert_eq!(
1779 as_yaml(&round_trip(&config).grpc_api_config),
1780 as_yaml(&Some(configured))
1781 );
1782 }
1783
1784 #[test]
1785 fn the_default_pruning_config_agrees_with_the_serde_default() {
1786 assert_eq!(
1787 super::AuthorityStorePruningConfig::default().periodic_compaction_threshold_days,
1788 default_periodic_compaction_threshold_days()
1789 );
1790 }
1791
1792 #[test]
1793 fn a_compaction_threshold_survives_a_round_trip_in_all_three_states() {
1794 let mut config = template_config();
1795
1796 for state in [None, default_periodic_compaction_threshold_days(), Some(7)] {
1797 config
1798 .authority_store_pruning_config
1799 .periodic_compaction_threshold_days = state;
1800 assert_eq!(
1801 round_trip(&config)
1802 .authority_store_pruning_config
1803 .periodic_compaction_threshold_days,
1804 state
1805 );
1806 }
1807 }
1808
1809 #[test]
1810 fn a_default_value_is_omitted_and_a_disabled_one_is_written_as_null() {
1811 let mut config = template_config();
1812 config.policy_config = default_traffic_controller_policy_config();
1813 config.grpc_api_config = default_grpc_api_config();
1814 config
1815 .authority_store_pruning_config
1816 .periodic_compaction_threshold_days = default_periodic_compaction_threshold_days();
1817
1818 let written = serde_yaml::to_value(&config).unwrap();
1819 assert_eq!(written_at(&written, POLICY_CONFIG), None);
1820 assert_eq!(written_at(&written, GRPC_API_CONFIG), None);
1821 assert_eq!(written_at(&written, COMPACTION_THRESHOLD), None);
1822
1823 config.policy_config = None;
1824 config.grpc_api_config = None;
1825 config
1826 .authority_store_pruning_config
1827 .periodic_compaction_threshold_days = None;
1828
1829 let written = serde_yaml::to_value(&config).unwrap();
1830 assert_eq!(written_at(&written, POLICY_CONFIG), Some(Value::Null));
1831 assert_eq!(written_at(&written, GRPC_API_CONFIG), Some(Value::Null));
1832 assert_eq!(
1833 written_at(&written, COMPACTION_THRESHOLD),
1834 Some(Value::Null)
1835 );
1836 }
1837}
1838
1839#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)]
1843pub enum RunWithRange {
1844 Epoch(EpochId),
1845 Checkpoint(CheckpointSequenceNumber),
1846}
1847
1848impl RunWithRange {
1849 pub fn is_epoch_gt(&self, epoch_id: EpochId) -> bool {
1851 matches!(self, RunWithRange::Epoch(e) if epoch_id > *e)
1852 }
1853
1854 pub fn matches_checkpoint(&self, seq_num: CheckpointSequenceNumber) -> bool {
1855 matches!(self, RunWithRange::Checkpoint(seq) if *seq == seq_num)
1856 }
1857
1858 pub fn into_checkpoint_bound(self) -> Option<CheckpointSequenceNumber> {
1859 match self {
1860 RunWithRange::Epoch(_) => None,
1861 RunWithRange::Checkpoint(seq) => Some(seq),
1862 }
1863 }
1864}
1865
1866mod bech32_formatted_keypair {
1870 use std::ops::Deref;
1871
1872 use fastcrypto::encoding::{Base64, Encoding};
1873 use iota_sdk_crypto::{ToFromBech32, simple::SimpleKeypair};
1874 use serde::{Deserialize, Deserializer, Serializer};
1875
1876 pub fn serialize<S, T>(kp: &T, serializer: S) -> Result<S::Ok, S::Error>
1877 where
1878 S: Serializer,
1879 T: Deref<Target = SimpleKeypair>,
1880 {
1881 use serde::ser::Error;
1882
1883 let s = kp.to_bech32().map_err(Error::custom)?;
1885
1886 serializer.serialize_str(&s)
1887 }
1888
1889 pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
1890 where
1891 D: Deserializer<'de>,
1892 T: From<SimpleKeypair>,
1893 {
1894 use serde::de::Error;
1895
1896 let s = String::deserialize(deserializer)?;
1897
1898 SimpleKeypair::from_bech32(&s)
1900 .map_err(Error::custom)
1901 .or_else(|_: D::Error| {
1902 let bytes = Base64::decode(&s).map_err(Error::custom)?;
1904 SimpleKeypair::from_bytes(&bytes).map_err(Error::custom)
1905 })
1906 .map(Into::into)
1907 }
1908}