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
82 #[serde(default = "default_metrics_address")]
84 pub metrics_address: SocketAddr,
85
86 #[serde(default = "default_admin_interface_address")]
90 pub admin_interface_address: SocketAddr,
91
92 #[serde(skip_serializing_if = "Option::is_none")]
94 pub consensus_config: Option<ConsensusConfig>,
95
96 #[serde(default = "default_enable_index_processing")]
101 pub enable_index_processing: bool,
102
103 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
104 pub remove_deprecated_tables: bool,
105
106 #[serde(default)]
108 pub jsonrpc_server_type: Option<ServerType>,
113
114 #[serde(default)]
118 pub grpc_load_shed: Option<bool>,
119
120 #[serde(default = "default_concurrency_limit")]
121 pub grpc_concurrency_limit: Option<usize>,
122
123 #[serde(default)]
125 pub p2p_config: P2pConfig,
126
127 pub genesis: Genesis,
131
132 pub migration_tx_data_path: Option<PathBuf>,
134
135 #[serde(default = "default_authority_store_pruning_config")]
138 pub authority_store_pruning_config: AuthorityStorePruningConfig,
139
140 #[serde(default = "default_end_of_epoch_broadcast_channel_capacity")]
145 pub end_of_epoch_broadcast_channel_capacity: usize,
146
147 #[serde(default)]
151 pub checkpoint_executor_config: CheckpointExecutorConfig,
152
153 #[serde(skip_serializing_if = "Option::is_none")]
154 pub metrics: Option<MetricsConfig>,
155
156 #[serde(skip)]
161 pub supported_protocol_versions: Option<SupportedProtocolVersions>,
162
163 #[serde(default)]
167 pub db_checkpoint_config: DBCheckpointConfig,
168
169 #[serde(default)]
172 pub indirect_objects_threshold: usize,
173
174 #[serde(default)]
176 pub expensive_safety_check_config: ExpensiveSafetyCheckConfig,
177
178 #[serde(default)]
182 pub transaction_deny_config: TransactionDenyConfig,
183
184 #[serde(default)]
190 pub certificate_deny_config: CertificateDenyConfig,
191
192 #[serde(default)]
195 pub state_debug_dump_config: StateDebugDumpConfig,
196
197 #[serde(default)]
201 pub state_archive_write_config: StateArchiveConfig,
202
203 #[serde(default)]
204 pub state_archive_read_config: Vec<StateArchiveConfig>,
205
206 #[serde(default)]
208 pub state_snapshot_write_config: StateSnapshotConfig,
209
210 #[serde(default)]
211 pub indexer_max_subscriptions: Option<usize>,
212
213 #[serde(default)]
214 pub transaction_kv_store_read_config: TransactionKeyValueStoreReadConfig,
215
216 #[serde(skip_serializing_if = "Option::is_none")]
218 pub transaction_kv_store_write_config: Option<TransactionKeyValueStoreWriteConfig>,
219
220 #[serde(default = "default_jwk_fetch_interval_seconds")]
221 pub jwk_fetch_interval_seconds: u64,
222
223 #[serde(default = "default_zklogin_oauth_providers")]
224 pub zklogin_oauth_providers: BTreeMap<Chain, BTreeSet<String>>,
225
226 #[serde(default = "default_authority_overload_config")]
229 pub authority_overload_config: AuthorityOverloadConfig,
230
231 #[serde(skip_serializing_if = "Option::is_none")]
235 pub run_with_range: Option<RunWithRange>,
236
237 #[serde(skip_serializing_if = "Option::is_none")]
239 pub policy_config: Option<PolicyConfig>,
240
241 #[serde(skip_serializing_if = "Option::is_none")]
242 pub firewall_config: Option<RemoteFirewallConfig>,
243
244 #[serde(default)]
245 pub execution_cache: ExecutionCacheConfig,
246
247 #[serde(default = "bool_true")]
248 pub enable_validator_tx_finalizer: bool,
249
250 #[serde(default)]
251 pub verifier_signing_config: VerifierSigningConfig,
252
253 #[serde(default, skip_serializing_if = "Option::is_none")]
254 pub iota_names_config: Option<IotaNamesConfig>,
255}
256
257#[derive(Clone, Debug, Deserialize, Serialize, Default)]
258#[serde(rename_all = "kebab-case")]
259pub enum ExecutionCacheConfig {
260 #[default]
261 PassthroughCache,
262 WritebackCache {
263 max_cache_size: Option<usize>,
264 },
265}
266
267#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
268#[serde(rename_all = "lowercase")]
269pub enum ServerType {
270 WebSocket,
271 Http,
272 Both,
273}
274
275#[derive(Clone, Debug, Deserialize, Serialize, Default)]
276#[serde(rename_all = "kebab-case")]
277pub struct TransactionKeyValueStoreReadConfig {
278 pub base_url: String,
279}
280
281fn default_jwk_fetch_interval_seconds() -> u64 {
282 3600
283}
284
285pub fn default_zklogin_oauth_providers() -> BTreeMap<Chain, BTreeSet<String>> {
286 let mut map = BTreeMap::new();
287
288 let experimental_providers = BTreeSet::from([
290 "Google".to_string(),
291 "Facebook".to_string(),
292 "Twitch".to_string(),
293 "Kakao".to_string(),
294 "Apple".to_string(),
295 "Slack".to_string(),
296 "TestIssuer".to_string(),
297 "Microsoft".to_string(),
298 "KarrierOne".to_string(),
299 "Credenza3".to_string(),
300 ]);
301
302 let providers = BTreeSet::from([
304 "Google".to_string(),
305 "Facebook".to_string(),
306 "Twitch".to_string(),
307 "Apple".to_string(),
308 "KarrierOne".to_string(),
309 "Credenza3".to_string(),
310 ]);
311 map.insert(Chain::Mainnet, providers.clone());
312 map.insert(Chain::Testnet, providers);
313 map.insert(Chain::Unknown, experimental_providers);
314 map
315}
316
317fn default_authority_store_pruning_config() -> AuthorityStorePruningConfig {
318 AuthorityStorePruningConfig::default()
319}
320
321pub fn default_enable_index_processing() -> bool {
322 true
323}
324
325fn default_grpc_address() -> Multiaddr {
326 "/ip4/0.0.0.0/tcp/8080".parse().unwrap()
327}
328fn default_authority_key_pair() -> AuthorityKeyPairWithPath {
329 AuthorityKeyPairWithPath::new(get_key_pair_from_rng::<AuthorityKeyPair, _>(&mut OsRng).1)
330}
331
332fn default_key_pair() -> KeyPairWithPath {
333 KeyPairWithPath::new(
334 get_key_pair_from_rng::<AccountKeyPair, _>(&mut OsRng)
335 .1
336 .into(),
337 )
338}
339
340fn default_metrics_address() -> SocketAddr {
341 use std::net::{IpAddr, Ipv4Addr};
342 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9184)
343}
344
345pub fn default_admin_interface_address() -> SocketAddr {
346 SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 1337)
347}
348
349pub fn default_json_rpc_address() -> SocketAddr {
350 use std::net::{IpAddr, Ipv4Addr};
351 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9000)
352}
353
354pub fn default_concurrency_limit() -> Option<usize> {
355 Some(DEFAULT_GRPC_CONCURRENCY_LIMIT)
356}
357
358pub fn default_end_of_epoch_broadcast_channel_capacity() -> usize {
359 128
360}
361
362pub fn bool_true() -> bool {
363 true
364}
365
366fn is_true(value: &bool) -> bool {
367 *value
368}
369
370impl Config for NodeConfig {}
371
372impl NodeConfig {
373 pub fn authority_key_pair(&self) -> &AuthorityKeyPair {
374 self.authority_key_pair.authority_keypair()
375 }
376
377 pub fn protocol_key_pair(&self) -> &NetworkKeyPair {
378 match self.protocol_key_pair.keypair() {
379 IotaKeyPair::Ed25519(kp) => kp,
380 other => panic!(
381 "invalid keypair type: {:?}, only Ed25519 is allowed for protocol key",
382 other
383 ),
384 }
385 }
386
387 pub fn network_key_pair(&self) -> &NetworkKeyPair {
388 match self.network_key_pair.keypair() {
389 IotaKeyPair::Ed25519(kp) => kp,
390 other => panic!(
391 "invalid keypair type: {:?}, only Ed25519 is allowed for network key",
392 other
393 ),
394 }
395 }
396
397 pub fn authority_public_key(&self) -> AuthorityPublicKeyBytes {
398 self.authority_key_pair().public().into()
399 }
400
401 pub fn db_path(&self) -> PathBuf {
402 self.db_path.join("live")
403 }
404
405 pub fn db_checkpoint_path(&self) -> PathBuf {
406 self.db_path.join("db_checkpoints")
407 }
408
409 pub fn archive_path(&self) -> PathBuf {
410 self.db_path.join("archive")
411 }
412
413 pub fn snapshot_path(&self) -> PathBuf {
414 self.db_path.join("snapshot")
415 }
416
417 pub fn network_address(&self) -> &Multiaddr {
418 &self.network_address
419 }
420
421 pub fn consensus_config(&self) -> Option<&ConsensusConfig> {
422 self.consensus_config.as_ref()
423 }
424
425 pub fn genesis(&self) -> Result<&genesis::Genesis> {
426 self.genesis.genesis()
427 }
428
429 pub fn load_migration_tx_data(&self) -> Result<MigrationTxData> {
430 let Some(location) = &self.migration_tx_data_path else {
431 anyhow::bail!("no file location set");
432 };
433
434 let migration_tx_data = MigrationTxData::load(location)?;
436
437 migration_tx_data.validate_from_genesis(self.genesis.genesis()?)?;
439 Ok(migration_tx_data)
440 }
441
442 pub fn iota_address(&self) -> IotaAddress {
443 (&self.account_key_pair.keypair().public()).into()
444 }
445
446 pub fn archive_reader_config(&self) -> Vec<ArchiveReaderConfig> {
447 self.state_archive_read_config
448 .iter()
449 .flat_map(|config| {
450 config
451 .object_store_config
452 .as_ref()
453 .map(|remote_store_config| ArchiveReaderConfig {
454 remote_store_config: remote_store_config.clone(),
455 download_concurrency: NonZeroUsize::new(config.concurrency)
456 .unwrap_or(NonZeroUsize::new(5).unwrap()),
457 use_for_pruning_watermark: config.use_for_pruning_watermark,
458 })
459 })
460 .collect()
461 }
462
463 pub fn jsonrpc_server_type(&self) -> ServerType {
464 self.jsonrpc_server_type.unwrap_or(ServerType::Http)
465 }
466}
467
468#[derive(Debug, Clone, Deserialize, Serialize)]
469pub enum ConsensusProtocol {
470 #[serde(rename = "mysticeti")]
471 Mysticeti,
472}
473
474#[derive(Debug, Clone, Deserialize, Serialize)]
475#[serde(rename_all = "kebab-case")]
476pub struct ConsensusConfig {
477 pub db_path: PathBuf,
479
480 pub db_retention_epochs: Option<u64>,
483
484 pub db_pruner_period_secs: Option<u64>,
487
488 pub max_pending_transactions: Option<usize>,
494
495 pub max_submit_position: Option<usize>,
501
502 pub submit_delay_step_override_millis: Option<u64>,
508
509 pub parameters: Option<ConsensusParameters>,
510}
511
512impl ConsensusConfig {
513 pub fn db_path(&self) -> &Path {
514 &self.db_path
515 }
516
517 pub fn max_pending_transactions(&self) -> usize {
518 self.max_pending_transactions.unwrap_or(20_000)
519 }
520
521 pub fn submit_delay_step_override(&self) -> Option<Duration> {
522 self.submit_delay_step_override_millis
523 .map(Duration::from_millis)
524 }
525
526 pub fn db_retention_epochs(&self) -> u64 {
527 self.db_retention_epochs.unwrap_or(0)
528 }
529
530 pub fn db_pruner_period(&self) -> Duration {
531 self.db_pruner_period_secs
533 .map(Duration::from_secs)
534 .unwrap_or(Duration::from_secs(3_600))
535 }
536}
537
538#[derive(Clone, Debug, Deserialize, Serialize)]
539#[serde(rename_all = "kebab-case")]
540pub struct CheckpointExecutorConfig {
541 #[serde(default = "default_checkpoint_execution_max_concurrency")]
546 pub checkpoint_execution_max_concurrency: usize,
547
548 #[serde(default = "default_local_execution_timeout_sec")]
554 pub local_execution_timeout_sec: u64,
555
556 #[serde(default, skip_serializing_if = "Option::is_none")]
561 pub data_ingestion_dir: Option<PathBuf>,
562}
563
564#[derive(Clone, Debug, Default, Deserialize, Serialize)]
565#[serde(rename_all = "kebab-case")]
566pub struct ExpensiveSafetyCheckConfig {
567 #[serde(default)]
572 enable_epoch_iota_conservation_check: bool,
573
574 #[serde(default)]
578 enable_deep_per_tx_iota_conservation_check: bool,
579
580 #[serde(default)]
583 force_disable_epoch_iota_conservation_check: bool,
584
585 #[serde(default)]
588 enable_state_consistency_check: bool,
589
590 #[serde(default)]
592 force_disable_state_consistency_check: bool,
593
594 #[serde(default)]
595 enable_secondary_index_checks: bool,
596 }
598
599impl ExpensiveSafetyCheckConfig {
600 pub fn new_enable_all() -> Self {
601 Self {
602 enable_epoch_iota_conservation_check: true,
603 enable_deep_per_tx_iota_conservation_check: true,
604 force_disable_epoch_iota_conservation_check: false,
605 enable_state_consistency_check: true,
606 force_disable_state_consistency_check: false,
607 enable_secondary_index_checks: false, }
609 }
610
611 pub fn new_disable_all() -> Self {
612 Self {
613 enable_epoch_iota_conservation_check: false,
614 enable_deep_per_tx_iota_conservation_check: false,
615 force_disable_epoch_iota_conservation_check: true,
616 enable_state_consistency_check: false,
617 force_disable_state_consistency_check: true,
618 enable_secondary_index_checks: false,
619 }
620 }
621
622 pub fn force_disable_epoch_iota_conservation_check(&mut self) {
623 self.force_disable_epoch_iota_conservation_check = true;
624 }
625
626 pub fn enable_epoch_iota_conservation_check(&self) -> bool {
627 (self.enable_epoch_iota_conservation_check || cfg!(debug_assertions))
628 && !self.force_disable_epoch_iota_conservation_check
629 }
630
631 pub fn force_disable_state_consistency_check(&mut self) {
632 self.force_disable_state_consistency_check = true;
633 }
634
635 pub fn enable_state_consistency_check(&self) -> bool {
636 (self.enable_state_consistency_check || cfg!(debug_assertions))
637 && !self.force_disable_state_consistency_check
638 }
639
640 pub fn enable_deep_per_tx_iota_conservation_check(&self) -> bool {
641 self.enable_deep_per_tx_iota_conservation_check || cfg!(debug_assertions)
642 }
643
644 pub fn enable_secondary_index_checks(&self) -> bool {
645 self.enable_secondary_index_checks
646 }
647}
648
649fn default_checkpoint_execution_max_concurrency() -> usize {
650 200
651}
652
653fn default_local_execution_timeout_sec() -> u64 {
654 30
655}
656
657impl Default for CheckpointExecutorConfig {
658 fn default() -> Self {
659 Self {
660 checkpoint_execution_max_concurrency: default_checkpoint_execution_max_concurrency(),
661 local_execution_timeout_sec: default_local_execution_timeout_sec(),
662 data_ingestion_dir: None,
663 }
664 }
665}
666
667#[derive(Debug, Clone, Deserialize, Serialize)]
668#[serde(rename_all = "kebab-case")]
669pub struct AuthorityStorePruningConfig {
670 #[serde(default = "default_num_latest_epoch_dbs_to_retain")]
672 pub num_latest_epoch_dbs_to_retain: usize,
673 #[serde(default = "default_epoch_db_pruning_period_secs")]
676 pub epoch_db_pruning_period_secs: u64,
677 #[serde(default)]
682 pub num_epochs_to_retain: u64,
683 #[serde(skip_serializing_if = "Option::is_none")]
685 pub pruning_run_delay_seconds: Option<u64>,
686 #[serde(default = "default_max_checkpoints_in_batch")]
689 pub max_checkpoints_in_batch: usize,
690 #[serde(default = "default_max_transactions_in_batch")]
692 pub max_transactions_in_batch: usize,
693 #[serde(skip_serializing_if = "Option::is_none")]
698 pub periodic_compaction_threshold_days: Option<usize>,
699 #[serde(skip_serializing_if = "Option::is_none")]
702 pub num_epochs_to_retain_for_checkpoints: Option<u64>,
703 #[serde(default = "default_smoothing", skip_serializing_if = "is_true")]
704 pub smooth: bool,
705}
706
707fn default_num_latest_epoch_dbs_to_retain() -> usize {
708 3
709}
710
711fn default_epoch_db_pruning_period_secs() -> u64 {
712 3600
713}
714
715fn default_max_transactions_in_batch() -> usize {
716 1000
717}
718
719fn default_max_checkpoints_in_batch() -> usize {
720 10
721}
722
723fn default_smoothing() -> bool {
724 cfg!(not(test))
725}
726
727impl Default for AuthorityStorePruningConfig {
728 fn default() -> Self {
729 Self {
730 num_latest_epoch_dbs_to_retain: default_num_latest_epoch_dbs_to_retain(),
731 epoch_db_pruning_period_secs: default_epoch_db_pruning_period_secs(),
732 num_epochs_to_retain: 0,
733 pruning_run_delay_seconds: if cfg!(msim) { Some(2) } else { None },
734 max_checkpoints_in_batch: default_max_checkpoints_in_batch(),
735 max_transactions_in_batch: default_max_transactions_in_batch(),
736 periodic_compaction_threshold_days: None,
737 num_epochs_to_retain_for_checkpoints: if cfg!(msim) { Some(2) } else { None },
738 smooth: true,
739 }
740 }
741}
742
743impl AuthorityStorePruningConfig {
744 pub fn set_num_epochs_to_retain_for_checkpoints(&mut self, num_epochs_to_retain: Option<u64>) {
745 self.num_epochs_to_retain_for_checkpoints = num_epochs_to_retain;
746 }
747
748 pub fn num_epochs_to_retain_for_checkpoints(&self) -> Option<u64> {
749 self.num_epochs_to_retain_for_checkpoints
750 .map(|n| {
752 if n < 2 {
753 info!("num_epochs_to_retain_for_checkpoints must be at least 2, rounding up from {}", n);
754 2
755 } else {
756 n
757 }
758 })
759 }
760}
761
762#[derive(Debug, Clone, Deserialize, Serialize)]
763#[serde(rename_all = "kebab-case")]
764pub struct MetricsConfig {
765 #[serde(skip_serializing_if = "Option::is_none")]
766 pub push_interval_seconds: Option<u64>,
767 #[serde(skip_serializing_if = "Option::is_none")]
768 pub push_url: Option<String>,
769}
770
771#[derive(Default, Debug, Clone, Deserialize, Serialize)]
772#[serde(rename_all = "kebab-case")]
773pub struct DBCheckpointConfig {
774 #[serde(default)]
775 pub perform_db_checkpoints_at_epoch_end: bool,
776 #[serde(skip_serializing_if = "Option::is_none")]
777 pub checkpoint_path: Option<PathBuf>,
778 #[serde(skip_serializing_if = "Option::is_none")]
779 pub object_store_config: Option<ObjectStoreConfig>,
780 #[serde(skip_serializing_if = "Option::is_none")]
781 pub perform_index_db_checkpoints_at_epoch_end: Option<bool>,
782 #[serde(skip_serializing_if = "Option::is_none")]
783 pub prune_and_compact_before_upload: Option<bool>,
784}
785
786#[derive(Debug, Clone)]
787pub struct ArchiveReaderConfig {
788 pub remote_store_config: ObjectStoreConfig,
789 pub download_concurrency: NonZeroUsize,
790 pub use_for_pruning_watermark: bool,
791}
792
793#[derive(Default, Debug, Clone, Deserialize, Serialize)]
794#[serde(rename_all = "kebab-case")]
795pub struct StateArchiveConfig {
796 #[serde(skip_serializing_if = "Option::is_none")]
797 pub object_store_config: Option<ObjectStoreConfig>,
798 pub concurrency: usize,
799 pub use_for_pruning_watermark: bool,
800}
801
802#[derive(Default, Debug, Clone, Deserialize, Serialize)]
803#[serde(rename_all = "kebab-case")]
804pub struct StateSnapshotConfig {
805 #[serde(skip_serializing_if = "Option::is_none")]
806 pub object_store_config: Option<ObjectStoreConfig>,
807 pub concurrency: usize,
808}
809
810#[derive(Default, Debug, Clone, Deserialize, Serialize)]
811#[serde(rename_all = "kebab-case")]
812pub struct TransactionKeyValueStoreWriteConfig {
813 pub aws_access_key_id: String,
814 pub aws_secret_access_key: String,
815 pub aws_region: String,
816 pub table_name: String,
817 pub bucket_name: String,
818 pub concurrency: usize,
819}
820
821#[derive(Clone, Debug, Deserialize, Serialize)]
826#[serde(rename_all = "kebab-case")]
827pub struct AuthorityOverloadConfig {
828 #[serde(default = "default_max_txn_age_in_queue")]
829 pub max_txn_age_in_queue: Duration,
830
831 #[serde(default = "default_overload_monitor_interval")]
833 pub overload_monitor_interval: Duration,
834
835 #[serde(default = "default_execution_queue_latency_soft_limit")]
837 pub execution_queue_latency_soft_limit: Duration,
838
839 #[serde(default = "default_execution_queue_latency_hard_limit")]
841 pub execution_queue_latency_hard_limit: Duration,
842
843 #[serde(default = "default_max_load_shedding_percentage")]
845 pub max_load_shedding_percentage: u32,
846
847 #[serde(default = "default_min_load_shedding_percentage_above_hard_limit")]
850 pub min_load_shedding_percentage_above_hard_limit: u32,
851
852 #[serde(default = "default_safe_transaction_ready_rate")]
855 pub safe_transaction_ready_rate: u32,
856
857 #[serde(default = "default_check_system_overload_at_signing")]
860 pub check_system_overload_at_signing: bool,
861
862 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
865 pub check_system_overload_at_execution: bool,
866
867 #[serde(default = "default_max_transaction_manager_queue_length")]
870 pub max_transaction_manager_queue_length: usize,
871
872 #[serde(default = "default_max_transaction_manager_per_object_queue_length")]
875 pub max_transaction_manager_per_object_queue_length: usize,
876}
877
878fn default_max_txn_age_in_queue() -> Duration {
879 Duration::from_millis(500)
880}
881
882fn default_overload_monitor_interval() -> Duration {
883 Duration::from_secs(10)
884}
885
886fn default_execution_queue_latency_soft_limit() -> Duration {
887 Duration::from_secs(1)
888}
889
890fn default_execution_queue_latency_hard_limit() -> Duration {
891 Duration::from_secs(10)
892}
893
894fn default_max_load_shedding_percentage() -> u32 {
895 95
896}
897
898fn default_min_load_shedding_percentage_above_hard_limit() -> u32 {
899 50
900}
901
902fn default_safe_transaction_ready_rate() -> u32 {
903 100
904}
905
906fn default_check_system_overload_at_signing() -> bool {
907 true
908}
909
910fn default_max_transaction_manager_queue_length() -> usize {
911 100_000
912}
913
914fn default_max_transaction_manager_per_object_queue_length() -> usize {
915 100
916}
917
918impl Default for AuthorityOverloadConfig {
919 fn default() -> Self {
920 Self {
921 max_txn_age_in_queue: default_max_txn_age_in_queue(),
922 overload_monitor_interval: default_overload_monitor_interval(),
923 execution_queue_latency_soft_limit: default_execution_queue_latency_soft_limit(),
924 execution_queue_latency_hard_limit: default_execution_queue_latency_hard_limit(),
925 max_load_shedding_percentage: default_max_load_shedding_percentage(),
926 min_load_shedding_percentage_above_hard_limit:
927 default_min_load_shedding_percentage_above_hard_limit(),
928 safe_transaction_ready_rate: default_safe_transaction_ready_rate(),
929 check_system_overload_at_signing: true,
930 check_system_overload_at_execution: false,
931 max_transaction_manager_queue_length: default_max_transaction_manager_queue_length(),
932 max_transaction_manager_per_object_queue_length:
933 default_max_transaction_manager_per_object_queue_length(),
934 }
935 }
936}
937
938fn default_authority_overload_config() -> AuthorityOverloadConfig {
939 AuthorityOverloadConfig::default()
940}
941
942#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq)]
943pub struct Genesis {
944 #[serde(flatten)]
945 location: Option<GenesisLocation>,
946
947 #[serde(skip)]
948 genesis: once_cell::sync::OnceCell<genesis::Genesis>,
949}
950
951impl Genesis {
952 pub fn new(genesis: genesis::Genesis) -> Self {
953 Self {
954 location: Some(GenesisLocation::InPlace { genesis }),
955 genesis: Default::default(),
956 }
957 }
958
959 pub fn new_from_file<P: Into<PathBuf>>(path: P) -> Self {
960 Self {
961 location: Some(GenesisLocation::File {
962 genesis_file_location: path.into(),
963 }),
964 genesis: Default::default(),
965 }
966 }
967
968 pub fn new_empty() -> Self {
969 Self {
970 location: None,
971 genesis: Default::default(),
972 }
973 }
974
975 pub fn genesis(&self) -> Result<&genesis::Genesis> {
976 match &self.location {
977 Some(GenesisLocation::InPlace { genesis }) => Ok(genesis),
978 Some(GenesisLocation::File {
979 genesis_file_location,
980 }) => self
981 .genesis
982 .get_or_try_init(|| genesis::Genesis::load(genesis_file_location)),
983 None => anyhow::bail!("no genesis location set"),
984 }
985 }
986}
987
988#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq)]
989#[serde(untagged)]
990enum GenesisLocation {
991 InPlace {
992 genesis: genesis::Genesis,
993 },
994 File {
995 #[serde(rename = "genesis-file-location")]
996 genesis_file_location: PathBuf,
997 },
998}
999
1000#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
1003pub struct KeyPairWithPath {
1004 #[serde(flatten)]
1005 location: KeyPairLocation,
1006
1007 #[serde(skip)]
1008 keypair: OnceCell<Arc<IotaKeyPair>>,
1009}
1010
1011#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq)]
1012#[serde(untagged)]
1013enum KeyPairLocation {
1014 InPlace {
1015 #[serde(with = "bech32_formatted_keypair")]
1016 value: Arc<IotaKeyPair>,
1017 },
1018 File {
1019 path: PathBuf,
1020 },
1021}
1022
1023impl KeyPairWithPath {
1024 pub fn new(kp: IotaKeyPair) -> Self {
1025 let cell: OnceCell<Arc<IotaKeyPair>> = OnceCell::new();
1026 let arc_kp = Arc::new(kp);
1027 cell.set(arc_kp.clone()).expect("failed to set keypair");
1030 Self {
1031 location: KeyPairLocation::InPlace { value: arc_kp },
1032 keypair: cell,
1033 }
1034 }
1035
1036 pub fn new_from_path(path: PathBuf) -> Self {
1037 let cell: OnceCell<Arc<IotaKeyPair>> = OnceCell::new();
1038 cell.set(Arc::new(read_keypair_from_file(&path).unwrap_or_else(
1041 |e| panic!("invalid keypair file at path {:?}: {e}", &path),
1042 )))
1043 .expect("failed to set keypair");
1044 Self {
1045 location: KeyPairLocation::File { path },
1046 keypair: cell,
1047 }
1048 }
1049
1050 pub fn keypair(&self) -> &IotaKeyPair {
1051 self.keypair
1052 .get_or_init(|| match &self.location {
1053 KeyPairLocation::InPlace { value } => value.clone(),
1054 KeyPairLocation::File { path } => {
1055 Arc::new(
1058 read_keypair_from_file(path).unwrap_or_else(|e| {
1059 panic!("invalid keypair file at path {:?}: {e}", path)
1060 }),
1061 )
1062 }
1063 })
1064 .as_ref()
1065 }
1066}
1067
1068#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
1071pub struct AuthorityKeyPairWithPath {
1072 #[serde(flatten)]
1073 location: AuthorityKeyPairLocation,
1074
1075 #[serde(skip)]
1076 keypair: OnceCell<Arc<AuthorityKeyPair>>,
1077}
1078
1079#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq)]
1080#[serde(untagged)]
1081enum AuthorityKeyPairLocation {
1082 InPlace { value: Arc<AuthorityKeyPair> },
1083 File { path: PathBuf },
1084}
1085
1086impl AuthorityKeyPairWithPath {
1087 pub fn new(kp: AuthorityKeyPair) -> Self {
1088 let cell: OnceCell<Arc<AuthorityKeyPair>> = OnceCell::new();
1089 let arc_kp = Arc::new(kp);
1090 cell.set(arc_kp.clone())
1093 .expect("failed to set authority keypair");
1094 Self {
1095 location: AuthorityKeyPairLocation::InPlace { value: arc_kp },
1096 keypair: cell,
1097 }
1098 }
1099
1100 pub fn new_from_path(path: PathBuf) -> Self {
1101 let cell: OnceCell<Arc<AuthorityKeyPair>> = OnceCell::new();
1102 cell.set(Arc::new(
1105 read_authority_keypair_from_file(&path)
1106 .unwrap_or_else(|_| panic!("invalid authority keypair file at path {:?}", &path)),
1107 ))
1108 .expect("failed to set authority keypair");
1109 Self {
1110 location: AuthorityKeyPairLocation::File { path },
1111 keypair: cell,
1112 }
1113 }
1114
1115 pub fn authority_keypair(&self) -> &AuthorityKeyPair {
1116 self.keypair
1117 .get_or_init(|| match &self.location {
1118 AuthorityKeyPairLocation::InPlace { value } => value.clone(),
1119 AuthorityKeyPairLocation::File { path } => {
1120 Arc::new(
1123 read_authority_keypair_from_file(path).unwrap_or_else(|_| {
1124 panic!("invalid authority keypair file {:?}", &path)
1125 }),
1126 )
1127 }
1128 })
1129 .as_ref()
1130 }
1131}
1132
1133#[derive(Clone, Debug, Deserialize, Serialize, Default)]
1136#[serde(rename_all = "kebab-case")]
1137pub struct StateDebugDumpConfig {
1138 #[serde(skip_serializing_if = "Option::is_none")]
1139 pub dump_file_directory: Option<PathBuf>,
1140}
1141
1142#[cfg(test)]
1143mod tests {
1144 use std::path::PathBuf;
1145
1146 use fastcrypto::traits::KeyPair;
1147 use iota_keys::keypair_file::{write_authority_keypair_to_file, write_keypair_to_file};
1148 use iota_types::crypto::{
1149 AuthorityKeyPair, IotaKeyPair, NetworkKeyPair, get_key_pair_from_rng,
1150 };
1151 use rand::{SeedableRng, rngs::StdRng};
1152
1153 use super::Genesis;
1154 use crate::NodeConfig;
1155
1156 #[test]
1157 fn serialize_genesis_from_file() {
1158 let g = Genesis::new_from_file("path/to/file");
1159
1160 let s = serde_yaml::to_string(&g).unwrap();
1161 assert_eq!("---\ngenesis-file-location: path/to/file\n", s);
1162 let loaded_genesis: Genesis = serde_yaml::from_str(&s).unwrap();
1163 assert_eq!(g, loaded_genesis);
1164 }
1165
1166 #[test]
1167 fn fullnode_template() {
1168 const TEMPLATE: &str = include_str!("../data/fullnode-template.yaml");
1169
1170 let _template: NodeConfig = serde_yaml::from_str(TEMPLATE).unwrap();
1171 }
1172
1173 #[test]
1174 fn load_key_pairs_to_node_config() {
1175 let authority_key_pair: AuthorityKeyPair =
1176 get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1;
1177 let protocol_key_pair: NetworkKeyPair =
1178 get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1;
1179 let network_key_pair: NetworkKeyPair =
1180 get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1;
1181
1182 write_authority_keypair_to_file(&authority_key_pair, PathBuf::from("authority.key"))
1183 .unwrap();
1184 write_keypair_to_file(
1185 &IotaKeyPair::Ed25519(protocol_key_pair.copy()),
1186 PathBuf::from("protocol.key"),
1187 )
1188 .unwrap();
1189 write_keypair_to_file(
1190 &IotaKeyPair::Ed25519(network_key_pair.copy()),
1191 PathBuf::from("network.key"),
1192 )
1193 .unwrap();
1194
1195 const TEMPLATE: &str = include_str!("../data/fullnode-template-with-path.yaml");
1196 let template: NodeConfig = serde_yaml::from_str(TEMPLATE).unwrap();
1197 assert_eq!(
1198 template.authority_key_pair().public(),
1199 authority_key_pair.public()
1200 );
1201 assert_eq!(
1202 template.network_key_pair().public(),
1203 network_key_pair.public()
1204 );
1205 assert_eq!(
1206 template.protocol_key_pair().public(),
1207 protocol_key_pair.public()
1208 );
1209 }
1210}
1211
1212#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)]
1216pub enum RunWithRange {
1217 Epoch(EpochId),
1218 Checkpoint(CheckpointSequenceNumber),
1219}
1220
1221impl RunWithRange {
1222 pub fn is_epoch_gt(&self, epoch_id: EpochId) -> bool {
1224 matches!(self, RunWithRange::Epoch(e) if epoch_id > *e)
1225 }
1226
1227 pub fn matches_checkpoint(&self, seq_num: CheckpointSequenceNumber) -> bool {
1228 matches!(self, RunWithRange::Checkpoint(seq) if *seq == seq_num)
1229 }
1230}
1231
1232mod bech32_formatted_keypair {
1236 use std::ops::Deref;
1237
1238 use iota_types::crypto::{EncodeDecodeBase64, IotaKeyPair};
1239 use serde::{Deserialize, Deserializer, Serializer};
1240
1241 pub fn serialize<S, T>(kp: &T, serializer: S) -> Result<S::Ok, S::Error>
1242 where
1243 S: Serializer,
1244 T: Deref<Target = IotaKeyPair>,
1245 {
1246 use serde::ser::Error;
1247
1248 let s = kp.encode().map_err(Error::custom)?;
1250
1251 serializer.serialize_str(&s)
1252 }
1253
1254 pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
1255 where
1256 D: Deserializer<'de>,
1257 T: From<IotaKeyPair>,
1258 {
1259 use serde::de::Error;
1260
1261 let s = String::deserialize(deserializer)?;
1262
1263 IotaKeyPair::decode(&s)
1265 .or_else(|_| {
1266 IotaKeyPair::decode_base64(&s)
1268 })
1269 .map(Into::into)
1270 .map_err(Error::custom)
1271 }
1272}