Skip to main content

iota_node/
lib.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use 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    /// Handle for the consensus queue overload monitor task, present only
166    /// when the certificate-less (P-COOL) flow is enabled. The
167    /// task self-terminates via `Weak` references; this handle exists purely
168    /// for ownership clarity.
169    consensus_queue_overload_monitor_handle: Option<JoinHandle<()>>,
170    /// Handle for the soft-lock expiry sweep task. The task self-terminates
171    /// via a `Weak` reference; this handle exists purely for ownership clarity.
172    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    // Keeping the handle to the checkpoint service tasks to shut them down during reconfiguration.
179    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    /// The http server responsible for serving JSON-RPC
230    _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    /// Lets state sync fetch summaries to the end of the epoch being
240    /// executed; set for each epoch from `sync_summaries_to_epoch_end`.
241    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    /// Broadcast channel to send the starting system state for the next epoch.
248    end_of_epoch_channel: broadcast::Sender<IotaSystemState>,
249
250    /// Broadcast channel to notify [`DiscoveryEventLoop`] for new validator
251    /// peers.
252    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    // Channel to allow signaling upstream to shutdown iota-node
263    shutdown_channel_tx: broadcast::Sender<Option<RunWithRange>>,
264
265    /// Handle to the gRPC server for gRPC streaming and graceful shutdown
266    grpc_server_handle: Mutex<Option<GrpcServerHandle>>,
267
268    /// AuthorityAggregator of the network, created at start and beginning of
269    /// each epoch. Use ArcSwap so that we could mutate it without taking
270    /// mut reference.
271    // TODO: Eventually we can make this auth aggregator a shared reference so that this
272    // update will automatically propagate to other uses.
273    auth_agg: Arc<ArcSwap<AuthorityAggregator<NetworkAuthorityClient>>>,
274
275    /// Runtime that hosts the client-facing servers and their per-request
276    /// handlers, isolating external request load from the node core.
277    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
288/// Removes the `db_checkpoints` directory earlier releases wrote under the
289/// node's `db-path`. A failure is logged, not returned.
290// TODO(#12968): remove once a release containing this has shipped.
291fn 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        // The directory only costs disk, which is no reason to refuse to start.
302        Err(e) => warn!(
303            "failed to remove the leftover database checkpoint directory {}: {e}",
304            path.display()
305        ),
306    }
307}
308
309impl IotaNode {
310    /// Starts a node that hosts the client-facing servers on the caller's
311    /// runtime, alongside everything else.
312    ///
313    /// This is intentional: this entry point serves the in-process nodes of
314    /// iota-swarm, where a separate serving runtime is either impossible
315    /// (simtests must keep every task on the simulator's deterministic
316    /// scheduler) or not worth the threads (thread-mode swarm runs many nodes
317    /// per process). Only the `iota-node` binary isolates client-facing
318    /// request handling on the dedicated serving runtime of `IotaRuntimes`,
319    /// via [`IotaNode::start_async`].
320    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    /// Starts a background task that polls the authority's load shedding
335    /// percentage and broadcasts changes to other validators via consensus.
336    /// Returns the task handle if the feature flag is enabled, or `None`
337    /// otherwise.
338    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            // Seed from the percentage this authority last broadcasted
353            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    /// Setting `index_rebuild_cancelled` stops an RPC index rebuild running
380    /// during startup, which no other shutdown path can reach.
381    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(&registry_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        // Check and set the db_corrupted flag
419        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        // Initialize metrics to track db usage before creating any stores
425        DBMetrics::init(&prometheus_registry);
426
427        // Initialize IOTA metrics.
428        iota_metrics::init_metrics(&prometheus_registry);
429        // Unsupported (because of the use of static variable) and unnecessary in
430        // simtests.
431        #[cfg(not(msim))]
432        iota_metrics::thread_stall_monitor::start_thread_stall_monitor();
433
434        // Monitor the node-core and serving runtimes so that worker-thread
435        // starvation between them is observable. Gated out of simtests, where
436        // tokio runs under the deterministic simulator.
437        #[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        // Register uptime metric
454        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        // By default, only enable write stall on validators for perpetual db.
479        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        // The migration data is only needed to initialize an empty database and to
508        // execute the migration transactions, which are part of the genesis
509        // checkpoint. Loading it also leads to re-executing every migration
510        // transaction, so skip it once the genesis checkpoint has been executed.
511        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                // Here the load already verifies that the content of the migration blob is
517                // valid in respect to the content found in genesis
518                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(&registry_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        // the database is empty at genesis time
602        if is_genesis {
603            info!("checking IOTA conservation at genesis");
604            // When we are opening the db table, the only time when it's safe to
605            // check IOTA conservation is at genesis. Otherwise we may be in the middle of
606            // an epoch and the IOTA conservation check will fail. This also initialize
607            // the expected_network_iota_amount table.
608            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        // Database has everything from genesis, set corrupted key to 0
633        unmark_db_corruption(db_corrupted_path)?;
634
635        // A database created from genesis has nothing for the one-time passes
636        // below to find.
637        // TODO(https://github.com/iotaledger/iota/issues/12712): remove this.
638        if is_genesis {
639            store.mark_pre_bucket_passes_done()?;
640            checkpoint_store.mark_checkpoint_backlog_migrated()?;
641        }
642
643        // Before the first start changes anything an older release reads, so
644        // that a refused start leaves the database usable by that release.
645        // TODO(https://github.com/iotaledger/iota/issues/12763): remove this call.
646        let pruning_config = &config.authority_store_pruning_config;
647        // Only space freed on the history's file system helps the migration,
648        // which copies into it.
649        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        // The first one-way step: an older release reads the column family
665        // this drops.
666        store.retire_objects_pruner_watermark()?;
667
668        // Frees disk space ahead of the one-time migration passes below. The
669        // check above counted that space as free, so a failed removal must
670        // stop the start before the migration fills the disk.
671        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        // Before any service starts, since nothing reads the flat tables.
686        // TODO(https://github.com/iotaledger/iota/issues/12763): remove this call.
687        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        // Before any service starts: a missed marker would let a receive or a
701        // delete happen twice.
702        // TODO(https://github.com/iotaledger/iota/issues/12712): remove this call.
703        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        // Before any service that could expire a historic bucket starts, and
710        // before the index rebuild below scans the live `objects` table.
711        // TODO(https://github.com/iotaledger/iota/issues/12712): remove this call.
712        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        // As at an epoch change. After the one-time passes above, whose
726        // rewind writes only the saved synced watermark, and before state sync
727        // marks anything synced.
728        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        // Seed the open epoch's `epoch_info` row before services start.
782        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        // Create network
788        // TODO only configure validators as seed/preferred peers for validators and not
789        // for fullnodes once we've had a chance to re-work fullnode
790        // configuration generation.
791        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        // We must explicitly send this instead of relying on the initial value to
815        // trigger watch value change, so that state-sync is able to process it.
816        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        // The state snapshot writer is the consumer of the epoch end database
824        // snapshot: the boundary hands each epoch to it on this channel. A
825        // depth of one is enough, because an epoch arriving while the writer
826        // is still busy is skipped rather than queued.
827        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        // ensure genesis and migration txs were executed
872        if epoch_store.epoch() == 0 {
873            let genesis_tx = &genesis.transaction();
874            let span = error_span!("genesis_txn", tx_digest = ?genesis_tx.digest());
875            // Execute genesis transaction
876            Self::execute_transaction_immediately_at_zero_epoch(
877                &state,
878                &epoch_store,
879                genesis_tx,
880                span,
881            )
882            .await;
883
884            // Execute migration transactions if present
885            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        // Start the loop that receives new randomness and generates transactions for
900        // it.
901        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        // Run the JSON-RPC server (and its per-request handlers) on the serving
920        // runtime. `iota_http::Builder::serve` spawns the accept loop via
921        // `Handle::current()`, so the builder must execute on the serving runtime.
922        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", &registry_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(&registry_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        // Convert transaction orchestrator to executor trait object for gRPC server
979        // Note that the transaction_orchestrator (so as executor) will be None if it is
980        // a validator node or run_with_range is set
981        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        // Run the gRPC read API server (and its per-request handlers) on the
987        // serving runtime, for the same reason as the JSON-RPC server above.
988        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                    &registry_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            // Start the gRPC server
1032            components.validator_server_handle = components.validator_server_handle.start().await;
1033
1034            Some(components)
1035        } else {
1036            None
1037        };
1038
1039        // setup shutdown channel
1040        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    // Init reconfig process by starting to reject user certs
1106    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    // Testing-only API to start epoch close process.
1133    // For production code, please use the non-testing version.
1134    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    /// Creates a StateSnapshotUploader and starts it if
1140    /// `state-snapshot-write-config.object-store-config` is set. Snapshot
1141    /// publication is a fullnode-only role.
1142    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    /// Whether state sync should fetch summaries to the end of the epoch of
1170    /// `epoch_store`: this node is in its committee and waits for its own
1171    /// checkpoints there.
1172    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            // Inbound requests on this network are small (signatures, queries, summaries).
1248            // Cap request frames at 1 MiB.
1249            anemo_config.max_request_frame_size = Some(1 << 20);
1250            // Responses can be larger (checkpoint contents).
1251            // Cap response frames at 128 MiB.
1252            anemo_config.max_response_frame_size = Some(128 << 20);
1253
1254            // Set a higher default value for socket send/receive buffers if not already
1255            // configured.
1256            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            // Set high-performance defaults for quinn transport.
1266            // With 200MiB buffer size and ~500ms RTT, max throughput ~400MiB/s.
1267            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    /// Asynchronously constructs and initializes the components necessary for
1323    /// the validator node.
1324    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        // This only gets started up once, not on every epoch. (Make call to remove
1365        // every epoch.)
1366        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        // Spawn the soft-lock sweep once for the lifetime of this validator
1385        // instance. The task holds only a `Weak<PreConsensusSoftLocks>` so it
1386        // stops itself automatically: each iteration it tries to upgrade the
1387        // weak reference, and when all strong `Arc` owners have been dropped
1388        // (i.e. `ValidatorComponents` is destructured and the old epoch store
1389        // is released after an epoch transition that removes us from the
1390        // committee) the upgrade returns `None` and the loop exits. No explicit
1391        // `abort()` is needed. The same `Arc<PreConsensusSoftLocks>` is reused
1392        // across epoch transitions (see `start_epoch_specific_validator_components`),
1393        // so the task keeps running uninterrupted while the node remains a validator.
1394        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        // Starts an overload monitor that monitors the execution of the authority.
1411        // Don't start the overload monitor when max_load_shedding_percentage is 0.
1412        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        // Starts a monitor that periodically refreshes the
1429        // `consensus_queue_load_shedding_percentage` metric. Without this, the
1430        // metric goes stale once gRPC traffic stops (the only other update
1431        // path is `AuthorityState::check_consensus_queue_graduated_limits`, called on
1432        // each inbound tx). Used in the certificate-less (P-COOL)
1433        // mode.
1434        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    /// Initializes and starts components specific to the current
1474    /// epoch for the validator node.
1475    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        // create a new map that gets injected into both the consensus handler and the
1508        // consensus adapter the consensus handler will write values forwarded
1509        // from consensus, and the consensus adapter will read the values to
1510        // make decisions about which validator submits a transaction to consensus
1511        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        // Wire pre-consensus soft locks to the epoch store so that
1516        // post-consensus processing can release locks once permanent locks are
1517        // quarantined. Clear stale locks from the previous epoch and spawn a
1518        // background sweep task.
1519        soft_locks.clear();
1520        epoch_store.set_soft_locks(soft_locks.clone());
1521
1522        // A validator cannot participate without a randomness manager. Aborting here
1523        // fails loudly at the real cause (startup or reconfiguration) instead
1524        // of leaving the node to panic later on the first consensus commit that
1525        // unconditionally expects one.
1526        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        // Subscribe before starting consensus so that the replay waiter cannot miss the
1557        // one-shot consumer monitor broadcast if consensus starts immediately.
1558        let replay_waiter = consensus_manager.replay_waiter();
1559
1560        // Spawn consensus startup asynchronously to avoid blocking other components
1561        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        // With deterministic validation, a checkpoint built before a restart
1583        // has to be rebuilt from the replayed commits before it is executed.
1584        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    /// Starts the checkpoint service for the validator node, initializing
1619    /// necessary components and settings.
1620    /// The function ensures proper initialization of the checkpoint service,
1621    /// preparing it to handle checkpoint creation and submission to consensus,
1622    /// while also setting up the necessary monitoring and synchronization
1623    /// mechanisms.
1624    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        // The consensus adapter allows the authority to send user certificates through
1683        // consensus.
1684
1685        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        // Each service gets its own concurrency limit so that a flood of client
1717        // transaction submissions (Validator / ValidatorV2) cannot crowd the
1718        // validator-peer RPCs sharing this listener out of admission slots.
1719        // The config value is per core, so the same config scales with the
1720        // hardware; the effective limit is computed on the machine the server
1721        // actually runs on.
1722        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        // HTTP/2 keepalive is the only mechanism that closes a connection whose
1729        // peer has gone away without closing it: the server pings after this
1730        // long without inbound frames and drops the connection when the ping
1731        // goes unanswered for as long again.
1732        const VALIDATOR_GRPC_KEEPALIVE: Duration = Duration::from_secs(60);
1733        // Bounds the streams one connection may hold open, so a single peer
1734        // cannot fill a service's admission slots on its own. A fullnode sends
1735        // every request to this validator over one connection, so the cap must
1736        // stay well above a busy fullnode's peak concurrency.
1737        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    /// Re-executes pending consensus certificates, which may not have been
1785    /// committed to disk before the node restarted. This is necessary for
1786    /// the following reasons:
1787    ///
1788    /// 1. For any transaction for which we returned signed effects to a client, we must ensure that
1789    ///    we have re-executed the transaction before we begin accepting grpc requests. Otherwise we
1790    ///    would appear to have forgotten about the transaction.
1791    /// 2. While this is running, we are concurrently waiting for all previously built checkpoints
1792    ///    to be rebuilt. Since there may be dependencies in either direction (from checkpointed
1793    ///    consensus transactions to pending consensus transactions, or vice versa), we must
1794    ///    re-execute pending consensus transactions to ensure that both processes can complete.
1795    /// 3. Also note that for any pending consensus transactions for which we wrote a signed effects
1796    ///    digest to disk, we must re-execute using that digest as the expected effects digest, to
1797    ///    ensure that we cannot arrive at different effects than what we previously signed.
1798    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                // TODO: what to do with UserTransactionV1 here? It seems like this only applies to
1808                //  optimistically executed owned-object transactions that possibly didn't go
1809                //  through  consensus before the node restarted. UserTransactionsV1
1810                //  always needs to go  through consensus, so it will be replayed
1811                //  there, just like shared object  transactions.
1812                //
1813                // Shared object txns
1814                // cannot be re-executed at this  point, because we must wait for
1815                // consensus replay to assign shared  object versions.
1816                ConsensusTransactionKind::CertifiedTransaction(tx)
1817                    if !tx.contains_shared_object() =>
1818                {
1819                    let tx = *tx;
1820                    // new_unchecked is safe because we never submit a transaction to consensus
1821                    // without verifying it
1822                    let tx = VerifiedExecutableTransaction::new_from_certificate(
1823                        VerifiedCertificate::new_unchecked(tx),
1824                    );
1825                    // we only need to re-execute if we previously signed the effects (which
1826                    // indicates we returned the effects to a client).
1827                    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            // unwrap_digest okay because only user certs are in
1846            // pending_consensus_certificates
1847            .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        // If this times out, the validator will still almost certainly start up fine.
1864        // But, it is possible that it may temporarily "forget" about
1865        // transactions that it had previously executed. This could confuse
1866        // clients in some circumstances. However, the transactions are still in
1867        // pending_consensus_certificates, so we cannot lose any finality guarantees.
1868        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            // Log all the digests that were not executed to help debugging.
1882            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    // Only used for testing because of how epoch store is loaded.
1914    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_store(&self) -> Arc<AuthorityStore> {
1923    // self.state.db()
1924    // }
1925
1926    /// Clone an AuthorityAggregator from the transaction orchestrator, if
1927    /// this is a fullnode. The snapshot goes stale after an epoch change;
1928    /// call again for a fresh one.
1929    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    /// Read-only client for the SDK's `TransactionBuilder` backed by this
1944    /// node's local state instead of a remote endpoint.
1945    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    /// Subscribe to the quorum driver's effects stream; errors while the
1954    /// quorum driver is not the currently served flow on this node.
1955    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    /// This function awaits the completion of checkpoint execution of the
1973    /// current epoch, after which it initiates reconfiguration of the
1974    /// entire system. This function also handles role changes for the node when
1975    /// epoch changes and, if the node is a validator, advertises capabilities
1976    /// and submits the local deny rule proposal to consensus.
1977    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            // Create closures that handle gRPC type conversion
1993            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            // Update the current protocol version metric.
2021            self.metrics
2022                .current_protocol_version
2023                .set(cur_epoch_store.protocol_config().version.as_u64() as i64);
2024
2025            // Advertise capabilities to committee, if we are a validator.
2026            if let Some(components) = &*self.validator_components.lock().await {
2027                // TODO: without this sleep, the consensus message is not delivered reliably.
2028                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                            // no need to send digests of versions less than the current version
2039                            .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                // Announce the local deny rules. Recorded proposals are
2049                // epoch-scoped, so this re-announces on every epoch change.
2050                // The empty set is announced too: every committee member
2051                // attests its configuration each epoch, so silence means
2052                // offline rather than "no rules".
2053                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                // Send signed capabilities to committee validators if we are a non-committee
2077                // validator in a separate task to not block the caller. Sending is done only if
2078                // the feature flag supporting it is enabled.
2079                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            // Safe to call because we are in the middle of reconfiguration.
2106            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            // We save the connection monitor status map regardless of validator / fullnode
2154            // status so that we don't need to restart the connection monitor
2155            // every epoch. Update the mappings that will be used by the
2156            // consensus adapter if it exists or is about to be created.
2157            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            // The following code handles 4 different cases, depending on whether the node
2173            // was a validator in the previous epoch, and whether the node is a validator
2174            // in the new epoch.
2175            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                // Cancel the old overload notifier task so a new one can be
2207                // started for the next epoch.
2208                if let Some(handle) = overload_notifier_handle {
2209                    handle.abort();
2210                }
2211                // Cancel the old checkpoint service tasks.
2212                // Waiting for checkpoint builder to finish gracefully is not possible, because
2213                // it may wait on transactions while consensus on peers have
2214                // already shut down.
2215                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                // No other components should be holding a strong reference to state hasher
2232                // at this point. Confirm here before we swap in the new hasher.
2233                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                    // Only restart consensus if this node is still a validator in the new epoch.
2247                    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                // No other components should be holding a strong reference to state hasher
2285                // at this point. Confirm here before we swap in the new hasher.
2286                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            // Force releasing current epoch store DB handle, because the
2326            // Arc<AuthorityPerEpochStore> may linger.
2327            cur_epoch_store.release_db_handles();
2328
2329            // Drop the old epoch store to free its in-memory structures
2330            // (ConsensusOutputCache, ConsensusQuarantine, DashMaps, etc.).
2331            // The DB tables were already released above.
2332            drop(cur_epoch_store);
2333
2334            // Prune old epoch databases after each epoch transition to prevent
2335            // accumulation of RocksDB instances during fast catch-up sync
2336            // (e.g. syncing from genesis).
2337            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    /// Stops consensus, the JSON-RPC index backfill and the gRPC server.
2345    /// Does nothing the second time it is called.
2346    pub async fn shutdown(&self) {
2347        // First, so that a running expiry or compaction, which the runtime's
2348        // shutdown waits for, ends soon.
2349        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        // Stop the background index backfill so shutdown does not block on
2356        // a full history replay.
2357        if let Some(indexes) = &self.state.rpc_indexes_store {
2358            indexes.shutdown().await;
2359        }
2360
2361        // Shutdown the gRPC server if it's running
2362        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    /// Asynchronously reconfigures the state of the authority node for the next
2371    /// epoch.
2372    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        // Every checkpoint of the ending epoch has executed, so the saved
2429        // synced watermark is safe to go on from while readers' value is held
2430        // in memory. Nodes outside the committee build no checkpoints, so
2431        // their saved watermark never falls behind and the hold is not turned
2432        // on for them. A hold turned on in an earlier epoch stays on, which is
2433        // harmless (see `CheckpointStore::hold_synced_watermark_in_memory`).
2434        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    /// Returns the registry service holding the node's Prometheus registries
2476    /// and their shared exposure filter.
2477    pub(crate) fn registry_service(&self) -> &RegistryService {
2478        &self.registry_service
2479    }
2480
2481    /// Sends signed capability notification to committee validators for
2482    /// non-committee validators. This method implements retry logic to handle
2483    /// failed attempts to send the notification. It will retry sending the
2484    /// notification with an increasing interval until it receives a successful
2485    /// response from a f+1 committee members or 2f+1 non-retryable errors.
2486    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; // 5 minutes
2493
2494        // Create the capability notification once
2495        let config = epoch_store.protocol_config();
2496
2497        // Create the capability notification
2498        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        // Sign the capabilities using the authority key pair from config
2509        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                    // Wait before retrying
2556                    tokio::time::sleep(retry_interval).await;
2557
2558                    // Increase retry interval for the next attempt, capped at max
2559                    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    /// Gathers the metric families the node exposes under the current filter.
2576    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    // Mutex is only needed to make SpawnOnce Sync
2590    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                // bind() and serve() must execute on the serving runtime:
2610                // iota_http::Builder::serve captures Handle::current() there for
2611                // the accept loop and every request handler.
2612                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
2641/// Notify [`DiscoveryEventLoop`] that a new list of trusted peers are now
2642/// available.
2643fn 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
2693/// Builds and starts the gRPC server for the IOTA node based on the node's
2694/// configuration.
2695///
2696/// Returns `None` on a validator and when the gRPC API is disabled.
2697///
2698/// # Panics
2699///
2700/// Panics if the gRPC API is enabled without a `grpc-api-config`.
2701/// [`NodeConfig::validate`] rejects such a config at startup.
2702async 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    // Validators do not expose gRPC APIs. This return must agree with the
2711    // gRPC rule in `NodeConfig::validate`, which is what makes the `expect`
2712    // below unreachable.
2713    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    // Get chain identifier from state directly
2723    let chain_id = state.get_chain_identifier();
2724
2725    let grpc_read_store = Arc::new(GrpcReadStore::new(state.clone(), state_sync_store));
2726
2727    // Create cancellation token for proper shutdown hierarchy
2728    let shutdown_token = CancellationToken::new();
2729
2730    // Create GrpcReader
2731    let grpc_reader = Arc::new(GrpcReader::new(
2732        grpc_read_store,
2733        Some(server_version.to_string()),
2734    ));
2735
2736    // Create gRPC server metrics
2737    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
2758/// Builds and starts the HTTP server for the IOTA node, exposing the JSON-RPC
2759/// API based on the node's configuration.
2760///
2761/// This function performs the following tasks:
2762/// 1. Checks if the node is a validator by inspecting the consensus configuration; if so, it
2763///    returns early as validators do not expose these APIs.
2764/// 2. Creates an Axum router to handle HTTP requests.
2765/// 3. If the JSON-RPC API is enabled, initializes the JSON-RPC server and registers various RPC
2766///    modules based on the node's state and configuration, including CoinApi,
2767///    TransactionBuilderApi, GovernanceApi, TransactionExecutionApi, and IndexerApi.
2768/// 4. Adds the `/health` endpoint, which is served whether or not the JSON-RPC API is enabled.
2769/// 5. Binds the server to the specified JSON-RPC address and starts listening for incoming
2770///    connections.
2771pub 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    // Validators do not expose these APIs
2778    if config.is_validator() {
2779        return Ok(None);
2780    }
2781
2782    let mut router = axum::Router::new();
2783
2784    // A full node with JSON-RPC off still serves `/health`, which liveness
2785    // probes rely on.
2786    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 run_with_range is enabled we want to prevent any transactions
2811            // run_with_range = None is normal operating conditions
2812            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        // Attempt to get the latest checkpoint
2896        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        // Calculate the threshold time based on the provided threshold_seconds
2912        let latest_chain_time = summary.timestamp();
2913        let threshold =
2914            std::time::SystemTime::now() - Duration::from_secs(threshold_seconds as u64);
2915
2916        // Check if the latest checkpoint is within the threshold
2917        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    // if health endpoint is responding and no threshold is given, respond success
2927    (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// Not msim: this test asserts routing across real OS worker-thread pools by
2941// name, which the deterministic simulator collapses onto a single thread.
2942#[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    /// A single-worker-thread runtime whose worker thread carries `name`, so a
2954    /// task can tell which runtime it is running on via `current_pool()`.
2955    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    /// Name of the runtime whose worker thread is executing this code.
2965    fn current_pool() -> String {
2966        std::thread::current()
2967            .name()
2968            .unwrap_or("<unnamed>")
2969            .to_string()
2970    }
2971
2972    /// Regression guard for the runtime split. `SpawnOnce::start()` is invoked
2973    /// on the node-core runtime (as `IotaNode::start_async` does), but it
2974    /// must run the server *bind* on the serving runtime:
2975    /// `iota_http::Builder::serve` captures `Handle::current()` there for
2976    /// the accept loop and every request handler.
2977    ///
2978    /// The test records the runtime `start()` runs on and the runtime the bind
2979    /// runs on, and asserts the former is node-core and the latter is
2980    /// serving (so they differ). With the pre-fix inline bind the bind ran
2981    /// on the caller (node-core) runtime, and this test fails.
2982    #[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        // The "bind" future records where it runs, then binds a minimal real
2989        // server (health service only) on an ephemeral port.
2990        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        // Drive start() ON the node-core runtime and record the runtime it runs on.
3004        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        // Collect both readings.
3011        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    /// A config whose `db-path` is `db_path`, with nothing else a node would
3051    /// need to start.
3052    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    /// `start_async` validates the config before it does anything else. That
3068    /// keeps the `expect` in `build_grpc_server` and the `debug_assert` in
3069    /// `start_state_snapshot` unreachable.
3070    #[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    /// `start_async` refuses a config whose index retention outlives its
3113    /// ledger retention before it opens a database.
3114    #[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    /// Starts an HTTP listener with `metrics` and sends it one request.
3179    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    /// The registry of a node with the listener metrics registered the way the
3200    /// node registers them, after one TLS connection to the validator listener
3201    /// and one request to each of the JSON-RPC and gRPC API listeners.
3202    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(&registry))
3215            .listener_metrics(validator_server_listener_metrics(&registry))
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(&registry)).await;
3234        let grpc_api = iota_grpc_server::GrpcServerMetrics::new(&registry);
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    /// `node_grpc_response_message_bytes` is not listed: it has a series per
3256    /// method, so it shows only once the gRPC API has sent a response.
3257    const GRPC_API_FAMILIES: &[&str] = &["response_item_bytes_peak", "requested_max_message_bytes"];
3258
3259    /// The families of the gRPC API that show by default. The request
3260    /// metrics per method are `warn` too, but have no series before the first
3261    /// request.
3262    const GRPC_API_DEFAULT_FAMILIES: &[&str] = &["inflight_checkpoint_stream_subscribers"];
3263
3264    /// Every family the listener of `prefix` registers, but not its TLS
3265    /// families.
3266    fn listener_families(prefix: &str) -> BTreeSet<String> {
3267        prefix_names(prefix, CONNECTION_FAMILIES).collect()
3268    }
3269
3270    /// Every family the three listeners register. Only the validator listener
3271    /// uses TLS here.
3272    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    /// The families of the response sizes of the gRPC API.
3282    fn grpc_api_families() -> BTreeSet<String> {
3283        prefix_names("node_grpc", GRPC_API_FAMILIES).collect()
3284    }
3285
3286    /// Every family that shows by default.
3287    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}