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: ExecutionCacheType,
248
249 #[serde(default)]
250 pub execution_cache_config: ExecutionCacheConfig,
251
252 #[serde(default = "bool_true")]
253 pub enable_validator_tx_finalizer: bool,
254
255 #[serde(default)]
256 pub verifier_signing_config: VerifierSigningConfig,
257
258 #[serde(skip_serializing_if = "Option::is_none")]
262 pub enable_db_write_stall: Option<bool>,
263
264 #[serde(default, skip_serializing_if = "Option::is_none")]
265 pub iota_names_config: Option<IotaNamesConfig>,
266}
267
268#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize)]
269#[serde(rename_all = "kebab-case")]
270pub enum ExecutionCacheType {
271 #[default]
272 WritebackCache,
273 PassthroughCache,
274}
275
276impl From<ExecutionCacheType> for u8 {
277 fn from(cache_type: ExecutionCacheType) -> Self {
278 match cache_type {
279 ExecutionCacheType::WritebackCache => 0,
280 ExecutionCacheType::PassthroughCache => 1,
281 }
282 }
283}
284
285impl From<&u8> for ExecutionCacheType {
286 fn from(cache_type: &u8) -> Self {
287 match cache_type {
288 0 => ExecutionCacheType::WritebackCache,
289 1 => ExecutionCacheType::PassthroughCache,
290 _ => unreachable!("Invalid value for ExecutionCacheType"),
291 }
292 }
293}
294
295pub type ExecutionCacheTypeAtomicU8 = std::sync::atomic::AtomicU8;
298
299impl From<ExecutionCacheType> for ExecutionCacheTypeAtomicU8 {
300 fn from(cache_type: ExecutionCacheType) -> Self {
301 ExecutionCacheTypeAtomicU8::new(u8::from(cache_type))
302 }
303}
304
305impl ExecutionCacheType {
306 pub fn cache_type(self) -> Self {
307 if std::env::var("DISABLE_WRITEBACK_CACHE").is_ok() {
308 Self::PassthroughCache
309 } else {
310 self
311 }
312 }
313}
314
315#[derive(Clone, Debug, Default, Deserialize, Serialize)]
316#[serde(rename_all = "kebab-case")]
317pub struct ExecutionCacheConfig {
318 #[serde(default)]
319 pub writeback_cache: WritebackCacheConfig,
320}
321
322#[derive(Clone, Debug, Default, Deserialize, Serialize)]
323#[serde(rename_all = "kebab-case")]
324pub struct WritebackCacheConfig {
325 #[serde(default, skip_serializing_if = "Option::is_none")]
328 pub max_cache_size: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
331 pub package_cache_size: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
334 pub object_cache_size: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
336 pub marker_cache_size: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
338 pub object_by_id_cache_size: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
341 pub transaction_cache_size: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
343 pub executed_effect_cache_size: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
345 pub effect_cache_size: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
348 pub events_cache_size: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
351 pub transaction_objects_cache_size: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
356 pub backpressure_threshold: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
362 pub backpressure_threshold_for_rpc: Option<u64>, }
364
365impl WritebackCacheConfig {
366 pub fn max_cache_size(&self) -> u64 {
367 std::env::var("IOTA_CACHE_WRITEBACK_SIZE_MAX")
368 .ok()
369 .and_then(|s| s.parse().ok())
370 .or(self.max_cache_size)
371 .unwrap_or(100000)
372 }
373
374 pub fn package_cache_size(&self) -> u64 {
375 std::env::var("IOTA_CACHE_WRITEBACK_SIZE_PACKAGE")
376 .ok()
377 .and_then(|s| s.parse().ok())
378 .or(self.package_cache_size)
379 .unwrap_or(1000)
380 }
381
382 pub fn object_cache_size(&self) -> u64 {
383 std::env::var("IOTA_CACHE_WRITEBACK_SIZE_OBJECT")
384 .ok()
385 .and_then(|s| s.parse().ok())
386 .or(self.object_cache_size)
387 .unwrap_or_else(|| self.max_cache_size())
388 }
389
390 pub fn marker_cache_size(&self) -> u64 {
391 std::env::var("IOTA_CACHE_WRITEBACK_SIZE_MARKER")
392 .ok()
393 .and_then(|s| s.parse().ok())
394 .or(self.marker_cache_size)
395 .unwrap_or_else(|| self.object_cache_size())
396 }
397
398 pub fn object_by_id_cache_size(&self) -> u64 {
399 std::env::var("IOTA_CACHE_WRITEBACK_SIZE_OBJECT_BY_ID")
400 .ok()
401 .and_then(|s| s.parse().ok())
402 .or(self.object_by_id_cache_size)
403 .unwrap_or_else(|| self.object_cache_size())
404 }
405
406 pub fn transaction_cache_size(&self) -> u64 {
407 std::env::var("IOTA_CACHE_WRITEBACK_SIZE_TRANSACTION")
408 .ok()
409 .and_then(|s| s.parse().ok())
410 .or(self.transaction_cache_size)
411 .unwrap_or_else(|| self.max_cache_size())
412 }
413
414 pub fn executed_effect_cache_size(&self) -> u64 {
415 std::env::var("IOTA_CACHE_WRITEBACK_SIZE_EXECUTED_EFFECT")
416 .ok()
417 .and_then(|s| s.parse().ok())
418 .or(self.executed_effect_cache_size)
419 .unwrap_or_else(|| self.transaction_cache_size())
420 }
421
422 pub fn effect_cache_size(&self) -> u64 {
423 std::env::var("IOTA_CACHE_WRITEBACK_SIZE_EFFECT")
424 .ok()
425 .and_then(|s| s.parse().ok())
426 .or(self.effect_cache_size)
427 .unwrap_or_else(|| self.executed_effect_cache_size())
428 }
429
430 pub fn events_cache_size(&self) -> u64 {
431 std::env::var("IOTA_CACHE_WRITEBACK_SIZE_EVENTS")
432 .ok()
433 .and_then(|s| s.parse().ok())
434 .or(self.events_cache_size)
435 .unwrap_or_else(|| self.transaction_cache_size())
436 }
437
438 pub fn transaction_objects_cache_size(&self) -> u64 {
439 std::env::var("IOTA_CACHE_WRITEBACK_SIZE_TRANSACTION_OBJECTS")
440 .ok()
441 .and_then(|s| s.parse().ok())
442 .or(self.transaction_objects_cache_size)
443 .unwrap_or(1000)
444 }
445
446 pub fn backpressure_threshold(&self) -> u64 {
447 std::env::var("IOTA_CACHE_WRITEBACK_BACKPRESSURE_THRESHOLD")
448 .ok()
449 .and_then(|s| s.parse().ok())
450 .or(self.backpressure_threshold)
451 .unwrap_or(100_000)
452 }
453
454 pub fn backpressure_threshold_for_rpc(&self) -> u64 {
455 std::env::var("IOTA_CACHE_WRITEBACK_BACKPRESSURE_THRESHOLD_FOR_RPC")
456 .ok()
457 .and_then(|s| s.parse().ok())
458 .or(self.backpressure_threshold_for_rpc)
459 .unwrap_or(self.backpressure_threshold())
460 }
461}
462
463#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
464#[serde(rename_all = "lowercase")]
465pub enum ServerType {
466 WebSocket,
467 Http,
468 Both,
469}
470
471#[derive(Clone, Debug, Deserialize, Serialize)]
472#[serde(rename_all = "kebab-case")]
473pub struct TransactionKeyValueStoreReadConfig {
474 #[serde(default = "default_base_url")]
475 pub base_url: String,
476
477 #[serde(default = "default_cache_size")]
478 pub cache_size: u64,
479}
480
481impl Default for TransactionKeyValueStoreReadConfig {
482 fn default() -> Self {
483 Self {
484 base_url: default_base_url(),
485 cache_size: default_cache_size(),
486 }
487 }
488}
489
490fn default_base_url() -> String {
491 "".to_string()
492}
493
494fn default_cache_size() -> u64 {
495 100_000
496}
497
498fn default_jwk_fetch_interval_seconds() -> u64 {
499 3600
500}
501
502pub fn default_zklogin_oauth_providers() -> BTreeMap<Chain, BTreeSet<String>> {
503 let mut map = BTreeMap::new();
504
505 let experimental_providers = BTreeSet::from([
507 "Google".to_string(),
508 "Facebook".to_string(),
509 "Twitch".to_string(),
510 "Kakao".to_string(),
511 "Apple".to_string(),
512 "Slack".to_string(),
513 "TestIssuer".to_string(),
514 "Microsoft".to_string(),
515 "KarrierOne".to_string(),
516 "Credenza3".to_string(),
517 ]);
518
519 let providers = BTreeSet::from([
521 "Google".to_string(),
522 "Facebook".to_string(),
523 "Twitch".to_string(),
524 "Apple".to_string(),
525 "KarrierOne".to_string(),
526 "Credenza3".to_string(),
527 ]);
528 map.insert(Chain::Mainnet, providers.clone());
529 map.insert(Chain::Testnet, providers);
530 map.insert(Chain::Unknown, experimental_providers);
531 map
532}
533
534fn default_transaction_kv_store_config() -> TransactionKeyValueStoreReadConfig {
535 TransactionKeyValueStoreReadConfig::default()
536}
537
538fn default_authority_store_pruning_config() -> AuthorityStorePruningConfig {
539 AuthorityStorePruningConfig::default()
540}
541
542pub fn default_enable_index_processing() -> bool {
543 true
544}
545
546fn default_grpc_address() -> Multiaddr {
547 "/ip4/0.0.0.0/tcp/8080".parse().unwrap()
548}
549fn default_authority_key_pair() -> AuthorityKeyPairWithPath {
550 AuthorityKeyPairWithPath::new(get_key_pair_from_rng::<AuthorityKeyPair, _>(&mut OsRng).1)
551}
552
553fn default_key_pair() -> KeyPairWithPath {
554 KeyPairWithPath::new(
555 get_key_pair_from_rng::<AccountKeyPair, _>(&mut OsRng)
556 .1
557 .into(),
558 )
559}
560
561fn default_metrics_address() -> SocketAddr {
562 use std::net::{IpAddr, Ipv4Addr};
563 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9184)
564}
565
566pub fn default_admin_interface_address() -> SocketAddr {
567 SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 1337)
568}
569
570pub fn default_json_rpc_address() -> SocketAddr {
571 use std::net::{IpAddr, Ipv4Addr};
572 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9000)
573}
574
575pub fn default_concurrency_limit() -> Option<usize> {
576 Some(DEFAULT_GRPC_CONCURRENCY_LIMIT)
577}
578
579pub fn default_end_of_epoch_broadcast_channel_capacity() -> usize {
580 128
581}
582
583pub fn bool_true() -> bool {
584 true
585}
586
587fn is_true(value: &bool) -> bool {
588 *value
589}
590
591impl Config for NodeConfig {}
592
593impl NodeConfig {
594 pub fn authority_key_pair(&self) -> &AuthorityKeyPair {
595 self.authority_key_pair.authority_keypair()
596 }
597
598 pub fn protocol_key_pair(&self) -> &NetworkKeyPair {
599 match self.protocol_key_pair.keypair() {
600 IotaKeyPair::Ed25519(kp) => kp,
601 other => {
602 panic!("invalid keypair type: {other:?}, only Ed25519 is allowed for protocol key")
603 }
604 }
605 }
606
607 pub fn network_key_pair(&self) -> &NetworkKeyPair {
608 match self.network_key_pair.keypair() {
609 IotaKeyPair::Ed25519(kp) => kp,
610 other => {
611 panic!("invalid keypair type: {other:?}, only Ed25519 is allowed for network key")
612 }
613 }
614 }
615
616 pub fn authority_public_key(&self) -> AuthorityPublicKeyBytes {
617 self.authority_key_pair().public().into()
618 }
619
620 pub fn db_path(&self) -> PathBuf {
621 self.db_path.join("live")
622 }
623
624 pub fn db_checkpoint_path(&self) -> PathBuf {
625 self.db_path.join("db_checkpoints")
626 }
627
628 pub fn archive_path(&self) -> PathBuf {
629 self.db_path.join("archive")
630 }
631
632 pub fn snapshot_path(&self) -> PathBuf {
633 self.db_path.join("snapshot")
634 }
635
636 pub fn network_address(&self) -> &Multiaddr {
637 &self.network_address
638 }
639
640 pub fn consensus_config(&self) -> Option<&ConsensusConfig> {
641 self.consensus_config.as_ref()
642 }
643
644 pub fn genesis(&self) -> Result<&genesis::Genesis> {
645 self.genesis.genesis()
646 }
647
648 pub fn load_migration_tx_data(&self) -> Result<MigrationTxData> {
649 let Some(location) = &self.migration_tx_data_path else {
650 anyhow::bail!("no file location set");
651 };
652
653 let migration_tx_data = MigrationTxData::load(location)?;
655
656 migration_tx_data.validate_from_genesis(self.genesis.genesis()?)?;
658 Ok(migration_tx_data)
659 }
660
661 pub fn iota_address(&self) -> IotaAddress {
662 (&self.account_key_pair.keypair().public()).into()
663 }
664
665 pub fn archive_reader_config(&self) -> Vec<ArchiveReaderConfig> {
666 self.state_archive_read_config
667 .iter()
668 .flat_map(|config| {
669 config
670 .object_store_config
671 .as_ref()
672 .map(|remote_store_config| ArchiveReaderConfig {
673 remote_store_config: remote_store_config.clone(),
674 download_concurrency: NonZeroUsize::new(config.concurrency)
675 .unwrap_or(NonZeroUsize::new(5).unwrap()),
676 use_for_pruning_watermark: config.use_for_pruning_watermark,
677 })
678 })
679 .collect()
680 }
681
682 pub fn jsonrpc_server_type(&self) -> ServerType {
683 self.jsonrpc_server_type.unwrap_or(ServerType::Http)
684 }
685}
686
687#[derive(Debug, Clone, Deserialize, Serialize)]
688pub enum ConsensusProtocol {
689 #[serde(rename = "mysticeti")]
690 Mysticeti,
691}
692
693#[derive(Debug, Clone, Deserialize, Serialize)]
694#[serde(rename_all = "kebab-case")]
695pub struct ConsensusConfig {
696 pub db_path: PathBuf,
698
699 pub db_retention_epochs: Option<u64>,
702
703 pub db_pruner_period_secs: Option<u64>,
706
707 pub max_pending_transactions: Option<usize>,
713
714 pub max_submit_position: Option<usize>,
720
721 pub submit_delay_step_override_millis: Option<u64>,
727
728 pub parameters: Option<ConsensusParameters>,
729}
730
731impl ConsensusConfig {
732 pub fn db_path(&self) -> &Path {
733 &self.db_path
734 }
735
736 pub fn max_pending_transactions(&self) -> usize {
737 self.max_pending_transactions.unwrap_or(20_000)
738 }
739
740 pub fn submit_delay_step_override(&self) -> Option<Duration> {
741 self.submit_delay_step_override_millis
742 .map(Duration::from_millis)
743 }
744
745 pub fn db_retention_epochs(&self) -> u64 {
746 self.db_retention_epochs.unwrap_or(0)
747 }
748
749 pub fn db_pruner_period(&self) -> Duration {
750 self.db_pruner_period_secs
752 .map(Duration::from_secs)
753 .unwrap_or(Duration::from_secs(3_600))
754 }
755}
756
757#[derive(Clone, Debug, Deserialize, Serialize)]
758#[serde(rename_all = "kebab-case")]
759pub struct CheckpointExecutorConfig {
760 #[serde(default = "default_checkpoint_execution_max_concurrency")]
765 pub checkpoint_execution_max_concurrency: usize,
766
767 #[serde(default = "default_local_execution_timeout_sec")]
773 pub local_execution_timeout_sec: u64,
774
775 #[serde(default, skip_serializing_if = "Option::is_none")]
780 pub data_ingestion_dir: Option<PathBuf>,
781}
782
783#[derive(Clone, Debug, Default, Deserialize, Serialize)]
784#[serde(rename_all = "kebab-case")]
785pub struct ExpensiveSafetyCheckConfig {
786 #[serde(default)]
791 enable_epoch_iota_conservation_check: bool,
792
793 #[serde(default)]
797 enable_deep_per_tx_iota_conservation_check: bool,
798
799 #[serde(default)]
802 force_disable_epoch_iota_conservation_check: bool,
803
804 #[serde(default)]
807 enable_state_consistency_check: bool,
808
809 #[serde(default)]
811 force_disable_state_consistency_check: bool,
812
813 #[serde(default)]
814 enable_secondary_index_checks: bool,
815 }
817
818impl ExpensiveSafetyCheckConfig {
819 pub fn new_enable_all() -> Self {
820 Self {
821 enable_epoch_iota_conservation_check: true,
822 enable_deep_per_tx_iota_conservation_check: true,
823 force_disable_epoch_iota_conservation_check: false,
824 enable_state_consistency_check: true,
825 force_disable_state_consistency_check: false,
826 enable_secondary_index_checks: false, }
828 }
829
830 pub fn new_disable_all() -> Self {
831 Self {
832 enable_epoch_iota_conservation_check: false,
833 enable_deep_per_tx_iota_conservation_check: false,
834 force_disable_epoch_iota_conservation_check: true,
835 enable_state_consistency_check: false,
836 force_disable_state_consistency_check: true,
837 enable_secondary_index_checks: false,
838 }
839 }
840
841 pub fn force_disable_epoch_iota_conservation_check(&mut self) {
842 self.force_disable_epoch_iota_conservation_check = true;
843 }
844
845 pub fn enable_epoch_iota_conservation_check(&self) -> bool {
846 (self.enable_epoch_iota_conservation_check || cfg!(debug_assertions))
847 && !self.force_disable_epoch_iota_conservation_check
848 }
849
850 pub fn force_disable_state_consistency_check(&mut self) {
851 self.force_disable_state_consistency_check = true;
852 }
853
854 pub fn enable_state_consistency_check(&self) -> bool {
855 (self.enable_state_consistency_check || cfg!(debug_assertions))
856 && !self.force_disable_state_consistency_check
857 }
858
859 pub fn enable_deep_per_tx_iota_conservation_check(&self) -> bool {
860 self.enable_deep_per_tx_iota_conservation_check || cfg!(debug_assertions)
861 }
862
863 pub fn enable_secondary_index_checks(&self) -> bool {
864 self.enable_secondary_index_checks
865 }
866}
867
868fn default_checkpoint_execution_max_concurrency() -> usize {
869 200
870}
871
872fn default_local_execution_timeout_sec() -> u64 {
873 30
874}
875
876impl Default for CheckpointExecutorConfig {
877 fn default() -> Self {
878 Self {
879 checkpoint_execution_max_concurrency: default_checkpoint_execution_max_concurrency(),
880 local_execution_timeout_sec: default_local_execution_timeout_sec(),
881 data_ingestion_dir: None,
882 }
883 }
884}
885
886#[derive(Debug, Clone, Deserialize, Serialize)]
887#[serde(rename_all = "kebab-case")]
888pub struct AuthorityStorePruningConfig {
889 #[serde(default = "default_num_latest_epoch_dbs_to_retain")]
891 pub num_latest_epoch_dbs_to_retain: usize,
892 #[serde(default = "default_epoch_db_pruning_period_secs")]
895 pub epoch_db_pruning_period_secs: u64,
896 #[serde(default)]
901 pub num_epochs_to_retain: u64,
902 #[serde(skip_serializing_if = "Option::is_none")]
904 pub pruning_run_delay_seconds: Option<u64>,
905 #[serde(default = "default_max_checkpoints_in_batch")]
908 pub max_checkpoints_in_batch: usize,
909 #[serde(default = "default_max_transactions_in_batch")]
911 pub max_transactions_in_batch: usize,
912 #[serde(
917 default = "default_periodic_compaction_threshold_days",
918 skip_serializing_if = "Option::is_none"
919 )]
920 pub periodic_compaction_threshold_days: Option<usize>,
921 #[serde(skip_serializing_if = "Option::is_none")]
924 pub num_epochs_to_retain_for_checkpoints: Option<u64>,
925 #[serde(default = "default_smoothing", skip_serializing_if = "is_true")]
926 pub smooth: bool,
927 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
933 pub enable_compaction_filter: bool,
934}
935
936fn default_num_latest_epoch_dbs_to_retain() -> usize {
937 3
938}
939
940fn default_epoch_db_pruning_period_secs() -> u64 {
941 3600
942}
943
944fn default_max_transactions_in_batch() -> usize {
945 1000
946}
947
948fn default_max_checkpoints_in_batch() -> usize {
949 10
950}
951
952fn default_smoothing() -> bool {
953 cfg!(not(test))
954}
955
956fn default_periodic_compaction_threshold_days() -> Option<usize> {
957 Some(1)
958}
959
960impl Default for AuthorityStorePruningConfig {
961 fn default() -> Self {
962 Self {
963 num_latest_epoch_dbs_to_retain: default_num_latest_epoch_dbs_to_retain(),
964 epoch_db_pruning_period_secs: default_epoch_db_pruning_period_secs(),
965 num_epochs_to_retain: 0,
966 pruning_run_delay_seconds: if cfg!(msim) { Some(2) } else { None },
967 max_checkpoints_in_batch: default_max_checkpoints_in_batch(),
968 max_transactions_in_batch: default_max_transactions_in_batch(),
969 periodic_compaction_threshold_days: None,
970 num_epochs_to_retain_for_checkpoints: if cfg!(msim) { Some(2) } else { None },
971 smooth: true,
972 enable_compaction_filter: cfg!(test) || cfg!(msim),
973 }
974 }
975}
976
977impl AuthorityStorePruningConfig {
978 pub fn set_num_epochs_to_retain(&mut self, num_epochs_to_retain: u64) {
979 self.num_epochs_to_retain = num_epochs_to_retain;
980 }
981
982 pub fn set_num_epochs_to_retain_for_checkpoints(&mut self, num_epochs_to_retain: Option<u64>) {
983 self.num_epochs_to_retain_for_checkpoints = num_epochs_to_retain;
984 }
985
986 pub fn num_epochs_to_retain_for_checkpoints(&self) -> Option<u64> {
987 self.num_epochs_to_retain_for_checkpoints
988 .map(|n| {
990 if n < 2 {
991 info!("num_epochs_to_retain_for_checkpoints must be at least 2, rounding up from {}", n);
992 2
993 } else {
994 n
995 }
996 })
997 }
998}
999
1000#[derive(Debug, Clone, Deserialize, Serialize)]
1001#[serde(rename_all = "kebab-case")]
1002pub struct MetricsConfig {
1003 #[serde(skip_serializing_if = "Option::is_none")]
1004 pub push_interval_seconds: Option<u64>,
1005 #[serde(skip_serializing_if = "Option::is_none")]
1006 pub push_url: Option<String>,
1007}
1008
1009#[derive(Default, Debug, Clone, Deserialize, Serialize)]
1010#[serde(rename_all = "kebab-case")]
1011pub struct DBCheckpointConfig {
1012 #[serde(default)]
1013 pub perform_db_checkpoints_at_epoch_end: bool,
1014 #[serde(skip_serializing_if = "Option::is_none")]
1015 pub checkpoint_path: Option<PathBuf>,
1016 #[serde(skip_serializing_if = "Option::is_none")]
1017 pub object_store_config: Option<ObjectStoreConfig>,
1018 #[serde(skip_serializing_if = "Option::is_none")]
1019 pub perform_index_db_checkpoints_at_epoch_end: Option<bool>,
1020 #[serde(skip_serializing_if = "Option::is_none")]
1021 pub prune_and_compact_before_upload: Option<bool>,
1022}
1023
1024#[derive(Debug, Clone)]
1025pub struct ArchiveReaderConfig {
1026 pub remote_store_config: ObjectStoreConfig,
1027 pub download_concurrency: NonZeroUsize,
1028 pub use_for_pruning_watermark: bool,
1029}
1030
1031#[derive(Default, Debug, Clone, Deserialize, Serialize)]
1032#[serde(rename_all = "kebab-case")]
1033pub struct StateArchiveConfig {
1034 #[serde(skip_serializing_if = "Option::is_none")]
1035 pub object_store_config: Option<ObjectStoreConfig>,
1036 pub concurrency: usize,
1037 pub use_for_pruning_watermark: bool,
1038}
1039
1040#[derive(Default, Debug, Clone, Deserialize, Serialize)]
1041#[serde(rename_all = "kebab-case")]
1042pub struct StateSnapshotConfig {
1043 #[serde(skip_serializing_if = "Option::is_none")]
1044 pub object_store_config: Option<ObjectStoreConfig>,
1045 pub concurrency: usize,
1046}
1047
1048#[derive(Default, Debug, Clone, Deserialize, Serialize)]
1049#[serde(rename_all = "kebab-case")]
1050pub struct TransactionKeyValueStoreWriteConfig {
1051 pub aws_access_key_id: String,
1052 pub aws_secret_access_key: String,
1053 pub aws_region: String,
1054 pub table_name: String,
1055 pub bucket_name: String,
1056 pub concurrency: usize,
1057}
1058
1059#[derive(Clone, Debug, Deserialize, Serialize)]
1064#[serde(rename_all = "kebab-case")]
1065pub struct AuthorityOverloadConfig {
1066 #[serde(default = "default_max_txn_age_in_queue")]
1067 pub max_txn_age_in_queue: Duration,
1068
1069 #[serde(default = "default_overload_monitor_interval")]
1071 pub overload_monitor_interval: Duration,
1072
1073 #[serde(default = "default_execution_queue_latency_soft_limit")]
1075 pub execution_queue_latency_soft_limit: Duration,
1076
1077 #[serde(default = "default_execution_queue_latency_hard_limit")]
1079 pub execution_queue_latency_hard_limit: Duration,
1080
1081 #[serde(default = "default_max_load_shedding_percentage")]
1083 pub max_load_shedding_percentage: u32,
1084
1085 #[serde(default = "default_min_load_shedding_percentage_above_hard_limit")]
1088 pub min_load_shedding_percentage_above_hard_limit: u32,
1089
1090 #[serde(default = "default_safe_transaction_ready_rate")]
1093 pub safe_transaction_ready_rate: u32,
1094
1095 #[serde(default = "default_check_system_overload_at_signing")]
1098 pub check_system_overload_at_signing: bool,
1099
1100 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1103 pub check_system_overload_at_execution: bool,
1104
1105 #[serde(default = "default_max_transaction_manager_queue_length")]
1108 pub max_transaction_manager_queue_length: usize,
1109
1110 #[serde(default = "default_max_transaction_manager_per_object_queue_length")]
1113 pub max_transaction_manager_per_object_queue_length: usize,
1114}
1115
1116fn default_max_txn_age_in_queue() -> Duration {
1117 Duration::from_millis(500)
1118}
1119
1120fn default_overload_monitor_interval() -> Duration {
1121 Duration::from_secs(10)
1122}
1123
1124fn default_execution_queue_latency_soft_limit() -> Duration {
1125 Duration::from_secs(1)
1126}
1127
1128fn default_execution_queue_latency_hard_limit() -> Duration {
1129 Duration::from_secs(10)
1130}
1131
1132fn default_max_load_shedding_percentage() -> u32 {
1133 95
1134}
1135
1136fn default_min_load_shedding_percentage_above_hard_limit() -> u32 {
1137 50
1138}
1139
1140fn default_safe_transaction_ready_rate() -> u32 {
1141 100
1142}
1143
1144fn default_check_system_overload_at_signing() -> bool {
1145 true
1146}
1147
1148fn default_max_transaction_manager_queue_length() -> usize {
1149 100_000
1150}
1151
1152fn default_max_transaction_manager_per_object_queue_length() -> usize {
1153 20
1154}
1155
1156impl Default for AuthorityOverloadConfig {
1157 fn default() -> Self {
1158 Self {
1159 max_txn_age_in_queue: default_max_txn_age_in_queue(),
1160 overload_monitor_interval: default_overload_monitor_interval(),
1161 execution_queue_latency_soft_limit: default_execution_queue_latency_soft_limit(),
1162 execution_queue_latency_hard_limit: default_execution_queue_latency_hard_limit(),
1163 max_load_shedding_percentage: default_max_load_shedding_percentage(),
1164 min_load_shedding_percentage_above_hard_limit:
1165 default_min_load_shedding_percentage_above_hard_limit(),
1166 safe_transaction_ready_rate: default_safe_transaction_ready_rate(),
1167 check_system_overload_at_signing: true,
1168 check_system_overload_at_execution: false,
1169 max_transaction_manager_queue_length: default_max_transaction_manager_queue_length(),
1170 max_transaction_manager_per_object_queue_length:
1171 default_max_transaction_manager_per_object_queue_length(),
1172 }
1173 }
1174}
1175
1176fn default_authority_overload_config() -> AuthorityOverloadConfig {
1177 AuthorityOverloadConfig::default()
1178}
1179
1180#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq)]
1181pub struct Genesis {
1182 #[serde(flatten)]
1183 location: Option<GenesisLocation>,
1184
1185 #[serde(skip)]
1186 genesis: once_cell::sync::OnceCell<genesis::Genesis>,
1187}
1188
1189impl Genesis {
1190 pub fn new(genesis: genesis::Genesis) -> Self {
1191 Self {
1192 location: Some(GenesisLocation::InPlace {
1193 genesis: Box::new(genesis),
1194 }),
1195 genesis: Default::default(),
1196 }
1197 }
1198
1199 pub fn new_from_file<P: Into<PathBuf>>(path: P) -> Self {
1200 Self {
1201 location: Some(GenesisLocation::File {
1202 genesis_file_location: path.into(),
1203 }),
1204 genesis: Default::default(),
1205 }
1206 }
1207
1208 pub fn new_empty() -> Self {
1209 Self {
1210 location: None,
1211 genesis: Default::default(),
1212 }
1213 }
1214
1215 pub fn genesis(&self) -> Result<&genesis::Genesis> {
1216 match &self.location {
1217 Some(GenesisLocation::InPlace { genesis }) => Ok(genesis),
1218 Some(GenesisLocation::File {
1219 genesis_file_location,
1220 }) => self
1221 .genesis
1222 .get_or_try_init(|| genesis::Genesis::load(genesis_file_location)),
1223 None => anyhow::bail!("no genesis location set"),
1224 }
1225 }
1226}
1227
1228#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq)]
1229#[serde(untagged)]
1230enum GenesisLocation {
1231 InPlace {
1232 genesis: Box<genesis::Genesis>,
1233 },
1234 File {
1235 #[serde(rename = "genesis-file-location")]
1236 genesis_file_location: PathBuf,
1237 },
1238}
1239
1240#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
1243pub struct KeyPairWithPath {
1244 #[serde(flatten)]
1245 location: KeyPairLocation,
1246
1247 #[serde(skip)]
1248 keypair: OnceCell<Arc<IotaKeyPair>>,
1249}
1250
1251#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq)]
1252#[serde(untagged)]
1253enum KeyPairLocation {
1254 InPlace {
1255 #[serde(with = "bech32_formatted_keypair")]
1256 value: Arc<IotaKeyPair>,
1257 },
1258 File {
1259 path: PathBuf,
1260 },
1261}
1262
1263impl KeyPairWithPath {
1264 pub fn new(kp: IotaKeyPair) -> Self {
1265 let cell: OnceCell<Arc<IotaKeyPair>> = OnceCell::new();
1266 let arc_kp = Arc::new(kp);
1267 cell.set(arc_kp.clone()).expect("failed to set keypair");
1270 Self {
1271 location: KeyPairLocation::InPlace { value: arc_kp },
1272 keypair: cell,
1273 }
1274 }
1275
1276 pub fn new_from_path(path: PathBuf) -> Self {
1277 let cell: OnceCell<Arc<IotaKeyPair>> = OnceCell::new();
1278 cell.set(Arc::new(read_keypair_from_file(&path).unwrap_or_else(
1281 |e| panic!("invalid keypair file at path {:?}: {e}", &path),
1282 )))
1283 .expect("failed to set keypair");
1284 Self {
1285 location: KeyPairLocation::File { path },
1286 keypair: cell,
1287 }
1288 }
1289
1290 pub fn keypair(&self) -> &IotaKeyPair {
1291 self.keypair
1292 .get_or_init(|| match &self.location {
1293 KeyPairLocation::InPlace { value } => value.clone(),
1294 KeyPairLocation::File { path } => {
1295 Arc::new(
1298 read_keypair_from_file(path).unwrap_or_else(|e| {
1299 panic!("invalid keypair file at path {path:?}: {e}")
1300 }),
1301 )
1302 }
1303 })
1304 .as_ref()
1305 }
1306}
1307
1308#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
1311pub struct AuthorityKeyPairWithPath {
1312 #[serde(flatten)]
1313 location: AuthorityKeyPairLocation,
1314
1315 #[serde(skip)]
1316 keypair: OnceCell<Arc<AuthorityKeyPair>>,
1317}
1318
1319#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq)]
1320#[serde(untagged)]
1321enum AuthorityKeyPairLocation {
1322 InPlace { value: Arc<AuthorityKeyPair> },
1323 File { path: PathBuf },
1324}
1325
1326impl AuthorityKeyPairWithPath {
1327 pub fn new(kp: AuthorityKeyPair) -> Self {
1328 let cell: OnceCell<Arc<AuthorityKeyPair>> = OnceCell::new();
1329 let arc_kp = Arc::new(kp);
1330 cell.set(arc_kp.clone())
1333 .expect("failed to set authority keypair");
1334 Self {
1335 location: AuthorityKeyPairLocation::InPlace { value: arc_kp },
1336 keypair: cell,
1337 }
1338 }
1339
1340 pub fn new_from_path(path: PathBuf) -> Self {
1341 let cell: OnceCell<Arc<AuthorityKeyPair>> = OnceCell::new();
1342 cell.set(Arc::new(
1345 read_authority_keypair_from_file(&path)
1346 .unwrap_or_else(|_| panic!("invalid authority keypair file at path {:?}", &path)),
1347 ))
1348 .expect("failed to set authority keypair");
1349 Self {
1350 location: AuthorityKeyPairLocation::File { path },
1351 keypair: cell,
1352 }
1353 }
1354
1355 pub fn authority_keypair(&self) -> &AuthorityKeyPair {
1356 self.keypair
1357 .get_or_init(|| match &self.location {
1358 AuthorityKeyPairLocation::InPlace { value } => value.clone(),
1359 AuthorityKeyPairLocation::File { path } => {
1360 Arc::new(
1363 read_authority_keypair_from_file(path).unwrap_or_else(|_| {
1364 panic!("invalid authority keypair file {:?}", &path)
1365 }),
1366 )
1367 }
1368 })
1369 .as_ref()
1370 }
1371}
1372
1373#[derive(Clone, Debug, Deserialize, Serialize, Default)]
1376#[serde(rename_all = "kebab-case")]
1377pub struct StateDebugDumpConfig {
1378 #[serde(skip_serializing_if = "Option::is_none")]
1379 pub dump_file_directory: Option<PathBuf>,
1380}
1381
1382#[cfg(test)]
1383mod tests {
1384 use std::path::PathBuf;
1385
1386 use fastcrypto::traits::KeyPair;
1387 use iota_keys::keypair_file::{write_authority_keypair_to_file, write_keypair_to_file};
1388 use iota_types::crypto::{
1389 AuthorityKeyPair, IotaKeyPair, NetworkKeyPair, get_key_pair_from_rng,
1390 };
1391 use rand::{SeedableRng, rngs::StdRng};
1392
1393 use super::Genesis;
1394 use crate::NodeConfig;
1395
1396 #[test]
1397 fn serialize_genesis_from_file() {
1398 let g = Genesis::new_from_file("path/to/file");
1399
1400 let s = serde_yaml::to_string(&g).unwrap();
1401 assert_eq!("---\ngenesis-file-location: path/to/file\n", s);
1402 let loaded_genesis: Genesis = serde_yaml::from_str(&s).unwrap();
1403 assert_eq!(g, loaded_genesis);
1404 }
1405
1406 #[test]
1407 fn fullnode_template() {
1408 const TEMPLATE: &str = include_str!("../data/fullnode-template.yaml");
1409
1410 let _template: NodeConfig = serde_yaml::from_str(TEMPLATE).unwrap();
1411 }
1412
1413 #[test]
1414 fn load_key_pairs_to_node_config() {
1415 let authority_key_pair: AuthorityKeyPair =
1416 get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1;
1417 let protocol_key_pair: NetworkKeyPair =
1418 get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1;
1419 let network_key_pair: NetworkKeyPair =
1420 get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1;
1421
1422 write_authority_keypair_to_file(&authority_key_pair, PathBuf::from("authority.key"))
1423 .unwrap();
1424 write_keypair_to_file(
1425 &IotaKeyPair::Ed25519(protocol_key_pair.copy()),
1426 PathBuf::from("protocol.key"),
1427 )
1428 .unwrap();
1429 write_keypair_to_file(
1430 &IotaKeyPair::Ed25519(network_key_pair.copy()),
1431 PathBuf::from("network.key"),
1432 )
1433 .unwrap();
1434
1435 const TEMPLATE: &str = include_str!("../data/fullnode-template-with-path.yaml");
1436 let template: NodeConfig = serde_yaml::from_str(TEMPLATE).unwrap();
1437 assert_eq!(
1438 template.authority_key_pair().public(),
1439 authority_key_pair.public()
1440 );
1441 assert_eq!(
1442 template.network_key_pair().public(),
1443 network_key_pair.public()
1444 );
1445 assert_eq!(
1446 template.protocol_key_pair().public(),
1447 protocol_key_pair.public()
1448 );
1449 }
1450}
1451
1452#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)]
1456pub enum RunWithRange {
1457 Epoch(EpochId),
1458 Checkpoint(CheckpointSequenceNumber),
1459}
1460
1461impl RunWithRange {
1462 pub fn is_epoch_gt(&self, epoch_id: EpochId) -> bool {
1464 matches!(self, RunWithRange::Epoch(e) if epoch_id > *e)
1465 }
1466
1467 pub fn matches_checkpoint(&self, seq_num: CheckpointSequenceNumber) -> bool {
1468 matches!(self, RunWithRange::Checkpoint(seq) if *seq == seq_num)
1469 }
1470}
1471
1472mod bech32_formatted_keypair {
1476 use std::ops::Deref;
1477
1478 use iota_types::crypto::{EncodeDecodeBase64, IotaKeyPair};
1479 use serde::{Deserialize, Deserializer, Serializer};
1480
1481 pub fn serialize<S, T>(kp: &T, serializer: S) -> Result<S::Ok, S::Error>
1482 where
1483 S: Serializer,
1484 T: Deref<Target = IotaKeyPair>,
1485 {
1486 use serde::ser::Error;
1487
1488 let s = kp.encode().map_err(Error::custom)?;
1490
1491 serializer.serialize_str(&s)
1492 }
1493
1494 pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
1495 where
1496 D: Deserializer<'de>,
1497 T: From<IotaKeyPair>,
1498 {
1499 use serde::de::Error;
1500
1501 let s = String::deserialize(deserializer)?;
1502
1503 IotaKeyPair::decode(&s)
1505 .or_else(|_| {
1506 IotaKeyPair::decode_base64(&s)
1508 })
1509 .map(Into::into)
1510 .map_err(Error::custom)
1511 }
1512}