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 = "default_transaction_kv_store_config")]
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(skip_serializing_if = "Option::is_none")]
257 pub enable_db_write_stall: Option<bool>,
258
259 #[serde(default, skip_serializing_if = "Option::is_none")]
260 pub iota_names_config: Option<IotaNamesConfig>,
261}
262
263#[derive(Clone, Debug, Deserialize, Serialize, Default)]
264#[serde(rename_all = "kebab-case")]
265pub enum ExecutionCacheConfig {
266 #[default]
267 PassthroughCache,
268 WritebackCache {
269 max_cache_size: Option<usize>,
270 },
271}
272
273#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
274#[serde(rename_all = "lowercase")]
275pub enum ServerType {
276 WebSocket,
277 Http,
278 Both,
279}
280
281#[derive(Clone, Debug, Deserialize, Serialize)]
282#[serde(rename_all = "kebab-case")]
283pub struct TransactionKeyValueStoreReadConfig {
284 #[serde(default = "default_base_url")]
285 pub base_url: String,
286
287 #[serde(default = "default_cache_size")]
288 pub cache_size: u64,
289}
290
291impl Default for TransactionKeyValueStoreReadConfig {
292 fn default() -> Self {
293 Self {
294 base_url: default_base_url(),
295 cache_size: default_cache_size(),
296 }
297 }
298}
299
300fn default_base_url() -> String {
301 "".to_string()
302}
303
304fn default_cache_size() -> u64 {
305 100_000
306}
307
308fn default_jwk_fetch_interval_seconds() -> u64 {
309 3600
310}
311
312pub fn default_zklogin_oauth_providers() -> BTreeMap<Chain, BTreeSet<String>> {
313 let mut map = BTreeMap::new();
314
315 let experimental_providers = BTreeSet::from([
317 "Google".to_string(),
318 "Facebook".to_string(),
319 "Twitch".to_string(),
320 "Kakao".to_string(),
321 "Apple".to_string(),
322 "Slack".to_string(),
323 "TestIssuer".to_string(),
324 "Microsoft".to_string(),
325 "KarrierOne".to_string(),
326 "Credenza3".to_string(),
327 ]);
328
329 let providers = BTreeSet::from([
331 "Google".to_string(),
332 "Facebook".to_string(),
333 "Twitch".to_string(),
334 "Apple".to_string(),
335 "KarrierOne".to_string(),
336 "Credenza3".to_string(),
337 ]);
338 map.insert(Chain::Mainnet, providers.clone());
339 map.insert(Chain::Testnet, providers);
340 map.insert(Chain::Unknown, experimental_providers);
341 map
342}
343
344fn default_transaction_kv_store_config() -> TransactionKeyValueStoreReadConfig {
345 TransactionKeyValueStoreReadConfig::default()
346}
347
348fn default_authority_store_pruning_config() -> AuthorityStorePruningConfig {
349 AuthorityStorePruningConfig::default()
350}
351
352pub fn default_enable_index_processing() -> bool {
353 true
354}
355
356fn default_grpc_address() -> Multiaddr {
357 "/ip4/0.0.0.0/tcp/8080".parse().unwrap()
358}
359fn default_authority_key_pair() -> AuthorityKeyPairWithPath {
360 AuthorityKeyPairWithPath::new(get_key_pair_from_rng::<AuthorityKeyPair, _>(&mut OsRng).1)
361}
362
363fn default_key_pair() -> KeyPairWithPath {
364 KeyPairWithPath::new(
365 get_key_pair_from_rng::<AccountKeyPair, _>(&mut OsRng)
366 .1
367 .into(),
368 )
369}
370
371fn default_metrics_address() -> SocketAddr {
372 use std::net::{IpAddr, Ipv4Addr};
373 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9184)
374}
375
376pub fn default_admin_interface_address() -> SocketAddr {
377 SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 1337)
378}
379
380pub fn default_json_rpc_address() -> SocketAddr {
381 use std::net::{IpAddr, Ipv4Addr};
382 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9000)
383}
384
385pub fn default_concurrency_limit() -> Option<usize> {
386 Some(DEFAULT_GRPC_CONCURRENCY_LIMIT)
387}
388
389pub fn default_end_of_epoch_broadcast_channel_capacity() -> usize {
390 128
391}
392
393pub fn bool_true() -> bool {
394 true
395}
396
397fn is_true(value: &bool) -> bool {
398 *value
399}
400
401impl Config for NodeConfig {}
402
403impl NodeConfig {
404 pub fn authority_key_pair(&self) -> &AuthorityKeyPair {
405 self.authority_key_pair.authority_keypair()
406 }
407
408 pub fn protocol_key_pair(&self) -> &NetworkKeyPair {
409 match self.protocol_key_pair.keypair() {
410 IotaKeyPair::Ed25519(kp) => kp,
411 other => panic!(
412 "invalid keypair type: {:?}, only Ed25519 is allowed for protocol key",
413 other
414 ),
415 }
416 }
417
418 pub fn network_key_pair(&self) -> &NetworkKeyPair {
419 match self.network_key_pair.keypair() {
420 IotaKeyPair::Ed25519(kp) => kp,
421 other => panic!(
422 "invalid keypair type: {:?}, only Ed25519 is allowed for network key",
423 other
424 ),
425 }
426 }
427
428 pub fn authority_public_key(&self) -> AuthorityPublicKeyBytes {
429 self.authority_key_pair().public().into()
430 }
431
432 pub fn db_path(&self) -> PathBuf {
433 self.db_path.join("live")
434 }
435
436 pub fn db_checkpoint_path(&self) -> PathBuf {
437 self.db_path.join("db_checkpoints")
438 }
439
440 pub fn archive_path(&self) -> PathBuf {
441 self.db_path.join("archive")
442 }
443
444 pub fn snapshot_path(&self) -> PathBuf {
445 self.db_path.join("snapshot")
446 }
447
448 pub fn network_address(&self) -> &Multiaddr {
449 &self.network_address
450 }
451
452 pub fn consensus_config(&self) -> Option<&ConsensusConfig> {
453 self.consensus_config.as_ref()
454 }
455
456 pub fn genesis(&self) -> Result<&genesis::Genesis> {
457 self.genesis.genesis()
458 }
459
460 pub fn load_migration_tx_data(&self) -> Result<MigrationTxData> {
461 let Some(location) = &self.migration_tx_data_path else {
462 anyhow::bail!("no file location set");
463 };
464
465 let migration_tx_data = MigrationTxData::load(location)?;
467
468 migration_tx_data.validate_from_genesis(self.genesis.genesis()?)?;
470 Ok(migration_tx_data)
471 }
472
473 pub fn iota_address(&self) -> IotaAddress {
474 (&self.account_key_pair.keypair().public()).into()
475 }
476
477 pub fn archive_reader_config(&self) -> Vec<ArchiveReaderConfig> {
478 self.state_archive_read_config
479 .iter()
480 .flat_map(|config| {
481 config
482 .object_store_config
483 .as_ref()
484 .map(|remote_store_config| ArchiveReaderConfig {
485 remote_store_config: remote_store_config.clone(),
486 download_concurrency: NonZeroUsize::new(config.concurrency)
487 .unwrap_or(NonZeroUsize::new(5).unwrap()),
488 use_for_pruning_watermark: config.use_for_pruning_watermark,
489 })
490 })
491 .collect()
492 }
493
494 pub fn jsonrpc_server_type(&self) -> ServerType {
495 self.jsonrpc_server_type.unwrap_or(ServerType::Http)
496 }
497}
498
499#[derive(Debug, Clone, Deserialize, Serialize)]
500pub enum ConsensusProtocol {
501 #[serde(rename = "mysticeti")]
502 Mysticeti,
503}
504
505#[derive(Debug, Clone, Deserialize, Serialize)]
506#[serde(rename_all = "kebab-case")]
507pub struct ConsensusConfig {
508 pub db_path: PathBuf,
510
511 pub db_retention_epochs: Option<u64>,
514
515 pub db_pruner_period_secs: Option<u64>,
518
519 pub max_pending_transactions: Option<usize>,
525
526 pub max_submit_position: Option<usize>,
532
533 pub submit_delay_step_override_millis: Option<u64>,
539
540 pub parameters: Option<ConsensusParameters>,
541}
542
543impl ConsensusConfig {
544 pub fn db_path(&self) -> &Path {
545 &self.db_path
546 }
547
548 pub fn max_pending_transactions(&self) -> usize {
549 self.max_pending_transactions.unwrap_or(20_000)
550 }
551
552 pub fn submit_delay_step_override(&self) -> Option<Duration> {
553 self.submit_delay_step_override_millis
554 .map(Duration::from_millis)
555 }
556
557 pub fn db_retention_epochs(&self) -> u64 {
558 self.db_retention_epochs.unwrap_or(0)
559 }
560
561 pub fn db_pruner_period(&self) -> Duration {
562 self.db_pruner_period_secs
564 .map(Duration::from_secs)
565 .unwrap_or(Duration::from_secs(3_600))
566 }
567}
568
569#[derive(Clone, Debug, Deserialize, Serialize)]
570#[serde(rename_all = "kebab-case")]
571pub struct CheckpointExecutorConfig {
572 #[serde(default = "default_checkpoint_execution_max_concurrency")]
577 pub checkpoint_execution_max_concurrency: usize,
578
579 #[serde(default = "default_local_execution_timeout_sec")]
585 pub local_execution_timeout_sec: u64,
586
587 #[serde(default, skip_serializing_if = "Option::is_none")]
592 pub data_ingestion_dir: Option<PathBuf>,
593}
594
595#[derive(Clone, Debug, Default, Deserialize, Serialize)]
596#[serde(rename_all = "kebab-case")]
597pub struct ExpensiveSafetyCheckConfig {
598 #[serde(default)]
603 enable_epoch_iota_conservation_check: bool,
604
605 #[serde(default)]
609 enable_deep_per_tx_iota_conservation_check: bool,
610
611 #[serde(default)]
614 force_disable_epoch_iota_conservation_check: bool,
615
616 #[serde(default)]
619 enable_state_consistency_check: bool,
620
621 #[serde(default)]
623 force_disable_state_consistency_check: bool,
624
625 #[serde(default)]
626 enable_secondary_index_checks: bool,
627 }
629
630impl ExpensiveSafetyCheckConfig {
631 pub fn new_enable_all() -> Self {
632 Self {
633 enable_epoch_iota_conservation_check: true,
634 enable_deep_per_tx_iota_conservation_check: true,
635 force_disable_epoch_iota_conservation_check: false,
636 enable_state_consistency_check: true,
637 force_disable_state_consistency_check: false,
638 enable_secondary_index_checks: false, }
640 }
641
642 pub fn new_disable_all() -> Self {
643 Self {
644 enable_epoch_iota_conservation_check: false,
645 enable_deep_per_tx_iota_conservation_check: false,
646 force_disable_epoch_iota_conservation_check: true,
647 enable_state_consistency_check: false,
648 force_disable_state_consistency_check: true,
649 enable_secondary_index_checks: false,
650 }
651 }
652
653 pub fn force_disable_epoch_iota_conservation_check(&mut self) {
654 self.force_disable_epoch_iota_conservation_check = true;
655 }
656
657 pub fn enable_epoch_iota_conservation_check(&self) -> bool {
658 (self.enable_epoch_iota_conservation_check || cfg!(debug_assertions))
659 && !self.force_disable_epoch_iota_conservation_check
660 }
661
662 pub fn force_disable_state_consistency_check(&mut self) {
663 self.force_disable_state_consistency_check = true;
664 }
665
666 pub fn enable_state_consistency_check(&self) -> bool {
667 (self.enable_state_consistency_check || cfg!(debug_assertions))
668 && !self.force_disable_state_consistency_check
669 }
670
671 pub fn enable_deep_per_tx_iota_conservation_check(&self) -> bool {
672 self.enable_deep_per_tx_iota_conservation_check || cfg!(debug_assertions)
673 }
674
675 pub fn enable_secondary_index_checks(&self) -> bool {
676 self.enable_secondary_index_checks
677 }
678}
679
680fn default_checkpoint_execution_max_concurrency() -> usize {
681 200
682}
683
684fn default_local_execution_timeout_sec() -> u64 {
685 30
686}
687
688impl Default for CheckpointExecutorConfig {
689 fn default() -> Self {
690 Self {
691 checkpoint_execution_max_concurrency: default_checkpoint_execution_max_concurrency(),
692 local_execution_timeout_sec: default_local_execution_timeout_sec(),
693 data_ingestion_dir: None,
694 }
695 }
696}
697
698#[derive(Debug, Clone, Deserialize, Serialize)]
699#[serde(rename_all = "kebab-case")]
700pub struct AuthorityStorePruningConfig {
701 #[serde(default = "default_num_latest_epoch_dbs_to_retain")]
703 pub num_latest_epoch_dbs_to_retain: usize,
704 #[serde(default = "default_epoch_db_pruning_period_secs")]
707 pub epoch_db_pruning_period_secs: u64,
708 #[serde(default)]
713 pub num_epochs_to_retain: u64,
714 #[serde(skip_serializing_if = "Option::is_none")]
716 pub pruning_run_delay_seconds: Option<u64>,
717 #[serde(default = "default_max_checkpoints_in_batch")]
720 pub max_checkpoints_in_batch: usize,
721 #[serde(default = "default_max_transactions_in_batch")]
723 pub max_transactions_in_batch: usize,
724 #[serde(skip_serializing_if = "Option::is_none")]
729 pub periodic_compaction_threshold_days: Option<usize>,
730 #[serde(skip_serializing_if = "Option::is_none")]
733 pub num_epochs_to_retain_for_checkpoints: Option<u64>,
734 #[serde(default = "default_smoothing", skip_serializing_if = "is_true")]
735 pub smooth: bool,
736}
737
738fn default_num_latest_epoch_dbs_to_retain() -> usize {
739 3
740}
741
742fn default_epoch_db_pruning_period_secs() -> u64 {
743 3600
744}
745
746fn default_max_transactions_in_batch() -> usize {
747 1000
748}
749
750fn default_max_checkpoints_in_batch() -> usize {
751 10
752}
753
754fn default_smoothing() -> bool {
755 cfg!(not(test))
756}
757
758impl Default for AuthorityStorePruningConfig {
759 fn default() -> Self {
760 Self {
761 num_latest_epoch_dbs_to_retain: default_num_latest_epoch_dbs_to_retain(),
762 epoch_db_pruning_period_secs: default_epoch_db_pruning_period_secs(),
763 num_epochs_to_retain: 0,
764 pruning_run_delay_seconds: if cfg!(msim) { Some(2) } else { None },
765 max_checkpoints_in_batch: default_max_checkpoints_in_batch(),
766 max_transactions_in_batch: default_max_transactions_in_batch(),
767 periodic_compaction_threshold_days: None,
768 num_epochs_to_retain_for_checkpoints: if cfg!(msim) { Some(2) } else { None },
769 smooth: true,
770 }
771 }
772}
773
774impl AuthorityStorePruningConfig {
775 pub fn set_num_epochs_to_retain_for_checkpoints(&mut self, num_epochs_to_retain: Option<u64>) {
776 self.num_epochs_to_retain_for_checkpoints = num_epochs_to_retain;
777 }
778
779 pub fn num_epochs_to_retain_for_checkpoints(&self) -> Option<u64> {
780 self.num_epochs_to_retain_for_checkpoints
781 .map(|n| {
783 if n < 2 {
784 info!("num_epochs_to_retain_for_checkpoints must be at least 2, rounding up from {}", n);
785 2
786 } else {
787 n
788 }
789 })
790 }
791}
792
793#[derive(Debug, Clone, Deserialize, Serialize)]
794#[serde(rename_all = "kebab-case")]
795pub struct MetricsConfig {
796 #[serde(skip_serializing_if = "Option::is_none")]
797 pub push_interval_seconds: Option<u64>,
798 #[serde(skip_serializing_if = "Option::is_none")]
799 pub push_url: Option<String>,
800}
801
802#[derive(Default, Debug, Clone, Deserialize, Serialize)]
803#[serde(rename_all = "kebab-case")]
804pub struct DBCheckpointConfig {
805 #[serde(default)]
806 pub perform_db_checkpoints_at_epoch_end: bool,
807 #[serde(skip_serializing_if = "Option::is_none")]
808 pub checkpoint_path: Option<PathBuf>,
809 #[serde(skip_serializing_if = "Option::is_none")]
810 pub object_store_config: Option<ObjectStoreConfig>,
811 #[serde(skip_serializing_if = "Option::is_none")]
812 pub perform_index_db_checkpoints_at_epoch_end: Option<bool>,
813 #[serde(skip_serializing_if = "Option::is_none")]
814 pub prune_and_compact_before_upload: Option<bool>,
815}
816
817#[derive(Debug, Clone)]
818pub struct ArchiveReaderConfig {
819 pub remote_store_config: ObjectStoreConfig,
820 pub download_concurrency: NonZeroUsize,
821 pub use_for_pruning_watermark: bool,
822}
823
824#[derive(Default, Debug, Clone, Deserialize, Serialize)]
825#[serde(rename_all = "kebab-case")]
826pub struct StateArchiveConfig {
827 #[serde(skip_serializing_if = "Option::is_none")]
828 pub object_store_config: Option<ObjectStoreConfig>,
829 pub concurrency: usize,
830 pub use_for_pruning_watermark: bool,
831}
832
833#[derive(Default, Debug, Clone, Deserialize, Serialize)]
834#[serde(rename_all = "kebab-case")]
835pub struct StateSnapshotConfig {
836 #[serde(skip_serializing_if = "Option::is_none")]
837 pub object_store_config: Option<ObjectStoreConfig>,
838 pub concurrency: usize,
839}
840
841#[derive(Default, Debug, Clone, Deserialize, Serialize)]
842#[serde(rename_all = "kebab-case")]
843pub struct TransactionKeyValueStoreWriteConfig {
844 pub aws_access_key_id: String,
845 pub aws_secret_access_key: String,
846 pub aws_region: String,
847 pub table_name: String,
848 pub bucket_name: String,
849 pub concurrency: usize,
850}
851
852#[derive(Clone, Debug, Deserialize, Serialize)]
857#[serde(rename_all = "kebab-case")]
858pub struct AuthorityOverloadConfig {
859 #[serde(default = "default_max_txn_age_in_queue")]
860 pub max_txn_age_in_queue: Duration,
861
862 #[serde(default = "default_overload_monitor_interval")]
864 pub overload_monitor_interval: Duration,
865
866 #[serde(default = "default_execution_queue_latency_soft_limit")]
868 pub execution_queue_latency_soft_limit: Duration,
869
870 #[serde(default = "default_execution_queue_latency_hard_limit")]
872 pub execution_queue_latency_hard_limit: Duration,
873
874 #[serde(default = "default_max_load_shedding_percentage")]
876 pub max_load_shedding_percentage: u32,
877
878 #[serde(default = "default_min_load_shedding_percentage_above_hard_limit")]
881 pub min_load_shedding_percentage_above_hard_limit: u32,
882
883 #[serde(default = "default_safe_transaction_ready_rate")]
886 pub safe_transaction_ready_rate: u32,
887
888 #[serde(default = "default_check_system_overload_at_signing")]
891 pub check_system_overload_at_signing: bool,
892
893 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
896 pub check_system_overload_at_execution: bool,
897
898 #[serde(default = "default_max_transaction_manager_queue_length")]
901 pub max_transaction_manager_queue_length: usize,
902
903 #[serde(default = "default_max_transaction_manager_per_object_queue_length")]
906 pub max_transaction_manager_per_object_queue_length: usize,
907}
908
909fn default_max_txn_age_in_queue() -> Duration {
910 Duration::from_millis(500)
911}
912
913fn default_overload_monitor_interval() -> Duration {
914 Duration::from_secs(10)
915}
916
917fn default_execution_queue_latency_soft_limit() -> Duration {
918 Duration::from_secs(1)
919}
920
921fn default_execution_queue_latency_hard_limit() -> Duration {
922 Duration::from_secs(10)
923}
924
925fn default_max_load_shedding_percentage() -> u32 {
926 95
927}
928
929fn default_min_load_shedding_percentage_above_hard_limit() -> u32 {
930 50
931}
932
933fn default_safe_transaction_ready_rate() -> u32 {
934 100
935}
936
937fn default_check_system_overload_at_signing() -> bool {
938 true
939}
940
941fn default_max_transaction_manager_queue_length() -> usize {
942 100_000
943}
944
945fn default_max_transaction_manager_per_object_queue_length() -> usize {
946 100
947}
948
949impl Default for AuthorityOverloadConfig {
950 fn default() -> Self {
951 Self {
952 max_txn_age_in_queue: default_max_txn_age_in_queue(),
953 overload_monitor_interval: default_overload_monitor_interval(),
954 execution_queue_latency_soft_limit: default_execution_queue_latency_soft_limit(),
955 execution_queue_latency_hard_limit: default_execution_queue_latency_hard_limit(),
956 max_load_shedding_percentage: default_max_load_shedding_percentage(),
957 min_load_shedding_percentage_above_hard_limit:
958 default_min_load_shedding_percentage_above_hard_limit(),
959 safe_transaction_ready_rate: default_safe_transaction_ready_rate(),
960 check_system_overload_at_signing: true,
961 check_system_overload_at_execution: false,
962 max_transaction_manager_queue_length: default_max_transaction_manager_queue_length(),
963 max_transaction_manager_per_object_queue_length:
964 default_max_transaction_manager_per_object_queue_length(),
965 }
966 }
967}
968
969fn default_authority_overload_config() -> AuthorityOverloadConfig {
970 AuthorityOverloadConfig::default()
971}
972
973#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq)]
974pub struct Genesis {
975 #[serde(flatten)]
976 location: Option<GenesisLocation>,
977
978 #[serde(skip)]
979 genesis: once_cell::sync::OnceCell<genesis::Genesis>,
980}
981
982impl Genesis {
983 pub fn new(genesis: genesis::Genesis) -> Self {
984 Self {
985 location: Some(GenesisLocation::InPlace { genesis }),
986 genesis: Default::default(),
987 }
988 }
989
990 pub fn new_from_file<P: Into<PathBuf>>(path: P) -> Self {
991 Self {
992 location: Some(GenesisLocation::File {
993 genesis_file_location: path.into(),
994 }),
995 genesis: Default::default(),
996 }
997 }
998
999 pub fn new_empty() -> Self {
1000 Self {
1001 location: None,
1002 genesis: Default::default(),
1003 }
1004 }
1005
1006 pub fn genesis(&self) -> Result<&genesis::Genesis> {
1007 match &self.location {
1008 Some(GenesisLocation::InPlace { genesis }) => Ok(genesis),
1009 Some(GenesisLocation::File {
1010 genesis_file_location,
1011 }) => self
1012 .genesis
1013 .get_or_try_init(|| genesis::Genesis::load(genesis_file_location)),
1014 None => anyhow::bail!("no genesis location set"),
1015 }
1016 }
1017}
1018
1019#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq)]
1020#[serde(untagged)]
1021enum GenesisLocation {
1022 InPlace {
1023 genesis: genesis::Genesis,
1024 },
1025 File {
1026 #[serde(rename = "genesis-file-location")]
1027 genesis_file_location: PathBuf,
1028 },
1029}
1030
1031#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
1034pub struct KeyPairWithPath {
1035 #[serde(flatten)]
1036 location: KeyPairLocation,
1037
1038 #[serde(skip)]
1039 keypair: OnceCell<Arc<IotaKeyPair>>,
1040}
1041
1042#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq)]
1043#[serde(untagged)]
1044enum KeyPairLocation {
1045 InPlace {
1046 #[serde(with = "bech32_formatted_keypair")]
1047 value: Arc<IotaKeyPair>,
1048 },
1049 File {
1050 path: PathBuf,
1051 },
1052}
1053
1054impl KeyPairWithPath {
1055 pub fn new(kp: IotaKeyPair) -> Self {
1056 let cell: OnceCell<Arc<IotaKeyPair>> = OnceCell::new();
1057 let arc_kp = Arc::new(kp);
1058 cell.set(arc_kp.clone()).expect("failed to set keypair");
1061 Self {
1062 location: KeyPairLocation::InPlace { value: arc_kp },
1063 keypair: cell,
1064 }
1065 }
1066
1067 pub fn new_from_path(path: PathBuf) -> Self {
1068 let cell: OnceCell<Arc<IotaKeyPair>> = OnceCell::new();
1069 cell.set(Arc::new(read_keypair_from_file(&path).unwrap_or_else(
1072 |e| panic!("invalid keypair file at path {:?}: {e}", &path),
1073 )))
1074 .expect("failed to set keypair");
1075 Self {
1076 location: KeyPairLocation::File { path },
1077 keypair: cell,
1078 }
1079 }
1080
1081 pub fn keypair(&self) -> &IotaKeyPair {
1082 self.keypair
1083 .get_or_init(|| match &self.location {
1084 KeyPairLocation::InPlace { value } => value.clone(),
1085 KeyPairLocation::File { path } => {
1086 Arc::new(
1089 read_keypair_from_file(path).unwrap_or_else(|e| {
1090 panic!("invalid keypair file at path {:?}: {e}", path)
1091 }),
1092 )
1093 }
1094 })
1095 .as_ref()
1096 }
1097}
1098
1099#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
1102pub struct AuthorityKeyPairWithPath {
1103 #[serde(flatten)]
1104 location: AuthorityKeyPairLocation,
1105
1106 #[serde(skip)]
1107 keypair: OnceCell<Arc<AuthorityKeyPair>>,
1108}
1109
1110#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq)]
1111#[serde(untagged)]
1112enum AuthorityKeyPairLocation {
1113 InPlace { value: Arc<AuthorityKeyPair> },
1114 File { path: PathBuf },
1115}
1116
1117impl AuthorityKeyPairWithPath {
1118 pub fn new(kp: AuthorityKeyPair) -> Self {
1119 let cell: OnceCell<Arc<AuthorityKeyPair>> = OnceCell::new();
1120 let arc_kp = Arc::new(kp);
1121 cell.set(arc_kp.clone())
1124 .expect("failed to set authority keypair");
1125 Self {
1126 location: AuthorityKeyPairLocation::InPlace { value: arc_kp },
1127 keypair: cell,
1128 }
1129 }
1130
1131 pub fn new_from_path(path: PathBuf) -> Self {
1132 let cell: OnceCell<Arc<AuthorityKeyPair>> = OnceCell::new();
1133 cell.set(Arc::new(
1136 read_authority_keypair_from_file(&path)
1137 .unwrap_or_else(|_| panic!("invalid authority keypair file at path {:?}", &path)),
1138 ))
1139 .expect("failed to set authority keypair");
1140 Self {
1141 location: AuthorityKeyPairLocation::File { path },
1142 keypair: cell,
1143 }
1144 }
1145
1146 pub fn authority_keypair(&self) -> &AuthorityKeyPair {
1147 self.keypair
1148 .get_or_init(|| match &self.location {
1149 AuthorityKeyPairLocation::InPlace { value } => value.clone(),
1150 AuthorityKeyPairLocation::File { path } => {
1151 Arc::new(
1154 read_authority_keypair_from_file(path).unwrap_or_else(|_| {
1155 panic!("invalid authority keypair file {:?}", &path)
1156 }),
1157 )
1158 }
1159 })
1160 .as_ref()
1161 }
1162}
1163
1164#[derive(Clone, Debug, Deserialize, Serialize, Default)]
1167#[serde(rename_all = "kebab-case")]
1168pub struct StateDebugDumpConfig {
1169 #[serde(skip_serializing_if = "Option::is_none")]
1170 pub dump_file_directory: Option<PathBuf>,
1171}
1172
1173#[cfg(test)]
1174mod tests {
1175 use std::path::PathBuf;
1176
1177 use fastcrypto::traits::KeyPair;
1178 use iota_keys::keypair_file::{write_authority_keypair_to_file, write_keypair_to_file};
1179 use iota_types::crypto::{
1180 AuthorityKeyPair, IotaKeyPair, NetworkKeyPair, get_key_pair_from_rng,
1181 };
1182 use rand::{SeedableRng, rngs::StdRng};
1183
1184 use super::Genesis;
1185 use crate::NodeConfig;
1186
1187 #[test]
1188 fn serialize_genesis_from_file() {
1189 let g = Genesis::new_from_file("path/to/file");
1190
1191 let s = serde_yaml::to_string(&g).unwrap();
1192 assert_eq!("---\ngenesis-file-location: path/to/file\n", s);
1193 let loaded_genesis: Genesis = serde_yaml::from_str(&s).unwrap();
1194 assert_eq!(g, loaded_genesis);
1195 }
1196
1197 #[test]
1198 fn fullnode_template() {
1199 const TEMPLATE: &str = include_str!("../data/fullnode-template.yaml");
1200
1201 let _template: NodeConfig = serde_yaml::from_str(TEMPLATE).unwrap();
1202 }
1203
1204 #[test]
1205 fn load_key_pairs_to_node_config() {
1206 let authority_key_pair: AuthorityKeyPair =
1207 get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1;
1208 let protocol_key_pair: NetworkKeyPair =
1209 get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1;
1210 let network_key_pair: NetworkKeyPair =
1211 get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1;
1212
1213 write_authority_keypair_to_file(&authority_key_pair, PathBuf::from("authority.key"))
1214 .unwrap();
1215 write_keypair_to_file(
1216 &IotaKeyPair::Ed25519(protocol_key_pair.copy()),
1217 PathBuf::from("protocol.key"),
1218 )
1219 .unwrap();
1220 write_keypair_to_file(
1221 &IotaKeyPair::Ed25519(network_key_pair.copy()),
1222 PathBuf::from("network.key"),
1223 )
1224 .unwrap();
1225
1226 const TEMPLATE: &str = include_str!("../data/fullnode-template-with-path.yaml");
1227 let template: NodeConfig = serde_yaml::from_str(TEMPLATE).unwrap();
1228 assert_eq!(
1229 template.authority_key_pair().public(),
1230 authority_key_pair.public()
1231 );
1232 assert_eq!(
1233 template.network_key_pair().public(),
1234 network_key_pair.public()
1235 );
1236 assert_eq!(
1237 template.protocol_key_pair().public(),
1238 protocol_key_pair.public()
1239 );
1240 }
1241}
1242
1243#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)]
1247pub enum RunWithRange {
1248 Epoch(EpochId),
1249 Checkpoint(CheckpointSequenceNumber),
1250}
1251
1252impl RunWithRange {
1253 pub fn is_epoch_gt(&self, epoch_id: EpochId) -> bool {
1255 matches!(self, RunWithRange::Epoch(e) if epoch_id > *e)
1256 }
1257
1258 pub fn matches_checkpoint(&self, seq_num: CheckpointSequenceNumber) -> bool {
1259 matches!(self, RunWithRange::Checkpoint(seq) if *seq == seq_num)
1260 }
1261}
1262
1263mod bech32_formatted_keypair {
1267 use std::ops::Deref;
1268
1269 use iota_types::crypto::{EncodeDecodeBase64, IotaKeyPair};
1270 use serde::{Deserialize, Deserializer, Serializer};
1271
1272 pub fn serialize<S, T>(kp: &T, serializer: S) -> Result<S::Ok, S::Error>
1273 where
1274 S: Serializer,
1275 T: Deref<Target = IotaKeyPair>,
1276 {
1277 use serde::ser::Error;
1278
1279 let s = kp.encode().map_err(Error::custom)?;
1281
1282 serializer.serialize_str(&s)
1283 }
1284
1285 pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
1286 where
1287 D: Deserializer<'de>,
1288 T: From<IotaKeyPair>,
1289 {
1290 use serde::de::Error;
1291
1292 let s = String::deserialize(deserializer)?;
1293
1294 IotaKeyPair::decode(&s)
1296 .or_else(|_| {
1297 IotaKeyPair::decode_base64(&s)
1299 })
1300 .map(Into::into)
1301 .map_err(Error::custom)
1302 }
1303}