1use std::{
6 net::{IpAddr, Ipv4Addr, SocketAddr},
7 path::{Path, PathBuf},
8 sync::Arc,
9 time::Duration,
10};
11
12use anyhow::Result;
13use iota_keys::keypair_file::{read_authority_keypair_from_file, read_keypair_from_file};
14use iota_metrics::MetricGroups;
15use iota_names::config::IotaNamesConfig;
16use iota_sdk_types::Address;
17use iota_types::{
18 committee::EpochId,
19 crypto::{
20 AccountKeyPair, AuthorityKeyPair, AuthorityPublicKeyBytes, IotaKeyPair, KeypairTraits,
21 NetworkKeyPair, get_key_pair_from_rng,
22 },
23 messages_checkpoint::CheckpointSequenceNumber,
24 multiaddr::Multiaddr,
25 supported_protocol_versions::{Chain, SupportedProtocolVersions},
26 traffic_control::{PolicyConfig, RemoteFirewallConfig},
27};
28use once_cell::sync::OnceCell;
29use rand::rngs::OsRng;
30use serde::{Deserialize, Serialize};
31use starfish_config::Parameters as StarfishParameters;
32use tracing::info;
33
34use crate::{
35 Config, certificate_deny_config::CertificateDenyConfig, genesis,
36 migration_tx_data::MigrationTxData, object_storage_config::ObjectStoreConfig, p2p::P2pConfig,
37 transaction_deny_config::TransactionDenyConfig, verifier_signing_config::VerifierSigningConfig,
38};
39
40pub const DEFAULT_GRPC_CONCURRENCY_LIMIT: usize = 20000000000;
42
43pub const DEFAULT_VALIDATOR_GAS_PRICE: u64 = iota_types::transaction::DEFAULT_VALIDATOR_GAS_PRICE;
45
46pub const DEFAULT_COMMISSION_RATE: u64 = 200;
48
49pub const DEFAULT_FULL_CHECKPOINT_CONTENTS_CACHE_SIZE_MB: usize = 1024;
51
52#[derive(Clone, Debug, Deserialize, Serialize)]
53#[serde(rename_all = "kebab-case")]
54pub struct NodeConfig {
55 #[serde(default = "default_authority_key_pair")]
58 pub authority_key_pair: AuthorityKeyPairWithPath,
59 #[serde(default = "default_key_pair")]
62 pub protocol_key_pair: KeyPairWithPath,
63 #[serde(default = "default_key_pair")]
64 pub account_key_pair: KeyPairWithPath,
65 #[serde(default = "default_key_pair")]
68 pub network_key_pair: KeyPairWithPath,
69 pub db_path: PathBuf,
70
71 #[serde(default = "default_grpc_address")]
75 pub network_address: Multiaddr,
76 #[serde(default = "default_json_rpc_address")]
77 pub json_rpc_address: SocketAddr,
78
79 #[serde(default = "default_metrics_address")]
81 pub metrics_address: SocketAddr,
82
83 #[serde(default = "default_admin_interface_address")]
87 pub admin_interface_address: SocketAddr,
88
89 #[serde(skip_serializing_if = "Option::is_none")]
91 pub consensus_config: Option<ConsensusConfig>,
92
93 #[serde(default = "default_enable_index_processing")]
98 pub enable_index_processing: bool,
99
100 #[serde(default)]
102 pub jsonrpc_server_type: Option<ServerType>,
107
108 #[serde(default)]
112 pub grpc_load_shed: Option<bool>,
113
114 #[serde(default = "default_concurrency_limit")]
115 pub grpc_concurrency_limit: Option<usize>,
116
117 #[serde(default)]
119 pub p2p_config: P2pConfig,
120
121 pub genesis: Genesis,
125
126 pub migration_tx_data_path: Option<PathBuf>,
128
129 #[serde(default = "default_authority_store_pruning_config")]
132 pub authority_store_pruning_config: AuthorityStorePruningConfig,
133
134 #[serde(default = "default_end_of_epoch_broadcast_channel_capacity")]
139 pub end_of_epoch_broadcast_channel_capacity: usize,
140
141 #[serde(default)]
145 pub checkpoint_executor_config: CheckpointExecutorConfig,
146
147 #[serde(skip_serializing_if = "Option::is_none")]
148 pub metrics: Option<MetricsConfig>,
149
150 #[serde(skip)]
155 pub supported_protocol_versions: Option<SupportedProtocolVersions>,
156
157 #[serde(default)]
161 pub db_checkpoint_config: DBCheckpointConfig,
162
163 #[serde(default)]
165 pub expensive_safety_check_config: ExpensiveSafetyCheckConfig,
166
167 #[serde(default)]
171 pub transaction_deny_config: TransactionDenyConfig,
172
173 #[serde(default)]
179 pub certificate_deny_config: CertificateDenyConfig,
180
181 #[serde(default)]
184 pub state_debug_dump_config: StateDebugDumpConfig,
185
186 #[serde(default)]
187 pub checkpoint_archive_config: Option<CheckpointArchiveConfig>,
188
189 #[serde(default)]
191 pub state_snapshot_write_config: StateSnapshotConfig,
192
193 #[serde(default)]
194 pub indexer_max_subscriptions: Option<usize>,
195
196 #[serde(default = "default_transaction_kv_store_config")]
197 pub transaction_kv_store_read_config: TransactionKeyValueStoreReadConfig,
198
199 #[serde(skip_serializing_if = "Option::is_none")]
201 pub transaction_kv_store_write_config: Option<TransactionKeyValueStoreWriteConfig>,
202
203 #[serde(default = "default_authority_overload_config")]
206 pub authority_overload_config: AuthorityOverloadConfig,
207
208 #[serde(skip_serializing_if = "Option::is_none")]
212 pub run_with_range: Option<RunWithRange>,
213
214 #[serde(
216 skip_serializing_if = "Option::is_none",
217 default = "default_traffic_controller_policy_config"
218 )]
219 pub policy_config: Option<PolicyConfig>,
220
221 #[serde(skip_serializing_if = "Option::is_none")]
222 pub firewall_config: Option<RemoteFirewallConfig>,
223
224 #[serde(default)]
225 pub execution_cache_config: ExecutionCacheConfig,
226
227 #[serde(default = "default_full_checkpoint_contents_cache_size_mb")]
238 pub full_checkpoint_contents_cache_size_mb: usize,
239
240 #[serde(default = "bool_true")]
241 pub enable_validator_tx_finalizer: bool,
242
243 #[serde(default = "bool_true")]
249 pub enable_soft_locking: bool,
250
251 #[serde(default)]
252 pub verifier_signing_config: VerifierSigningConfig,
253
254 #[serde(skip_serializing_if = "Option::is_none")]
258 pub enable_db_write_stall: Option<bool>,
259
260 #[serde(default, skip_serializing_if = "Option::is_none")]
261 pub iota_names_config: Option<IotaNamesConfig>,
262
263 #[serde(default)]
265 pub enable_grpc_api: bool,
266 #[serde(
267 default = "default_grpc_api_config",
268 skip_serializing_if = "Option::is_none"
269 )]
270 pub grpc_api_config: Option<GrpcApiConfig>,
271
272 #[serde(skip_serializing_if = "Option::is_none")]
277 pub chain_override_for_testing: Option<Chain>,
278
279 #[serde(default, skip_serializing_if = "Option::is_none")]
282 pub validator_client_monitor_config:
283 Option<crate::validator_client_monitor_config::ValidatorClientMonitorConfig>,
284}
285
286#[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize)]
287#[serde(rename_all = "kebab-case")]
288pub struct TlsConfig {
289 cert: String,
291 key: String,
293}
294
295impl TlsConfig {
296 pub fn cert(&self) -> &str {
297 &self.cert
298 }
299
300 pub fn key(&self) -> &str {
301 &self.key
302 }
303}
304
305#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
307#[serde(rename_all = "kebab-case")]
308pub struct GrpcApiConfig {
309 #[serde(default = "default_grpc_api_address")]
311 pub address: SocketAddr,
312
313 #[serde(skip_serializing_if = "Option::is_none")]
317 pub tls: Option<TlsConfig>,
318
319 #[serde(default = "default_grpc_api_max_message_size_bytes")]
321 pub max_message_size_bytes: u32,
322
323 #[serde(default = "default_grpc_api_broadcast_buffer_size")]
325 pub broadcast_buffer_size: u32,
326
327 #[serde(default = "default_grpc_api_max_concurrent_stream_subscribers")]
333 pub max_concurrent_stream_subscribers: u32,
334
335 #[serde(default = "default_grpc_api_max_json_move_value_size")]
338 pub max_json_move_value_size: usize,
339
340 #[serde(default = "default_grpc_api_max_execute_transaction_batch_size")]
343 pub max_execute_transaction_batch_size: u32,
344
345 #[serde(default = "default_grpc_api_max_simulate_transaction_batch_size")]
348 pub max_simulate_transaction_batch_size: u32,
349
350 #[serde(default = "default_grpc_api_max_checkpoint_inclusion_timeout_ms")]
354 pub max_checkpoint_inclusion_timeout_ms: u64,
355}
356
357fn default_grpc_api_address() -> SocketAddr {
358 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 50051)
359}
360
361fn default_grpc_api_broadcast_buffer_size() -> u32 {
362 100
363}
364
365fn default_grpc_api_max_concurrent_stream_subscribers() -> u32 {
366 1024
367}
368
369fn default_grpc_api_max_message_size_bytes() -> u32 {
370 128 * 1024 * 1024 }
372
373fn default_grpc_api_max_json_move_value_size() -> usize {
374 1024 * 1024 }
376
377fn default_grpc_api_max_execute_transaction_batch_size() -> u32 {
378 20
379}
380
381fn default_grpc_api_max_simulate_transaction_batch_size() -> u32 {
382 20
383}
384
385fn default_grpc_api_max_checkpoint_inclusion_timeout_ms() -> u64 {
386 60_000 }
388
389impl Default for GrpcApiConfig {
390 fn default() -> Self {
391 Self {
392 address: default_grpc_api_address(),
393 tls: None,
394 max_message_size_bytes: default_grpc_api_max_message_size_bytes(),
395 broadcast_buffer_size: default_grpc_api_broadcast_buffer_size(),
396 max_concurrent_stream_subscribers: default_grpc_api_max_concurrent_stream_subscribers(),
397 max_json_move_value_size: default_grpc_api_max_json_move_value_size(),
398 max_execute_transaction_batch_size: default_grpc_api_max_execute_transaction_batch_size(
399 ),
400 max_simulate_transaction_batch_size:
401 default_grpc_api_max_simulate_transaction_batch_size(),
402 max_checkpoint_inclusion_timeout_ms:
403 default_grpc_api_max_checkpoint_inclusion_timeout_ms(),
404 }
405 }
406}
407
408impl GrpcApiConfig {
409 const GRPC_TONIC_DEFAULT_MAX_RECV_MESSAGE_SIZE: u32 = 4 * 1024 * 1024; const GRPC_MIN_CLIENT_MAX_MESSAGE_SIZE_BYTES: u32 =
413 Self::GRPC_TONIC_DEFAULT_MAX_RECV_MESSAGE_SIZE;
414
415 pub fn tls_config(&self) -> Option<&TlsConfig> {
416 self.tls.as_ref()
417 }
418
419 pub fn max_message_size_bytes(&self) -> u32 {
420 self.max_message_size_bytes
422 .max(Self::GRPC_MIN_CLIENT_MAX_MESSAGE_SIZE_BYTES)
423 }
424
425 pub fn max_message_size_client_bytes(&self, client_max_message_size_bytes: Option<u32>) -> u32 {
429 client_max_message_size_bytes
430 .unwrap_or(Self::GRPC_TONIC_DEFAULT_MAX_RECV_MESSAGE_SIZE)
433 .clamp(
435 Self::GRPC_MIN_CLIENT_MAX_MESSAGE_SIZE_BYTES,
436 self.max_message_size_bytes(),
437 )
438 }
439}
440
441#[derive(Clone, Debug, Default, Deserialize, Serialize)]
442#[serde(rename_all = "kebab-case")]
443pub struct ExecutionCacheConfig {
444 #[serde(default)]
445 pub writeback_cache: WritebackCacheConfig,
446}
447
448#[derive(Clone, Debug, Default, Deserialize, Serialize)]
449#[serde(rename_all = "kebab-case")]
450pub struct WritebackCacheConfig {
451 #[serde(default, skip_serializing_if = "Option::is_none")]
454 pub max_cache_size: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
457 pub package_cache_size: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
460 pub object_cache_size: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
462 pub marker_cache_size: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
464 pub object_by_id_cache_size: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
467 pub transaction_cache_size: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
469 pub executed_effect_cache_size: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
471 pub effect_cache_size: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
474 pub events_cache_size: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
477 pub transaction_objects_cache_size: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
482 pub backpressure_threshold: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
488 pub backpressure_threshold_for_rpc: Option<u64>, #[serde(default, skip_serializing_if = "Option::is_none")]
498 pub backpressure_soft_limit_pct: Option<u32>,
499}
500
501impl WritebackCacheConfig {
502 pub fn max_cache_size(&self) -> u64 {
503 std::env::var("IOTA_CACHE_WRITEBACK_SIZE_MAX")
504 .ok()
505 .and_then(|s| s.parse().ok())
506 .or(self.max_cache_size)
507 .unwrap_or(100000)
508 }
509
510 pub fn package_cache_size(&self) -> u64 {
511 std::env::var("IOTA_CACHE_WRITEBACK_SIZE_PACKAGE")
512 .ok()
513 .and_then(|s| s.parse().ok())
514 .or(self.package_cache_size)
515 .unwrap_or(1000)
516 }
517
518 pub fn object_cache_size(&self) -> u64 {
519 std::env::var("IOTA_CACHE_WRITEBACK_SIZE_OBJECT")
520 .ok()
521 .and_then(|s| s.parse().ok())
522 .or(self.object_cache_size)
523 .unwrap_or_else(|| self.max_cache_size())
524 }
525
526 pub fn marker_cache_size(&self) -> u64 {
527 std::env::var("IOTA_CACHE_WRITEBACK_SIZE_MARKER")
528 .ok()
529 .and_then(|s| s.parse().ok())
530 .or(self.marker_cache_size)
531 .unwrap_or_else(|| self.object_cache_size())
532 }
533
534 pub fn object_by_id_cache_size(&self) -> u64 {
535 std::env::var("IOTA_CACHE_WRITEBACK_SIZE_OBJECT_BY_ID")
536 .ok()
537 .and_then(|s| s.parse().ok())
538 .or(self.object_by_id_cache_size)
539 .unwrap_or_else(|| self.object_cache_size())
540 }
541
542 pub fn transaction_cache_size(&self) -> u64 {
543 std::env::var("IOTA_CACHE_WRITEBACK_SIZE_TRANSACTION")
544 .ok()
545 .and_then(|s| s.parse().ok())
546 .or(self.transaction_cache_size)
547 .unwrap_or_else(|| self.max_cache_size())
548 }
549
550 pub fn executed_effect_cache_size(&self) -> u64 {
551 std::env::var("IOTA_CACHE_WRITEBACK_SIZE_EXECUTED_EFFECT")
552 .ok()
553 .and_then(|s| s.parse().ok())
554 .or(self.executed_effect_cache_size)
555 .unwrap_or_else(|| self.transaction_cache_size())
556 }
557
558 pub fn effect_cache_size(&self) -> u64 {
559 std::env::var("IOTA_CACHE_WRITEBACK_SIZE_EFFECT")
560 .ok()
561 .and_then(|s| s.parse().ok())
562 .or(self.effect_cache_size)
563 .unwrap_or_else(|| self.executed_effect_cache_size())
564 }
565
566 pub fn events_cache_size(&self) -> u64 {
567 std::env::var("IOTA_CACHE_WRITEBACK_SIZE_EVENTS")
568 .ok()
569 .and_then(|s| s.parse().ok())
570 .or(self.events_cache_size)
571 .unwrap_or_else(|| self.transaction_cache_size())
572 }
573
574 pub fn transaction_objects_cache_size(&self) -> u64 {
575 std::env::var("IOTA_CACHE_WRITEBACK_SIZE_TRANSACTION_OBJECTS")
576 .ok()
577 .and_then(|s| s.parse().ok())
578 .or(self.transaction_objects_cache_size)
579 .unwrap_or(1000)
580 }
581
582 pub fn backpressure_threshold(&self) -> u64 {
583 std::env::var("IOTA_CACHE_WRITEBACK_BACKPRESSURE_THRESHOLD")
584 .ok()
585 .and_then(|s| s.parse().ok())
586 .or(self.backpressure_threshold)
587 .unwrap_or(100_000)
588 }
589
590 pub fn backpressure_threshold_for_rpc(&self) -> u64 {
591 std::env::var("IOTA_CACHE_WRITEBACK_BACKPRESSURE_THRESHOLD_FOR_RPC")
592 .ok()
593 .and_then(|s| s.parse().ok())
594 .or(self.backpressure_threshold_for_rpc)
595 .unwrap_or(self.backpressure_threshold())
596 }
597
598 pub fn backpressure_soft_limit_pct(&self) -> u32 {
599 std::env::var("IOTA_CACHE_WRITEBACK_BACKPRESSURE_SOFT_LIMIT_PCT")
600 .ok()
601 .and_then(|s| s.parse().ok())
602 .or(self.backpressure_soft_limit_pct)
603 .unwrap_or(50)
604 .min(100)
605 }
606}
607
608#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
609#[serde(rename_all = "lowercase")]
610pub enum ServerType {
611 WebSocket,
612 Http,
613 Both,
614}
615
616#[derive(Clone, Debug, Deserialize, Serialize)]
617#[serde(rename_all = "kebab-case")]
618pub struct TransactionKeyValueStoreReadConfig {
619 #[serde(default = "default_base_url")]
620 pub base_url: String,
621
622 #[serde(default = "default_cache_size")]
623 pub cache_size: u64,
624}
625
626impl Default for TransactionKeyValueStoreReadConfig {
627 fn default() -> Self {
628 Self {
629 base_url: default_base_url(),
630 cache_size: default_cache_size(),
631 }
632 }
633}
634
635fn default_base_url() -> String {
636 "".to_string()
637}
638
639fn default_cache_size() -> u64 {
640 100_000
641}
642
643fn default_transaction_kv_store_config() -> TransactionKeyValueStoreReadConfig {
644 TransactionKeyValueStoreReadConfig::default()
645}
646
647fn default_authority_store_pruning_config() -> AuthorityStorePruningConfig {
648 AuthorityStorePruningConfig::default()
649}
650
651pub fn default_enable_index_processing() -> bool {
652 true
653}
654
655fn default_grpc_address() -> Multiaddr {
656 "/ip4/0.0.0.0/tcp/8080".parse().unwrap()
657}
658fn default_authority_key_pair() -> AuthorityKeyPairWithPath {
659 AuthorityKeyPairWithPath::new(get_key_pair_from_rng::<AuthorityKeyPair, _>(&mut OsRng).1)
660}
661
662fn default_key_pair() -> KeyPairWithPath {
663 KeyPairWithPath::new(
664 get_key_pair_from_rng::<AccountKeyPair, _>(&mut OsRng)
665 .1
666 .into(),
667 )
668}
669
670fn default_metrics_address() -> SocketAddr {
671 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9184)
672}
673
674pub fn default_admin_interface_address() -> SocketAddr {
675 SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 1337)
676}
677
678pub fn default_json_rpc_address() -> SocketAddr {
679 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9000)
680}
681
682pub fn default_grpc_api_config() -> Option<GrpcApiConfig> {
683 Some(GrpcApiConfig::default())
684}
685
686pub fn default_concurrency_limit() -> Option<usize> {
687 Some(DEFAULT_GRPC_CONCURRENCY_LIMIT)
688}
689
690pub fn default_end_of_epoch_broadcast_channel_capacity() -> usize {
691 128
692}
693
694pub fn default_full_checkpoint_contents_cache_size_mb() -> usize {
695 DEFAULT_FULL_CHECKPOINT_CONTENTS_CACHE_SIZE_MB
696}
697
698pub fn bool_true() -> bool {
699 true
700}
701
702impl Config for NodeConfig {}
703
704impl NodeConfig {
705 pub fn authority_key_pair(&self) -> &AuthorityKeyPair {
706 self.authority_key_pair.authority_keypair()
707 }
708
709 pub fn protocol_key_pair(&self) -> &NetworkKeyPair {
710 match self.protocol_key_pair.keypair() {
711 IotaKeyPair::Ed25519(kp) => kp,
712 other => {
713 panic!("invalid keypair type: {other:?}, only Ed25519 is allowed for protocol key")
714 }
715 }
716 }
717
718 pub fn network_key_pair(&self) -> &NetworkKeyPair {
719 match self.network_key_pair.keypair() {
720 IotaKeyPair::Ed25519(kp) => kp,
721 other => {
722 panic!("invalid keypair type: {other:?}, only Ed25519 is allowed for network key")
723 }
724 }
725 }
726
727 pub fn authority_public_key(&self) -> AuthorityPublicKeyBytes {
728 self.authority_key_pair().public().into()
729 }
730
731 pub fn db_path(&self) -> PathBuf {
732 self.db_path.join("live")
733 }
734
735 pub fn db_checkpoint_path(&self) -> PathBuf {
736 self.db_path.join("db_checkpoints")
737 }
738
739 pub fn snapshot_path(&self) -> PathBuf {
740 self.db_path.join("snapshot")
741 }
742
743 pub fn network_address(&self) -> &Multiaddr {
744 &self.network_address
745 }
746
747 pub fn consensus_config(&self) -> Option<&ConsensusConfig> {
748 self.consensus_config.as_ref()
749 }
750
751 pub fn genesis(&self) -> Result<&genesis::Genesis> {
752 self.genesis.genesis()
753 }
754
755 pub fn load_migration_tx_data(&self) -> Result<MigrationTxData> {
756 let Some(location) = &self.migration_tx_data_path else {
757 anyhow::bail!("no file location set");
758 };
759
760 let migration_tx_data = MigrationTxData::load(location)?;
762
763 migration_tx_data.validate_from_genesis(self.genesis.genesis()?)?;
765 Ok(migration_tx_data)
766 }
767
768 pub fn iota_address(&self) -> Address {
769 (&self.account_key_pair.keypair().public()).into()
770 }
771
772 pub fn checkpoint_archive_config(&self) -> Option<&CheckpointArchiveConfig> {
773 self.checkpoint_archive_config.as_ref()
774 }
775
776 pub fn jsonrpc_server_type(&self) -> ServerType {
777 self.jsonrpc_server_type.unwrap_or(ServerType::Http)
778 }
779}
780
781#[derive(Debug, Clone, Deserialize, Serialize)]
782#[serde(rename_all = "kebab-case")]
783pub struct ConsensusConfig {
784 pub db_path: PathBuf,
786
787 pub db_retention_epochs: Option<u64>,
791
792 pub db_pruner_period_secs: Option<u64>,
796
797 pub max_pending_transactions: Option<usize>,
808
809 pub max_submit_position: Option<usize>,
815
816 pub submit_delay_step_override_millis: Option<u64>,
822
823 #[serde(skip_serializing_if = "Option::is_none", alias = "starfish_parameters")]
825 pub parameters: Option<StarfishParameters>,
826
827 #[serde(skip_serializing_if = "Option::is_none")]
833 pub graduated_load_shedding_soft_limit_pct: Option<u32>,
834}
835
836impl ConsensusConfig {
837 pub fn db_path(&self) -> &Path {
838 &self.db_path
839 }
840
841 pub fn max_pending_transactions(&self) -> usize {
845 self.max_pending_transactions.unwrap_or(20_000)
846 }
847
848 pub fn graduated_load_shedding_soft_limit_pct(&self) -> u32 {
853 self.graduated_load_shedding_soft_limit_pct
854 .unwrap_or(50)
855 .min(100)
856 }
857
858 pub fn submit_delay_step_override(&self) -> Option<Duration> {
859 self.submit_delay_step_override_millis
860 .map(Duration::from_millis)
861 }
862
863 pub fn db_retention_epochs(&self) -> u64 {
864 self.db_retention_epochs.unwrap_or(0)
865 }
866
867 pub fn db_pruner_period(&self) -> Duration {
868 self.db_pruner_period_secs
870 .map(Duration::from_secs)
871 .unwrap_or(Duration::from_secs(3_600))
872 }
873}
874
875#[derive(Clone, Debug, Deserialize, Serialize)]
876#[serde(rename_all = "kebab-case")]
877pub struct CheckpointExecutorConfig {
878 #[serde(default = "default_checkpoint_execution_max_concurrency")]
883 pub checkpoint_execution_max_concurrency: usize,
884
885 #[serde(default = "default_local_execution_timeout_sec")]
891 pub local_execution_timeout_sec: u64,
892
893 #[serde(default, skip_serializing_if = "Option::is_none")]
898 pub data_ingestion_dir: Option<PathBuf>,
899}
900
901#[derive(Clone, Debug, Default, Deserialize, Serialize)]
902#[serde(rename_all = "kebab-case")]
903pub struct ExpensiveSafetyCheckConfig {
904 #[serde(default)]
909 enable_epoch_iota_conservation_check: bool,
910
911 #[serde(default)]
915 enable_deep_per_tx_iota_conservation_check: bool,
916
917 #[serde(default)]
920 force_disable_epoch_iota_conservation_check: bool,
921
922 #[serde(default)]
925 enable_state_consistency_check: bool,
926
927 #[serde(default)]
929 force_disable_state_consistency_check: bool,
930
931 #[serde(default)]
932 enable_secondary_index_checks: bool,
933 }
935
936impl ExpensiveSafetyCheckConfig {
937 pub fn new_enable_all() -> Self {
938 Self {
939 enable_epoch_iota_conservation_check: true,
940 enable_deep_per_tx_iota_conservation_check: true,
941 force_disable_epoch_iota_conservation_check: false,
942 enable_state_consistency_check: true,
943 force_disable_state_consistency_check: false,
944 enable_secondary_index_checks: false, }
946 }
947
948 pub fn new_disable_all() -> Self {
949 Self {
950 enable_epoch_iota_conservation_check: false,
951 enable_deep_per_tx_iota_conservation_check: false,
952 force_disable_epoch_iota_conservation_check: true,
953 enable_state_consistency_check: false,
954 force_disable_state_consistency_check: true,
955 enable_secondary_index_checks: false,
956 }
957 }
958
959 pub fn force_disable_epoch_iota_conservation_check(&mut self) {
960 self.force_disable_epoch_iota_conservation_check = true;
961 }
962
963 pub fn enable_epoch_iota_conservation_check(&self) -> bool {
964 (self.enable_epoch_iota_conservation_check || cfg!(debug_assertions))
965 && !self.force_disable_epoch_iota_conservation_check
966 }
967
968 pub fn force_disable_state_consistency_check(&mut self) {
969 self.force_disable_state_consistency_check = true;
970 }
971
972 pub fn enable_state_consistency_check(&self) -> bool {
973 (self.enable_state_consistency_check || cfg!(debug_assertions))
974 && !self.force_disable_state_consistency_check
975 }
976
977 pub fn enable_deep_per_tx_iota_conservation_check(&self) -> bool {
978 self.enable_deep_per_tx_iota_conservation_check || cfg!(debug_assertions)
979 }
980
981 pub fn enable_secondary_index_checks(&self) -> bool {
982 self.enable_secondary_index_checks
983 }
984}
985
986fn default_checkpoint_execution_max_concurrency() -> usize {
987 4
988}
989
990fn default_local_execution_timeout_sec() -> u64 {
991 30
992}
993
994impl Default for CheckpointExecutorConfig {
995 fn default() -> Self {
996 Self {
997 checkpoint_execution_max_concurrency: default_checkpoint_execution_max_concurrency(),
998 local_execution_timeout_sec: default_local_execution_timeout_sec(),
999 data_ingestion_dir: None,
1000 }
1001 }
1002}
1003
1004#[derive(Debug, Clone, Deserialize, Serialize)]
1005#[serde(rename_all = "kebab-case")]
1006pub struct AuthorityStorePruningConfig {
1007 #[serde(default = "default_num_latest_epoch_dbs_to_retain")]
1009 pub num_latest_epoch_dbs_to_retain: usize,
1010 #[serde(default)]
1015 pub num_epochs_to_retain: u64,
1016 #[serde(
1021 default = "default_periodic_compaction_threshold_days",
1022 skip_serializing_if = "Option::is_none"
1023 )]
1024 pub periodic_compaction_threshold_days: Option<usize>,
1025 #[serde(skip_serializing_if = "Option::is_none")]
1028 pub num_epochs_to_retain_for_checkpoints: Option<u64>,
1029 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1035 pub enable_compaction_filter: bool,
1036 #[serde(skip_serializing_if = "Option::is_none")]
1037 pub num_epochs_to_retain_for_indexes: Option<u64>,
1038}
1039
1040fn default_num_latest_epoch_dbs_to_retain() -> usize {
1041 3
1042}
1043
1044fn default_periodic_compaction_threshold_days() -> Option<usize> {
1045 Some(1)
1046}
1047
1048impl Default for AuthorityStorePruningConfig {
1049 fn default() -> Self {
1050 Self {
1051 num_latest_epoch_dbs_to_retain: default_num_latest_epoch_dbs_to_retain(),
1052 num_epochs_to_retain: 0,
1053 periodic_compaction_threshold_days: None,
1054 num_epochs_to_retain_for_checkpoints: if cfg!(msim) { Some(2) } else { None },
1055 enable_compaction_filter: cfg!(test) || cfg!(msim),
1056 num_epochs_to_retain_for_indexes: None,
1057 }
1058 }
1059}
1060
1061impl AuthorityStorePruningConfig {
1062 pub fn set_num_epochs_to_retain(&mut self, num_epochs_to_retain: u64) {
1063 self.num_epochs_to_retain = num_epochs_to_retain;
1064 }
1065
1066 pub fn set_num_epochs_to_retain_for_checkpoints(&mut self, num_epochs_to_retain: Option<u64>) {
1067 self.num_epochs_to_retain_for_checkpoints = num_epochs_to_retain;
1068 }
1069
1070 pub fn num_epochs_to_retain_for_checkpoints(&self) -> Option<u64> {
1071 self.num_epochs_to_retain_for_checkpoints
1072 .map(|n| {
1074 if n < 2 {
1075 info!("num_epochs_to_retain_for_checkpoints must be at least 2, rounding up from {}", n);
1076 2
1077 } else {
1078 n
1079 }
1080 })
1081 }
1082}
1083
1084#[derive(Debug, Clone, Deserialize, Serialize)]
1085#[serde(rename_all = "kebab-case")]
1086pub struct MetricsConfig {
1087 #[serde(skip_serializing_if = "Option::is_none")]
1088 pub push_interval_seconds: Option<u64>,
1089 #[serde(skip_serializing_if = "Option::is_none")]
1090 pub push_url: Option<String>,
1091 #[serde(skip_serializing_if = "Option::is_none")]
1092 pub groups: Option<MetricGroups>,
1093}
1094
1095#[derive(Default, Debug, Clone, Deserialize, Serialize)]
1096#[serde(rename_all = "kebab-case")]
1097pub struct DBCheckpointConfig {
1098 #[serde(default)]
1099 pub perform_db_checkpoints_at_epoch_end: bool,
1100 #[serde(skip_serializing_if = "Option::is_none")]
1101 pub checkpoint_path: Option<PathBuf>,
1102 #[serde(skip_serializing_if = "Option::is_none")]
1103 pub object_store_config: Option<ObjectStoreConfig>,
1104 #[serde(skip_serializing_if = "Option::is_none")]
1105 pub perform_index_db_checkpoints_at_epoch_end: Option<bool>,
1106 #[serde(skip_serializing_if = "Option::is_none")]
1107 pub prune_and_compact_before_upload: Option<bool>,
1108}
1109
1110fn default_checkpoint_archive_download_concurrency() -> usize {
1111 10
1112}
1113
1114#[derive(Debug, Clone, Deserialize, Serialize)]
1117#[serde(rename_all = "kebab-case")]
1118pub struct CheckpointArchiveConfig {
1119 pub url: String,
1121 #[serde(default = "default_checkpoint_archive_download_concurrency")]
1123 pub download_concurrency: usize,
1124}
1125
1126#[derive(Default, Debug, Clone, Deserialize, Serialize)]
1134#[serde(rename_all = "kebab-case")]
1135pub struct StateSnapshotConfig {
1136 #[serde(skip_serializing_if = "Option::is_none")]
1137 pub object_store_config: Option<ObjectStoreConfig>,
1138 pub concurrency: usize,
1139}
1140
1141#[derive(Default, Debug, Clone, Deserialize, Serialize)]
1142#[serde(rename_all = "kebab-case")]
1143pub struct TransactionKeyValueStoreWriteConfig {
1144 pub aws_access_key_id: String,
1145 pub aws_secret_access_key: String,
1146 pub aws_region: String,
1147 pub table_name: String,
1148 pub bucket_name: String,
1149 pub concurrency: usize,
1150}
1151
1152#[derive(Clone, Debug, Deserialize, Serialize)]
1157#[serde(rename_all = "kebab-case")]
1158pub struct AuthorityOverloadConfig {
1159 #[serde(default = "default_max_txn_age_in_queue")]
1163 pub max_txn_age_in_queue: Duration,
1164
1165 #[serde(default = "default_overload_monitor_interval")]
1167 pub overload_monitor_interval: Duration,
1168
1169 #[serde(default = "default_execution_queue_latency_soft_limit")]
1171 pub execution_queue_latency_soft_limit: Duration,
1172
1173 #[serde(default = "default_execution_queue_latency_hard_limit")]
1176 pub execution_queue_latency_hard_limit: Duration,
1177
1178 #[serde(default = "default_max_load_shedding_percentage")]
1180 pub max_load_shedding_percentage: u32,
1181
1182 #[serde(default = "default_min_load_shedding_percentage_above_hard_limit")]
1185 pub min_load_shedding_percentage_above_hard_limit: u32,
1186
1187 #[serde(default = "default_safe_transaction_ready_rate")]
1190 pub safe_transaction_ready_rate: u32,
1191
1192 #[serde(default = "default_check_system_overload_at_signing")]
1195 pub check_system_overload_at_signing: bool,
1196
1197 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1200 pub check_system_overload_at_execution: bool,
1201
1202 #[serde(default = "default_max_transaction_manager_queue_length")]
1206 pub max_transaction_manager_queue_length: usize,
1207
1208 #[serde(default = "default_max_transaction_manager_per_object_queue_length")]
1211 pub max_transaction_manager_per_object_queue_length: usize,
1212
1213 #[serde(default = "default_max_transaction_manager_queue_length_soft_limit_pct")]
1217 pub max_transaction_manager_queue_length_soft_limit_pct: u32,
1218}
1219
1220impl AuthorityOverloadConfig {
1221 pub fn max_transaction_manager_queue_length_soft_limit_pct(&self) -> u32 {
1224 self.max_transaction_manager_queue_length_soft_limit_pct
1225 .min(100)
1226 }
1227}
1228
1229fn default_max_txn_age_in_queue() -> Duration {
1230 Duration::from_millis(500)
1231}
1232
1233fn default_overload_monitor_interval() -> Duration {
1234 Duration::from_secs(10)
1235}
1236
1237fn default_execution_queue_latency_soft_limit() -> Duration {
1238 Duration::from_secs(1)
1239}
1240
1241fn default_execution_queue_latency_hard_limit() -> Duration {
1242 Duration::from_secs(10)
1243}
1244
1245fn default_max_load_shedding_percentage() -> u32 {
1246 95
1247}
1248
1249fn default_min_load_shedding_percentage_above_hard_limit() -> u32 {
1250 50
1251}
1252
1253fn default_safe_transaction_ready_rate() -> u32 {
1254 100
1255}
1256
1257fn default_check_system_overload_at_signing() -> bool {
1258 true
1259}
1260
1261fn default_max_transaction_manager_queue_length() -> usize {
1262 100_000
1263}
1264
1265fn default_max_transaction_manager_queue_length_soft_limit_pct() -> u32 {
1266 50
1267}
1268
1269fn default_max_transaction_manager_per_object_queue_length() -> usize {
1270 20
1271}
1272
1273impl Default for AuthorityOverloadConfig {
1274 fn default() -> Self {
1275 Self {
1276 max_txn_age_in_queue: default_max_txn_age_in_queue(),
1277 overload_monitor_interval: default_overload_monitor_interval(),
1278 execution_queue_latency_soft_limit: default_execution_queue_latency_soft_limit(),
1279 execution_queue_latency_hard_limit: default_execution_queue_latency_hard_limit(),
1280 max_load_shedding_percentage: default_max_load_shedding_percentage(),
1281 min_load_shedding_percentage_above_hard_limit:
1282 default_min_load_shedding_percentage_above_hard_limit(),
1283 safe_transaction_ready_rate: default_safe_transaction_ready_rate(),
1284 check_system_overload_at_signing: true,
1285 check_system_overload_at_execution: false,
1286 max_transaction_manager_queue_length: default_max_transaction_manager_queue_length(),
1287 max_transaction_manager_queue_length_soft_limit_pct:
1288 default_max_transaction_manager_queue_length_soft_limit_pct(),
1289 max_transaction_manager_per_object_queue_length:
1290 default_max_transaction_manager_per_object_queue_length(),
1291 }
1292 }
1293}
1294
1295fn default_authority_overload_config() -> AuthorityOverloadConfig {
1296 AuthorityOverloadConfig::default()
1297}
1298
1299fn default_traffic_controller_policy_config() -> Option<PolicyConfig> {
1300 Some(PolicyConfig::default_dos_protection_policy())
1301}
1302
1303#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq)]
1304pub struct Genesis {
1305 #[serde(flatten)]
1306 location: Option<GenesisLocation>,
1307
1308 #[serde(skip)]
1309 genesis: once_cell::sync::OnceCell<genesis::Genesis>,
1310}
1311
1312impl Genesis {
1313 pub fn new(genesis: genesis::Genesis) -> Self {
1314 Self {
1315 location: Some(GenesisLocation::InPlace {
1316 genesis: Box::new(genesis),
1317 }),
1318 genesis: Default::default(),
1319 }
1320 }
1321
1322 pub fn new_from_file<P: Into<PathBuf>>(path: P) -> Self {
1323 Self {
1324 location: Some(GenesisLocation::File {
1325 genesis_file_location: path.into(),
1326 }),
1327 genesis: Default::default(),
1328 }
1329 }
1330
1331 pub fn new_empty() -> Self {
1332 Self {
1333 location: None,
1334 genesis: Default::default(),
1335 }
1336 }
1337
1338 pub fn genesis(&self) -> Result<&genesis::Genesis> {
1339 match &self.location {
1340 Some(GenesisLocation::InPlace { genesis }) => Ok(genesis),
1341 Some(GenesisLocation::File {
1342 genesis_file_location,
1343 }) => self
1344 .genesis
1345 .get_or_try_init(|| genesis::Genesis::load(genesis_file_location)),
1346 None => anyhow::bail!("no genesis location set"),
1347 }
1348 }
1349}
1350
1351#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq)]
1352#[serde(untagged)]
1353enum GenesisLocation {
1354 InPlace {
1355 genesis: Box<genesis::Genesis>,
1356 },
1357 File {
1358 #[serde(rename = "genesis-file-location")]
1359 genesis_file_location: PathBuf,
1360 },
1361}
1362
1363#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
1366pub struct KeyPairWithPath {
1367 #[serde(flatten)]
1368 location: KeyPairLocation,
1369
1370 #[serde(skip)]
1371 keypair: OnceCell<Arc<IotaKeyPair>>,
1372}
1373
1374#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq)]
1375#[serde(untagged)]
1376enum KeyPairLocation {
1377 InPlace {
1378 #[serde(with = "bech32_formatted_keypair")]
1379 value: Arc<IotaKeyPair>,
1380 },
1381 File {
1382 path: PathBuf,
1383 },
1384}
1385
1386impl KeyPairWithPath {
1387 pub fn new(kp: IotaKeyPair) -> Self {
1388 let cell: OnceCell<Arc<IotaKeyPair>> = OnceCell::new();
1389 let arc_kp = Arc::new(kp);
1390 cell.set(arc_kp.clone()).expect("failed to set keypair");
1393 Self {
1394 location: KeyPairLocation::InPlace { value: arc_kp },
1395 keypair: cell,
1396 }
1397 }
1398
1399 pub fn new_from_path(path: PathBuf) -> Self {
1400 let cell: OnceCell<Arc<IotaKeyPair>> = OnceCell::new();
1401 cell.set(Arc::new(read_keypair_from_file(&path).unwrap_or_else(
1404 |e| panic!("invalid keypair file at path {path:?}: {e}"),
1405 )))
1406 .expect("failed to set keypair");
1407 Self {
1408 location: KeyPairLocation::File { path },
1409 keypair: cell,
1410 }
1411 }
1412
1413 pub fn keypair(&self) -> &IotaKeyPair {
1414 self.keypair
1415 .get_or_init(|| match &self.location {
1416 KeyPairLocation::InPlace { value } => value.clone(),
1417 KeyPairLocation::File { path } => {
1418 Arc::new(
1421 read_keypair_from_file(path).unwrap_or_else(|e| {
1422 panic!("invalid keypair file at path {path:?}: {e}")
1423 }),
1424 )
1425 }
1426 })
1427 .as_ref()
1428 }
1429}
1430
1431#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
1434pub struct AuthorityKeyPairWithPath {
1435 #[serde(flatten)]
1436 location: AuthorityKeyPairLocation,
1437
1438 #[serde(skip)]
1439 keypair: OnceCell<Arc<AuthorityKeyPair>>,
1440}
1441
1442#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq)]
1443#[serde(untagged)]
1444enum AuthorityKeyPairLocation {
1445 InPlace { value: Arc<AuthorityKeyPair> },
1446 File { path: PathBuf },
1447}
1448
1449impl AuthorityKeyPairWithPath {
1450 pub fn new(kp: AuthorityKeyPair) -> Self {
1451 let cell: OnceCell<Arc<AuthorityKeyPair>> = OnceCell::new();
1452 let arc_kp = Arc::new(kp);
1453 cell.set(arc_kp.clone())
1456 .expect("failed to set authority keypair");
1457 Self {
1458 location: AuthorityKeyPairLocation::InPlace { value: arc_kp },
1459 keypair: cell,
1460 }
1461 }
1462
1463 pub fn new_from_path(path: PathBuf) -> Self {
1464 let cell: OnceCell<Arc<AuthorityKeyPair>> = OnceCell::new();
1465 cell.set(Arc::new(
1468 read_authority_keypair_from_file(&path)
1469 .unwrap_or_else(|_| panic!("invalid authority keypair file at path {path:?}")),
1470 ))
1471 .expect("failed to set authority keypair");
1472 Self {
1473 location: AuthorityKeyPairLocation::File { path },
1474 keypair: cell,
1475 }
1476 }
1477
1478 pub fn authority_keypair(&self) -> &AuthorityKeyPair {
1479 self.keypair
1480 .get_or_init(|| match &self.location {
1481 AuthorityKeyPairLocation::InPlace { value } => value.clone(),
1482 AuthorityKeyPairLocation::File { path } => {
1483 Arc::new(
1486 read_authority_keypair_from_file(path)
1487 .unwrap_or_else(|_| panic!("invalid authority keypair file {path:?}")),
1488 )
1489 }
1490 })
1491 .as_ref()
1492 }
1493}
1494
1495#[derive(Clone, Debug, Deserialize, Serialize, Default)]
1498#[serde(rename_all = "kebab-case")]
1499pub struct StateDebugDumpConfig {
1500 #[serde(skip_serializing_if = "Option::is_none")]
1501 pub dump_file_directory: Option<PathBuf>,
1502}
1503
1504#[cfg(test)]
1505mod tests {
1506 use std::path::PathBuf;
1507
1508 use fastcrypto::traits::KeyPair;
1509 use iota_keys::keypair_file::{write_authority_keypair_to_file, write_keypair_to_file};
1510 use iota_types::crypto::{
1511 AuthorityKeyPair, IotaKeyPair, NetworkKeyPair, get_key_pair_from_rng,
1512 };
1513 use rand::{SeedableRng, rngs::StdRng};
1514
1515 use super::Genesis;
1516 use crate::NodeConfig;
1517
1518 #[test]
1519 fn serialize_genesis_from_file() {
1520 let g = Genesis::new_from_file("path/to/file");
1521
1522 let s = serde_yaml::to_string(&g).unwrap();
1523 assert_eq!("---\ngenesis-file-location: path/to/file\n", s);
1524 let loaded_genesis: Genesis = serde_yaml::from_str(&s).unwrap();
1525 assert_eq!(g, loaded_genesis);
1526 }
1527
1528 #[test]
1529 fn fullnode_template() {
1530 const TEMPLATE: &str = include_str!("../data/fullnode-template.yaml");
1531
1532 let _template: NodeConfig = serde_yaml::from_str(TEMPLATE).unwrap();
1533 }
1534
1535 #[test]
1536 fn enable_soft_locking_defaults_to_enabled() {
1537 const TEMPLATE: &str = include_str!("../data/fullnode-template.yaml");
1540
1541 let config: NodeConfig = serde_yaml::from_str(TEMPLATE).unwrap();
1542 assert!(config.enable_soft_locking);
1543 }
1544
1545 #[test]
1546 fn load_key_pairs_to_node_config() {
1547 let authority_key_pair: AuthorityKeyPair =
1548 get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1;
1549 let protocol_key_pair: NetworkKeyPair =
1550 get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1;
1551 let network_key_pair: NetworkKeyPair =
1552 get_key_pair_from_rng(&mut StdRng::from_seed([0; 32])).1;
1553
1554 write_authority_keypair_to_file(&authority_key_pair, PathBuf::from("authority.key"))
1555 .unwrap();
1556 write_keypair_to_file(
1557 &IotaKeyPair::Ed25519(protocol_key_pair.copy()),
1558 PathBuf::from("protocol.key"),
1559 )
1560 .unwrap();
1561 write_keypair_to_file(
1562 &IotaKeyPair::Ed25519(network_key_pair.copy()),
1563 PathBuf::from("network.key"),
1564 )
1565 .unwrap();
1566
1567 const TEMPLATE: &str = include_str!("../data/fullnode-template-with-path.yaml");
1568 let template: NodeConfig = serde_yaml::from_str(TEMPLATE).unwrap();
1569 assert_eq!(
1570 template.authority_key_pair().public(),
1571 authority_key_pair.public()
1572 );
1573 assert_eq!(
1574 template.network_key_pair().public(),
1575 network_key_pair.public()
1576 );
1577 assert_eq!(
1578 template.protocol_key_pair().public(),
1579 protocol_key_pair.public()
1580 );
1581 }
1582}
1583
1584#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)]
1588pub enum RunWithRange {
1589 Epoch(EpochId),
1590 Checkpoint(CheckpointSequenceNumber),
1591}
1592
1593impl RunWithRange {
1594 pub fn is_epoch_gt(&self, epoch_id: EpochId) -> bool {
1596 matches!(self, RunWithRange::Epoch(e) if epoch_id > *e)
1597 }
1598
1599 pub fn matches_checkpoint(&self, seq_num: CheckpointSequenceNumber) -> bool {
1600 matches!(self, RunWithRange::Checkpoint(seq) if *seq == seq_num)
1601 }
1602
1603 pub fn into_checkpoint_bound(self) -> Option<CheckpointSequenceNumber> {
1604 match self {
1605 RunWithRange::Epoch(_) => None,
1606 RunWithRange::Checkpoint(seq) => Some(seq),
1607 }
1608 }
1609}
1610
1611mod bech32_formatted_keypair {
1615 use std::ops::Deref;
1616
1617 use iota_types::crypto::{EncodeDecodeBase64, IotaKeyPair};
1618 use serde::{Deserialize, Deserializer, Serializer};
1619
1620 pub fn serialize<S, T>(kp: &T, serializer: S) -> Result<S::Ok, S::Error>
1621 where
1622 S: Serializer,
1623 T: Deref<Target = IotaKeyPair>,
1624 {
1625 use serde::ser::Error;
1626
1627 let s = kp.encode().map_err(Error::custom)?;
1629
1630 serializer.serialize_str(&s)
1631 }
1632
1633 pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
1634 where
1635 D: Deserializer<'de>,
1636 T: From<IotaKeyPair>,
1637 {
1638 use serde::de::Error;
1639
1640 let s = String::deserialize(deserializer)?;
1641
1642 IotaKeyPair::decode(&s)
1644 .or_else(|_| {
1645 IotaKeyPair::decode_base64(&s)
1647 })
1648 .map(Into::into)
1649 .map_err(Error::custom)
1650 }
1651}