1use std::{
6 collections::{BTreeMap, BTreeSet},
7 net::{IpAddr, Ipv4Addr, SocketAddr},
8 num::NonZeroUsize,
9 path::{Path, PathBuf},
10 sync::Arc,
11 time::Duration,
12};
13
14use anyhow::Result;
15use consensus_config::Parameters as ConsensusParameters;
16use iota_keys::keypair_file::{read_authority_keypair_from_file, read_keypair_from_file};
17use iota_names::config::IotaNamesConfig;
18use iota_types::{
19 base_types::IotaAddress,
20 committee::EpochId,
21 crypto::{
22 AccountKeyPair, AuthorityKeyPair, AuthorityPublicKeyBytes, IotaKeyPair, KeypairTraits,
23 NetworkKeyPair, get_key_pair_from_rng,
24 },
25 messages_checkpoint::CheckpointSequenceNumber,
26 multiaddr::Multiaddr,
27 supported_protocol_versions::{Chain, SupportedProtocolVersions},
28 traffic_control::{PolicyConfig, RemoteFirewallConfig},
29};
30use once_cell::sync::OnceCell;
31use rand::rngs::OsRng;
32use serde::{Deserialize, Serialize};
33use tracing::info;
34
35use crate::{
36 Config, certificate_deny_config::CertificateDenyConfig, genesis,
37 migration_tx_data::MigrationTxData, object_storage_config::ObjectStoreConfig, p2p::P2pConfig,
38 transaction_deny_config::TransactionDenyConfig, verifier_signing_config::VerifierSigningConfig,
39};
40
41pub const DEFAULT_GRPC_CONCURRENCY_LIMIT: usize = 20000000000;
43
44pub const DEFAULT_VALIDATOR_GAS_PRICE: u64 = iota_types::transaction::DEFAULT_VALIDATOR_GAS_PRICE;
46
47pub const DEFAULT_COMMISSION_RATE: u64 = 200;
49
50#[derive(Clone, Debug, Deserialize, Serialize)]
51#[serde(rename_all = "kebab-case")]
52pub struct NodeConfig {
53 #[serde(default = "default_authority_key_pair")]
56 pub authority_key_pair: AuthorityKeyPairWithPath,
57 #[serde(default = "default_key_pair")]
60 pub protocol_key_pair: KeyPairWithPath,
61 #[serde(default = "default_key_pair")]
62 pub account_key_pair: KeyPairWithPath,
63 #[serde(default = "default_key_pair")]
66 pub network_key_pair: KeyPairWithPath,
67 pub db_path: PathBuf,
68
69 #[serde(default = "default_grpc_address")]
73 pub network_address: Multiaddr,
74 #[serde(default = "default_json_rpc_address")]
75 pub json_rpc_address: SocketAddr,
76
77 #[serde(default)]
80 pub enable_rest_api: bool,
81 #[serde(skip_serializing_if = "Option::is_none")]
82 pub rest: Option<iota_rest_api::Config>,
83
84 #[serde(default = "default_metrics_address")]
86 pub metrics_address: SocketAddr,
87
88 #[serde(default = "default_admin_interface_address")]
92 pub admin_interface_address: SocketAddr,
93
94 #[serde(skip_serializing_if = "Option::is_none")]
96 pub consensus_config: Option<ConsensusConfig>,
97
98 #[serde(default = "default_enable_index_processing")]
103 pub enable_index_processing: bool,
104
105 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
106 pub remove_deprecated_tables: bool,
107
108 #[serde(default)]
110 pub jsonrpc_server_type: Option<ServerType>,
115
116 #[serde(default)]
120 pub grpc_load_shed: Option<bool>,
121
122 #[serde(default = "default_concurrency_limit")]
123 pub grpc_concurrency_limit: Option<usize>,
124
125 #[serde(default)]
127 pub p2p_config: P2pConfig,
128
129 pub genesis: Genesis,
133
134 pub migration_tx_data_path: Option<PathBuf>,
136
137 #[serde(default = "default_authority_store_pruning_config")]
140 pub authority_store_pruning_config: AuthorityStorePruningConfig,
141
142 #[serde(default = "default_end_of_epoch_broadcast_channel_capacity")]
147 pub end_of_epoch_broadcast_channel_capacity: usize,
148
149 #[serde(default)]
153 pub checkpoint_executor_config: CheckpointExecutorConfig,
154
155 #[serde(skip_serializing_if = "Option::is_none")]
156 pub metrics: Option<MetricsConfig>,
157
158 #[serde(skip)]
163 pub supported_protocol_versions: Option<SupportedProtocolVersions>,
164
165 #[serde(default)]
169 pub db_checkpoint_config: DBCheckpointConfig,
170
171 #[serde(default)]
174 pub indirect_objects_threshold: usize,
175
176 #[serde(default)]
178 pub expensive_safety_check_config: ExpensiveSafetyCheckConfig,
179
180 #[serde(default)]
184 pub transaction_deny_config: TransactionDenyConfig,
185
186 #[serde(default)]
192 pub certificate_deny_config: CertificateDenyConfig,
193
194 #[serde(default)]
197 pub state_debug_dump_config: StateDebugDumpConfig,
198
199 #[serde(default)]
203 pub state_archive_write_config: StateArchiveConfig,
204
205 #[serde(default)]
206 pub state_archive_read_config: Vec<StateArchiveConfig>,
207
208 #[serde(default)]
210 pub state_snapshot_write_config: StateSnapshotConfig,
211
212 #[serde(default)]
213 pub indexer_max_subscriptions: Option<usize>,
214
215 #[serde(default = "default_transaction_kv_store_config")]
216 pub transaction_kv_store_read_config: TransactionKeyValueStoreReadConfig,
217
218 #[serde(skip_serializing_if = "Option::is_none")]
220 pub transaction_kv_store_write_config: Option<TransactionKeyValueStoreWriteConfig>,
221
222 #[serde(default = "default_jwk_fetch_interval_seconds")]
223 pub jwk_fetch_interval_seconds: u64,
224
225 #[serde(default = "default_zklogin_oauth_providers")]
226 pub zklogin_oauth_providers: BTreeMap<Chain, BTreeSet<String>>,
227
228 #[serde(default = "default_authority_overload_config")]
231 pub authority_overload_config: AuthorityOverloadConfig,
232
233 #[serde(skip_serializing_if = "Option::is_none")]
237 pub run_with_range: Option<RunWithRange>,
238
239 #[serde(skip_serializing_if = "Option::is_none")]
241 pub policy_config: Option<PolicyConfig>,
242
243 #[serde(skip_serializing_if = "Option::is_none")]
244 pub firewall_config: Option<RemoteFirewallConfig>,
245
246 #[serde(default)]
247 pub execution_cache: ExecutionCacheConfig,
248
249 #[serde(default = "bool_true")]
250 pub enable_validator_tx_finalizer: bool,
251
252 #[serde(default)]
253 pub verifier_signing_config: VerifierSigningConfig,
254
255 #[serde(skip_serializing_if = "Option::is_none")]
259 pub enable_db_write_stall: Option<bool>,
260
261 #[serde(default, skip_serializing_if = "Option::is_none")]
262 pub iota_names_config: Option<IotaNamesConfig>,
263}
264
265#[derive(Clone, Debug, Deserialize, Serialize)]
266#[serde(rename_all = "kebab-case")]
267pub enum ExecutionCacheConfig {
268 PassthroughCache,
269 WritebackCache {
270 max_cache_size: Option<usize>,
273 },
274}
275
276impl Default for ExecutionCacheConfig {
277 fn default() -> Self {
278 ExecutionCacheConfig::WritebackCache {
279 max_cache_size: None,
280 }
281 }
282}
283
284#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
285#[serde(rename_all = "lowercase")]
286pub enum ServerType {
287 WebSocket,
288 Http,
289 Both,
290}
291
292#[derive(Clone, Debug, Deserialize, Serialize)]
293#[serde(rename_all = "kebab-case")]
294pub struct TransactionKeyValueStoreReadConfig {
295 #[serde(default = "default_base_url")]
296 pub base_url: String,
297
298 #[serde(default = "default_cache_size")]
299 pub cache_size: u64,
300}
301
302impl Default for TransactionKeyValueStoreReadConfig {
303 fn default() -> Self {
304 Self {
305 base_url: default_base_url(),
306 cache_size: default_cache_size(),
307 }
308 }
309}
310
311fn default_base_url() -> String {
312 "".to_string()
313}
314
315fn default_cache_size() -> u64 {
316 100_000
317}
318
319fn default_jwk_fetch_interval_seconds() -> u64 {
320 3600
321}
322
323pub fn default_zklogin_oauth_providers() -> BTreeMap<Chain, BTreeSet<String>> {
324 let mut map = BTreeMap::new();
325
326 let experimental_providers = BTreeSet::from([
328 "Google".to_string(),
329 "Facebook".to_string(),
330 "Twitch".to_string(),
331 "Kakao".to_string(),
332 "Apple".to_string(),
333 "Slack".to_string(),
334 "TestIssuer".to_string(),
335 "Microsoft".to_string(),
336 "KarrierOne".to_string(),
337 "Credenza3".to_string(),
338 ]);
339
340 let providers = BTreeSet::from([
342 "Google".to_string(),
343 "Facebook".to_string(),
344 "Twitch".to_string(),
345 "Apple".to_string(),
346 "KarrierOne".to_string(),
347 "Credenza3".to_string(),
348 ]);
349 map.insert(Chain::Mainnet, providers.clone());
350 map.insert(Chain::Testnet, providers);
351 map.insert(Chain::Unknown, experimental_providers);
352 map
353}
354
355fn default_transaction_kv_store_config() -> TransactionKeyValueStoreReadConfig {
356 TransactionKeyValueStoreReadConfig::default()
357}
358
359fn default_authority_store_pruning_config() -> AuthorityStorePruningConfig {
360 AuthorityStorePruningConfig::default()
361}
362
363pub fn default_enable_index_processing() -> bool {
364 true
365}
366
367fn default_grpc_address() -> Multiaddr {
368 "/ip4/0.0.0.0/tcp/8080".parse().unwrap()
369}
370fn default_authority_key_pair() -> AuthorityKeyPairWithPath {
371 AuthorityKeyPairWithPath::new(get_key_pair_from_rng::<AuthorityKeyPair, _>(&mut OsRng).1)
372}
373
374fn default_key_pair() -> KeyPairWithPath {
375 KeyPairWithPath::new(
376 get_key_pair_from_rng::<AccountKeyPair, _>(&mut OsRng)
377 .1
378 .into(),
379 )
380}
381
382fn default_metrics_address() -> SocketAddr {
383 use std::net::{IpAddr, Ipv4Addr};
384 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9184)
385}
386
387pub fn default_admin_interface_address() -> SocketAddr {
388 SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 1337)
389}
390
391pub fn default_json_rpc_address() -> SocketAddr {
392 use std::net::{IpAddr, Ipv4Addr};
393 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9000)
394}
395
396pub fn default_concurrency_limit() -> Option<usize> {
397 Some(DEFAULT_GRPC_CONCURRENCY_LIMIT)
398}
399
400pub fn default_end_of_epoch_broadcast_channel_capacity() -> usize {
401 128
402}
403
404pub fn bool_true() -> bool {
405 true
406}
407
408fn is_true(value: &bool) -> bool {
409 *value
410}
411
412impl Config for NodeConfig {}
413
414impl NodeConfig {
415 pub fn authority_key_pair(&self) -> &AuthorityKeyPair {
416 self.authority_key_pair.authority_keypair()
417 }
418
419 pub fn protocol_key_pair(&self) -> &NetworkKeyPair {
420 match self.protocol_key_pair.keypair() {
421 IotaKeyPair::Ed25519(kp) => kp,
422 other => {
423 panic!("invalid keypair type: {other:?}, only Ed25519 is allowed for protocol key")
424 }
425 }
426 }
427
428 pub fn network_key_pair(&self) -> &NetworkKeyPair {
429 match self.network_key_pair.keypair() {
430 IotaKeyPair::Ed25519(kp) => kp,
431 other => {
432 panic!("invalid keypair type: {other:?}, only Ed25519 is allowed for network key")
433 }
434 }
435 }
436
437 pub fn authority_public_key(&self) -> AuthorityPublicKeyBytes {
438 self.authority_key_pair().public().into()
439 }
440
441 pub fn db_path(&self) -> PathBuf {
442 self.db_path.join("live")
443 }
444
445 pub fn db_checkpoint_path(&self) -> PathBuf {
446 self.db_path.join("db_checkpoints")
447 }
448
449 pub fn archive_path(&self) -> PathBuf {
450 self.db_path.join("archive")
451 }
452
453 pub fn snapshot_path(&self) -> PathBuf {
454 self.db_path.join("snapshot")
455 }
456
457 pub fn network_address(&self) -> &Multiaddr {
458 &self.network_address
459 }
460
461 pub fn consensus_config(&self) -> Option<&ConsensusConfig> {
462 self.consensus_config.as_ref()
463 }
464
465 pub fn genesis(&self) -> Result<&genesis::Genesis> {
466 self.genesis.genesis()
467 }
468
469 pub fn load_migration_tx_data(&self) -> Result<MigrationTxData> {
470 let Some(location) = &self.migration_tx_data_path else {
471 anyhow::bail!("no file location set");
472 };
473
474 let migration_tx_data = MigrationTxData::load(location)?;
476
477 migration_tx_data.validate_from_genesis(self.genesis.genesis()?)?;
479 Ok(migration_tx_data)
480 }
481
482 pub fn iota_address(&self) -> IotaAddress {
483 (&self.account_key_pair.keypair().public()).into()
484 }
485
486 pub fn archive_reader_config(&self) -> Vec<ArchiveReaderConfig> {
487 self.state_archive_read_config
488 .iter()
489 .flat_map(|config| {
490 config
491 .object_store_config
492 .as_ref()
493 .map(|remote_store_config| ArchiveReaderConfig {
494 remote_store_config: remote_store_config.clone(),
495 download_concurrency: NonZeroUsize::new(config.concurrency)
496 .unwrap_or(NonZeroUsize::new(5).unwrap()),
497 use_for_pruning_watermark: config.use_for_pruning_watermark,
498 })
499 })
500 .collect()
501 }
502
503 pub fn jsonrpc_server_type(&self) -> ServerType {
504 self.jsonrpc_server_type.unwrap_or(ServerType::Http)
505 }
506}
507
508#[derive(Debug, Clone, Deserialize, Serialize)]
509pub enum ConsensusProtocol {
510 #[serde(rename = "mysticeti")]
511 Mysticeti,
512}
513
514#[derive(Debug, Clone, Deserialize, Serialize)]
515#[serde(rename_all = "kebab-case")]
516pub struct ConsensusConfig {
517 pub db_path: PathBuf,
519
520 pub db_retention_epochs: Option<u64>,
523
524 pub db_pruner_period_secs: Option<u64>,
527
528 pub max_pending_transactions: Option<usize>,
534
535 pub max_submit_position: Option<usize>,
541
542 pub submit_delay_step_override_millis: Option<u64>,
548
549 pub parameters: Option<ConsensusParameters>,
550}
551
552impl ConsensusConfig {
553 pub fn db_path(&self) -> &Path {
554 &self.db_path
555 }
556
557 pub fn max_pending_transactions(&self) -> usize {
558 self.max_pending_transactions.unwrap_or(20_000)
559 }
560
561 pub fn submit_delay_step_override(&self) -> Option<Duration> {
562 self.submit_delay_step_override_millis
563 .map(Duration::from_millis)
564 }
565
566 pub fn db_retention_epochs(&self) -> u64 {
567 self.db_retention_epochs.unwrap_or(0)
568 }
569
570 pub fn db_pruner_period(&self) -> Duration {
571 self.db_pruner_period_secs
573 .map(Duration::from_secs)
574 .unwrap_or(Duration::from_secs(3_600))
575 }
576}
577
578#[derive(Clone, Debug, Deserialize, Serialize)]
579#[serde(rename_all = "kebab-case")]
580pub struct CheckpointExecutorConfig {
581 #[serde(default = "default_checkpoint_execution_max_concurrency")]
586 pub checkpoint_execution_max_concurrency: usize,
587
588 #[serde(default = "default_local_execution_timeout_sec")]
594 pub local_execution_timeout_sec: u64,
595
596 #[serde(default, skip_serializing_if = "Option::is_none")]
601 pub data_ingestion_dir: Option<PathBuf>,
602}
603
604#[derive(Clone, Debug, Default, Deserialize, Serialize)]
605#[serde(rename_all = "kebab-case")]
606pub struct ExpensiveSafetyCheckConfig {
607 #[serde(default)]
612 enable_epoch_iota_conservation_check: bool,
613
614 #[serde(default)]
618 enable_deep_per_tx_iota_conservation_check: bool,
619
620 #[serde(default)]
623 force_disable_epoch_iota_conservation_check: bool,
624
625 #[serde(default)]
628 enable_state_consistency_check: bool,
629
630 #[serde(default)]
632 force_disable_state_consistency_check: bool,
633
634 #[serde(default)]
635 enable_secondary_index_checks: bool,
636 }
638
639impl ExpensiveSafetyCheckConfig {
640 pub fn new_enable_all() -> Self {
641 Self {
642 enable_epoch_iota_conservation_check: true,
643 enable_deep_per_tx_iota_conservation_check: true,
644 force_disable_epoch_iota_conservation_check: false,
645 enable_state_consistency_check: true,
646 force_disable_state_consistency_check: false,
647 enable_secondary_index_checks: false, }
649 }
650
651 pub fn new_disable_all() -> Self {
652 Self {
653 enable_epoch_iota_conservation_check: false,
654 enable_deep_per_tx_iota_conservation_check: false,
655 force_disable_epoch_iota_conservation_check: true,
656 enable_state_consistency_check: false,
657 force_disable_state_consistency_check: true,
658 enable_secondary_index_checks: false,
659 }
660 }
661
662 pub fn force_disable_epoch_iota_conservation_check(&mut self) {
663 self.force_disable_epoch_iota_conservation_check = true;
664 }
665
666 pub fn enable_epoch_iota_conservation_check(&self) -> bool {
667 (self.enable_epoch_iota_conservation_check || cfg!(debug_assertions))
668 && !self.force_disable_epoch_iota_conservation_check
669 }
670
671 pub fn force_disable_state_consistency_check(&mut self) {
672 self.force_disable_state_consistency_check = true;
673 }
674
675 pub fn enable_state_consistency_check(&self) -> bool {
676 (self.enable_state_consistency_check || cfg!(debug_assertions))
677 && !self.force_disable_state_consistency_check
678 }
679
680 pub fn enable_deep_per_tx_iota_conservation_check(&self) -> bool {
681 self.enable_deep_per_tx_iota_conservation_check || cfg!(debug_assertions)
682 }
683
684 pub fn enable_secondary_index_checks(&self) -> bool {
685 self.enable_secondary_index_checks
686 }
687}
688
689fn default_checkpoint_execution_max_concurrency() -> usize {
690 200
691}
692
693fn default_local_execution_timeout_sec() -> u64 {
694 30
695}
696
697impl Default for CheckpointExecutorConfig {
698 fn default() -> Self {
699 Self {
700 checkpoint_execution_max_concurrency: default_checkpoint_execution_max_concurrency(),
701 local_execution_timeout_sec: default_local_execution_timeout_sec(),
702 data_ingestion_dir: None,
703 }
704 }
705}
706
707#[derive(Debug, Clone, Deserialize, Serialize)]
708#[serde(rename_all = "kebab-case")]
709pub struct AuthorityStorePruningConfig {
710 #[serde(default = "default_num_latest_epoch_dbs_to_retain")]
712 pub num_latest_epoch_dbs_to_retain: usize,
713 #[serde(default = "default_epoch_db_pruning_period_secs")]
716 pub epoch_db_pruning_period_secs: u64,
717 #[serde(default)]
722 pub num_epochs_to_retain: u64,
723 #[serde(skip_serializing_if = "Option::is_none")]
725 pub pruning_run_delay_seconds: Option<u64>,
726 #[serde(default = "default_max_checkpoints_in_batch")]
729 pub max_checkpoints_in_batch: usize,
730 #[serde(default = "default_max_transactions_in_batch")]
732 pub max_transactions_in_batch: usize,
733 #[serde(
738 default = "default_periodic_compaction_threshold_days",
739 skip_serializing_if = "Option::is_none"
740 )]
741 pub periodic_compaction_threshold_days: Option<usize>,
742 #[serde(skip_serializing_if = "Option::is_none")]
745 pub num_epochs_to_retain_for_checkpoints: Option<u64>,
746 #[serde(default = "default_smoothing", skip_serializing_if = "is_true")]
747 pub smooth: bool,
748}
749
750fn default_num_latest_epoch_dbs_to_retain() -> usize {
751 3
752}
753
754fn default_epoch_db_pruning_period_secs() -> u64 {
755 3600
756}
757
758fn default_max_transactions_in_batch() -> usize {
759 1000
760}
761
762fn default_max_checkpoints_in_batch() -> usize {
763 10
764}
765
766fn default_smoothing() -> bool {
767 cfg!(not(test))
768}
769
770fn default_periodic_compaction_threshold_days() -> Option<usize> {
771 Some(1)
772}
773
774impl Default for AuthorityStorePruningConfig {
775 fn default() -> Self {
776 Self {
777 num_latest_epoch_dbs_to_retain: default_num_latest_epoch_dbs_to_retain(),
778 epoch_db_pruning_period_secs: default_epoch_db_pruning_period_secs(),
779 num_epochs_to_retain: 0,
780 pruning_run_delay_seconds: if cfg!(msim) { Some(2) } else { None },
781 max_checkpoints_in_batch: default_max_checkpoints_in_batch(),
782 max_transactions_in_batch: default_max_transactions_in_batch(),
783 periodic_compaction_threshold_days: None,
784 num_epochs_to_retain_for_checkpoints: if cfg!(msim) { Some(2) } else { None },
785 smooth: true,
786 }
787 }
788}
789
790impl AuthorityStorePruningConfig {
791 pub fn set_num_epochs_to_retain(&mut self, num_epochs_to_retain: u64) {
792 self.num_epochs_to_retain = num_epochs_to_retain;
793 }
794
795 pub fn set_num_epochs_to_retain_for_checkpoints(&mut self, num_epochs_to_retain: Option<u64>) {
796 self.num_epochs_to_retain_for_checkpoints = num_epochs_to_retain;
797 }
798
799 pub fn num_epochs_to_retain_for_checkpoints(&self) -> Option<u64> {
800 self.num_epochs_to_retain_for_checkpoints
801 .map(|n| {
803 if n < 2 {
804 info!("num_epochs_to_retain_for_checkpoints must be at least 2, rounding up from {}", n);
805 2
806 } else {
807 n
808 }
809 })
810 }
811}
812
813#[derive(Debug, Clone, Deserialize, Serialize)]
814#[serde(rename_all = "kebab-case")]
815pub struct MetricsConfig {
816 #[serde(skip_serializing_if = "Option::is_none")]
817 pub push_interval_seconds: Option<u64>,
818 #[serde(skip_serializing_if = "Option::is_none")]
819 pub push_url: Option<String>,
820}
821
822#[derive(Default, Debug, Clone, Deserialize, Serialize)]
823#[serde(rename_all = "kebab-case")]
824pub struct DBCheckpointConfig {
825 #[serde(default)]
826 pub perform_db_checkpoints_at_epoch_end: bool,
827 #[serde(skip_serializing_if = "Option::is_none")]
828 pub checkpoint_path: Option<PathBuf>,
829 #[serde(skip_serializing_if = "Option::is_none")]
830 pub object_store_config: Option<ObjectStoreConfig>,
831 #[serde(skip_serializing_if = "Option::is_none")]
832 pub perform_index_db_checkpoints_at_epoch_end: Option<bool>,
833 #[serde(skip_serializing_if = "Option::is_none")]
834 pub prune_and_compact_before_upload: Option<bool>,
835}
836
837#[derive(Debug, Clone)]
838pub struct ArchiveReaderConfig {
839 pub remote_store_config: ObjectStoreConfig,
840 pub download_concurrency: NonZeroUsize,
841 pub use_for_pruning_watermark: bool,
842}
843
844#[derive(Default, Debug, Clone, Deserialize, Serialize)]
845#[serde(rename_all = "kebab-case")]
846pub struct StateArchiveConfig {
847 #[serde(skip_serializing_if = "Option::is_none")]
848 pub object_store_config: Option<ObjectStoreConfig>,
849 pub concurrency: usize,
850 pub use_for_pruning_watermark: bool,
851}
852
853#[derive(Default, Debug, Clone, Deserialize, Serialize)]
854#[serde(rename_all = "kebab-case")]
855pub struct StateSnapshotConfig {
856 #[serde(skip_serializing_if = "Option::is_none")]
857 pub object_store_config: Option<ObjectStoreConfig>,
858 pub concurrency: usize,
859}
860
861#[derive(Default, Debug, Clone, Deserialize, Serialize)]
862#[serde(rename_all = "kebab-case")]
863pub struct TransactionKeyValueStoreWriteConfig {
864 pub aws_access_key_id: String,
865 pub aws_secret_access_key: String,
866 pub aws_region: String,
867 pub table_name: String,
868 pub bucket_name: String,
869 pub concurrency: usize,
870}
871
872#[derive(Clone, Debug, Deserialize, Serialize)]
877#[serde(rename_all = "kebab-case")]
878pub struct AuthorityOverloadConfig {
879 #[serde(default = "default_max_txn_age_in_queue")]
880 pub max_txn_age_in_queue: Duration,
881
882 #[serde(default = "default_overload_monitor_interval")]
884 pub overload_monitor_interval: Duration,
885
886 #[serde(default = "default_execution_queue_latency_soft_limit")]
888 pub execution_queue_latency_soft_limit: Duration,
889
890 #[serde(default = "default_execution_queue_latency_hard_limit")]
892 pub execution_queue_latency_hard_limit: Duration,
893
894 #[serde(default = "default_max_load_shedding_percentage")]
896 pub max_load_shedding_percentage: u32,
897
898 #[serde(default = "default_min_load_shedding_percentage_above_hard_limit")]
901 pub min_load_shedding_percentage_above_hard_limit: u32,
902
903 #[serde(default = "default_safe_transaction_ready_rate")]
906 pub safe_transaction_ready_rate: u32,
907
908 #[serde(default = "default_check_system_overload_at_signing")]
911 pub check_system_overload_at_signing: bool,
912
913 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
916 pub check_system_overload_at_execution: bool,
917
918 #[serde(default = "default_max_transaction_manager_queue_length")]
921 pub max_transaction_manager_queue_length: usize,
922
923 #[serde(default = "default_max_transaction_manager_per_object_queue_length")]
926 pub max_transaction_manager_per_object_queue_length: usize,
927}
928
929fn default_max_txn_age_in_queue() -> Duration {
930 Duration::from_millis(500)
931}
932
933fn default_overload_monitor_interval() -> Duration {
934 Duration::from_secs(10)
935}
936
937fn default_execution_queue_latency_soft_limit() -> Duration {
938 Duration::from_secs(1)
939}
940
941fn default_execution_queue_latency_hard_limit() -> Duration {
942 Duration::from_secs(10)
943}
944
945fn default_max_load_shedding_percentage() -> u32 {
946 95
947}
948
949fn default_min_load_shedding_percentage_above_hard_limit() -> u32 {
950 50
951}
952
953fn default_safe_transaction_ready_rate() -> u32 {
954 100
955}
956
957fn default_check_system_overload_at_signing() -> bool {
958 true
959}
960
961fn default_max_transaction_manager_queue_length() -> usize {
962 100_000
963}
964
965fn default_max_transaction_manager_per_object_queue_length() -> usize {
966 20
967}
968
969impl Default for AuthorityOverloadConfig {
970 fn default() -> Self {
971 Self {
972 max_txn_age_in_queue: default_max_txn_age_in_queue(),
973 overload_monitor_interval: default_overload_monitor_interval(),
974 execution_queue_latency_soft_limit: default_execution_queue_latency_soft_limit(),
975 execution_queue_latency_hard_limit: default_execution_queue_latency_hard_limit(),
976 max_load_shedding_percentage: default_max_load_shedding_percentage(),
977 min_load_shedding_percentage_above_hard_limit:
978 default_min_load_shedding_percentage_above_hard_limit(),
979 safe_transaction_ready_rate: default_safe_transaction_ready_rate(),
980 check_system_overload_at_signing: true,
981 check_system_overload_at_execution: false,
982 max_transaction_manager_queue_length: default_max_transaction_manager_queue_length(),
983 max_transaction_manager_per_object_queue_length:
984 default_max_transaction_manager_per_object_queue_length(),
985 }
986 }
987}
988
989fn default_authority_overload_config() -> AuthorityOverloadConfig {
990 AuthorityOverloadConfig::default()
991}
992
993#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq)]
994pub struct Genesis {
995 #[serde(flatten)]
996 location: Option<GenesisLocation>,
997
998 #[serde(skip)]
999 genesis: once_cell::sync::OnceCell<genesis::Genesis>,
1000}
1001
1002impl Genesis {
1003 pub fn new(genesis: genesis::Genesis) -> Self {
1004 Self {
1005 location: Some(GenesisLocation::InPlace {
1006 genesis: Box::new(genesis),
1007 }),
1008 genesis: Default::default(),
1009 }
1010 }
1011
1012 pub fn new_from_file<P: Into<PathBuf>>(path: P) -> Self {
1013 Self {
1014 location: Some(GenesisLocation::File {
1015 genesis_file_location: path.into(),
1016 }),
1017 genesis: Default::default(),
1018 }
1019 }
1020
1021 pub fn new_empty() -> Self {
1022 Self {
1023 location: None,
1024 genesis: Default::default(),
1025 }
1026 }
1027
1028 pub fn genesis(&self) -> Result<&genesis::Genesis> {
1029 match &self.location {
1030 Some(GenesisLocation::InPlace { genesis }) => Ok(genesis),
1031 Some(GenesisLocation::File {
1032 genesis_file_location,
1033 }) => self
1034 .genesis
1035 .get_or_try_init(|| genesis::Genesis::load(genesis_file_location)),
1036 None => anyhow::bail!("no genesis location set"),
1037 }
1038 }
1039}
1040
1041#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq)]
1042#[serde(untagged)]
1043enum GenesisLocation {
1044 InPlace {
1045 genesis: Box<genesis::Genesis>,
1046 },
1047 File {
1048 #[serde(rename = "genesis-file-location")]
1049 genesis_file_location: PathBuf,
1050 },
1051}
1052
1053#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
1056pub struct KeyPairWithPath {
1057 #[serde(flatten)]
1058 location: KeyPairLocation,
1059
1060 #[serde(skip)]
1061 keypair: OnceCell<Arc<IotaKeyPair>>,
1062}
1063
1064#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq)]
1065#[serde(untagged)]
1066enum KeyPairLocation {
1067 InPlace {
1068 #[serde(with = "bech32_formatted_keypair")]
1069 value: Arc<IotaKeyPair>,
1070 },
1071 File {
1072 path: PathBuf,
1073 },
1074}
1075
1076impl KeyPairWithPath {
1077 pub fn new(kp: IotaKeyPair) -> Self {
1078 let cell: OnceCell<Arc<IotaKeyPair>> = OnceCell::new();
1079 let arc_kp = Arc::new(kp);
1080 cell.set(arc_kp.clone()).expect("failed to set keypair");
1083 Self {
1084 location: KeyPairLocation::InPlace { value: arc_kp },
1085 keypair: cell,
1086 }
1087 }
1088
1089 pub fn new_from_path(path: PathBuf) -> Self {
1090 let cell: OnceCell<Arc<IotaKeyPair>> = OnceCell::new();
1091 cell.set(Arc::new(read_keypair_from_file(&path).unwrap_or_else(
1094 |e| panic!("invalid keypair file at path {:?}: {e}", &path),
1095 )))
1096 .expect("failed to set keypair");
1097 Self {
1098 location: KeyPairLocation::File { path },
1099 keypair: cell,
1100 }
1101 }
1102
1103 pub fn keypair(&self) -> &IotaKeyPair {
1104 self.keypair
1105 .get_or_init(|| match &self.location {
1106 KeyPairLocation::InPlace { value } => value.clone(),
1107 KeyPairLocation::File { path } => {
1108 Arc::new(
1111 read_keypair_from_file(path).unwrap_or_else(|e| {
1112 panic!("invalid keypair file at path {path:?}: {e}")
1113 }),
1114 )
1115 }
1116 })
1117 .as_ref()
1118 }
1119}
1120
1121#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
1124pub struct AuthorityKeyPairWithPath {
1125 #[serde(flatten)]
1126 location: AuthorityKeyPairLocation,
1127
1128 #[serde(skip)]
1129 keypair: OnceCell<Arc<AuthorityKeyPair>>,
1130}
1131
1132#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq)]
1133#[serde(untagged)]
1134enum AuthorityKeyPairLocation {
1135 InPlace { value: Arc<AuthorityKeyPair> },
1136 File { path: PathBuf },
1137}
1138
1139impl AuthorityKeyPairWithPath {
1140 pub fn new(kp: AuthorityKeyPair) -> Self {
1141 let cell: OnceCell<Arc<AuthorityKeyPair>> = OnceCell::new();
1142 let arc_kp = Arc::new(kp);
1143 cell.set(arc_kp.clone())
1146 .expect("failed to set authority keypair");
1147 Self {
1148 location: AuthorityKeyPairLocation::InPlace { value: arc_kp },
1149 keypair: cell,
1150 }
1151 }
1152
1153 pub fn new_from_path(path: PathBuf) -> Self {
1154 let cell: OnceCell<Arc<AuthorityKeyPair>> = OnceCell::new();
1155 cell.set(Arc::new(
1158 read_authority_keypair_from_file(&path)
1159 .unwrap_or_else(|_| panic!("invalid authority keypair file at path {:?}", &path)),
1160 ))
1161 .expect("failed to set authority keypair");
1162 Self {
1163 location: AuthorityKeyPairLocation::File { path },
1164 keypair: cell,
1165 }
1166 }
1167
1168 pub fn authority_keypair(&self) -> &AuthorityKeyPair {
1169 self.keypair
1170 .get_or_init(|| match &self.location {
1171 AuthorityKeyPairLocation::InPlace { value } => value.clone(),
1172 AuthorityKeyPairLocation::File { path } => {
1173 Arc::new(
1176 read_authority_keypair_from_file(path).unwrap_or_else(|_| {
1177 panic!("invalid authority keypair file {:?}", &path)
1178 }),
1179 )
1180 }
1181 })
1182 .as_ref()
1183 }
1184}
1185
1186#[derive(Clone, Debug, Deserialize, Serialize, Default)]
1189#[serde(rename_all = "kebab-case")]
1190pub struct StateDebugDumpConfig {
1191 #[serde(skip_serializing_if = "Option::is_none")]
1192 pub dump_file_directory: Option<PathBuf>,
1193}
1194
1195#[cfg(test)]
1196mod tests {
1197 use std::path::PathBuf;
1198
1199 use fastcrypto::traits::KeyPair;
1200 use iota_keys::keypair_file::{write_authority_keypair_to_file, write_keypair_to_file};
1201 use iota_types::crypto::{
1202 AuthorityKeyPair, IotaKeyPair, NetworkKeyPair, get_key_pair_from_rng,
1203 };
1204 use rand::{SeedableRng, rngs::StdRng};
1205
1206 use super::Genesis;
1207 use crate::NodeConfig;
1208
1209 #[test]
1210 fn serialize_genesis_from_file() {
1211 let g = Genesis::new_from_file("path/to/file");
1212
1213 let s = serde_yaml::to_string(&g).unwrap();
1214 assert_eq!("---\ngenesis-file-location: path/to/file\n", s);
1215 let loaded_genesis: Genesis = serde_yaml::from_str(&s).unwrap();
1216 assert_eq!(g, loaded_genesis);
1217 }
1218
1219 #[test]
1220 fn fullnode_template() {
1221 const TEMPLATE: &str = include_str!("../data/fullnode-template.yaml");
1222
1223 let _template: NodeConfig = serde_yaml::from_str(TEMPLATE).unwrap();
1224 }
1225
1226 #[test]
1227 fn load_key_pairs_to_node_config() {
1228 let authority_key_pair: AuthorityKeyPair =
1229 get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1;
1230 let protocol_key_pair: NetworkKeyPair =
1231 get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1;
1232 let network_key_pair: NetworkKeyPair =
1233 get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1;
1234
1235 write_authority_keypair_to_file(&authority_key_pair, PathBuf::from("authority.key"))
1236 .unwrap();
1237 write_keypair_to_file(
1238 &IotaKeyPair::Ed25519(protocol_key_pair.copy()),
1239 PathBuf::from("protocol.key"),
1240 )
1241 .unwrap();
1242 write_keypair_to_file(
1243 &IotaKeyPair::Ed25519(network_key_pair.copy()),
1244 PathBuf::from("network.key"),
1245 )
1246 .unwrap();
1247
1248 const TEMPLATE: &str = include_str!("../data/fullnode-template-with-path.yaml");
1249 let template: NodeConfig = serde_yaml::from_str(TEMPLATE).unwrap();
1250 assert_eq!(
1251 template.authority_key_pair().public(),
1252 authority_key_pair.public()
1253 );
1254 assert_eq!(
1255 template.network_key_pair().public(),
1256 network_key_pair.public()
1257 );
1258 assert_eq!(
1259 template.protocol_key_pair().public(),
1260 protocol_key_pair.public()
1261 );
1262 }
1263}
1264
1265#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)]
1269pub enum RunWithRange {
1270 Epoch(EpochId),
1271 Checkpoint(CheckpointSequenceNumber),
1272}
1273
1274impl RunWithRange {
1275 pub fn is_epoch_gt(&self, epoch_id: EpochId) -> bool {
1277 matches!(self, RunWithRange::Epoch(e) if epoch_id > *e)
1278 }
1279
1280 pub fn matches_checkpoint(&self, seq_num: CheckpointSequenceNumber) -> bool {
1281 matches!(self, RunWithRange::Checkpoint(seq) if *seq == seq_num)
1282 }
1283}
1284
1285mod bech32_formatted_keypair {
1289 use std::ops::Deref;
1290
1291 use iota_types::crypto::{EncodeDecodeBase64, IotaKeyPair};
1292 use serde::{Deserialize, Deserializer, Serializer};
1293
1294 pub fn serialize<S, T>(kp: &T, serializer: S) -> Result<S::Ok, S::Error>
1295 where
1296 S: Serializer,
1297 T: Deref<Target = IotaKeyPair>,
1298 {
1299 use serde::ser::Error;
1300
1301 let s = kp.encode().map_err(Error::custom)?;
1303
1304 serializer.serialize_str(&s)
1305 }
1306
1307 pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
1308 where
1309 D: Deserializer<'de>,
1310 T: From<IotaKeyPair>,
1311 {
1312 use serde::de::Error;
1313
1314 let s = String::deserialize(deserializer)?;
1315
1316 IotaKeyPair::decode(&s)
1318 .or_else(|_| {
1319 IotaKeyPair::decode_base64(&s)
1321 })
1322 .map(Into::into)
1323 .map_err(Error::custom)
1324 }
1325}