1use std::{
6 collections::{BTreeSet, HashMap},
7 fmt,
8 future::Future,
9 num::NonZeroUsize,
10 sync::{
11 Arc, Weak,
12 atomic::{AtomicBool, Ordering},
13 },
14 time::Duration,
15};
16
17use anemo::Network;
18use anemo_tower::{
19 callback::CallbackLayer,
20 trace::{DefaultMakeSpan, DefaultOnFailure, TraceLayer},
21};
22use anyhow::{Result, anyhow};
23use arc_swap::ArcSwap;
24use futures::future::BoxFuture;
25pub use handle::IotaNodeHandle;
26use iota_common::{debug_fatal, fatal};
27use iota_config::{
28 ConsensusConfig, NodeConfig, node::RunWithRange, node_config_metrics::NodeConfigMetrics,
29};
30use iota_core::{
31 authority::{
32 AuthorityState, AuthorityStore, ExecutionEnv, RandomnessRoundReceiver,
33 authority_per_epoch_store::AuthorityPerEpochStore,
34 authority_store_tables::{AuthorityPerpetualTables, AuthorityPerpetualTablesOptions},
35 backpressure::BackpressureManager,
36 epoch_start_configuration::{EpochFlag, EpochStartConfigTrait, EpochStartConfiguration},
37 ledger_backlog_migration, object_backlog_sweep,
38 shared_object_version_manager::Schedulable,
39 },
40 authority_aggregator::{
41 AggregatorSendCapabilityNotificationError, AuthAggMetrics, AuthorityAggregator,
42 },
43 authority_client::NetworkAuthorityClient,
44 authority_server::{
45 ValidatorService, ValidatorServiceMetrics, soft_lock::PreConsensusSoftLocks,
46 },
47 checkpoint_progress_tracker::CheckpointProgressTracker,
48 checkpoints::{
49 CheckpointMetrics, CheckpointService, CheckpointStore, FullCheckpointContentsCache,
50 FullCheckpointContentsCacheMetrics, SendCheckpointToStateSync, SubmitCheckpointToConsensus,
51 checkpoint_executor::{CheckpointExecutor, StopReason, metrics::CheckpointExecutorMetrics},
52 },
53 connection_monitor::ConnectionMonitor,
54 consensus_adapter::{
55 CheckConnection, ConnectionMonitorStatus, ConsensusAdapter, ConsensusAdapterMetrics,
56 ConsensusClient,
57 },
58 consensus_handler::ConsensusHandlerInitializer,
59 consensus_manager::{ConsensusManager, ConsensusManagerTrait, UpdatableConsensusClient},
60 consensus_validator::{IotaTxValidator, IotaTxValidatorMetrics},
61 epoch::{
62 committee_store::CommitteeStore, consensus_store_pruner::ConsensusStorePruner,
63 epoch_metrics::EpochMetrics, randomness::RandomnessManager,
64 reconfiguration::ReconfigurationInitiator,
65 },
66 epoch_buckets::HISTORIC_DB_DIR,
67 epoch_end_db_snapshot::{EpochEndDbSnapshotHandle, EpochEndDbSnapshotRequest},
68 execution_cache::build_execution_cache,
69 execution_scheduler::ExecutionSchedulerAPI,
70 global_state_hasher::{GlobalStateHashMetrics, GlobalStateHasher},
71 module_cache_metrics::ResolverMetrics,
72 overload_monitor::{consensus_queue_overload_monitor, overload_monitor},
73 rpc_indexes::{
74 RpcIndexesStore, legacy_index_dirs_size, remove_legacy_index_dirs,
75 schema::{IndexGroup, RPC_INDEXES_DIR},
76 },
77 safe_client::SafeClientMetricsBase,
78 signature_verifier::SignatureVerifierMetrics,
79 storage::{GrpcReadStore, RocksDbStore},
80 transaction_orchestrator::TransactionOrchestrator,
81 validator_tx_finalizer::ValidatorTxFinalizer,
82};
83use iota_grpc_server::{GrpcReader, GrpcServerHandle, start_grpc_server};
84use iota_http::metrics::ListenerMetrics;
85use iota_json_rpc::{
86 JsonRpcServerBuilder, coin_api::CoinReadApi, governance_api::GovernanceReadApi,
87 indexer_api::IndexerApi, move_utils::MoveUtils, read_api::ReadApi,
88 transaction_builder_api::TransactionBuilderApi,
89 transaction_execution_api::TransactionExecutionApi,
90};
91use iota_json_rpc_api::JsonRpcMetrics;
92use iota_macros::{fail_point, fail_point_async, replay_log};
93use iota_metrics::{
94 RegistryID, RegistryService,
95 metrics_network::{MetricsMakeCallbackHandler, NetworkConnectionMetrics, NetworkMetrics},
96 server_timing_middleware, spawn_monitored_task,
97};
98use iota_names::config::IotaNamesConfig;
99use iota_network::{
100 api::{ValidatorPeerServer, ValidatorServer, ValidatorV2Server},
101 discovery,
102 discovery::TrustedPeerChangeEvent,
103 randomness, state_sync,
104};
105use iota_network_stack::server::{IOTA_TLS_SERVER_NAME, ServerBuilder};
106use iota_node_transaction_builder::NodeTransactionBuilderLedgerClient;
107use iota_protocol_config::{ProtocolConfig, ProtocolVersion};
108use iota_sdk_types::{
109 RandomnessRound,
110 crypto::{Intent, IntentMessage, IntentScope},
111};
112use iota_snapshot::uploader::StateSnapshotUploader;
113use iota_storage::{
114 http_key_value_store::HttpKVStore,
115 key_value_store::{FallbackTransactionKVStore, TransactionKeyValueStore},
116 key_value_store_metrics::KeyValueStoreMetrics,
117};
118use iota_types::{
119 base_types::{AuthorityName, ConciseableName, EpochId},
120 committee::Committee,
121 crypto::{AuthoritySignature, IotaAuthoritySignature, KeypairTraits},
122 digests::ChainIdentifier,
123 error::{IotaError, IotaResult},
124 executable_transaction::VerifiedExecutableTransaction,
125 full_checkpoint_content::CheckpointData,
126 iota_system_state::{
127 IotaSystemState, IotaSystemStateTrait,
128 epoch_start_iota_system_state::{EpochStartSystemState, EpochStartSystemStateTrait},
129 },
130 messages_checkpoint::CheckpointSummaryExt,
131 messages_consensus::{
132 AuthorityCapabilitiesV1, ConsensusTransaction, ConsensusTransactionKind,
133 SignedAuthorityCapabilitiesV1, TransactionDenyRuleProposal,
134 },
135 messages_grpc::HandleCapabilityNotificationRequestV1,
136 quorum_driver_types::QuorumDriverEffectsQueueResult,
137 supported_protocol_versions::SupportedProtocolVersions,
138 transaction::{SenderSignedTransactionAPI, TransactionEnvelope, VerifiedCertificate},
139};
140use prometheus_filtered::{MetricLevel, Registry};
141#[cfg(msim)]
142use simulator::*;
143use tap::tap::TapFallible;
144use tokio::{
145 sync::{Mutex, broadcast, mpsc, watch},
146 task::{JoinHandle, JoinSet},
147};
148use tokio_util::sync::CancellationToken;
149use tower::ServiceBuilder;
150use tracing::{Instrument, debug, error, error_span, info, trace_span, warn};
151use typed_store::{
152 DBMetrics,
153 rocks::{check_and_mark_db_corruption, default_db_options, unmark_db_corruption},
154};
155
156use crate::metrics::{GrpcMetrics, IotaNodeMetrics};
157
158pub mod admin;
159mod handle;
160pub mod metrics;
161
162pub struct ValidatorComponents {
163 validator_server_handle: SpawnOnce,
164 validator_overload_monitor_handle: Option<JoinHandle<()>>,
165 consensus_queue_overload_monitor_handle: Option<JoinHandle<()>>,
170 soft_lock_sweep_handle: JoinHandle<()>,
173 overload_notifier_handle: Option<JoinHandle<()>>,
174 consensus_manager: Arc<ConsensusManager>,
175 consensus_store_pruner: ConsensusStorePruner,
176 consensus_adapter: Arc<ConsensusAdapter>,
177 soft_locks: Arc<PreConsensusSoftLocks>,
178 checkpoint_service_tasks: JoinSet<()>,
180 checkpoint_metrics: Arc<CheckpointMetrics>,
181 iota_tx_validator_metrics: Arc<IotaTxValidatorMetrics>,
182 validator_registry_id: RegistryID,
183}
184
185#[cfg(msim)]
186mod simulator {
187 use std::sync::atomic::AtomicBool;
188
189 pub(super) struct SimState {
190 pub sim_node: iota_simulator::runtime::NodeHandle,
191 pub sim_safe_mode_expected: AtomicBool,
192 _leak_detector: iota_simulator::NodeLeakDetector,
193 }
194
195 impl Default for SimState {
196 fn default() -> Self {
197 Self {
198 sim_node: iota_simulator::runtime::NodeHandle::current(),
199 sim_safe_mode_expected: AtomicBool::new(false),
200 _leak_detector: iota_simulator::NodeLeakDetector::new(),
201 }
202 }
203 }
204}
205
206#[derive(Clone)]
207pub struct ServerVersion {
208 pub bin: &'static str,
209 pub version: &'static str,
210}
211
212impl ServerVersion {
213 pub fn new(bin: &'static str, version: &'static str) -> Self {
214 Self { bin, version }
215 }
216}
217
218impl std::fmt::Display for ServerVersion {
219 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
220 f.write_str(self.bin)?;
221 f.write_str("/")?;
222 f.write_str(self.version)
223 }
224}
225
226pub struct IotaNode {
227 config: NodeConfig,
228 validator_components: Mutex<Option<ValidatorComponents>>,
229 _http_server: Option<iota_http::ServerHandle>,
231 state: Arc<AuthorityState>,
232 transaction_orchestrator: Option<Arc<TransactionOrchestrator<NetworkAuthorityClient>>>,
233 registry_service: RegistryService,
234 metrics: Arc<IotaNodeMetrics>,
235
236 _discovery: discovery::Handle,
237 state_sync_handle: state_sync::Handle,
238 randomness_handle: randomness::Handle,
239 sync_summaries_to_epoch_end: Arc<AtomicBool>,
242 checkpoint_store: Arc<CheckpointStore>,
243 state_sync_store: RocksDbStore,
244 global_state_hasher: Mutex<Option<Arc<GlobalStateHasher>>>,
245 connection_monitor_status: Arc<ConnectionMonitorStatus>,
246
247 end_of_epoch_channel: broadcast::Sender<IotaSystemState>,
249
250 trusted_peer_change_tx: watch::Sender<TrustedPeerChangeEvent>,
253
254 backpressure_manager: Arc<BackpressureManager>,
255
256 checkpoint_progress_tracker: Arc<CheckpointProgressTracker>,
257
258 #[cfg(msim)]
259 sim_state: SimState,
260
261 _state_snapshot_uploader_handle: Option<broadcast::Sender<()>>,
262 shutdown_channel_tx: broadcast::Sender<Option<RunWithRange>>,
264
265 grpc_server_handle: Mutex<Option<GrpcServerHandle>>,
267
268 auth_agg: Arc<ArcSwap<AuthorityAggregator<NetworkAuthorityClient>>>,
274
275 serving_rt_handle: tokio::runtime::Handle,
278}
279
280impl fmt::Debug for IotaNode {
281 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
282 f.debug_struct("IotaNode")
283 .field("name", &self.state.name.concise())
284 .finish()
285 }
286}
287
288fn remove_legacy_db_checkpoints(config: &NodeConfig) {
292 let path = config.db_path.join("db_checkpoints");
293 if !path.exists() {
294 return;
295 }
296 match std::fs::remove_dir_all(&path) {
297 Ok(()) => info!(
298 "removed {}, the database checkpoint directory of an earlier release",
299 path.display()
300 ),
301 Err(e) => warn!(
303 "failed to remove the leftover database checkpoint directory {}: {e}",
304 path.display()
305 ),
306 }
307}
308
309impl IotaNode {
310 pub async fn start(
321 config: NodeConfig,
322 registry_service: RegistryService,
323 ) -> Result<Arc<IotaNode>> {
324 Self::start_async(
325 config,
326 registry_service,
327 ServerVersion::new("iota-node", "unknown"),
328 tokio::runtime::Handle::current(),
329 Arc::default(),
330 )
331 .await
332 }
333
334 fn start_overload_notifier(
339 config: &NodeConfig,
340 state: Arc<AuthorityState>,
341 epoch_store: Arc<AuthorityPerEpochStore>,
342 consensus_adapter: Arc<ConsensusAdapter>,
343 ) -> Option<JoinHandle<()>> {
344 if !epoch_store.protocol_config().enable_pcool_flow() {
345 return None;
346 }
347
348 let poll_interval = config.authority_overload_config.overload_monitor_interval;
349 let authority_name = state.name;
350
351 Some(spawn_monitored_task!(async move {
352 let mut last_notified_percentage: u32 = epoch_store
354 .load_overload_notification(&authority_name)
355 .unwrap_or(0) as u32;
356 loop {
357 tokio::time::sleep(poll_interval).await;
358 let current = state
359 .overload_info
360 .local_load_shedding_percentage
361 .load(std::sync::atomic::Ordering::Relaxed);
362 if current != last_notified_percentage {
363 last_notified_percentage = current;
364 let transaction = ConsensusTransaction::new_overload_notification_v1(
365 authority_name,
366 current as u8,
367 );
368 if let Err(e) = consensus_adapter.submit(transaction, None, &epoch_store) {
369 tracing::warn!(
370 "Failed to submit overload notification to consensus: {:?}",
371 e
372 );
373 }
374 }
375 }
376 }))
377 }
378
379 pub async fn start_async(
382 mut config: NodeConfig,
383 registry_service: RegistryService,
384 server_version: ServerVersion,
385 serving_rt_handle: tokio::runtime::Handle,
386 index_rebuild_cancelled: Arc<AtomicBool>,
387 ) -> Result<Arc<IotaNode>> {
388 config.check_renamed_keys()?;
389 config.validate()?;
390 if config.maintains_rpc_indexes() {
391 config
392 .authority_store_pruning_config
393 .check_index_retention_within_ledger()?;
394 }
395 NodeConfigMetrics::new(®istry_service.default_registry()).record_metrics(&config);
396 if config.supported_protocol_versions.is_none() {
397 info!(
398 "populating config.supported_protocol_versions with default {:?}",
399 SupportedProtocolVersions::SYSTEM_DEFAULT
400 );
401 config.supported_protocol_versions = Some(SupportedProtocolVersions::SYSTEM_DEFAULT);
402 }
403
404 let run_with_range = config.run_with_range;
405 let is_validator = config.is_validator();
406 let is_full_node = !is_validator;
407 let prometheus_registry = registry_service.default_registry();
408
409 info!(node =? config.authority_public_key(),
410 "Initializing iota-node listening on {}", config.network_address
411 );
412
413 let genesis = config.genesis()?.clone();
414
415 let chain_identifier = ChainIdentifier::from(*genesis.checkpoint().digest());
416 info!("IOTA chain identifier: {chain_identifier}");
417
418 let db_corrupted_path = &config.db_path().join("status");
420 if let Err(err) = check_and_mark_db_corruption(db_corrupted_path) {
421 panic!("Failed to check database corruption: {err}");
422 }
423
424 DBMetrics::init(&prometheus_registry);
426
427 iota_metrics::init_metrics(&prometheus_registry);
429 #[cfg(not(msim))]
432 iota_metrics::thread_stall_monitor::start_thread_stall_monitor();
433
434 #[cfg(not(msim))]
438 {
439 let runtime_monitor_metrics =
440 iota_metrics::runtime_metrics::RuntimeMonitorMetrics::new(&prometheus_registry);
441 iota_metrics::runtime_metrics::start_runtime_monitor(
442 "iota_node",
443 &tokio::runtime::Handle::current(),
444 runtime_monitor_metrics.clone(),
445 );
446 iota_metrics::runtime_metrics::start_runtime_monitor(
447 "serving",
448 &serving_rt_handle,
449 runtime_monitor_metrics,
450 );
451 }
452
453 prometheus_registry
455 .register(iota_metrics::uptime_metric(
456 if is_validator {
457 "validator"
458 } else {
459 "fullnode"
460 },
461 server_version.version,
462 &chain_identifier.to_string(),
463 ))
464 .expect("Failed registering uptime metric");
465
466 remove_legacy_db_checkpoints(&config);
467
468 let secret = Arc::pin(config.authority_key_pair().copy());
469 let genesis_committee = genesis.committee()?;
470 let committee_store = Arc::new(CommitteeStore::new(
471 config.db_path().join("epochs"),
472 &genesis_committee,
473 None,
474 ));
475
476 let historic_db_path = config.db_path().join(HISTORIC_DB_DIR);
477
478 let enable_write_stall = config.enable_db_write_stall.unwrap_or(is_validator);
480 let perpetual_tables_options = AuthorityPerpetualTablesOptions {
481 enable_write_stall,
482 historic_db_path: Some(historic_db_path.clone()),
483 };
484 let (perpetual_tables, historic_objects, historic_ledger, epoch_markers) =
485 AuthorityPerpetualTables::open_with_historic_objects(
486 &config.db_path().join("store"),
487 Some(perpetual_tables_options),
488 )?;
489 let perpetual_tables = Arc::new(perpetual_tables);
490 let historic_objects = Arc::new(historic_objects);
491 let historic_ledger = Arc::new(historic_ledger);
492 let is_genesis = perpetual_tables
493 .database_is_empty()
494 .expect("Database read should not fail at init.");
495
496 let checkpoint_store = CheckpointStore::new_with_contents_cache(
497 &config.db_path().join("checkpoints"),
498 Some(&historic_db_path),
499 FullCheckpointContentsCache::new(
500 config
501 .full_checkpoint_contents_cache_size_mb
502 .saturating_mul(1024 * 1024),
503 FullCheckpointContentsCacheMetrics::new(&prometheus_registry),
504 ),
505 );
506
507 let genesis_checkpoint_executed = checkpoint_store
512 .get_highest_executed_checkpoint_seq_number()?
513 .is_some();
514 let migration_tx_data =
515 if genesis.contains_migrations() && (is_genesis || !genesis_checkpoint_executed) {
516 Some(config.load_migration_tx_data()?)
519 } else {
520 None
521 };
522
523 let chain = match config.chain_override_for_testing {
524 Some(chain) => chain,
525 None => chain_identifier.chain(),
526 };
527 let backpressure_manager =
528 BackpressureManager::new_from_checkpoint_store(&checkpoint_store);
529
530 let historic_objects_for_progress = historic_objects.clone();
531 let perpetual_tables_for_snapshots = perpetual_tables.clone();
532 let store = AuthorityStore::open(
533 perpetual_tables,
534 historic_objects,
535 historic_ledger,
536 Arc::new(epoch_markers),
537 &genesis,
538 &config,
539 &prometheus_registry,
540 migration_tx_data.as_ref(),
541 )
542 .await?;
543
544 let cur_epoch = store.get_recovery_epoch_at_restart()?;
545 let committee = committee_store
546 .get_committee(&cur_epoch)?
547 .expect("Committee of the current epoch must exist");
548 let epoch_start_configuration = store
549 .get_epoch_start_configuration()?
550 .expect("EpochStartConfiguration of the current epoch must exist");
551 let cache_metrics = Arc::new(ResolverMetrics::new(&prometheus_registry));
552 let signature_verifier_metrics = SignatureVerifierMetrics::new(&prometheus_registry);
553
554 let cache_traits = build_execution_cache(
555 &config.execution_cache_config,
556 &prometheus_registry,
557 &store,
558 backpressure_manager.clone(),
559 );
560
561 let auth_agg = {
562 let safe_client_metrics_base = SafeClientMetricsBase::new(&prometheus_registry);
563 let auth_agg_metrics = Arc::new(AuthAggMetrics::new(&prometheus_registry));
564 Arc::new(ArcSwap::new(Arc::new(
565 AuthorityAggregator::new_from_epoch_start_state(
566 epoch_start_configuration.epoch_start_state(),
567 &committee_store,
568 safe_client_metrics_base,
569 auth_agg_metrics,
570 ),
571 )))
572 };
573
574 let epoch_options = default_db_options().optimize_db_for_write_throughput(4);
575 let epoch_store = AuthorityPerEpochStore::new(
576 config.authority_public_key(),
577 committee.clone(),
578 &config.db_path().join("store"),
579 Some(epoch_options.options),
580 EpochMetrics::new(®istry_service.default_registry()),
581 epoch_start_configuration,
582 cache_traits.backing_package_store.clone(),
583 cache_metrics,
584 signature_verifier_metrics,
585 &config.expensive_safety_check_config,
586 (chain_identifier, chain),
587 checkpoint_store
588 .get_highest_executed_checkpoint_seq_number()
589 .expect("checkpoint store read cannot fail")
590 .unwrap_or(0),
591 )?;
592
593 info!("created epoch store");
594
595 replay_log!(
596 "Beginning replay run. Epoch: {:?}, Protocol config: {:?}",
597 epoch_store.epoch(),
598 epoch_store.protocol_config()
599 );
600
601 if is_genesis {
603 info!("checking IOTA conservation at genesis");
604 cache_traits
609 .reconfig_api
610 .try_expensive_check_iota_conservation(&epoch_store, None)
611 .expect("IOTA conservation check cannot fail at genesis");
612 }
613
614 let effective_buffer_stake = epoch_store.get_effective_buffer_stake_bps();
615 let default_buffer_stake = epoch_store
616 .protocol_config()
617 .buffer_stake_for_protocol_upgrade_bps();
618 if effective_buffer_stake != default_buffer_stake {
619 warn!(
620 ?effective_buffer_stake,
621 ?default_buffer_stake,
622 "buffer_stake_for_protocol_upgrade_bps is currently overridden"
623 );
624 }
625
626 checkpoint_store.insert_genesis_checkpoint(
627 genesis.checkpoint(),
628 genesis.checkpoint_contents().clone(),
629 &epoch_store,
630 );
631
632 unmark_db_corruption(db_corrupted_path)?;
634
635 if is_genesis {
639 store.mark_pre_bucket_passes_done()?;
640 checkpoint_store.mark_checkpoint_backlog_migrated()?;
641 }
642
643 let pruning_config = &config.authority_store_pruning_config;
647 let legacy_index_size = if is_full_node {
650 legacy_index_dirs_size(&config.db_path(), &historic_db_path)
651 } else {
652 0
653 };
654 ledger_backlog_migration::check_before_first_start(
655 &store,
656 checkpoint_store.clone(),
657 epoch_store.epoch(),
658 pruning_config.num_epochs_to_retain_for_checkpoints,
659 pruning_config.num_epochs_to_retain_for_checkpoints(),
660 legacy_index_size,
661 )
662 .map_err(|e| anyhow!("refusing to start: {e}"))?;
663
664 store.retire_objects_pruner_watermark()?;
667
668 if is_full_node {
672 if let Err(e) = remove_legacy_index_dirs(&config.db_path()) {
673 if legacy_index_size > 0 {
674 return Err(anyhow!(
675 "refusing to start: failed to remove a legacy index database in {}, \
676 whose space the ledger migration needs: {e}. Remove the `indexes`, \
677 `jsonrpc_indexes` and `grpc_indexes` directories there by hand",
678 config.db_path().display()
679 ));
680 }
681 warn!("failed to remove a legacy index database: {e}");
682 }
683 }
684
685 ledger_backlog_migration::migrate(
688 store.clone(),
689 checkpoint_store.clone(),
690 epoch_store.epoch(),
691 pruning_config.num_epochs_to_retain_for_checkpoints(),
692 )
693 .await
694 .map_err(|e| {
695 anyhow!(
696 "failed to migrate the ledger and checkpoint history written before this build: {e}"
697 )
698 })?;
699
700 store
704 .migrate_flat_markers(epoch_store.epoch())
705 .map_err(|e| {
706 anyhow!("failed to migrate the object markers written before this build: {e}")
707 })?;
708
709 object_backlog_sweep::sweep(store.clone(), epoch_store.epoch())
713 .await
714 .map_err(|e| {
715 anyhow!(
716 "failed to sweep the object versions superseded before this build: {e}. If it \
717 fails on a row it cannot read every time, `iota-tool db-tool --db-path {} \
718 mark-object-backlog-swept`, with the node stopped, lets it start without \
719 the sweep; the versions it had not reached then stay in the live object \
720 table",
721 config.db_path().display()
722 )
723 })?;
724
725 if epoch_store.protocol_config().enable_pcool_flow()
729 && epoch_store
730 .committee()
731 .authority_exists(&config.authority_public_key())
732 {
733 checkpoint_store
734 .hold_synced_watermark_in_memory(store.get_historic_ledger().clone())?;
735 }
736
737 info!("creating state sync store");
738 let state_sync_store = RocksDbStore::new(
739 cache_traits.clone(),
740 committee_store.clone(),
741 checkpoint_store.clone(),
742 );
743
744 let mut index_groups = BTreeSet::new();
745 if is_full_node && config.enable_jsonrpc_api {
746 index_groups.insert(IndexGroup::JsonRpc);
747 }
748 if is_full_node && config.enable_grpc_api {
749 index_groups.insert(IndexGroup::Grpc);
750 }
751 let rpc_indexes_store = if index_groups.is_empty() {
752 None
753 } else {
754 info!("creating index store");
755 let epochs_to_retain = config
756 .authority_store_pruning_config
757 .num_epochs_to_retain_for_indexes();
758 if epochs_to_retain.is_none() {
759 warn!(
760 "index pruning is off: the history index backing iotax_queryTransactionBlocks() and iotax_queryEvents() adds a column family per epoch and grows without bound. Set num-epochs-to-retain-for-checkpoints, which num-epochs-to-retain-for-indexes follows, or num-epochs-to-retain-for-indexes itself"
761 );
762 }
763 Some(
764 RpcIndexesStore::new(
765 config.db_path().join(RPC_INDEXES_DIR),
766 Some(&historic_db_path),
767 &prometheus_registry,
768 index_groups,
769 epoch_store
770 .protocol_config()
771 .max_move_identifier_len_as_option(),
772 epochs_to_retain,
773 &store,
774 &checkpoint_store,
775 index_rebuild_cancelled,
776 )
777 .await?,
778 )
779 };
780
781 checkpoint_store
783 .seed_epoch_info(&store, chain_identifier)
784 .expect("failed to seed the epoch_info chain");
785
786 info!("creating archive reader");
787 let (trusted_peer_change_tx, trusted_peer_change_rx) = watch::channel(Default::default());
792 let (randomness_tx, randomness_rx) = mpsc::channel(
793 config
794 .p2p_config
795 .randomness
796 .clone()
797 .unwrap_or_default()
798 .mailbox_capacity(),
799 );
800 let sync_summaries_to_epoch_end = Arc::new(AtomicBool::new(
801 Self::sync_summaries_to_epoch_end(&config, &epoch_store),
802 ));
803 let (p2p_network, discovery_handle, state_sync_handle, randomness_handle) =
804 Self::create_p2p_network(
805 &config,
806 state_sync_store.clone(),
807 chain_identifier,
808 trusted_peer_change_rx,
809 randomness_tx,
810 sync_summaries_to_epoch_end.clone(),
811 &prometheus_registry,
812 )?;
813
814 send_trusted_peer_change(
817 &config,
818 &trusted_peer_change_tx,
819 epoch_store.epoch_start_state(),
820 );
821
822 info!("start snapshot upload");
823 let (state_snapshot_requests, state_snapshot_receiver) = mpsc::channel(1);
828 let state_snapshot_handle = Self::start_state_snapshot(
829 &config,
830 &prometheus_registry,
831 checkpoint_store.clone(),
832 perpetual_tables_for_snapshots,
833 state_snapshot_receiver,
834 )?;
835 let epoch_end_db_snapshots = state_snapshot_handle
836 .is_some()
837 .then(|| EpochEndDbSnapshotHandle::new(state_snapshot_requests));
838
839 let checkpoint_progress_tracker = Arc::new(CheckpointProgressTracker::new());
840
841 let authority_name = config.authority_public_key();
842 let validator_tx_finalizer =
843 config
844 .enable_validator_tx_finalizer
845 .then_some(Arc::new(ValidatorTxFinalizer::new(
846 auth_agg.clone(),
847 authority_name,
848 &prometheus_registry,
849 )));
850
851 info!("create authority state");
852 let state = AuthorityState::new(
853 authority_name,
854 secret,
855 config.supported_protocol_versions.unwrap(),
856 store.clone(),
857 cache_traits.clone(),
858 epoch_store.clone(),
859 committee_store.clone(),
860 rpc_indexes_store,
861 checkpoint_store.clone(),
862 &prometheus_registry,
863 config.clone(),
864 validator_tx_finalizer,
865 chain_identifier,
866 config.policy_config.clone(),
867 epoch_end_db_snapshots,
868 )
869 .await;
870
871 if epoch_store.epoch() == 0 {
873 let genesis_tx = &genesis.transaction();
874 let span = error_span!("genesis_txn", tx_digest = ?genesis_tx.digest());
875 Self::execute_transaction_immediately_at_zero_epoch(
877 &state,
878 &epoch_store,
879 genesis_tx,
880 span,
881 )
882 .await;
883
884 if let Some(migration_tx_data) = migration_tx_data {
886 for (tx_digest, (tx, _, _)) in migration_tx_data.txs_data() {
887 let span = error_span!("migration_txn", tx_digest = ?tx_digest);
888 Self::execute_transaction_immediately_at_zero_epoch(
889 &state,
890 &epoch_store,
891 tx,
892 span,
893 )
894 .await;
895 }
896 }
897 }
898
899 RandomnessRoundReceiver::spawn(state.clone(), randomness_rx);
902
903 let (end_of_epoch_channel, end_of_epoch_receiver) =
904 broadcast::channel(config.end_of_epoch_broadcast_channel_capacity);
905
906 let transaction_orchestrator = if is_full_node && run_with_range.is_none() {
907 Some(Arc::new(TransactionOrchestrator::new_with_auth_aggregator(
908 auth_agg.load_full(),
909 state.clone(),
910 end_of_epoch_receiver,
911 &config.db_path(),
912 &prometheus_registry,
913 Some(&config),
914 )))
915 } else {
916 None
917 };
918
919 let http_server = serving_rt_handle
923 .spawn({
924 let state = state.clone();
925 let transaction_orchestrator = transaction_orchestrator.clone();
926 let config = config.clone();
927 let prometheus_registry = prometheus_registry.clone();
928 async move {
929 build_http_server(
930 state,
931 &transaction_orchestrator,
932 &config,
933 &prometheus_registry,
934 )
935 .await
936 }
937 })
938 .await
939 .expect("Failed to join JSON-RPC server startup task")?;
940
941 let global_state_hasher = Arc::new(GlobalStateHasher::new(
942 cache_traits.global_state_hash_store.clone(),
943 GlobalStateHashMetrics::new(&prometheus_registry),
944 ));
945
946 let authority_names_to_peer_ids = epoch_store
947 .epoch_start_state()
948 .get_authority_names_to_peer_ids();
949
950 let network_connection_metrics =
951 NetworkConnectionMetrics::new("iota", ®istry_service.default_registry());
952
953 let authority_names_to_peer_ids = ArcSwap::from_pointee(authority_names_to_peer_ids);
954
955 let (_connection_monitor_handle, connection_statuses) = ConnectionMonitor::spawn(
956 p2p_network.downgrade(),
957 network_connection_metrics,
958 HashMap::new(),
959 None,
960 );
961
962 let connection_monitor_status = ConnectionMonitorStatus {
963 connection_statuses,
964 authority_names_to_peer_ids,
965 };
966
967 let connection_monitor_status = Arc::new(connection_monitor_status);
968 let iota_node_metrics =
969 Arc::new(IotaNodeMetrics::new(®istry_service.default_registry()));
970
971 iota_node_metrics
972 .binary_max_protocol_version
973 .set(ProtocolVersion::MAX.as_u64() as i64);
974 iota_node_metrics
975 .configured_max_protocol_version
976 .set(config.supported_protocol_versions.unwrap().max.as_u64() as i64);
977
978 let executor: Option<Arc<dyn iota_types::transaction_executor::TransactionExecutor>> =
982 transaction_orchestrator
983 .clone()
984 .map(|o| o as Arc<dyn iota_types::transaction_executor::TransactionExecutor>);
985
986 let grpc_server_handle = serving_rt_handle
989 .spawn({
990 let config = config.clone();
991 let state = state.clone();
992 let state_sync_store = state_sync_store.clone();
993 let prometheus_registry = prometheus_registry.clone();
994 async move {
995 build_grpc_server(
996 &config,
997 state,
998 state_sync_store,
999 executor,
1000 &prometheus_registry,
1001 server_version,
1002 )
1003 .await
1004 }
1005 })
1006 .await
1007 .expect("Failed to join gRPC server startup task")?;
1008
1009 let validator_components = if state.is_committee_validator(&epoch_store) {
1010 let (components, _) = futures::join!(
1011 Self::construct_validator_components(
1012 config.clone(),
1013 state.clone(),
1014 committee,
1015 epoch_store.clone(),
1016 checkpoint_store.clone(),
1017 state_sync_handle.clone(),
1018 randomness_handle.clone(),
1019 Arc::downgrade(&global_state_hasher),
1020 backpressure_manager.clone(),
1021 connection_monitor_status.clone(),
1022 ®istry_service,
1023 serving_rt_handle.clone(),
1024 ),
1025 Self::reexecute_pending_consensus_certs(&epoch_store, &state,)
1026 );
1027 let mut components = components?;
1028
1029 components.consensus_adapter.submit_recovered(&epoch_store);
1030
1031 components.validator_server_handle = components.validator_server_handle.start().await;
1033
1034 Some(components)
1035 } else {
1036 None
1037 };
1038
1039 let (shutdown_channel, _) = broadcast::channel::<Option<RunWithRange>>(1);
1041
1042 let node = Self {
1043 config,
1044 validator_components: Mutex::new(validator_components),
1045 _http_server: http_server,
1046 state,
1047 transaction_orchestrator,
1048 registry_service,
1049 metrics: iota_node_metrics,
1050
1051 _discovery: discovery_handle,
1052 state_sync_handle,
1053 randomness_handle,
1054 sync_summaries_to_epoch_end,
1055 checkpoint_store,
1056 state_sync_store,
1057 global_state_hasher: Mutex::new(Some(global_state_hasher)),
1058 end_of_epoch_channel,
1059 connection_monitor_status,
1060 trusted_peer_change_tx,
1061 backpressure_manager,
1062 checkpoint_progress_tracker: checkpoint_progress_tracker.clone(),
1063
1064 #[cfg(msim)]
1065 sim_state: Default::default(),
1066
1067 _state_snapshot_uploader_handle: state_snapshot_handle,
1068 shutdown_channel_tx: shutdown_channel,
1069
1070 grpc_server_handle: Mutex::new(grpc_server_handle),
1071
1072 auth_agg,
1073
1074 serving_rt_handle,
1075 };
1076
1077 info!("IotaNode started!");
1078 let node = Arc::new(node);
1079 let node_copy = node.clone();
1080 spawn_monitored_task!(async move {
1081 let result = Self::monitor_reconfiguration(node_copy, epoch_store).await;
1082 if let Err(error) = result {
1083 warn!("Reconfiguration finished with error {:?}", error);
1084 }
1085 });
1086
1087 node.checkpoint_progress_tracker
1088 .spawn_logging_task(node.checkpoint_store.clone(), historic_objects_for_progress);
1089
1090 Ok(node)
1091 }
1092
1093 pub fn subscribe_to_epoch_change(&self) -> broadcast::Receiver<IotaSystemState> {
1094 self.end_of_epoch_channel.subscribe()
1095 }
1096
1097 pub fn subscribe_to_shutdown_channel(&self) -> broadcast::Receiver<Option<RunWithRange>> {
1098 self.shutdown_channel_tx.subscribe()
1099 }
1100
1101 pub fn current_epoch_for_testing(&self) -> EpochId {
1102 self.state.current_epoch_for_testing()
1103 }
1104
1105 pub async fn close_epoch(&self, epoch_store: &Arc<AuthorityPerEpochStore>) -> IotaResult {
1107 info!("close_epoch (current epoch = {})", epoch_store.epoch());
1108 self.validator_components
1109 .lock()
1110 .await
1111 .as_ref()
1112 .ok_or_else(|| IotaError::from("Node is not a validator"))?
1113 .consensus_adapter
1114 .close_epoch(epoch_store);
1115 Ok(())
1116 }
1117
1118 pub fn clear_override_protocol_upgrade_buffer_stake(&self, epoch: EpochId) -> IotaResult {
1119 self.state
1120 .clear_override_protocol_upgrade_buffer_stake(epoch)
1121 }
1122
1123 pub fn set_override_protocol_upgrade_buffer_stake(
1124 &self,
1125 epoch: EpochId,
1126 buffer_stake_bps: u64,
1127 ) -> IotaResult {
1128 self.state
1129 .set_override_protocol_upgrade_buffer_stake(epoch, buffer_stake_bps)
1130 }
1131
1132 pub async fn close_epoch_for_testing(&self) -> IotaResult {
1135 let epoch_store = self.state.epoch_store_for_testing();
1136 self.close_epoch(&epoch_store).await
1137 }
1138
1139 fn start_state_snapshot(
1143 config: &NodeConfig,
1144 prometheus_registry: &Registry,
1145 checkpoint_store: Arc<CheckpointStore>,
1146 perpetual_tables: Arc<AuthorityPerpetualTables>,
1147 requests: mpsc::Receiver<EpochEndDbSnapshotRequest>,
1148 ) -> Result<Option<tokio::sync::broadcast::Sender<()>>> {
1149 if let Some(remote_store_config) = &config.state_snapshot_write_config.object_store_config {
1150 debug_assert!(
1151 !config.is_validator(),
1152 "`NodeConfig::validate` rejects snapshot upload on a validator"
1153 );
1154 let snapshot_uploader = StateSnapshotUploader::new(
1155 &config.snapshot_path(),
1156 remote_store_config.clone(),
1157 config.state_snapshot_write_config.concurrency,
1158 60,
1159 prometheus_registry,
1160 checkpoint_store,
1161 perpetual_tables,
1162 )?;
1163 Ok(Some(snapshot_uploader.start(requests)))
1164 } else {
1165 Ok(None)
1166 }
1167 }
1168
1169 fn sync_summaries_to_epoch_end(
1173 config: &NodeConfig,
1174 epoch_store: &AuthorityPerEpochStore,
1175 ) -> bool {
1176 config.is_validator() && epoch_store.pcool_bookkeeping_enabled()
1177 }
1178
1179 fn create_p2p_network(
1180 config: &NodeConfig,
1181 state_sync_store: RocksDbStore,
1182 chain_identifier: ChainIdentifier,
1183 trusted_peer_change_rx: watch::Receiver<TrustedPeerChangeEvent>,
1184 randomness_tx: mpsc::Sender<(EpochId, RandomnessRound, Vec<u8>)>,
1185 sync_summaries_to_epoch_end: Arc<AtomicBool>,
1186 prometheus_registry: &Registry,
1187 ) -> Result<(
1188 Network,
1189 discovery::Handle,
1190 state_sync::Handle,
1191 randomness::Handle,
1192 )> {
1193 let (state_sync, state_sync_server) = state_sync::Builder::new()
1194 .config(config.p2p_config.state_sync.clone().unwrap_or_default())
1195 .store(state_sync_store)
1196 .checkpoint_archive_config(config.checkpoint_archive_config().cloned())
1197 .sync_summaries_to_epoch_end(sync_summaries_to_epoch_end)
1198 .with_metrics(prometheus_registry)
1199 .build();
1200
1201 let (discovery, discovery_server) = discovery::Builder::new(trusted_peer_change_rx)
1202 .config(config.p2p_config.clone())
1203 .build();
1204
1205 let (randomness, randomness_router) =
1206 randomness::Builder::new(config.authority_public_key(), randomness_tx)
1207 .config(config.p2p_config.randomness.clone().unwrap_or_default())
1208 .with_metrics(prometheus_registry)
1209 .build();
1210
1211 let p2p_network = {
1212 let routes = anemo::Router::new()
1213 .add_rpc_service(discovery_server)
1214 .add_rpc_service(state_sync_server);
1215 let routes = routes.merge(randomness_router);
1216
1217 let inbound_network_metrics =
1218 NetworkMetrics::new("iota", "inbound", prometheus_registry);
1219 let outbound_network_metrics =
1220 NetworkMetrics::new("iota", "outbound", prometheus_registry);
1221
1222 let service = ServiceBuilder::new()
1223 .layer(
1224 TraceLayer::new_for_server_errors()
1225 .make_span_with(DefaultMakeSpan::new().level(tracing::Level::INFO))
1226 .on_failure(DefaultOnFailure::new().level(tracing::Level::WARN)),
1227 )
1228 .layer(CallbackLayer::new(MetricsMakeCallbackHandler::new(
1229 Arc::new(inbound_network_metrics),
1230 config.p2p_config.excessive_message_size(),
1231 )))
1232 .service(routes);
1233
1234 let outbound_layer = ServiceBuilder::new()
1235 .layer(
1236 TraceLayer::new_for_client_and_server_errors()
1237 .make_span_with(DefaultMakeSpan::new().level(tracing::Level::INFO))
1238 .on_failure(DefaultOnFailure::new().level(tracing::Level::DEBUG)),
1239 )
1240 .layer(CallbackLayer::new(MetricsMakeCallbackHandler::new(
1241 Arc::new(outbound_network_metrics),
1242 config.p2p_config.excessive_message_size(),
1243 )))
1244 .into_inner();
1245
1246 let mut anemo_config = config.p2p_config.anemo_config.clone().unwrap_or_default();
1247 anemo_config.max_request_frame_size = Some(1 << 20);
1250 anemo_config.max_response_frame_size = Some(128 << 20);
1253
1254 let mut quic_config = anemo_config.quic.unwrap_or_default();
1257 if quic_config.socket_send_buffer_size.is_none() {
1258 quic_config.socket_send_buffer_size = Some(20 << 20);
1259 }
1260 if quic_config.socket_receive_buffer_size.is_none() {
1261 quic_config.socket_receive_buffer_size = Some(20 << 20);
1262 }
1263 quic_config.allow_failed_socket_buffer_size_setting = true;
1264
1265 if quic_config.max_concurrent_bidi_streams.is_none() {
1268 quic_config.max_concurrent_bidi_streams = Some(500);
1269 }
1270 if quic_config.max_concurrent_uni_streams.is_none() {
1271 quic_config.max_concurrent_uni_streams = Some(500);
1272 }
1273 if quic_config.stream_receive_window.is_none() {
1274 quic_config.stream_receive_window = Some(100 << 20);
1275 }
1276 if quic_config.receive_window.is_none() {
1277 quic_config.receive_window = Some(200 << 20);
1278 }
1279 if quic_config.send_window.is_none() {
1280 quic_config.send_window = Some(200 << 20);
1281 }
1282 if quic_config.crypto_buffer_size.is_none() {
1283 quic_config.crypto_buffer_size = Some(1 << 20);
1284 }
1285 if quic_config.max_idle_timeout_ms.is_none() {
1286 quic_config.max_idle_timeout_ms = Some(10_000);
1287 }
1288 if quic_config.keep_alive_interval_ms.is_none() {
1289 quic_config.keep_alive_interval_ms = Some(5_000);
1290 }
1291 anemo_config.quic = Some(quic_config);
1292
1293 let server_name = format!("iota-{chain_identifier}");
1294 let network = Network::bind(config.p2p_config.listen_address)
1295 .server_name(&server_name)
1296 .private_key(config.network_key_pair().copy().private().0.to_bytes())
1297 .config(anemo_config)
1298 .outbound_request_layer(outbound_layer)
1299 .start(service)?;
1300 info!(
1301 server_name = server_name,
1302 "P2p network started on {}",
1303 network.local_addr()
1304 );
1305
1306 network
1307 };
1308
1309 let discovery_handle =
1310 discovery.start(p2p_network.clone(), config.network_key_pair().copy());
1311 let state_sync_handle = state_sync.start(p2p_network.clone());
1312 let randomness_handle = randomness.start(p2p_network.clone());
1313
1314 Ok((
1315 p2p_network,
1316 discovery_handle,
1317 state_sync_handle,
1318 randomness_handle,
1319 ))
1320 }
1321
1322 async fn construct_validator_components(
1325 config: NodeConfig,
1326 state: Arc<AuthorityState>,
1327 committee: Arc<Committee>,
1328 epoch_store: Arc<AuthorityPerEpochStore>,
1329 checkpoint_store: Arc<CheckpointStore>,
1330 state_sync_handle: state_sync::Handle,
1331 randomness_handle: randomness::Handle,
1332 global_state_hasher: Weak<GlobalStateHasher>,
1333 backpressure_manager: Arc<BackpressureManager>,
1334 connection_monitor_status: Arc<ConnectionMonitorStatus>,
1335 registry_service: &RegistryService,
1336 serving_rt_handle: tokio::runtime::Handle,
1337 ) -> Result<ValidatorComponents> {
1338 let mut config_clone = config.clone();
1339 let consensus_config = config_clone
1340 .consensus_config
1341 .as_mut()
1342 .ok_or_else(|| anyhow!("Validator is missing consensus config"))?;
1343 let validator_registry = registry_service.new_registry_custom(None, None)?;
1344 let validator_registry_id = registry_service.add(validator_registry.clone());
1345
1346 let client = Arc::new(UpdatableConsensusClient::new());
1347 let consensus_adapter = Arc::new(Self::construct_consensus_adapter(
1348 &committee,
1349 consensus_config,
1350 state.name,
1351 connection_monitor_status.clone(),
1352 &validator_registry,
1353 client.clone(),
1354 checkpoint_store.clone(),
1355 ));
1356 let consensus_manager = Arc::new(ConsensusManager::new(
1357 &config,
1358 consensus_config,
1359 registry_service,
1360 &validator_registry,
1361 client,
1362 ));
1363
1364 let consensus_store_pruner = ConsensusStorePruner::new(
1367 consensus_manager.get_storage_base_path(),
1368 consensus_config.db_retention_epochs(),
1369 consensus_config.db_pruner_period(),
1370 &validator_registry,
1371 );
1372
1373 let soft_locks = Arc::new(if config.enable_soft_locking {
1374 PreConsensusSoftLocks::new()
1375 } else {
1376 info!("pre-consensus soft-locking disabled via node config");
1377 PreConsensusSoftLocks::disabled()
1378 });
1379
1380 let checkpoint_metrics = CheckpointMetrics::new(&validator_registry);
1381 let iota_tx_validator_metrics = IotaTxValidatorMetrics::new(&validator_registry);
1382 let validator_service_metrics = Arc::new(ValidatorServiceMetrics::new(&validator_registry));
1383
1384 let soft_lock_sweep_handle = PreConsensusSoftLocks::spawn_sweep(
1395 Arc::downgrade(&soft_locks),
1396 validator_service_metrics.clone(),
1397 );
1398
1399 let validator_server_handle = Self::start_grpc_validator_service(
1400 &config,
1401 state.clone(),
1402 consensus_adapter.clone(),
1403 &validator_registry,
1404 soft_locks.clone(),
1405 validator_service_metrics.clone(),
1406 serving_rt_handle,
1407 )
1408 .await?;
1409
1410 let validator_overload_monitor_handle = if config
1413 .authority_overload_config
1414 .max_load_shedding_percentage
1415 > 0
1416 {
1417 let authority_state = Arc::downgrade(&state);
1418 let overload_config = config.authority_overload_config.clone();
1419 fail_point!("starting_overload_monitor");
1420 Some(spawn_monitored_task!(overload_monitor(
1421 authority_state,
1422 overload_config,
1423 )))
1424 } else {
1425 None
1426 };
1427
1428 let consensus_queue_overload_monitor_handle =
1435 if epoch_store.protocol_config().enable_pcool_flow() {
1436 let consensus_queue_monitor_authority_state = Arc::downgrade(&state);
1437 let consensus_queue_monitor_consensus_adapter = Arc::downgrade(&consensus_adapter);
1438 let consensus_queue_monitor_interval =
1439 config.authority_overload_config.overload_monitor_interval;
1440 Some(spawn_monitored_task!(consensus_queue_overload_monitor(
1441 consensus_queue_monitor_authority_state,
1442 consensus_queue_monitor_consensus_adapter,
1443 consensus_queue_monitor_interval,
1444 )))
1445 } else {
1446 None
1447 };
1448
1449 Self::start_epoch_specific_validator_components(
1450 &config,
1451 state.clone(),
1452 consensus_adapter,
1453 checkpoint_store,
1454 epoch_store,
1455 state_sync_handle,
1456 randomness_handle,
1457 consensus_manager,
1458 consensus_store_pruner,
1459 global_state_hasher,
1460 backpressure_manager,
1461 soft_locks,
1462 validator_server_handle,
1463 validator_overload_monitor_handle,
1464 consensus_queue_overload_monitor_handle,
1465 soft_lock_sweep_handle,
1466 checkpoint_metrics,
1467 iota_tx_validator_metrics,
1468 validator_registry_id,
1469 )
1470 .await
1471 }
1472
1473 async fn start_epoch_specific_validator_components(
1476 config: &NodeConfig,
1477 state: Arc<AuthorityState>,
1478 consensus_adapter: Arc<ConsensusAdapter>,
1479 checkpoint_store: Arc<CheckpointStore>,
1480 epoch_store: Arc<AuthorityPerEpochStore>,
1481 state_sync_handle: state_sync::Handle,
1482 randomness_handle: randomness::Handle,
1483 consensus_manager: Arc<ConsensusManager>,
1484 consensus_store_pruner: ConsensusStorePruner,
1485 global_state_hasher: Weak<GlobalStateHasher>,
1486 backpressure_manager: Arc<BackpressureManager>,
1487 soft_locks: Arc<PreConsensusSoftLocks>,
1488 validator_server_handle: SpawnOnce,
1489 validator_overload_monitor_handle: Option<JoinHandle<()>>,
1490 consensus_queue_overload_monitor_handle: Option<JoinHandle<()>>,
1491 soft_lock_sweep_handle: JoinHandle<()>,
1492 checkpoint_metrics: Arc<CheckpointMetrics>,
1493 iota_tx_validator_metrics: Arc<IotaTxValidatorMetrics>,
1494 validator_registry_id: RegistryID,
1495 ) -> Result<ValidatorComponents> {
1496 let checkpoint_service = Self::build_checkpoint_service(
1497 config,
1498 consensus_adapter.clone(),
1499 checkpoint_store.clone(),
1500 epoch_store.clone(),
1501 state.clone(),
1502 state_sync_handle,
1503 global_state_hasher,
1504 checkpoint_metrics.clone(),
1505 );
1506
1507 let low_scoring_authorities = Arc::new(ArcSwap::new(Arc::new(HashMap::new())));
1512
1513 consensus_adapter.swap_low_scoring_authorities(low_scoring_authorities.clone());
1514
1515 soft_locks.clear();
1520 epoch_store.set_soft_locks(soft_locks.clone());
1521
1522 let randomness_manager = match RandomnessManager::try_new(
1527 Arc::downgrade(&epoch_store),
1528 Box::new(consensus_adapter.clone()),
1529 randomness_handle,
1530 config.authority_key_pair(),
1531 )
1532 .await
1533 {
1534 Ok(randomness_manager) => randomness_manager,
1535 Err(err) => {
1536 fatal!(
1537 "validator cannot start epoch {} without a randomness manager: {err}",
1538 epoch_store.epoch()
1539 );
1540 }
1541 };
1542 epoch_store
1543 .set_randomness_manager(randomness_manager)
1544 .await?;
1545
1546 let consensus_handler_initializer = ConsensusHandlerInitializer::new(
1547 state.clone(),
1548 checkpoint_service.clone(),
1549 epoch_store.clone(),
1550 low_scoring_authorities,
1551 backpressure_manager,
1552 );
1553
1554 info!("Starting consensus manager asynchronously");
1555
1556 let replay_waiter = consensus_manager.replay_waiter();
1559
1560 tokio::spawn({
1562 let config = config.clone();
1563 let epoch_store = epoch_store.clone();
1564 let iota_tx_validator = IotaTxValidator::new(
1565 epoch_store.clone(),
1566 checkpoint_service.clone(),
1567 iota_tx_validator_metrics.clone(),
1568 );
1569 let consensus_manager = consensus_manager.clone();
1570 async move {
1571 consensus_manager
1572 .start(
1573 &config,
1574 epoch_store,
1575 consensus_handler_initializer,
1576 iota_tx_validator,
1577 )
1578 .await;
1579 }
1580 });
1581 info!("Spawning checkpoint service");
1582 let replay_waiter = if std::env::var("DISABLE_REPLAY_WAITER").is_err() {
1585 Some(replay_waiter)
1586 } else if epoch_store.protocol_config().enable_pcool_flow() {
1587 warn!("DISABLE_REPLAY_WAITER is ignored with deterministic validation");
1588 Some(replay_waiter)
1589 } else {
1590 None
1591 };
1592 let checkpoint_service_tasks = checkpoint_service.spawn(replay_waiter).await;
1593
1594 let overload_notifier_handle = Self::start_overload_notifier(
1595 config,
1596 state.clone(),
1597 epoch_store.clone(),
1598 consensus_adapter.clone(),
1599 );
1600
1601 Ok(ValidatorComponents {
1602 validator_server_handle,
1603 validator_overload_monitor_handle,
1604 consensus_queue_overload_monitor_handle,
1605 soft_lock_sweep_handle,
1606 overload_notifier_handle,
1607 consensus_manager,
1608 consensus_store_pruner,
1609 consensus_adapter,
1610 soft_locks,
1611 checkpoint_service_tasks,
1612 checkpoint_metrics,
1613 iota_tx_validator_metrics,
1614 validator_registry_id,
1615 })
1616 }
1617
1618 fn build_checkpoint_service(
1625 config: &NodeConfig,
1626 consensus_adapter: Arc<ConsensusAdapter>,
1627 checkpoint_store: Arc<CheckpointStore>,
1628 epoch_store: Arc<AuthorityPerEpochStore>,
1629 state: Arc<AuthorityState>,
1630 state_sync_handle: state_sync::Handle,
1631 global_state_hasher: Weak<GlobalStateHasher>,
1632 checkpoint_metrics: Arc<CheckpointMetrics>,
1633 ) -> Arc<CheckpointService> {
1634 let epoch_start_timestamp_ms = epoch_store.epoch_start_state().epoch_start_timestamp_ms();
1635 let epoch_duration_ms = epoch_store.epoch_start_state().epoch_duration_ms();
1636
1637 debug!(
1638 "Starting checkpoint service with epoch start timestamp {}
1639 and epoch duration {}",
1640 epoch_start_timestamp_ms, epoch_duration_ms
1641 );
1642
1643 let checkpoint_output = Box::new(SubmitCheckpointToConsensus {
1644 sender: consensus_adapter,
1645 signer: state.secret.clone(),
1646 authority: config.authority_public_key(),
1647 next_reconfiguration_timestamp_ms: epoch_start_timestamp_ms
1648 .checked_add(epoch_duration_ms)
1649 .expect("Overflow calculating next_reconfiguration_timestamp_ms"),
1650 metrics: checkpoint_metrics.clone(),
1651 });
1652
1653 let certified_checkpoint_output = SendCheckpointToStateSync::new(state_sync_handle);
1654 let max_tx_per_checkpoint = max_tx_per_checkpoint(epoch_store.protocol_config());
1655 let max_checkpoint_size_bytes =
1656 epoch_store.protocol_config().max_checkpoint_size_bytes() as usize;
1657
1658 CheckpointService::build(
1659 state.clone(),
1660 checkpoint_store,
1661 epoch_store,
1662 state.get_transaction_cache_reader().clone(),
1663 global_state_hasher,
1664 checkpoint_output,
1665 Box::new(certified_checkpoint_output),
1666 checkpoint_metrics,
1667 max_tx_per_checkpoint,
1668 max_checkpoint_size_bytes,
1669 )
1670 }
1671
1672 fn construct_consensus_adapter(
1673 committee: &Committee,
1674 consensus_config: &ConsensusConfig,
1675 authority: AuthorityName,
1676 connection_monitor_status: Arc<ConnectionMonitorStatus>,
1677 prometheus_registry: &Registry,
1678 consensus_client: Arc<dyn ConsensusClient>,
1679 checkpoint_store: Arc<CheckpointStore>,
1680 ) -> ConsensusAdapter {
1681 let ca_metrics = ConsensusAdapterMetrics::new(prometheus_registry);
1682 ConsensusAdapter::new(
1686 consensus_client,
1687 checkpoint_store,
1688 authority,
1689 connection_monitor_status,
1690 consensus_config.max_pending_transactions(),
1691 consensus_config.max_pending_transactions() * 2 / committee.num_members(),
1692 consensus_config.max_submit_position,
1693 consensus_config.submit_delay_step_override(),
1694 ca_metrics,
1695 consensus_config.graduated_load_shedding_soft_limit_pct(),
1696 )
1697 }
1698
1699 async fn start_grpc_validator_service(
1700 config: &NodeConfig,
1701 state: Arc<AuthorityState>,
1702 consensus_adapter: Arc<ConsensusAdapter>,
1703 prometheus_registry: &Registry,
1704 soft_locks: Arc<PreConsensusSoftLocks>,
1705 validator_service_metrics: Arc<ValidatorServiceMetrics>,
1706 serving_rt_handle: tokio::runtime::Handle,
1707 ) -> Result<SpawnOnce> {
1708 let validator_service = ValidatorService::new(
1709 state,
1710 consensus_adapter,
1711 validator_service_metrics,
1712 config.policy_config.clone().map(|p| p.client_id_source),
1713 soft_locks,
1714 );
1715
1716 let concurrency_limit = config.grpc_concurrency_limit_per_core.saturating_mul(
1723 NonZeroUsize::new(iota_core::runtime::available_cpu_cores())
1724 .unwrap_or(NonZeroUsize::MIN),
1725 );
1726 let load_shed = config.grpc_load_shed.unwrap_or_default();
1727
1728 const VALIDATOR_GRPC_KEEPALIVE: Duration = Duration::from_secs(60);
1733 const VALIDATOR_GRPC_MAX_CONCURRENT_STREAMS: u32 = 1000;
1738
1739 let mut server_conf = iota_network_stack::config::Config::new();
1740 server_conf.http2_keepalive_interval = Some(VALIDATOR_GRPC_KEEPALIVE);
1741 server_conf.http2_keepalive_timeout = Some(VALIDATOR_GRPC_KEEPALIVE);
1742 server_conf.http2_max_concurrent_streams = Some(VALIDATOR_GRPC_MAX_CONCURRENT_STREAMS);
1743 let server_builder =
1744 ServerBuilder::from_config(&server_conf, GrpcMetrics::new(prometheus_registry))
1745 .listener_metrics(validator_server_listener_metrics(prometheus_registry))
1746 .add_service_with_concurrency_limit(
1747 ValidatorServer::new(validator_service.clone()),
1748 concurrency_limit,
1749 load_shed,
1750 )
1751 .add_service_with_concurrency_limit(
1752 ValidatorV2Server::new(validator_service.clone()),
1753 concurrency_limit,
1754 load_shed,
1755 )
1756 .add_service_with_concurrency_limit(
1757 ValidatorPeerServer::new(validator_service),
1758 concurrency_limit,
1759 load_shed,
1760 );
1761
1762 let tls_config = iota_tls::create_rustls_server_config(
1763 config.network_key_pair().copy().private(),
1764 IOTA_TLS_SERVER_NAME.to_string(),
1765 );
1766
1767 let network_address = config.network_address().clone();
1768
1769 let bind_future = async move {
1770 let server = server_builder
1771 .bind(&network_address, Some(tls_config))
1772 .await
1773 .map_err(|err| anyhow!("Failed to bind to {network_address}: {err}"))?;
1774
1775 let local_addr = server.local_addr();
1776 info!("Listening to traffic on {local_addr}");
1777
1778 Ok(server)
1779 };
1780
1781 Ok(SpawnOnce::new(bind_future, serving_rt_handle))
1782 }
1783
1784 async fn reexecute_pending_consensus_certs(
1799 epoch_store: &Arc<AuthorityPerEpochStore>,
1800 state: &Arc<AuthorityState>,
1801 ) {
1802 let mut pending_consensus_certificates = Vec::new();
1803 let mut additional_certs = Vec::new();
1804
1805 for tx in epoch_store.get_all_pending_consensus_transactions() {
1806 match tx.kind {
1807 ConsensusTransactionKind::CertifiedTransaction(tx)
1817 if !tx.contains_shared_object() =>
1818 {
1819 let tx = *tx;
1820 let tx = VerifiedExecutableTransaction::new_from_certificate(
1823 VerifiedCertificate::new_unchecked(tx),
1824 );
1825 if let Some(fx_digest) = epoch_store
1828 .get_signed_effects_digest(tx.digest())
1829 .expect("db error")
1830 {
1831 pending_consensus_certificates.push((
1832 Schedulable::Transaction(tx),
1833 ExecutionEnv::new().with_expected_effects_digest(fx_digest),
1834 ));
1835 } else {
1836 additional_certs.push((Schedulable::Transaction(tx), ExecutionEnv::new()));
1837 }
1838 }
1839 _ => (),
1840 }
1841 }
1842
1843 let digests = pending_consensus_certificates
1844 .iter()
1845 .map(|(tx, _)| *tx.key().unwrap_digest())
1848 .collect::<Vec<_>>();
1849
1850 info!(
1851 "reexecuting {} pending consensus certificates: {:?}",
1852 digests.len(),
1853 digests
1854 );
1855
1856 state
1857 .execution_scheduler()
1858 .enqueue(pending_consensus_certificates, epoch_store);
1859 state
1860 .execution_scheduler()
1861 .enqueue(additional_certs, epoch_store);
1862
1863 let timeout = if cfg!(msim) { 120 } else { 60 };
1869 if tokio::time::timeout(
1870 std::time::Duration::from_secs(timeout),
1871 state
1872 .get_transaction_cache_reader()
1873 .try_notify_read_executed_effects_digests(
1874 "IotaNode::notify_read_executed_effects_digests",
1875 &digests,
1876 ),
1877 )
1878 .await
1879 .is_err()
1880 {
1881 if let Ok(executed_effects_digests) = state
1883 .get_transaction_cache_reader()
1884 .try_multi_get_executed_effects_digests(&digests)
1885 {
1886 let pending_digests = digests
1887 .iter()
1888 .zip(executed_effects_digests.iter())
1889 .filter_map(|(digest, executed_effects_digest)| {
1890 if executed_effects_digest.is_none() {
1891 Some(digest)
1892 } else {
1893 None
1894 }
1895 })
1896 .collect::<Vec<_>>();
1897 debug_fatal!(
1898 "Timed out waiting for effects digests to be executed: {:?}",
1899 pending_digests
1900 );
1901 } else {
1902 debug_fatal!(
1903 "Timed out waiting for effects digests to be executed, digests not found"
1904 );
1905 }
1906 }
1907 }
1908
1909 pub fn state(&self) -> Arc<AuthorityState> {
1910 self.state.clone()
1911 }
1912
1913 pub fn reference_gas_price_for_testing(&self) -> Result<u64, anyhow::Error> {
1915 self.state.reference_gas_price_for_testing()
1916 }
1917
1918 pub fn clone_committee_store(&self) -> Arc<CommitteeStore> {
1919 self.state.committee_store().clone()
1920 }
1921
1922 pub fn clone_authority_aggregator(
1930 &self,
1931 ) -> Option<Arc<AuthorityAggregator<NetworkAuthorityClient>>> {
1932 self.transaction_orchestrator
1933 .as_ref()
1934 .map(|to| to.clone_authority_aggregator())
1935 }
1936
1937 pub fn transaction_orchestrator(
1938 &self,
1939 ) -> Option<Arc<TransactionOrchestrator<NetworkAuthorityClient>>> {
1940 self.transaction_orchestrator.clone()
1941 }
1942
1943 pub fn transaction_builder_ledger_client(&self) -> NodeTransactionBuilderLedgerClient {
1946 let reader = Arc::new(GrpcReadStore::new(
1947 self.state.clone(),
1948 self.state_sync_store.clone(),
1949 ));
1950 NodeTransactionBuilderLedgerClient::new(reader)
1951 }
1952
1953 pub fn subscribe_to_transaction_orchestrator_effects(
1956 &self,
1957 ) -> Result<tokio::sync::broadcast::Receiver<QuorumDriverEffectsQueueResult>> {
1958 self.transaction_orchestrator
1959 .as_ref()
1960 .ok_or_else(|| {
1961 anyhow::anyhow!("Transaction Orchestrator is not enabled in this node.")
1962 })?
1963 .subscribe_to_effects_queue()
1964 .ok_or_else(|| {
1965 anyhow::anyhow!(
1966 "Effects queue is not available: the quorum driver is not the currently \
1967 served flow on this node."
1968 )
1969 })
1970 }
1971
1972 pub async fn monitor_reconfiguration(
1978 self: Arc<Self>,
1979 mut epoch_store: Arc<AuthorityPerEpochStore>,
1980 ) -> Result<()> {
1981 let checkpoint_executor_metrics =
1982 CheckpointExecutorMetrics::new(&self.registry_service.default_registry());
1983
1984 loop {
1985 let mut hasher_guard = self.global_state_hasher.lock().await;
1986 let hasher = hasher_guard.take().unwrap();
1987 info!(
1988 "Creating checkpoint executor for epoch {}",
1989 epoch_store.epoch()
1990 );
1991
1992 let data_sender = if let Ok(guard) = self.grpc_server_handle.try_lock() {
1994 guard.as_ref().map(|handle| {
1995 let tx = handle.checkpoint_data_broadcaster().clone();
1996 Box::new(move |data: &CheckpointData| {
1997 tx.send_traced(data);
1998 }) as Box<dyn Fn(&CheckpointData) + Send + Sync>
1999 })
2000 } else {
2001 None
2002 };
2003
2004 let checkpoint_executor = CheckpointExecutor::new(
2005 epoch_store.clone(),
2006 self.checkpoint_store.clone(),
2007 self.state.clone(),
2008 hasher.clone(),
2009 self.backpressure_manager.clone(),
2010 self.config.checkpoint_executor_config.clone(),
2011 checkpoint_executor_metrics.clone(),
2012 data_sender,
2013 Some(self.checkpoint_progress_tracker.clone()),
2014 );
2015
2016 let run_with_range = self.config.run_with_range;
2017
2018 let cur_epoch_store = self.state.load_epoch_store_one_call_per_task();
2019
2020 self.metrics
2022 .current_protocol_version
2023 .set(cur_epoch_store.protocol_config().version.as_u64() as i64);
2024
2025 if let Some(components) = &*self.validator_components.lock().await {
2027 tokio::time::sleep(Duration::from_millis(1)).await;
2029
2030 let config = cur_epoch_store.protocol_config();
2031 let transaction = ConsensusTransaction::new_capability_notification_v1(
2032 AuthorityCapabilitiesV1::new(
2033 self.state.name,
2034 cur_epoch_store.get_chain(),
2035 self.config
2036 .supported_protocol_versions
2037 .expect("Supported versions should be populated")
2038 .truncate_below(config.version),
2040 self.state.get_available_system_packages(config).await,
2041 ),
2042 );
2043 info!(?transaction, "submitting capabilities to consensus");
2044 components
2045 .consensus_adapter
2046 .submit(transaction, None, &cur_epoch_store)?;
2047
2048 if config.enable_pcool_flow() {
2054 let proposed_rules = self.config.transaction_deny_config.to_deny_rule_set();
2055 let recorded = cur_epoch_store.recorded_deny_rule_proposal(&self.state.name);
2056 let transaction = ConsensusTransaction::new_transaction_deny_rule_proposal(
2057 TransactionDenyRuleProposal::new(
2058 self.state.name,
2059 proposed_rules,
2060 recorded.map(|p| p.generation),
2061 ),
2062 );
2063 info!(
2064 tracking_id = ?transaction.get_tracking_id(),
2065 "submitting deny rule proposal to consensus"
2066 );
2067 components
2068 .consensus_adapter
2069 .submit(transaction, None, &cur_epoch_store)?;
2070 }
2071 } else if self.state.is_active_validator(&cur_epoch_store)
2072 && cur_epoch_store
2073 .protocol_config()
2074 .track_non_committee_eligible_validators()
2075 {
2076 let epoch_store = cur_epoch_store.clone();
2080 let node_clone = self.clone();
2081 spawn_monitored_task!(epoch_store.clone().within_alive_epoch(async move {
2082 node_clone
2083 .send_signed_capability_notification_to_committee_with_retry(&epoch_store)
2084 .instrument(trace_span!(
2085 "send_signed_capability_notification_to_committee_with_retry"
2086 ))
2087 .await;
2088 }));
2089 }
2090
2091 let stop_condition = checkpoint_executor.run_epoch(run_with_range).await;
2092
2093 if stop_condition == StopReason::RuntimeShutdown {
2094 return Ok(());
2095 }
2096
2097 if stop_condition == StopReason::RunWithRangeCondition {
2098 IotaNode::shutdown(&self).await;
2099 self.shutdown_channel_tx
2100 .send(run_with_range)
2101 .expect("RunWithRangeCondition met but failed to send shutdown message");
2102 return Ok(());
2103 }
2104
2105 let latest_system_state = self
2107 .state
2108 .get_object_cache_reader()
2109 .try_get_iota_system_state_object_unsafe()
2110 .expect("Read IOTA System State object cannot fail");
2111
2112 #[cfg(msim)]
2113 if !self
2114 .sim_state
2115 .sim_safe_mode_expected
2116 .load(Ordering::Relaxed)
2117 {
2118 debug_assert!(!latest_system_state.safe_mode());
2119 }
2120
2121 #[cfg(not(msim))]
2122 debug_assert!(!latest_system_state.safe_mode());
2123
2124 if let Err(err) = self.end_of_epoch_channel.send(latest_system_state.clone()) {
2125 if self.state.is_fullnode(&cur_epoch_store) {
2126 warn!(
2127 "Failed to send end of epoch notification to subscriber: {:?}",
2128 err
2129 );
2130 }
2131 }
2132
2133 cur_epoch_store.record_is_safe_mode_metric(latest_system_state.safe_mode());
2134 let new_epoch_start_state = latest_system_state.into_epoch_start_state();
2135
2136 self.auth_agg.store(Arc::new(
2137 self.auth_agg
2138 .load()
2139 .recreate_with_new_epoch_start_state(&new_epoch_start_state),
2140 ));
2141
2142 let next_epoch_committee = new_epoch_start_state.get_iota_committee();
2143 let next_epoch = next_epoch_committee.epoch();
2144 assert_eq!(cur_epoch_store.epoch() + 1, next_epoch);
2145
2146 info!(
2147 next_epoch,
2148 "Finished executing all checkpoints in epoch. About to reconfigure the system."
2149 );
2150
2151 fail_point_async!("reconfig_delay");
2152
2153 let authority_names_to_peer_ids =
2158 new_epoch_start_state.get_authority_names_to_peer_ids();
2159 self.connection_monitor_status
2160 .update_mapping_for_epoch(authority_names_to_peer_ids);
2161
2162 cur_epoch_store.record_epoch_reconfig_start_time_metric();
2163
2164 send_trusted_peer_change(
2165 &self.config,
2166 &self.trusted_peer_change_tx,
2167 &new_epoch_start_state,
2168 );
2169
2170 let mut validator_components_lock_guard = self.validator_components.lock().await;
2171
2172 let new_epoch_store = self
2176 .reconfigure_state(
2177 &self.state,
2178 &cur_epoch_store,
2179 next_epoch_committee.clone(),
2180 new_epoch_start_state,
2181 hasher.clone(),
2182 )
2183 .await?;
2184 self.sync_summaries_to_epoch_end.store(
2185 Self::sync_summaries_to_epoch_end(&self.config, &new_epoch_store),
2186 Ordering::Relaxed,
2187 );
2188
2189 let new_validator_components = if let Some(ValidatorComponents {
2190 validator_server_handle,
2191 validator_overload_monitor_handle,
2192 consensus_queue_overload_monitor_handle,
2193 soft_lock_sweep_handle,
2194 overload_notifier_handle,
2195 consensus_manager,
2196 consensus_store_pruner,
2197 consensus_adapter,
2198 soft_locks,
2199 mut checkpoint_service_tasks,
2200 checkpoint_metrics,
2201 iota_tx_validator_metrics,
2202 validator_registry_id,
2203 }) = validator_components_lock_guard.take()
2204 {
2205 info!("Reconfiguring the validator.");
2206 if let Some(handle) = overload_notifier_handle {
2209 handle.abort();
2210 }
2211 checkpoint_service_tasks.abort_all();
2216 while let Some(result) = checkpoint_service_tasks.join_next().await {
2217 if let Err(err) = result {
2218 if err.is_panic() {
2219 std::panic::resume_unwind(err.into_panic());
2220 }
2221 warn!("Error in checkpoint service task: {:?}", err);
2222 }
2223 }
2224 info!("Checkpoint service has shut down.");
2225
2226 consensus_manager.shutdown().await;
2227 info!("Consensus has shut down.");
2228
2229 info!("Epoch store finished reconfiguration.");
2230
2231 let global_state_hasher_metrics = Arc::into_inner(hasher)
2234 .expect("Object state hasher should have no other references at this point")
2235 .metrics();
2236 let new_hasher = Arc::new(GlobalStateHasher::new(
2237 self.state.get_global_state_hash_store().clone(),
2238 global_state_hasher_metrics,
2239 ));
2240 let weak_hasher = Arc::downgrade(&new_hasher);
2241 *hasher_guard = Some(new_hasher);
2242
2243 consensus_store_pruner.prune(next_epoch).await;
2244
2245 if self.state.is_committee_validator(&new_epoch_store) {
2246 Some(
2248 Self::start_epoch_specific_validator_components(
2249 &self.config,
2250 self.state.clone(),
2251 consensus_adapter,
2252 self.checkpoint_store.clone(),
2253 new_epoch_store.clone(),
2254 self.state_sync_handle.clone(),
2255 self.randomness_handle.clone(),
2256 consensus_manager,
2257 consensus_store_pruner,
2258 weak_hasher,
2259 self.backpressure_manager.clone(),
2260 soft_locks,
2261 validator_server_handle,
2262 validator_overload_monitor_handle,
2263 consensus_queue_overload_monitor_handle,
2264 soft_lock_sweep_handle,
2265 checkpoint_metrics,
2266 iota_tx_validator_metrics,
2267 validator_registry_id,
2268 )
2269 .await?,
2270 )
2271 } else {
2272 info!("This node is no longer a validator after reconfiguration");
2273 if self.registry_service.remove(validator_registry_id) {
2274 debug!("Removed validator metrics registry");
2275 } else {
2276 warn!("Failed to remove validator metrics registry");
2277 }
2278 validator_server_handle.shutdown();
2279 debug!("Validator grpc server shutdown triggered");
2280
2281 None
2282 }
2283 } else {
2284 let global_state_hasher_metrics = Arc::into_inner(hasher)
2287 .expect("Object state hasher should have no other references at this point")
2288 .metrics();
2289 let new_hasher = Arc::new(GlobalStateHasher::new(
2290 self.state.get_global_state_hash_store().clone(),
2291 global_state_hasher_metrics,
2292 ));
2293 let weak_hasher = Arc::downgrade(&new_hasher);
2294 *hasher_guard = Some(new_hasher);
2295
2296 if self.state.is_committee_validator(&new_epoch_store) {
2297 info!("Promoting the node from fullnode to validator, starting grpc server");
2298
2299 let mut components = Self::construct_validator_components(
2300 self.config.clone(),
2301 self.state.clone(),
2302 Arc::new(next_epoch_committee.clone()),
2303 new_epoch_store.clone(),
2304 self.checkpoint_store.clone(),
2305 self.state_sync_handle.clone(),
2306 self.randomness_handle.clone(),
2307 weak_hasher,
2308 self.backpressure_manager.clone(),
2309 self.connection_monitor_status.clone(),
2310 &self.registry_service,
2311 self.serving_rt_handle.clone(),
2312 )
2313 .await?;
2314
2315 components.validator_server_handle =
2316 components.validator_server_handle.start().await;
2317
2318 Some(components)
2319 } else {
2320 None
2321 }
2322 };
2323 *validator_components_lock_guard = new_validator_components;
2324
2325 cur_epoch_store.release_db_handles();
2328
2329 drop(cur_epoch_store);
2333
2334 self.state.epoch_db_pruner().prune_old_epoch_dbs().await;
2338
2339 epoch_store = new_epoch_store;
2340 info!("Reconfiguration finished");
2341 }
2342 }
2343
2344 pub async fn shutdown(&self) {
2347 self.state.stop_historic_bucket_work();
2350
2351 if let Some(validator_components) = &*self.validator_components.lock().await {
2352 validator_components.consensus_manager.shutdown().await;
2353 }
2354
2355 if let Some(indexes) = &self.state.rpc_indexes_store {
2358 indexes.shutdown().await;
2359 }
2360
2361 if let Some(grpc_handle) = self.grpc_server_handle.lock().await.take() {
2363 info!("Shutting down gRPC server");
2364 if let Err(e) = grpc_handle.shutdown().await {
2365 warn!("Failed to gracefully shutdown gRPC server: {e}");
2366 }
2367 }
2368 }
2369
2370 async fn reconfigure_state(
2373 &self,
2374 state: &Arc<AuthorityState>,
2375 cur_epoch_store: &AuthorityPerEpochStore,
2376 next_epoch_committee: Committee,
2377 next_epoch_start_system_state: EpochStartSystemState,
2378 global_state_hasher: Arc<GlobalStateHasher>,
2379 ) -> IotaResult<Arc<AuthorityPerEpochStore>> {
2380 let next_epoch = next_epoch_committee.epoch();
2381
2382 let last_checkpoint = self
2383 .checkpoint_store
2384 .get_epoch_last_checkpoint(cur_epoch_store.epoch())
2385 .expect("Error loading last checkpoint for current epoch")
2386 .expect("Could not load last checkpoint for current epoch");
2387 let epoch_supply_change = last_checkpoint
2388 .end_of_epoch_data
2389 .as_ref()
2390 .ok_or_else(|| {
2391 IotaError::from("last checkpoint in epoch should contain end of epoch data")
2392 })?
2393 .epoch_supply_change;
2394
2395 let last_checkpoint_seq = last_checkpoint.sequence_number();
2396
2397 assert_eq!(
2398 Some(last_checkpoint_seq),
2399 self.checkpoint_store
2400 .get_highest_executed_checkpoint_seq_number()
2401 .expect("Error loading highest executed checkpoint sequence number")
2402 );
2403
2404 let epoch_start_configuration = EpochStartConfiguration::new(
2405 next_epoch_start_system_state,
2406 *last_checkpoint.digest(),
2407 state.get_object_store().as_ref(),
2408 EpochFlag::default_flags_for_new_epoch(&state.config),
2409 )
2410 .expect("EpochStartConfiguration construction cannot fail");
2411
2412 let new_epoch_store = self
2413 .state
2414 .reconfigure(
2415 cur_epoch_store,
2416 self.config.supported_protocol_versions.unwrap(),
2417 next_epoch_committee,
2418 epoch_start_configuration,
2419 global_state_hasher,
2420 &self.config.expensive_safety_check_config,
2421 epoch_supply_change,
2422 last_checkpoint_seq,
2423 )
2424 .await
2425 .expect("Reconfigure authority state cannot fail");
2426 info!(next_epoch, "Node State has been reconfigured");
2427 assert_eq!(next_epoch, new_epoch_store.epoch());
2428 if new_epoch_store.protocol_config().enable_pcool_flow()
2435 && self.state.is_committee_validator(&new_epoch_store)
2436 {
2437 self.checkpoint_store
2438 .hold_synced_watermark_in_memory(self.state.get_historic_ledger().clone())?;
2439 }
2440 self.state.get_reconfig_api().update_epoch_flags_metrics(
2441 cur_epoch_store.epoch_start_config().flags(),
2442 new_epoch_store.epoch_start_config().flags(),
2443 );
2444
2445 Ok(new_epoch_store)
2446 }
2447
2448 pub fn get_config(&self) -> &NodeConfig {
2449 &self.config
2450 }
2451
2452 async fn execute_transaction_immediately_at_zero_epoch(
2453 state: &Arc<AuthorityState>,
2454 epoch_store: &Arc<AuthorityPerEpochStore>,
2455 tx: &TransactionEnvelope,
2456 span: tracing::Span,
2457 ) {
2458 let _guard = span.enter();
2459 let transaction =
2460 iota_types::executable_transaction::VerifiedExecutableTransaction::new_unchecked(
2461 iota_types::executable_transaction::ExecutableTransaction::new_from_data_and_sig(
2462 tx.data().clone(),
2463 iota_types::executable_transaction::CertificateProof::Checkpoint(0, 0),
2464 ),
2465 );
2466 state
2467 .try_execute_immediately(&transaction, ExecutionEnv::new(), epoch_store)
2468 .unwrap();
2469 }
2470
2471 pub fn randomness_handle(&self) -> randomness::Handle {
2472 self.randomness_handle.clone()
2473 }
2474
2475 pub(crate) fn registry_service(&self) -> &RegistryService {
2478 &self.registry_service
2479 }
2480
2481 async fn send_signed_capability_notification_to_committee_with_retry(
2487 &self,
2488 epoch_store: &Arc<AuthorityPerEpochStore>,
2489 ) {
2490 const INITIAL_RETRY_INTERVAL_SECS: u64 = 5;
2491 const RETRY_INTERVAL_INCREMENT_SECS: u64 = 5;
2492 const MAX_RETRY_INTERVAL_SECS: u64 = 300; let config = epoch_store.protocol_config();
2496
2497 let capabilities = AuthorityCapabilitiesV1::new(
2499 self.state.name,
2500 epoch_store.get_chain(),
2501 self.config
2502 .supported_protocol_versions
2503 .expect("Supported versions should be populated")
2504 .truncate_below(config.version),
2505 self.state.get_available_system_packages(config).await,
2506 );
2507
2508 let signature = AuthoritySignature::new_secure(
2510 &IntentMessage::new(
2511 Intent::iota_app(IntentScope::AuthorityCapabilities),
2512 &capabilities,
2513 ),
2514 &epoch_store.epoch(),
2515 self.config.authority_key_pair(),
2516 );
2517
2518 let request = HandleCapabilityNotificationRequestV1 {
2519 message: SignedAuthorityCapabilitiesV1::new_from_data_and_sig(capabilities, signature),
2520 };
2521
2522 let mut retry_interval = Duration::from_secs(INITIAL_RETRY_INTERVAL_SECS);
2523
2524 loop {
2525 let auth_agg = self.auth_agg.load();
2526 match auth_agg
2527 .send_capability_notification_to_quorum(request.clone())
2528 .await
2529 {
2530 Ok(_) => {
2531 info!("Successfully sent capability notification to committee");
2532 break;
2533 }
2534 Err(err) => {
2535 match &err {
2536 AggregatorSendCapabilityNotificationError::RetryableNotification {
2537 errors,
2538 } => {
2539 warn!(
2540 "Failed to send capability notification to committee (retryable error), will retry in {:?}: {:?}",
2541 retry_interval, errors
2542 );
2543 }
2544 AggregatorSendCapabilityNotificationError::NonRetryableNotification {
2545 errors,
2546 } => {
2547 error!(
2548 "Failed to send capability notification to committee (non-retryable error): {:?}",
2549 errors
2550 );
2551 break;
2552 }
2553 };
2554
2555 tokio::time::sleep(retry_interval).await;
2557
2558 retry_interval = std::cmp::min(
2560 retry_interval + Duration::from_secs(RETRY_INTERVAL_INCREMENT_SECS),
2561 Duration::from_secs(MAX_RETRY_INTERVAL_SECS),
2562 );
2563 }
2564 }
2565 }
2566 }
2567}
2568
2569#[cfg(msim)]
2570impl IotaNode {
2571 pub fn get_sim_node_id(&self) -> iota_simulator::task::NodeId {
2572 self.sim_state.sim_node.id()
2573 }
2574
2575 pub fn gather_metrics(&self) -> Vec<prometheus_filtered::proto::MetricFamily> {
2577 self.registry_service.gather_all()
2578 }
2579
2580 pub fn set_safe_mode_expected(&self, new_value: bool) {
2581 info!("Setting safe mode expected to {}", new_value);
2582 self.sim_state
2583 .sim_safe_mode_expected
2584 .store(new_value, Ordering::Relaxed);
2585 }
2586}
2587
2588enum SpawnOnce {
2589 Unstarted(
2591 Mutex<BoxFuture<'static, Result<iota_network_stack::server::Server>>>,
2592 tokio::runtime::Handle,
2593 ),
2594 #[allow(unused)]
2595 Started(iota_http::ServerHandle),
2596}
2597
2598impl SpawnOnce {
2599 pub fn new(
2600 future: impl Future<Output = Result<iota_network_stack::server::Server>> + Send + 'static,
2601 serving_rt_handle: tokio::runtime::Handle,
2602 ) -> Self {
2603 Self::Unstarted(Mutex::new(Box::pin(future)), serving_rt_handle)
2604 }
2605
2606 pub async fn start(self) -> Self {
2607 match self {
2608 Self::Unstarted(future, serving_rt_handle) => {
2609 let (handle_tx, handle_rx) = tokio::sync::oneshot::channel();
2613 serving_rt_handle.spawn(async move {
2614 let server = future.into_inner().await.unwrap_or_else(|err| {
2615 panic!("Failed to start validator gRPC server: {err}")
2616 });
2617 if handle_tx.send(server.handle().clone()).is_err() {
2618 return;
2619 }
2620 match server.serve().await {
2621 Ok(()) => info!("Server stopped"),
2622 Err(err) => info!("Server stopped: {err}"),
2623 }
2624 });
2625 let handle = handle_rx
2626 .await
2627 .expect("validator gRPC server exited before returning its handle");
2628 Self::Started(handle)
2629 }
2630 Self::Started(_) => self,
2631 }
2632 }
2633
2634 pub fn shutdown(self) {
2635 if let SpawnOnce::Started(handle) = self {
2636 handle.trigger_shutdown();
2637 }
2638 }
2639}
2640
2641fn send_trusted_peer_change(
2644 config: &NodeConfig,
2645 sender: &watch::Sender<TrustedPeerChangeEvent>,
2646 new_epoch_start_state: &EpochStartSystemState,
2647) {
2648 let new_committee =
2649 new_epoch_start_state.get_validator_as_p2p_peers(config.authority_public_key());
2650
2651 sender.send_modify(|event| {
2652 core::mem::swap(&mut event.new_committee, &mut event.old_committee);
2653 event.new_committee = new_committee;
2654 })
2655}
2656
2657fn build_kv_store(
2658 state: &Arc<AuthorityState>,
2659 config: &NodeConfig,
2660 registry: &Registry,
2661) -> Result<Arc<TransactionKeyValueStore>> {
2662 let metrics = KeyValueStoreMetrics::new(registry);
2663 let db_store = TransactionKeyValueStore::new("rocksdb", metrics.clone(), state.clone());
2664
2665 let base_url = &config.transaction_kv_store_read_config.base_url;
2666
2667 if base_url.is_empty() {
2668 info!("no http kv store url provided, using local db only");
2669 return Ok(Arc::new(db_store));
2670 }
2671
2672 base_url.parse::<url::Url>().tap_err(|e| {
2673 error!(
2674 "failed to parse config.transaction_kv_store_config.base_url ({:?}) as url: {}",
2675 base_url, e
2676 )
2677 })?;
2678
2679 let http_store = HttpKVStore::new_kv(
2680 base_url,
2681 config.transaction_kv_store_read_config.cache_size,
2682 metrics.clone(),
2683 )?;
2684 info!("using local key-value store with fallback to http key-value store");
2685 Ok(Arc::new(FallbackTransactionKVStore::new_kv(
2686 db_store,
2687 http_store,
2688 metrics,
2689 "json_rpc_fallback",
2690 )))
2691}
2692
2693async fn build_grpc_server(
2703 config: &NodeConfig,
2704 state: Arc<AuthorityState>,
2705 state_sync_store: RocksDbStore,
2706 executor: Option<Arc<dyn iota_types::transaction_executor::TransactionExecutor>>,
2707 prometheus_registry: &Registry,
2708 server_version: ServerVersion,
2709) -> Result<Option<GrpcServerHandle>> {
2710 if config.is_validator() || !config.enable_grpc_api {
2714 return Ok(None);
2715 }
2716
2717 let grpc_config = config
2718 .grpc_api_config
2719 .as_ref()
2720 .expect("`NodeConfig::validate` rejects an enabled gRPC API without a config");
2721
2722 let chain_id = state.get_chain_identifier();
2724
2725 let grpc_read_store = Arc::new(GrpcReadStore::new(state.clone(), state_sync_store));
2726
2727 let shutdown_token = CancellationToken::new();
2729
2730 let grpc_reader = Arc::new(GrpcReader::new(
2732 grpc_read_store,
2733 Some(server_version.to_string()),
2734 ));
2735
2736 let grpc_server_metrics = iota_grpc_server::GrpcServerMetrics::new(prometheus_registry);
2738 let client_id_source = config
2739 .policy_config
2740 .as_ref()
2741 .map(|p| p.client_id_source.clone());
2742
2743 let handle = start_grpc_server(
2744 grpc_reader,
2745 executor,
2746 grpc_config.clone(),
2747 shutdown_token,
2748 chain_id,
2749 Some(grpc_server_metrics),
2750 state.traffic_controller.clone(),
2751 client_id_source,
2752 )
2753 .await?;
2754
2755 Ok(Some(handle))
2756}
2757
2758pub async fn build_http_server(
2772 state: Arc<AuthorityState>,
2773 transaction_orchestrator: &Option<Arc<TransactionOrchestrator<NetworkAuthorityClient>>>,
2774 config: &NodeConfig,
2775 prometheus_registry: &Registry,
2776) -> Result<Option<iota_http::ServerHandle>> {
2777 if config.is_validator() {
2779 return Ok(None);
2780 }
2781
2782 let mut router = axum::Router::new();
2783
2784 if config.enable_jsonrpc_api {
2787 let json_rpc_router = {
2788 let traffic_controller = state.traffic_controller.clone();
2789 let mut server = JsonRpcServerBuilder::new(
2790 env!("CARGO_PKG_VERSION"),
2791 prometheus_registry,
2792 traffic_controller,
2793 config.policy_config.clone(),
2794 );
2795
2796 let kv_store = build_kv_store(&state, config, prometheus_registry)?;
2797
2798 let metrics = Arc::new(JsonRpcMetrics::new(prometheus_registry));
2799 server.register_module(ReadApi::new(
2800 state.clone(),
2801 kv_store.clone(),
2802 metrics.clone(),
2803 ))?;
2804 server.register_module(CoinReadApi::new(
2805 state.clone(),
2806 kv_store.clone(),
2807 metrics.clone(),
2808 )?)?;
2809
2810 if config.run_with_range.is_none() {
2813 server.register_module(TransactionBuilderApi::new(state.clone()))?;
2814 }
2815 server.register_module(GovernanceReadApi::new(state.clone(), metrics.clone()))?;
2816
2817 if let Some(transaction_orchestrator) = transaction_orchestrator {
2818 server.register_module(TransactionExecutionApi::new(
2819 state.clone(),
2820 transaction_orchestrator.clone(),
2821 metrics.clone(),
2822 ))?;
2823 }
2824
2825 let iota_names_config = config.iota_names_config.clone().unwrap_or_else(|| {
2826 IotaNamesConfig::from_chain(&state.get_chain_identifier().chain())
2827 });
2828
2829 server.register_module(IndexerApi::new(
2830 state.clone(),
2831 ReadApi::new(state.clone(), kv_store.clone(), metrics.clone()),
2832 kv_store,
2833 metrics,
2834 iota_names_config,
2835 ))?;
2836 server.register_module(MoveUtils::new(state.clone()))?;
2837
2838 server.to_router().await?
2839 };
2840
2841 router = router.merge(json_rpc_router);
2842 }
2843
2844 router = router
2845 .route("/health", axum::routing::get(health_check_handler))
2846 .route_layer(axum::Extension(state));
2847
2848 let layers = ServiceBuilder::new()
2849 .map_request(|mut request: axum::http::Request<_>| {
2850 if let Some(connect_info) = request.extensions().get::<iota_http::ConnectInfo>() {
2851 let axum_connect_info = axum::extract::ConnectInfo(connect_info.remote_addr);
2852 request.extensions_mut().insert(axum_connect_info);
2853 }
2854 request
2855 })
2856 .layer(axum::middleware::from_fn(server_timing_middleware));
2857
2858 router = router.layer(layers);
2859
2860 let handle = iota_http::Builder::new()
2861 .config(
2862 iota_http::Config::default()
2863 .metrics(Some(json_rpc_listener_metrics(prometheus_registry))),
2864 )
2865 .serve(&config.json_rpc_address, router)
2866 .map_err(|e| anyhow::anyhow!("{e}"))?;
2867 info!(
2868 local_addr =? handle.local_addr(),
2869 json_rpc = config.enable_jsonrpc_api,
2870 "IOTA HTTP server listening on {}",
2871 handle.local_addr()
2872 );
2873
2874 Ok(Some(handle))
2875}
2876
2877fn json_rpc_listener_metrics(prometheus_registry: &Registry) -> ListenerMetrics {
2878 ListenerMetrics::new("json_rpc", prometheus_registry, MetricLevel::Warn)
2879}
2880
2881fn validator_server_listener_metrics(prometheus_registry: &Registry) -> ListenerMetrics {
2882 ListenerMetrics::new("authority_grpc", prometheus_registry, MetricLevel::Warn)
2883}
2884
2885#[derive(Debug, serde::Serialize, serde::Deserialize)]
2886pub struct Threshold {
2887 pub threshold_seconds: Option<u32>,
2888}
2889
2890async fn health_check_handler(
2891 axum::extract::Query(Threshold { threshold_seconds }): axum::extract::Query<Threshold>,
2892 axum::Extension(state): axum::Extension<Arc<AuthorityState>>,
2893) -> impl axum::response::IntoResponse {
2894 if let Some(threshold_seconds) = threshold_seconds {
2895 let summary = match state
2897 .get_checkpoint_store()
2898 .get_highest_executed_checkpoint()
2899 {
2900 Ok(Some(summary)) => summary,
2901 Ok(None) => {
2902 warn!("Highest executed checkpoint not found");
2903 return (axum::http::StatusCode::SERVICE_UNAVAILABLE, "down");
2904 }
2905 Err(err) => {
2906 warn!("Failed to retrieve highest executed checkpoint: {:?}", err);
2907 return (axum::http::StatusCode::SERVICE_UNAVAILABLE, "down");
2908 }
2909 };
2910
2911 let latest_chain_time = summary.timestamp();
2913 let threshold =
2914 std::time::SystemTime::now() - Duration::from_secs(threshold_seconds as u64);
2915
2916 if latest_chain_time < threshold {
2918 warn!(
2919 ?latest_chain_time,
2920 ?threshold,
2921 "failing health check due to checkpoint lag"
2922 );
2923 return (axum::http::StatusCode::SERVICE_UNAVAILABLE, "down");
2924 }
2925 }
2926 (axum::http::StatusCode::OK, "up")
2928}
2929
2930#[cfg(not(test))]
2931fn max_tx_per_checkpoint(protocol_config: &ProtocolConfig) -> usize {
2932 protocol_config.max_transactions_per_checkpoint() as usize
2933}
2934
2935#[cfg(test)]
2936fn max_tx_per_checkpoint(_: &ProtocolConfig) -> usize {
2937 2
2938}
2939
2940#[cfg(all(test, not(msim)))]
2943mod runtime_split_tests {
2944 use std::{
2945 sync::mpsc,
2946 time::{Duration, Instant},
2947 };
2948
2949 use anyhow::anyhow;
2950
2951 use super::SpawnOnce;
2952
2953 fn runtime(name: &'static str) -> tokio::runtime::Runtime {
2956 tokio::runtime::Builder::new_multi_thread()
2957 .worker_threads(1)
2958 .thread_name(name)
2959 .enable_all()
2960 .build()
2961 .unwrap()
2962 }
2963
2964 fn current_pool() -> String {
2966 std::thread::current()
2967 .name()
2968 .unwrap_or("<unnamed>")
2969 .to_string()
2970 }
2971
2972 #[test]
2983 fn spawn_once_binds_on_serving_not_the_core_runtime() {
2984 let node = runtime("node-core");
2985 let serving = runtime("serving");
2986 let (tx, rx) = mpsc::channel::<(&'static str, String)>();
2987
2988 let bind_tx = tx.clone();
2991 let bind_future = async move {
2992 let _ = bind_tx.send(("bind", current_pool()));
2993 let addr = "/ip4/127.0.0.1/tcp/0/http".parse().unwrap();
2994 let server = iota_network_stack::config::Config::new()
2995 .server_builder()
2996 .bind(&addr, None)
2997 .await
2998 .map_err(|e| anyhow!("bind failed: {e}"))?;
2999 Ok(server)
3000 };
3001 let once = SpawnOnce::new(bind_future, serving.handle().clone());
3002
3003 let caller_tx = tx.clone();
3005 node.spawn(async move {
3006 let _ = caller_tx.send(("caller", current_pool()));
3007 let _ = once.start().await;
3008 });
3009
3010 let (mut caller_pool, mut bind_pool) = (None, None);
3012 let deadline = Instant::now() + Duration::from_secs(10);
3013 while (caller_pool.is_none() || bind_pool.is_none()) && Instant::now() < deadline {
3014 if let Ok((which, pool)) = rx.recv_timeout(Duration::from_millis(200)) {
3015 match which {
3016 "caller" => caller_pool = Some(pool),
3017 "bind" => bind_pool = Some(pool),
3018 _ => {}
3019 }
3020 }
3021 }
3022 let caller_pool = caller_pool.expect("start() never ran");
3023 let bind_pool = bind_pool.expect("bind future never ran");
3024
3025 assert!(
3026 caller_pool.starts_with("node-core"),
3027 "start() should run on the node-core runtime, ran on: {caller_pool}"
3028 );
3029 assert!(
3030 bind_pool.starts_with("serving"),
3031 "server bind must run on the serving runtime, ran on: {bind_pool}"
3032 );
3033 assert_ne!(
3034 caller_pool, bind_pool,
3035 "the fix must move the bind off the caller (node-core) runtime onto serving"
3036 );
3037 }
3038}
3039
3040#[cfg(test)]
3041mod config_tests {
3042 use std::sync::{Arc, atomic::AtomicBool};
3043
3044 use iota_config::NodeConfig;
3045 use iota_metrics::RegistryService;
3046 use prometheus_filtered::Registry;
3047
3048 use super::{IotaNode, ServerVersion, remove_legacy_db_checkpoints};
3049
3050 fn config_with_db_path(db_path: &std::path::Path) -> NodeConfig {
3053 serde_yaml::from_str(&format!(
3054 r#"
3055db-path: {}
3056network-address: /dns/localhost/tcp/8080/http
3057metrics-address: "0.0.0.0:9184"
3058json-rpc-address: "0.0.0.0:9000"
3059genesis:
3060 genesis-file-location: /nonexistent/genesis.blob
3061"#,
3062 db_path.display()
3063 ))
3064 .unwrap()
3065 }
3066
3067 #[tokio::test]
3071 async fn start_rejects_a_config_no_node_could_start_with() {
3072 let mut config = config_with_db_path(std::path::Path::new("/nonexistent/db"));
3073 config.enable_grpc_api = true;
3074 config.grpc_api_config = None;
3075
3076 let err = IotaNode::start(config, RegistryService::new(Registry::new()))
3077 .await
3078 .unwrap_err();
3079
3080 let err = format!("{err:#}");
3081 assert!(err.contains("`grpc-api-config` is `null`"), "{err}");
3082 }
3083
3084 #[test]
3085 fn a_leftover_database_checkpoint_directory_is_removed() {
3086 let dir = iota_common::tempdir();
3087 let config = config_with_db_path(dir.path());
3088 let leftover = dir.path().join("db_checkpoints").join("epoch_0");
3089 std::fs::create_dir_all(&leftover).unwrap();
3090 std::fs::write(leftover.join("CURRENT"), b"hard link to a live SST").unwrap();
3091 let live = config.db_path();
3092 std::fs::create_dir_all(&live).unwrap();
3093
3094 remove_legacy_db_checkpoints(&config);
3095
3096 assert!(!dir.path().join("db_checkpoints").exists());
3097 assert!(live.exists(), "the live database must be left alone");
3098 }
3099
3100 #[test]
3101 fn a_database_without_one_is_left_alone() {
3102 let dir = iota_common::tempdir();
3103
3104 remove_legacy_db_checkpoints(&config_with_db_path(dir.path()));
3105
3106 assert!(
3107 !dir.path().join("db_checkpoints").exists(),
3108 "the cleanup must not create what it is there to remove",
3109 );
3110 }
3111
3112 #[tokio::test]
3115 async fn index_retention_beyond_ledger_retention_refuses_to_start() {
3116 const TEMPLATE: &str = include_str!("../../iota-config/data/fullnode-template.yaml");
3117 let mut config: NodeConfig = serde_yaml::from_str(TEMPLATE).unwrap();
3118 config
3119 .authority_store_pruning_config
3120 .num_epochs_to_retain_for_checkpoints = Some(2);
3121 config
3122 .authority_store_pruning_config
3123 .num_epochs_to_retain_for_indexes = Some(3);
3124
3125 let err = IotaNode::start_async(
3126 config,
3127 RegistryService::new(Registry::new()),
3128 ServerVersion::new("test", "0.0.0"),
3129 tokio::runtime::Handle::current(),
3130 Arc::new(AtomicBool::new(false)),
3131 )
3132 .await
3133 .unwrap_err()
3134 .to_string();
3135
3136 assert!(err.contains("num-epochs-to-retain-for-indexes"), "{err}");
3137 assert!(
3138 err.contains("num-epochs-to-retain-for-checkpoints"),
3139 "{err}"
3140 );
3141 }
3142}
3143
3144#[cfg(test)]
3145mod listener_metrics_tests {
3146 use std::{collections::BTreeSet, sync::Arc, time::Duration};
3147
3148 use iota_metrics::{MetricGroups, MetricLevel, test_utils::MetricsReader};
3149 use iota_network_stack::config::Config;
3150 use iota_types::crypto::{KeypairTraits, NetworkKeyPair, get_key_pair};
3151 use prometheus_filtered::Registry;
3152 use tokio::io::{AsyncReadExt, AsyncWriteExt};
3153 use tonic_health::pb::{HealthCheckRequest, health_client::HealthClient};
3154
3155 use super::{
3156 GrpcMetrics, ServerBuilder, json_rpc_listener_metrics, validator_server_listener_metrics,
3157 };
3158
3159 async fn get_health(handle: &iota_http::ServerHandle<std::net::SocketAddr>) {
3160 let mut stream = tokio::net::TcpStream::connect(handle.local_addr())
3161 .await
3162 .unwrap();
3163 stream
3164 .write_all(b"GET /health HTTP/1.1\r\nhost: localhost\r\nconnection: close\r\n\r\n")
3165 .await
3166 .unwrap();
3167 let mut response = String::new();
3168 tokio::time::timeout(
3169 Duration::from_secs(10),
3170 stream.read_to_string(&mut response),
3171 )
3172 .await
3173 .unwrap()
3174 .unwrap();
3175 assert!(response.starts_with("HTTP/1.1 200"), "{response}");
3176 }
3177
3178 async fn serve_health(
3180 metrics: iota_http::metrics::ListenerMetrics,
3181 ) -> iota_http::ServerHandle<std::net::SocketAddr> {
3182 let handle = iota_http::Builder::new()
3183 .config(iota_http::Config::default().metrics(Some(metrics)))
3184 .serve(
3185 "127.0.0.1:0",
3186 axum::Router::new().route("/health", axum::routing::get(|| async { "up" })),
3187 )
3188 .unwrap();
3189 get_health(&handle).await;
3190 handle
3191 }
3192
3193 fn registry_with_groups(groups: &MetricGroups) -> Registry {
3194 let (filter, errors) = groups.startup_filter(None);
3195 assert!(errors.is_empty());
3196 Registry::new_custom(None, None, Some(Arc::new(filter))).unwrap()
3197 }
3198
3199 async fn node_registry(groups: &MetricGroups) -> Registry {
3203 let registry = registry_with_groups(groups);
3204
3205 let key_pair = get_key_pair::<NetworkKeyPair>().1;
3206 let tls_config =
3207 iota_tls::create_rustls_server_config(key_pair.copy().private(), "test".to_string());
3208 let client_config = iota_tls::create_rustls_client_config(
3209 key_pair.public().to_owned(),
3210 "test".to_string(),
3211 None,
3212 );
3213 let config = Config::new();
3214 let validator = ServerBuilder::from_config(&config, GrpcMetrics::new(®istry))
3215 .listener_metrics(validator_server_listener_metrics(®istry))
3216 .bind(
3217 &"/ip4/127.0.0.1/tcp/0/http".parse().unwrap(),
3218 Some(tls_config),
3219 )
3220 .await
3221 .unwrap();
3222 let channel = config
3223 .connect(validator.local_addr(), client_config)
3224 .await
3225 .unwrap();
3226 HealthClient::new(channel)
3227 .check(HealthCheckRequest {
3228 service: String::new(),
3229 })
3230 .await
3231 .unwrap();
3232
3233 let json_rpc = serve_health(json_rpc_listener_metrics(®istry)).await;
3234 let grpc_api = iota_grpc_server::GrpcServerMetrics::new(®istry);
3235 let grpc_api_listener = serve_health(grpc_api.listener_metrics()).await;
3236
3237 validator.trigger_shutdown();
3238 json_rpc.trigger_shutdown();
3239 grpc_api_listener.trigger_shutdown();
3240 registry
3241 }
3242
3243 fn prefix_names<'a>(prefix: &'a str, names: &'a [&str]) -> impl Iterator<Item = String> + 'a {
3244 names.iter().map(move |name| format!("{prefix}_{name}"))
3245 }
3246
3247 const CONNECTION_FAMILIES: &[&str] = &[
3248 "inbound_connections_accepted",
3249 "inbound_connections",
3250 "inbound_connections_peak",
3251 "connection_lifetime_seconds",
3252 ];
3253 const TLS_FAMILIES: &[&str] = &["handshake_latency", "pending_handshakes_peak"];
3254
3255 const GRPC_API_FAMILIES: &[&str] = &["response_item_bytes_peak", "requested_max_message_bytes"];
3258
3259 const GRPC_API_DEFAULT_FAMILIES: &[&str] = &["inflight_checkpoint_stream_subscribers"];
3263
3264 fn listener_families(prefix: &str) -> BTreeSet<String> {
3267 prefix_names(prefix, CONNECTION_FAMILIES).collect()
3268 }
3269
3270 fn all_listener_families() -> BTreeSet<String> {
3273 listener_families("authority_grpc")
3274 .into_iter()
3275 .chain(prefix_names("authority_grpc", TLS_FAMILIES))
3276 .chain(listener_families("json_rpc"))
3277 .chain(listener_families("node_grpc"))
3278 .collect()
3279 }
3280
3281 fn grpc_api_families() -> BTreeSet<String> {
3283 prefix_names("node_grpc", GRPC_API_FAMILIES).collect()
3284 }
3285
3286 fn default_families() -> BTreeSet<String> {
3288 all_listener_families()
3289 .into_iter()
3290 .chain(prefix_names("node_grpc", GRPC_API_DEFAULT_FAMILIES))
3291 .collect()
3292 }
3293
3294 async fn shown(groups: &MetricGroups) -> BTreeSet<String> {
3295 MetricsReader::new(&node_registry(groups).await).family_names()
3296 }
3297
3298 #[tokio::test]
3299 async fn the_listeners_and_the_grpc_api_requests_show_by_default() {
3300 assert_eq!(shown(&MetricGroups::default()).await, default_families());
3301 }
3302
3303 #[tokio::test]
3304 async fn the_iota_grpc_server_override_shows_the_response_sizes_of_the_grpc_api() {
3305 let groups = MetricGroups {
3306 overrides: [("iota_grpc_server".to_owned(), MetricLevel::Info)].into(),
3307 ..MetricGroups::default()
3308 };
3309 let expected: BTreeSet<String> = default_families()
3310 .into_iter()
3311 .chain(grpc_api_families())
3312 .collect();
3313 assert_eq!(shown(&groups).await, expected);
3314 }
3315}