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
5#[cfg(msim)]
6use std::sync::atomic::Ordering;
7use std::{
8    collections::HashMap,
9    fmt,
10    future::Future,
11    num::NonZeroUsize,
12    sync::{Arc, Weak},
13    time::Duration,
14};
15
16use anemo::Network;
17use anemo_tower::{
18    callback::CallbackLayer,
19    trace::{DefaultMakeSpan, DefaultOnFailure, TraceLayer},
20};
21use anyhow::{Result, anyhow};
22use arc_swap::ArcSwap;
23use futures::future::BoxFuture;
24pub use handle::IotaNodeHandle;
25use iota_common::{debug_fatal, fatal};
26use iota_config::{
27    ConsensusConfig, NodeConfig, node::RunWithRange, node_config_metrics::NodeConfigMetrics,
28};
29use iota_core::{
30    authority::{
31        AuthorityState, AuthorityStore, RandomnessRoundReceiver,
32        authority_per_epoch_store::AuthorityPerEpochStore,
33        authority_store_pruner::ObjectsCompactionFilter,
34        authority_store_tables::{
35            AuthorityPerpetualTables, AuthorityPerpetualTablesOptions, AuthorityPrunerTables,
36        },
37        backpressure::BackpressureManager,
38        epoch_start_configuration::{EpochFlag, EpochStartConfigTrait, EpochStartConfiguration},
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    execution_cache::build_execution_cache,
67    global_state_hasher::{GlobalStateHashMetrics, GlobalStateHasher},
68    grpc_indexes::{GRPC_INDEXES_DIR, GrpcIndexesStore},
69    jsonrpc_index::IndexStore,
70    module_cache_metrics::ResolverMetrics,
71    overload_monitor::{consensus_queue_overload_monitor, overload_monitor},
72    safe_client::SafeClientMetricsBase,
73    signature_verifier::SignatureVerifierMetrics,
74    storage::{GrpcReadStore, RocksDbStore},
75    transaction_orchestrator::TransactionOrchestrator,
76    validator_tx_finalizer::ValidatorTxFinalizer,
77};
78use iota_genesis_common::MigrationTxDataExt;
79use iota_grpc_server::{GrpcReader, GrpcServerHandle, start_grpc_server};
80use iota_json_rpc::{
81    JsonRpcServerBuilder, coin_api::CoinReadApi, governance_api::GovernanceReadApi,
82    indexer_api::IndexerApi, move_utils::MoveUtils, read_api::ReadApi,
83    transaction_builder_api::TransactionBuilderApi,
84    transaction_execution_api::TransactionExecutionApi,
85};
86use iota_json_rpc_api::JsonRpcMetrics;
87use iota_macros::{fail_point, fail_point_async, replay_log};
88use iota_metrics::{
89    RegistryID, RegistryService,
90    metrics_network::{MetricsMakeCallbackHandler, NetworkConnectionMetrics, NetworkMetrics},
91    server_timing_middleware, spawn_monitored_task,
92};
93use iota_names::config::IotaNamesConfig;
94use iota_network::{
95    api::{ValidatorPeerServer, ValidatorServer, ValidatorV2Server},
96    discovery,
97    discovery::TrustedPeerChangeEvent,
98    randomness, state_sync,
99};
100use iota_network_stack::server::{IOTA_TLS_SERVER_NAME, ServerBuilder};
101use iota_node_transaction_builder::NodeTransactionBuilderLedgerClient;
102use iota_protocol_config::{ProtocolConfig, ProtocolVersion};
103use iota_sdk_types::{
104    RandomnessRound,
105    crypto::{Intent, IntentMessage, IntentScope},
106};
107use iota_snapshot::uploader::StateSnapshotUploader;
108use iota_storage::{
109    http_key_value_store::HttpKVStore,
110    key_value_store::{FallbackTransactionKVStore, TransactionKeyValueStore},
111    key_value_store_metrics::KeyValueStoreMetrics,
112};
113use iota_types::{
114    base_types::{AuthorityName, ConciseableName, EpochId},
115    committee::Committee,
116    crypto::{AuthoritySignature, IotaAuthoritySignature, KeypairTraits},
117    digests::ChainIdentifier,
118    error::{IotaError, IotaResult},
119    executable_transaction::VerifiedExecutableTransaction,
120    execution_config_utils::to_binary_config,
121    full_checkpoint_content::CheckpointData,
122    iota_system_state::{
123        IotaSystemState, IotaSystemStateTrait,
124        epoch_start_iota_system_state::{EpochStartSystemState, EpochStartSystemStateTrait},
125    },
126    messages_checkpoint::CheckpointSummaryExt,
127    messages_consensus::{
128        AuthorityCapabilitiesV1, ConsensusTransaction, ConsensusTransactionKind,
129        SignedAuthorityCapabilitiesV1, TransactionDenyRuleProposal,
130    },
131    messages_grpc::HandleCapabilityNotificationRequestV1,
132    quorum_driver_types::QuorumDriverEffectsQueueResult,
133    supported_protocol_versions::SupportedProtocolVersions,
134    transaction::{SenderSignedTransactionAPI, TransactionEnvelope, VerifiedCertificate},
135};
136use prometheus_filtered::Registry;
137#[cfg(msim)]
138use simulator::*;
139use tap::tap::TapFallible;
140use tokio::{
141    sync::{Mutex, broadcast, mpsc, watch},
142    task::{JoinHandle, JoinSet},
143};
144use tokio_util::sync::CancellationToken;
145use tower::ServiceBuilder;
146use tracing::{Instrument, debug, error, error_span, info, trace_span, warn};
147use typed_store::{
148    DBMetrics,
149    rocks::{check_and_mark_db_corruption, default_db_options, unmark_db_corruption},
150};
151
152use crate::metrics::{GrpcMetrics, IotaNodeMetrics};
153
154pub mod admin;
155mod handle;
156pub mod metrics;
157
158pub struct ValidatorComponents {
159    validator_server_handle: SpawnOnce,
160    validator_overload_monitor_handle: Option<JoinHandle<()>>,
161    /// Handle for the consensus queue overload monitor task, present only
162    /// when the certificate-less (P-COOL) flow is enabled. The
163    /// task self-terminates via `Weak` references; this handle exists purely
164    /// for ownership clarity.
165    consensus_queue_overload_monitor_handle: Option<JoinHandle<()>>,
166    /// Handle for the soft-lock expiry sweep task. The task self-terminates
167    /// via a `Weak` reference; this handle exists purely for ownership clarity.
168    soft_lock_sweep_handle: JoinHandle<()>,
169    overload_notifier_handle: Option<JoinHandle<()>>,
170    consensus_manager: Arc<ConsensusManager>,
171    consensus_store_pruner: ConsensusStorePruner,
172    consensus_adapter: Arc<ConsensusAdapter>,
173    soft_locks: Arc<PreConsensusSoftLocks>,
174    // Keeping the handle to the checkpoint service tasks to shut them down during reconfiguration.
175    checkpoint_service_tasks: JoinSet<()>,
176    checkpoint_metrics: Arc<CheckpointMetrics>,
177    iota_tx_validator_metrics: Arc<IotaTxValidatorMetrics>,
178    validator_registry_id: RegistryID,
179}
180
181#[cfg(msim)]
182mod simulator {
183    use std::sync::atomic::AtomicBool;
184
185    pub(super) struct SimState {
186        pub sim_node: iota_simulator::runtime::NodeHandle,
187        pub sim_safe_mode_expected: AtomicBool,
188        _leak_detector: iota_simulator::NodeLeakDetector,
189    }
190
191    impl Default for SimState {
192        fn default() -> Self {
193            Self {
194                sim_node: iota_simulator::runtime::NodeHandle::current(),
195                sim_safe_mode_expected: AtomicBool::new(false),
196                _leak_detector: iota_simulator::NodeLeakDetector::new(),
197            }
198        }
199    }
200}
201
202#[derive(Clone)]
203pub struct ServerVersion {
204    pub bin: &'static str,
205    pub version: &'static str,
206}
207
208impl ServerVersion {
209    pub fn new(bin: &'static str, version: &'static str) -> Self {
210        Self { bin, version }
211    }
212}
213
214impl std::fmt::Display for ServerVersion {
215    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
216        f.write_str(self.bin)?;
217        f.write_str("/")?;
218        f.write_str(self.version)
219    }
220}
221
222pub struct IotaNode {
223    config: NodeConfig,
224    validator_components: Mutex<Option<ValidatorComponents>>,
225    /// The http server responsible for serving JSON-RPC
226    _http_server: Option<iota_http::ServerHandle>,
227    state: Arc<AuthorityState>,
228    transaction_orchestrator: Option<Arc<TransactionOrchestrator<NetworkAuthorityClient>>>,
229    registry_service: RegistryService,
230    metrics: Arc<IotaNodeMetrics>,
231
232    _discovery: discovery::Handle,
233    state_sync_handle: state_sync::Handle,
234    randomness_handle: randomness::Handle,
235    checkpoint_store: Arc<CheckpointStore>,
236    state_sync_store: RocksDbStore,
237    global_state_hasher: Mutex<Option<Arc<GlobalStateHasher>>>,
238    connection_monitor_status: Arc<ConnectionMonitorStatus>,
239
240    /// Broadcast channel to send the starting system state for the next epoch.
241    end_of_epoch_channel: broadcast::Sender<IotaSystemState>,
242
243    /// Broadcast channel to notify [`DiscoveryEventLoop`] for new validator
244    /// peers.
245    trusted_peer_change_tx: watch::Sender<TrustedPeerChangeEvent>,
246
247    backpressure_manager: Arc<BackpressureManager>,
248
249    checkpoint_progress_tracker: Arc<CheckpointProgressTracker>,
250
251    #[cfg(msim)]
252    sim_state: SimState,
253
254    _state_snapshot_uploader_handle: Option<broadcast::Sender<()>>,
255    // Channel to allow signaling upstream to shutdown iota-node
256    shutdown_channel_tx: broadcast::Sender<Option<RunWithRange>>,
257
258    /// Handle to the gRPC server for gRPC streaming and graceful shutdown
259    grpc_server_handle: Mutex<Option<GrpcServerHandle>>,
260
261    /// AuthorityAggregator of the network, created at start and beginning of
262    /// each epoch. Use ArcSwap so that we could mutate it without taking
263    /// mut reference.
264    // TODO: Eventually we can make this auth aggregator a shared reference so that this
265    // update will automatically propagate to other uses.
266    auth_agg: Arc<ArcSwap<AuthorityAggregator<NetworkAuthorityClient>>>,
267
268    /// Runtime that hosts the client-facing servers and their per-request
269    /// handlers, isolating external request load from the node core.
270    serving_rt_handle: tokio::runtime::Handle,
271}
272
273impl fmt::Debug for IotaNode {
274    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
275        f.debug_struct("IotaNode")
276            .field("name", &self.state.name.concise())
277            .finish()
278    }
279}
280
281impl IotaNode {
282    /// Starts a node that hosts the client-facing servers on the caller's
283    /// runtime, alongside everything else.
284    ///
285    /// This is intentional: this entry point serves the in-process nodes of
286    /// iota-swarm, where a separate serving runtime is either impossible
287    /// (simtests must keep every task on the simulator's deterministic
288    /// scheduler) or not worth the threads (thread-mode swarm runs many nodes
289    /// per process). Only the `iota-node` binary isolates client-facing
290    /// request handling on the dedicated serving runtime of `IotaRuntimes`,
291    /// via [`IotaNode::start_async`].
292    pub async fn start(
293        config: NodeConfig,
294        registry_service: RegistryService,
295    ) -> Result<Arc<IotaNode>> {
296        Self::start_async(
297            config,
298            registry_service,
299            ServerVersion::new("iota-node", "unknown"),
300            tokio::runtime::Handle::current(),
301        )
302        .await
303    }
304
305    /// Starts a background task that polls the authority's load shedding
306    /// percentage and broadcasts changes to other validators via consensus.
307    /// Returns the task handle if the feature flag is enabled, or `None`
308    /// otherwise.
309    fn start_overload_notifier(
310        config: &NodeConfig,
311        state: Arc<AuthorityState>,
312        epoch_store: Arc<AuthorityPerEpochStore>,
313        consensus_adapter: Arc<ConsensusAdapter>,
314    ) -> Option<JoinHandle<()>> {
315        if !epoch_store.protocol_config().enable_pcool_flow() {
316            return None;
317        }
318
319        let poll_interval = config.authority_overload_config.overload_monitor_interval;
320        let authority_name = state.name;
321
322        Some(spawn_monitored_task!(async move {
323            // Seed from the percentage this authority last broadcasted
324            let mut last_notified_percentage: u32 = epoch_store
325                .load_overload_notification(&authority_name)
326                .unwrap_or(0) as u32;
327            loop {
328                tokio::time::sleep(poll_interval).await;
329                let current = state
330                    .overload_info
331                    .local_load_shedding_percentage
332                    .load(std::sync::atomic::Ordering::Relaxed);
333                if current != last_notified_percentage {
334                    last_notified_percentage = current;
335                    let transaction = ConsensusTransaction::new_overload_notification_v1(
336                        authority_name,
337                        current as u8,
338                    );
339                    if let Err(e) = consensus_adapter.submit(transaction, None, &epoch_store) {
340                        tracing::warn!(
341                            "Failed to submit overload notification to consensus: {:?}",
342                            e
343                        );
344                    }
345                }
346            }
347        }))
348    }
349
350    pub async fn start_async(
351        config: NodeConfig,
352        registry_service: RegistryService,
353        server_version: ServerVersion,
354        serving_rt_handle: tokio::runtime::Handle,
355    ) -> Result<Arc<IotaNode>> {
356        NodeConfigMetrics::new(&registry_service.default_registry()).record_metrics(&config);
357        let mut config = config.clone();
358        if config.supported_protocol_versions.is_none() {
359            info!(
360                "populating config.supported_protocol_versions with default {:?}",
361                SupportedProtocolVersions::SYSTEM_DEFAULT
362            );
363            config.supported_protocol_versions = Some(SupportedProtocolVersions::SYSTEM_DEFAULT);
364        }
365
366        let run_with_range = config.run_with_range;
367        let is_validator = config.consensus_config().is_some();
368        let is_full_node = !is_validator;
369        let prometheus_registry = registry_service.default_registry();
370
371        info!(node =? config.authority_public_key(),
372            "Initializing iota-node listening on {}", config.network_address
373        );
374
375        let genesis = config.genesis()?.clone();
376
377        let chain_identifier = ChainIdentifier::from(*genesis.checkpoint().digest());
378        info!("IOTA chain identifier: {chain_identifier}");
379
380        // Check and set the db_corrupted flag
381        let db_corrupted_path = &config.db_path().join("status");
382        if let Err(err) = check_and_mark_db_corruption(db_corrupted_path) {
383            panic!("Failed to check database corruption: {err}");
384        }
385
386        // Initialize metrics to track db usage before creating any stores
387        DBMetrics::init(&prometheus_registry);
388
389        // Initialize IOTA metrics.
390        iota_metrics::init_metrics(&prometheus_registry);
391        // Unsupported (because of the use of static variable) and unnecessary in
392        // simtests.
393        #[cfg(not(msim))]
394        iota_metrics::thread_stall_monitor::start_thread_stall_monitor();
395
396        // Monitor the node-core and serving runtimes so that worker-thread
397        // starvation between them is observable. Gated out of simtests, where
398        // tokio runs under the deterministic simulator.
399        #[cfg(not(msim))]
400        {
401            let runtime_monitor_metrics =
402                iota_metrics::runtime_metrics::RuntimeMonitorMetrics::new(&prometheus_registry);
403            iota_metrics::runtime_metrics::start_runtime_monitor(
404                "iota_node",
405                &tokio::runtime::Handle::current(),
406                runtime_monitor_metrics.clone(),
407            );
408            iota_metrics::runtime_metrics::start_runtime_monitor(
409                "serving",
410                &serving_rt_handle,
411                runtime_monitor_metrics,
412            );
413        }
414
415        // Register uptime metric
416        prometheus_registry
417            .register(iota_metrics::uptime_metric(
418                if is_validator {
419                    "validator"
420                } else {
421                    "fullnode"
422                },
423                server_version.version,
424                &chain_identifier.to_string(),
425            ))
426            .expect("Failed registering uptime metric");
427
428        // If genesis come with some migration data then load them into memory from the
429        // file path specified in config.
430        let migration_tx_data = if genesis.contains_migrations() {
431            // Here the load already verifies that the content of the migration blob is
432            // valid in respect to the content found in genesis
433            Some(config.load_migration_tx_data()?)
434        } else {
435            None
436        };
437
438        let secret = Arc::pin(config.authority_key_pair().copy());
439        let genesis_committee = genesis.committee()?;
440        let committee_store = Arc::new(CommitteeStore::new(
441            config.db_path().join("epochs"),
442            &genesis_committee,
443            None,
444        ));
445
446        let mut pruner_db = None;
447        if config
448            .authority_store_pruning_config
449            .enable_compaction_filter
450        {
451            pruner_db = Some(Arc::new(AuthorityPrunerTables::open(
452                &config.db_path().join("store"),
453            )));
454        }
455        let compaction_filter = pruner_db
456            .clone()
457            .map(|db| ObjectsCompactionFilter::new(db, &prometheus_registry));
458
459        // By default, only enable write stall on validators for perpetual db.
460        let enable_write_stall = config.enable_db_write_stall.unwrap_or(is_validator);
461        let perpetual_tables_options = AuthorityPerpetualTablesOptions {
462            enable_write_stall,
463            compaction_filter,
464        };
465        let perpetual_tables = Arc::new(AuthorityPerpetualTables::open(
466            &config.db_path().join("store"),
467            Some(perpetual_tables_options),
468        ));
469        let is_genesis = perpetual_tables
470            .database_is_empty()
471            .expect("Database read should not fail at init.");
472        let checkpoint_store = CheckpointStore::new_with_contents_cache(
473            &config.db_path().join("checkpoints"),
474            FullCheckpointContentsCache::new(
475                config
476                    .full_checkpoint_contents_cache_size_mb
477                    .saturating_mul(1024 * 1024),
478                FullCheckpointContentsCacheMetrics::new(&prometheus_registry),
479            ),
480        );
481        let backpressure_manager =
482            BackpressureManager::new_from_checkpoint_store(&checkpoint_store);
483
484        let perpetual_tables_for_progress = perpetual_tables.clone();
485        let store = AuthorityStore::open(
486            perpetual_tables,
487            &genesis,
488            &config,
489            &prometheus_registry,
490            migration_tx_data.as_ref(),
491        )
492        .await?;
493
494        let cur_epoch = store.get_recovery_epoch_at_restart()?;
495        let committee = committee_store
496            .get_committee(&cur_epoch)?
497            .expect("Committee of the current epoch must exist");
498        let epoch_start_configuration = store
499            .get_epoch_start_configuration()?
500            .expect("EpochStartConfiguration of the current epoch must exist");
501        let cache_metrics = Arc::new(ResolverMetrics::new(&prometheus_registry));
502        let signature_verifier_metrics = SignatureVerifierMetrics::new(&prometheus_registry);
503
504        let cache_traits = build_execution_cache(
505            &config.execution_cache_config,
506            &prometheus_registry,
507            &store,
508            backpressure_manager.clone(),
509        );
510
511        let auth_agg = {
512            let safe_client_metrics_base = SafeClientMetricsBase::new(&prometheus_registry);
513            let auth_agg_metrics = Arc::new(AuthAggMetrics::new(&prometheus_registry));
514            Arc::new(ArcSwap::new(Arc::new(
515                AuthorityAggregator::new_from_epoch_start_state(
516                    epoch_start_configuration.epoch_start_state(),
517                    &committee_store,
518                    safe_client_metrics_base,
519                    auth_agg_metrics,
520                ),
521            )))
522        };
523
524        let chain = match config.chain_override_for_testing {
525            Some(chain) => chain,
526            None => chain_identifier.chain(),
527        };
528
529        let epoch_options = default_db_options().optimize_db_for_write_throughput(4);
530        let epoch_store = AuthorityPerEpochStore::new(
531            config.authority_public_key(),
532            committee.clone(),
533            &config.db_path().join("store"),
534            Some(epoch_options.options),
535            EpochMetrics::new(&registry_service.default_registry()),
536            epoch_start_configuration,
537            cache_traits.backing_package_store.clone(),
538            cache_metrics,
539            signature_verifier_metrics,
540            &config.expensive_safety_check_config,
541            (chain_identifier, chain),
542            checkpoint_store
543                .get_highest_executed_checkpoint_seq_number()
544                .expect("checkpoint store read cannot fail")
545                .unwrap_or(0),
546        )?;
547
548        info!("created epoch store");
549
550        replay_log!(
551            "Beginning replay run. Epoch: {:?}, Protocol config: {:?}",
552            epoch_store.epoch(),
553            epoch_store.protocol_config()
554        );
555
556        // the database is empty at genesis time
557        if is_genesis {
558            info!("checking IOTA conservation at genesis");
559            // When we are opening the db table, the only time when it's safe to
560            // check IOTA conservation is at genesis. Otherwise we may be in the middle of
561            // an epoch and the IOTA conservation check will fail. This also initialize
562            // the expected_network_iota_amount table.
563            cache_traits
564                .reconfig_api
565                .try_expensive_check_iota_conservation(&epoch_store, None)
566                .expect("IOTA conservation check cannot fail at genesis");
567        }
568
569        let effective_buffer_stake = epoch_store.get_effective_buffer_stake_bps();
570        let default_buffer_stake = epoch_store
571            .protocol_config()
572            .buffer_stake_for_protocol_upgrade_bps();
573        if effective_buffer_stake != default_buffer_stake {
574            warn!(
575                ?effective_buffer_stake,
576                ?default_buffer_stake,
577                "buffer_stake_for_protocol_upgrade_bps is currently overridden"
578            );
579        }
580
581        checkpoint_store.insert_genesis_checkpoint(
582            genesis.checkpoint(),
583            genesis.checkpoint_contents().clone(),
584            &epoch_store,
585        );
586
587        // Database has everything from genesis, set corrupted key to 0
588        unmark_db_corruption(db_corrupted_path)?;
589
590        info!("creating state sync store");
591        let state_sync_store = RocksDbStore::new(
592            cache_traits.clone(),
593            committee_store.clone(),
594            checkpoint_store.clone(),
595        );
596
597        let index_store = if is_full_node && config.enable_index_processing {
598            info!("creating index store");
599            Some(Arc::new(IndexStore::new(
600                config.db_path().join("indexes"),
601                &prometheus_registry,
602                epoch_store
603                    .protocol_config()
604                    .max_move_identifier_len_as_option(),
605            )))
606        } else {
607            None
608        };
609
610        let grpc_indexes_store = if is_full_node && config.enable_grpc_api {
611            Some(Arc::new(
612                GrpcIndexesStore::new(
613                    config.db_path().join(GRPC_INDEXES_DIR),
614                    Arc::clone(&store),
615                    &checkpoint_store,
616                )
617                .await,
618            ))
619        } else {
620            None
621        };
622
623        // Seed the open epoch's `epoch_info` row before services start.
624        checkpoint_store
625            .seed_epoch_info(&store, chain_identifier)
626            .expect("failed to seed the epoch_info chain");
627
628        info!("creating archive reader");
629        // Create network
630        // TODO only configure validators as seed/preferred peers for validators and not
631        // for fullnodes once we've had a chance to re-work fullnode
632        // configuration generation.
633        let (trusted_peer_change_tx, trusted_peer_change_rx) = watch::channel(Default::default());
634        let (randomness_tx, randomness_rx) = mpsc::channel(
635            config
636                .p2p_config
637                .randomness
638                .clone()
639                .unwrap_or_default()
640                .mailbox_capacity(),
641        );
642        let (p2p_network, discovery_handle, state_sync_handle, randomness_handle) =
643            Self::create_p2p_network(
644                &config,
645                state_sync_store.clone(),
646                chain_identifier,
647                trusted_peer_change_rx,
648                randomness_tx,
649                &prometheus_registry,
650            )?;
651
652        // We must explicitly send this instead of relying on the initial value to
653        // trigger watch value change, so that state-sync is able to process it.
654        send_trusted_peer_change(
655            &config,
656            &trusted_peer_change_tx,
657            epoch_store.epoch_start_state(),
658        );
659
660        info!("start snapshot upload");
661        // Start uploading state snapshot to remote store
662        let state_snapshot_handle = Self::start_state_snapshot(
663            &config,
664            &prometheus_registry,
665            checkpoint_store.clone(),
666            is_full_node,
667        )?;
668
669        let checkpoint_progress_tracker = Arc::new(CheckpointProgressTracker::new());
670
671        let mut genesis_objects = genesis.objects().to_vec();
672        if let Some(migration_tx_data) = migration_tx_data.as_ref() {
673            genesis_objects.extend(migration_tx_data.get_objects());
674        }
675
676        let authority_name = config.authority_public_key();
677        let validator_tx_finalizer =
678            config
679                .enable_validator_tx_finalizer
680                .then_some(Arc::new(ValidatorTxFinalizer::new(
681                    auth_agg.clone(),
682                    authority_name,
683                    &prometheus_registry,
684                )));
685
686        info!("create authority state");
687        let state = AuthorityState::new(
688            authority_name,
689            secret,
690            config.supported_protocol_versions.unwrap(),
691            store.clone(),
692            cache_traits.clone(),
693            epoch_store.clone(),
694            committee_store.clone(),
695            index_store.clone(),
696            grpc_indexes_store,
697            checkpoint_store.clone(),
698            &prometheus_registry,
699            &genesis_objects,
700            config.clone(),
701            validator_tx_finalizer,
702            chain_identifier,
703            pruner_db,
704            Some(checkpoint_progress_tracker.clone()),
705            config.policy_config.clone(),
706            config.firewall_config.clone(),
707        )
708        .await;
709
710        // ensure genesis and migration txs were executed
711        if epoch_store.epoch() == 0 {
712            let genesis_tx = &genesis.transaction();
713            let span = error_span!("genesis_txn", tx_digest = ?genesis_tx.digest());
714            // Execute genesis transaction
715            Self::execute_transaction_immediately_at_zero_epoch(
716                &state,
717                &epoch_store,
718                genesis_tx,
719                span,
720            )
721            .await;
722
723            // Execute migration transactions if present
724            if let Some(migration_tx_data) = migration_tx_data {
725                for (tx_digest, (tx, _, _)) in migration_tx_data.txs_data() {
726                    let span = error_span!("migration_txn", tx_digest = ?tx_digest);
727                    Self::execute_transaction_immediately_at_zero_epoch(
728                        &state,
729                        &epoch_store,
730                        tx,
731                        span,
732                    )
733                    .await;
734                }
735            }
736        }
737
738        // Start the loop that receives new randomness and generates transactions for
739        // it.
740        RandomnessRoundReceiver::spawn(state.clone(), randomness_rx);
741
742        if config
743            .expensive_safety_check_config
744            .enable_secondary_index_checks()
745        {
746            if let Some(indexes) = state.indexes.clone() {
747                iota_core::verify_indexes::verify_indexes(
748                    state.get_global_state_hash_store().as_ref(),
749                    indexes,
750                )
751                .expect("secondary indexes are inconsistent");
752            }
753        }
754
755        let (end_of_epoch_channel, end_of_epoch_receiver) =
756            broadcast::channel(config.end_of_epoch_broadcast_channel_capacity);
757
758        let transaction_orchestrator = if is_full_node && run_with_range.is_none() {
759            Some(Arc::new(TransactionOrchestrator::new_with_auth_aggregator(
760                auth_agg.load_full(),
761                state.clone(),
762                end_of_epoch_receiver,
763                &config.db_path(),
764                &prometheus_registry,
765                Some(&config),
766            )))
767        } else {
768            None
769        };
770
771        // Run the JSON-RPC server (and its per-request handlers) on the serving
772        // runtime. `iota_http::Builder::serve` spawns the accept loop via
773        // `Handle::current()`, so the builder must execute on the serving runtime.
774        let http_server = serving_rt_handle
775            .spawn({
776                let state = state.clone();
777                let transaction_orchestrator = transaction_orchestrator.clone();
778                let config = config.clone();
779                let prometheus_registry = prometheus_registry.clone();
780                async move {
781                    build_http_server(
782                        state,
783                        &transaction_orchestrator,
784                        &config,
785                        &prometheus_registry,
786                    )
787                    .await
788                }
789            })
790            .await
791            .expect("Failed to join JSON-RPC server startup task")?;
792
793        let global_state_hasher = Arc::new(GlobalStateHasher::new(
794            cache_traits.global_state_hash_store.clone(),
795            GlobalStateHashMetrics::new(&prometheus_registry),
796        ));
797
798        let authority_names_to_peer_ids = epoch_store
799            .epoch_start_state()
800            .get_authority_names_to_peer_ids();
801
802        let network_connection_metrics =
803            NetworkConnectionMetrics::new("iota", &registry_service.default_registry());
804
805        let authority_names_to_peer_ids = ArcSwap::from_pointee(authority_names_to_peer_ids);
806
807        let (_connection_monitor_handle, connection_statuses) = ConnectionMonitor::spawn(
808            p2p_network.downgrade(),
809            network_connection_metrics,
810            HashMap::new(),
811            None,
812        );
813
814        let connection_monitor_status = ConnectionMonitorStatus {
815            connection_statuses,
816            authority_names_to_peer_ids,
817        };
818
819        let connection_monitor_status = Arc::new(connection_monitor_status);
820        let iota_node_metrics =
821            Arc::new(IotaNodeMetrics::new(&registry_service.default_registry()));
822
823        iota_node_metrics
824            .binary_max_protocol_version
825            .set(ProtocolVersion::MAX.as_u64() as i64);
826        iota_node_metrics
827            .configured_max_protocol_version
828            .set(config.supported_protocol_versions.unwrap().max.as_u64() as i64);
829
830        // Convert transaction orchestrator to executor trait object for gRPC server
831        // Note that the transaction_orchestrator (so as executor) will be None if it is
832        // a validator node or run_with_range is set
833        let executor: Option<Arc<dyn iota_types::transaction_executor::TransactionExecutor>> =
834            transaction_orchestrator
835                .clone()
836                .map(|o| o as Arc<dyn iota_types::transaction_executor::TransactionExecutor>);
837
838        // Run the gRPC read API server (and its per-request handlers) on the
839        // serving runtime, for the same reason as the JSON-RPC server above.
840        let grpc_server_handle = serving_rt_handle
841            .spawn({
842                let config = config.clone();
843                let state = state.clone();
844                let state_sync_store = state_sync_store.clone();
845                let prometheus_registry = prometheus_registry.clone();
846                async move {
847                    build_grpc_server(
848                        &config,
849                        state,
850                        state_sync_store,
851                        executor,
852                        &prometheus_registry,
853                        server_version,
854                    )
855                    .await
856                }
857            })
858            .await
859            .expect("Failed to join gRPC server startup task")?;
860
861        let validator_components = if state.is_committee_validator(&epoch_store) {
862            let (components, _) = futures::join!(
863                Self::construct_validator_components(
864                    config.clone(),
865                    state.clone(),
866                    committee,
867                    epoch_store.clone(),
868                    checkpoint_store.clone(),
869                    state_sync_handle.clone(),
870                    randomness_handle.clone(),
871                    Arc::downgrade(&global_state_hasher),
872                    backpressure_manager.clone(),
873                    connection_monitor_status.clone(),
874                    &registry_service,
875                    serving_rt_handle.clone(),
876                ),
877                Self::reexecute_pending_consensus_certs(&epoch_store, &state,)
878            );
879            let mut components = components?;
880
881            components.consensus_adapter.submit_recovered(&epoch_store);
882
883            // Start the gRPC server
884            components.validator_server_handle = components.validator_server_handle.start().await;
885
886            Some(components)
887        } else {
888            None
889        };
890
891        // setup shutdown channel
892        let (shutdown_channel, _) = broadcast::channel::<Option<RunWithRange>>(1);
893
894        let node = Self {
895            config,
896            validator_components: Mutex::new(validator_components),
897            _http_server: http_server,
898            state,
899            transaction_orchestrator,
900            registry_service,
901            metrics: iota_node_metrics,
902
903            _discovery: discovery_handle,
904            state_sync_handle,
905            randomness_handle,
906            checkpoint_store,
907            state_sync_store,
908            global_state_hasher: Mutex::new(Some(global_state_hasher)),
909            end_of_epoch_channel,
910            connection_monitor_status,
911            trusted_peer_change_tx,
912            backpressure_manager,
913            checkpoint_progress_tracker: checkpoint_progress_tracker.clone(),
914
915            #[cfg(msim)]
916            sim_state: Default::default(),
917
918            _state_snapshot_uploader_handle: state_snapshot_handle,
919            shutdown_channel_tx: shutdown_channel,
920
921            grpc_server_handle: Mutex::new(grpc_server_handle),
922
923            auth_agg,
924
925            serving_rt_handle,
926        };
927
928        info!("IotaNode started!");
929        let node = Arc::new(node);
930        let node_copy = node.clone();
931        spawn_monitored_task!(async move {
932            let result = Self::monitor_reconfiguration(node_copy, epoch_store).await;
933            if let Err(error) = result {
934                warn!("Reconfiguration finished with error {:?}", error);
935            }
936        });
937
938        node.checkpoint_progress_tracker
939            .spawn_logging_task(node.checkpoint_store.clone(), perpetual_tables_for_progress);
940
941        Ok(node)
942    }
943
944    pub fn subscribe_to_epoch_change(&self) -> broadcast::Receiver<IotaSystemState> {
945        self.end_of_epoch_channel.subscribe()
946    }
947
948    pub fn subscribe_to_shutdown_channel(&self) -> broadcast::Receiver<Option<RunWithRange>> {
949        self.shutdown_channel_tx.subscribe()
950    }
951
952    pub fn current_epoch_for_testing(&self) -> EpochId {
953        self.state.current_epoch_for_testing()
954    }
955
956    // Init reconfig process by starting to reject user certs
957    pub async fn close_epoch(&self, epoch_store: &Arc<AuthorityPerEpochStore>) -> IotaResult {
958        info!("close_epoch (current epoch = {})", epoch_store.epoch());
959        self.validator_components
960            .lock()
961            .await
962            .as_ref()
963            .ok_or_else(|| IotaError::from("Node is not a validator"))?
964            .consensus_adapter
965            .close_epoch(epoch_store);
966        Ok(())
967    }
968
969    pub fn clear_override_protocol_upgrade_buffer_stake(&self, epoch: EpochId) -> IotaResult {
970        self.state
971            .clear_override_protocol_upgrade_buffer_stake(epoch)
972    }
973
974    pub fn set_override_protocol_upgrade_buffer_stake(
975        &self,
976        epoch: EpochId,
977        buffer_stake_bps: u64,
978    ) -> IotaResult {
979        self.state
980            .set_override_protocol_upgrade_buffer_stake(epoch, buffer_stake_bps)
981    }
982
983    // Testing-only API to start epoch close process.
984    // For production code, please use the non-testing version.
985    pub async fn close_epoch_for_testing(&self) -> IotaResult {
986        let epoch_store = self.state.epoch_store_for_testing();
987        self.close_epoch(&epoch_store).await
988    }
989
990    /// Creates a StateSnapshotUploader and starts it if the StateSnapshotConfig
991    /// is set.
992    fn start_state_snapshot(
993        config: &NodeConfig,
994        prometheus_registry: &Registry,
995        checkpoint_store: Arc<CheckpointStore>,
996        is_full_node: bool,
997    ) -> Result<Option<tokio::sync::broadcast::Sender<()>>> {
998        if let Some(remote_store_config) = &config.state_snapshot_write_config.object_store_config {
999            // Snapshot publication is a fullnode-only role.
1000            anyhow::ensure!(
1001                is_full_node,
1002                "Snapshot upload is configured, but this node is a validator. \
1003                 Snapshot publication is only supported on fullnodes. Remove the \
1004                 `state_snapshot_write_config.object_store_config` setting, or move \
1005                 the upload to a fullnode."
1006            );
1007            let snapshot_uploader = StateSnapshotUploader::new(
1008                &config.db_checkpoint_path(),
1009                &config.snapshot_path(),
1010                remote_store_config.clone(),
1011                config.state_snapshot_write_config.concurrency,
1012                60,
1013                prometheus_registry,
1014                checkpoint_store,
1015            )?;
1016            Ok(Some(snapshot_uploader.start()))
1017        } else {
1018            Ok(None)
1019        }
1020    }
1021
1022    fn create_p2p_network(
1023        config: &NodeConfig,
1024        state_sync_store: RocksDbStore,
1025        chain_identifier: ChainIdentifier,
1026        trusted_peer_change_rx: watch::Receiver<TrustedPeerChangeEvent>,
1027        randomness_tx: mpsc::Sender<(EpochId, RandomnessRound, Vec<u8>)>,
1028        prometheus_registry: &Registry,
1029    ) -> Result<(
1030        Network,
1031        discovery::Handle,
1032        state_sync::Handle,
1033        randomness::Handle,
1034    )> {
1035        let (state_sync, state_sync_server) = state_sync::Builder::new()
1036            .config(config.p2p_config.state_sync.clone().unwrap_or_default())
1037            .store(state_sync_store)
1038            .checkpoint_archive_config(config.checkpoint_archive_config().cloned())
1039            .with_metrics(prometheus_registry)
1040            .build();
1041
1042        let (discovery, discovery_server) = discovery::Builder::new(trusted_peer_change_rx)
1043            .config(config.p2p_config.clone())
1044            .build();
1045
1046        let (randomness, randomness_router) =
1047            randomness::Builder::new(config.authority_public_key(), randomness_tx)
1048                .config(config.p2p_config.randomness.clone().unwrap_or_default())
1049                .with_metrics(prometheus_registry)
1050                .build();
1051
1052        let p2p_network = {
1053            let routes = anemo::Router::new()
1054                .add_rpc_service(discovery_server)
1055                .add_rpc_service(state_sync_server);
1056            let routes = routes.merge(randomness_router);
1057
1058            let inbound_network_metrics =
1059                NetworkMetrics::new("iota", "inbound", prometheus_registry);
1060            let outbound_network_metrics =
1061                NetworkMetrics::new("iota", "outbound", prometheus_registry);
1062
1063            let service = ServiceBuilder::new()
1064                .layer(
1065                    TraceLayer::new_for_server_errors()
1066                        .make_span_with(DefaultMakeSpan::new().level(tracing::Level::INFO))
1067                        .on_failure(DefaultOnFailure::new().level(tracing::Level::WARN)),
1068                )
1069                .layer(CallbackLayer::new(MetricsMakeCallbackHandler::new(
1070                    Arc::new(inbound_network_metrics),
1071                    config.p2p_config.excessive_message_size(),
1072                )))
1073                .service(routes);
1074
1075            let outbound_layer = ServiceBuilder::new()
1076                .layer(
1077                    TraceLayer::new_for_client_and_server_errors()
1078                        .make_span_with(DefaultMakeSpan::new().level(tracing::Level::INFO))
1079                        .on_failure(DefaultOnFailure::new().level(tracing::Level::DEBUG)),
1080                )
1081                .layer(CallbackLayer::new(MetricsMakeCallbackHandler::new(
1082                    Arc::new(outbound_network_metrics),
1083                    config.p2p_config.excessive_message_size(),
1084                )))
1085                .into_inner();
1086
1087            let mut anemo_config = config.p2p_config.anemo_config.clone().unwrap_or_default();
1088            // Inbound requests on this network are small (signatures, queries, summaries).
1089            // Cap request frames at 1 MiB.
1090            anemo_config.max_request_frame_size = Some(1 << 20);
1091            // Responses can be larger (checkpoint contents).
1092            // Cap response frames at 128 MiB.
1093            anemo_config.max_response_frame_size = Some(128 << 20);
1094
1095            // Set a higher default value for socket send/receive buffers if not already
1096            // configured.
1097            let mut quic_config = anemo_config.quic.unwrap_or_default();
1098            if quic_config.socket_send_buffer_size.is_none() {
1099                quic_config.socket_send_buffer_size = Some(20 << 20);
1100            }
1101            if quic_config.socket_receive_buffer_size.is_none() {
1102                quic_config.socket_receive_buffer_size = Some(20 << 20);
1103            }
1104            quic_config.allow_failed_socket_buffer_size_setting = true;
1105
1106            // Set high-performance defaults for quinn transport.
1107            // With 200MiB buffer size and ~500ms RTT, max throughput ~400MiB/s.
1108            if quic_config.max_concurrent_bidi_streams.is_none() {
1109                quic_config.max_concurrent_bidi_streams = Some(500);
1110            }
1111            if quic_config.max_concurrent_uni_streams.is_none() {
1112                quic_config.max_concurrent_uni_streams = Some(500);
1113            }
1114            if quic_config.stream_receive_window.is_none() {
1115                quic_config.stream_receive_window = Some(100 << 20);
1116            }
1117            if quic_config.receive_window.is_none() {
1118                quic_config.receive_window = Some(200 << 20);
1119            }
1120            if quic_config.send_window.is_none() {
1121                quic_config.send_window = Some(200 << 20);
1122            }
1123            if quic_config.crypto_buffer_size.is_none() {
1124                quic_config.crypto_buffer_size = Some(1 << 20);
1125            }
1126            if quic_config.max_idle_timeout_ms.is_none() {
1127                quic_config.max_idle_timeout_ms = Some(10_000);
1128            }
1129            if quic_config.keep_alive_interval_ms.is_none() {
1130                quic_config.keep_alive_interval_ms = Some(5_000);
1131            }
1132            anemo_config.quic = Some(quic_config);
1133
1134            let server_name = format!("iota-{chain_identifier}");
1135            let network = Network::bind(config.p2p_config.listen_address)
1136                .server_name(&server_name)
1137                .private_key(config.network_key_pair().copy().private().0.to_bytes())
1138                .config(anemo_config)
1139                .outbound_request_layer(outbound_layer)
1140                .start(service)?;
1141            info!(
1142                server_name = server_name,
1143                "P2p network started on {}",
1144                network.local_addr()
1145            );
1146
1147            network
1148        };
1149
1150        let discovery_handle =
1151            discovery.start(p2p_network.clone(), config.network_key_pair().copy());
1152        let state_sync_handle = state_sync.start(p2p_network.clone());
1153        let randomness_handle = randomness.start(p2p_network.clone());
1154
1155        Ok((
1156            p2p_network,
1157            discovery_handle,
1158            state_sync_handle,
1159            randomness_handle,
1160        ))
1161    }
1162
1163    /// Asynchronously constructs and initializes the components necessary for
1164    /// the validator node.
1165    async fn construct_validator_components(
1166        config: NodeConfig,
1167        state: Arc<AuthorityState>,
1168        committee: Arc<Committee>,
1169        epoch_store: Arc<AuthorityPerEpochStore>,
1170        checkpoint_store: Arc<CheckpointStore>,
1171        state_sync_handle: state_sync::Handle,
1172        randomness_handle: randomness::Handle,
1173        global_state_hasher: Weak<GlobalStateHasher>,
1174        backpressure_manager: Arc<BackpressureManager>,
1175        connection_monitor_status: Arc<ConnectionMonitorStatus>,
1176        registry_service: &RegistryService,
1177        serving_rt_handle: tokio::runtime::Handle,
1178    ) -> Result<ValidatorComponents> {
1179        let mut config_clone = config.clone();
1180        let consensus_config = config_clone
1181            .consensus_config
1182            .as_mut()
1183            .ok_or_else(|| anyhow!("Validator is missing consensus config"))?;
1184        let validator_registry = registry_service.new_registry_custom(None, None)?;
1185        let validator_registry_id = registry_service.add(validator_registry.clone());
1186
1187        let client = Arc::new(UpdatableConsensusClient::new());
1188        let consensus_adapter = Arc::new(Self::construct_consensus_adapter(
1189            &committee,
1190            consensus_config,
1191            state.name,
1192            connection_monitor_status.clone(),
1193            &validator_registry,
1194            client.clone(),
1195            checkpoint_store.clone(),
1196        ));
1197        let consensus_manager = Arc::new(ConsensusManager::new(
1198            &config,
1199            consensus_config,
1200            registry_service,
1201            &validator_registry,
1202            client,
1203        ));
1204
1205        // This only gets started up once, not on every epoch. (Make call to remove
1206        // every epoch.)
1207        let consensus_store_pruner = ConsensusStorePruner::new(
1208            consensus_manager.get_storage_base_path(),
1209            consensus_config.db_retention_epochs(),
1210            consensus_config.db_pruner_period(),
1211            &validator_registry,
1212        );
1213
1214        let soft_locks = Arc::new(if config.enable_soft_locking {
1215            PreConsensusSoftLocks::new()
1216        } else {
1217            info!("pre-consensus soft-locking disabled via node config");
1218            PreConsensusSoftLocks::disabled()
1219        });
1220
1221        let checkpoint_metrics = CheckpointMetrics::new(&validator_registry);
1222        let iota_tx_validator_metrics = IotaTxValidatorMetrics::new(&validator_registry);
1223        let validator_service_metrics = Arc::new(ValidatorServiceMetrics::new(&validator_registry));
1224
1225        // Spawn the soft-lock sweep once for the lifetime of this validator
1226        // instance. The task holds only a `Weak<PreConsensusSoftLocks>` so it
1227        // stops itself automatically: each iteration it tries to upgrade the
1228        // weak reference, and when all strong `Arc` owners have been dropped
1229        // (i.e. `ValidatorComponents` is destructured and the old epoch store
1230        // is released after an epoch transition that removes us from the
1231        // committee) the upgrade returns `None` and the loop exits. No explicit
1232        // `abort()` is needed. The same `Arc<PreConsensusSoftLocks>` is reused
1233        // across epoch transitions (see `start_epoch_specific_validator_components`),
1234        // so the task keeps running uninterrupted while the node remains a validator.
1235        let soft_lock_sweep_handle = PreConsensusSoftLocks::spawn_sweep(
1236            Arc::downgrade(&soft_locks),
1237            validator_service_metrics.clone(),
1238        );
1239
1240        let validator_server_handle = Self::start_grpc_validator_service(
1241            &config,
1242            state.clone(),
1243            consensus_adapter.clone(),
1244            &validator_registry,
1245            soft_locks.clone(),
1246            validator_service_metrics.clone(),
1247            serving_rt_handle,
1248        )
1249        .await?;
1250
1251        // Starts an overload monitor that monitors the execution of the authority.
1252        // Don't start the overload monitor when max_load_shedding_percentage is 0.
1253        let validator_overload_monitor_handle = if config
1254            .authority_overload_config
1255            .max_load_shedding_percentage
1256            > 0
1257        {
1258            let authority_state = Arc::downgrade(&state);
1259            let overload_config = config.authority_overload_config.clone();
1260            fail_point!("starting_overload_monitor");
1261            Some(spawn_monitored_task!(overload_monitor(
1262                authority_state,
1263                overload_config,
1264            )))
1265        } else {
1266            None
1267        };
1268
1269        // Starts a monitor that periodically refreshes the
1270        // `consensus_queue_load_shedding_percentage` metric. Without this, the
1271        // metric goes stale once gRPC traffic stops (the only other update
1272        // path is `AuthorityState::check_consensus_queue_graduated_limits`, called on
1273        // each inbound tx). Used in the certificate-less (P-COOL)
1274        // mode.
1275        let consensus_queue_overload_monitor_handle =
1276            if epoch_store.protocol_config().enable_pcool_flow() {
1277                let consensus_queue_monitor_authority_state = Arc::downgrade(&state);
1278                let consensus_queue_monitor_consensus_adapter = Arc::downgrade(&consensus_adapter);
1279                let consensus_queue_monitor_interval =
1280                    config.authority_overload_config.overload_monitor_interval;
1281                Some(spawn_monitored_task!(consensus_queue_overload_monitor(
1282                    consensus_queue_monitor_authority_state,
1283                    consensus_queue_monitor_consensus_adapter,
1284                    consensus_queue_monitor_interval,
1285                )))
1286            } else {
1287                None
1288            };
1289
1290        Self::start_epoch_specific_validator_components(
1291            &config,
1292            state.clone(),
1293            consensus_adapter,
1294            checkpoint_store,
1295            epoch_store,
1296            state_sync_handle,
1297            randomness_handle,
1298            consensus_manager,
1299            consensus_store_pruner,
1300            global_state_hasher,
1301            backpressure_manager,
1302            soft_locks,
1303            validator_server_handle,
1304            validator_overload_monitor_handle,
1305            consensus_queue_overload_monitor_handle,
1306            soft_lock_sweep_handle,
1307            checkpoint_metrics,
1308            iota_tx_validator_metrics,
1309            validator_registry_id,
1310        )
1311        .await
1312    }
1313
1314    /// Initializes and starts components specific to the current
1315    /// epoch for the validator node.
1316    async fn start_epoch_specific_validator_components(
1317        config: &NodeConfig,
1318        state: Arc<AuthorityState>,
1319        consensus_adapter: Arc<ConsensusAdapter>,
1320        checkpoint_store: Arc<CheckpointStore>,
1321        epoch_store: Arc<AuthorityPerEpochStore>,
1322        state_sync_handle: state_sync::Handle,
1323        randomness_handle: randomness::Handle,
1324        consensus_manager: Arc<ConsensusManager>,
1325        consensus_store_pruner: ConsensusStorePruner,
1326        global_state_hasher: Weak<GlobalStateHasher>,
1327        backpressure_manager: Arc<BackpressureManager>,
1328        soft_locks: Arc<PreConsensusSoftLocks>,
1329        validator_server_handle: SpawnOnce,
1330        validator_overload_monitor_handle: Option<JoinHandle<()>>,
1331        consensus_queue_overload_monitor_handle: Option<JoinHandle<()>>,
1332        soft_lock_sweep_handle: JoinHandle<()>,
1333        checkpoint_metrics: Arc<CheckpointMetrics>,
1334        iota_tx_validator_metrics: Arc<IotaTxValidatorMetrics>,
1335        validator_registry_id: RegistryID,
1336    ) -> Result<ValidatorComponents> {
1337        let checkpoint_service = Self::build_checkpoint_service(
1338            config,
1339            consensus_adapter.clone(),
1340            checkpoint_store.clone(),
1341            epoch_store.clone(),
1342            state.clone(),
1343            state_sync_handle,
1344            global_state_hasher,
1345            checkpoint_metrics.clone(),
1346        );
1347
1348        // create a new map that gets injected into both the consensus handler and the
1349        // consensus adapter the consensus handler will write values forwarded
1350        // from consensus, and the consensus adapter will read the values to
1351        // make decisions about which validator submits a transaction to consensus
1352        let low_scoring_authorities = Arc::new(ArcSwap::new(Arc::new(HashMap::new())));
1353
1354        consensus_adapter.swap_low_scoring_authorities(low_scoring_authorities.clone());
1355
1356        // Wire pre-consensus soft locks to the epoch store so that
1357        // post-consensus processing can release locks once permanent locks are
1358        // quarantined. Clear stale locks from the previous epoch and spawn a
1359        // background sweep task.
1360        soft_locks.clear();
1361        epoch_store.set_soft_locks(soft_locks.clone());
1362
1363        // A validator cannot participate without a randomness manager. Aborting here
1364        // fails loudly at the real cause (startup or reconfiguration) instead
1365        // of leaving the node to panic later on the first consensus commit that
1366        // unconditionally expects one.
1367        let randomness_manager = match RandomnessManager::try_new(
1368            Arc::downgrade(&epoch_store),
1369            Box::new(consensus_adapter.clone()),
1370            randomness_handle,
1371            config.authority_key_pair(),
1372        )
1373        .await
1374        {
1375            Ok(randomness_manager) => randomness_manager,
1376            Err(err) => {
1377                fatal!(
1378                    "validator cannot start epoch {} without a randomness manager: {err}",
1379                    epoch_store.epoch()
1380                );
1381            }
1382        };
1383        epoch_store
1384            .set_randomness_manager(randomness_manager)
1385            .await?;
1386
1387        let consensus_handler_initializer = ConsensusHandlerInitializer::new(
1388            state.clone(),
1389            checkpoint_service.clone(),
1390            epoch_store.clone(),
1391            low_scoring_authorities,
1392            backpressure_manager,
1393        );
1394
1395        info!("Starting consensus manager asynchronously");
1396
1397        // Spawn consensus startup asynchronously to avoid blocking other components
1398        tokio::spawn({
1399            let config = config.clone();
1400            let epoch_store = epoch_store.clone();
1401            let iota_tx_validator = IotaTxValidator::new(
1402                epoch_store.clone(),
1403                checkpoint_service.clone(),
1404                iota_tx_validator_metrics.clone(),
1405            );
1406            let consensus_manager = consensus_manager.clone();
1407            async move {
1408                consensus_manager
1409                    .start(
1410                        &config,
1411                        epoch_store,
1412                        consensus_handler_initializer,
1413                        iota_tx_validator,
1414                    )
1415                    .await;
1416            }
1417        });
1418        let replay_waiter = consensus_manager.replay_waiter();
1419
1420        info!("Spawning checkpoint service");
1421        let replay_waiter = if std::env::var("DISABLE_REPLAY_WAITER").is_ok() {
1422            None
1423        } else {
1424            Some(replay_waiter)
1425        };
1426        let checkpoint_service_tasks = checkpoint_service.spawn(replay_waiter).await;
1427
1428        let overload_notifier_handle = Self::start_overload_notifier(
1429            config,
1430            state.clone(),
1431            epoch_store.clone(),
1432            consensus_adapter.clone(),
1433        );
1434
1435        Ok(ValidatorComponents {
1436            validator_server_handle,
1437            validator_overload_monitor_handle,
1438            consensus_queue_overload_monitor_handle,
1439            soft_lock_sweep_handle,
1440            overload_notifier_handle,
1441            consensus_manager,
1442            consensus_store_pruner,
1443            consensus_adapter,
1444            soft_locks,
1445            checkpoint_service_tasks,
1446            checkpoint_metrics,
1447            iota_tx_validator_metrics,
1448            validator_registry_id,
1449        })
1450    }
1451
1452    /// Starts the checkpoint service for the validator node, initializing
1453    /// necessary components and settings.
1454    /// The function ensures proper initialization of the checkpoint service,
1455    /// preparing it to handle checkpoint creation and submission to consensus,
1456    /// while also setting up the necessary monitoring and synchronization
1457    /// mechanisms.
1458    fn build_checkpoint_service(
1459        config: &NodeConfig,
1460        consensus_adapter: Arc<ConsensusAdapter>,
1461        checkpoint_store: Arc<CheckpointStore>,
1462        epoch_store: Arc<AuthorityPerEpochStore>,
1463        state: Arc<AuthorityState>,
1464        state_sync_handle: state_sync::Handle,
1465        global_state_hasher: Weak<GlobalStateHasher>,
1466        checkpoint_metrics: Arc<CheckpointMetrics>,
1467    ) -> Arc<CheckpointService> {
1468        let epoch_start_timestamp_ms = epoch_store.epoch_start_state().epoch_start_timestamp_ms();
1469        let epoch_duration_ms = epoch_store.epoch_start_state().epoch_duration_ms();
1470
1471        debug!(
1472            "Starting checkpoint service with epoch start timestamp {}
1473            and epoch duration {}",
1474            epoch_start_timestamp_ms, epoch_duration_ms
1475        );
1476
1477        let checkpoint_output = Box::new(SubmitCheckpointToConsensus {
1478            sender: consensus_adapter,
1479            signer: state.secret.clone(),
1480            authority: config.authority_public_key(),
1481            next_reconfiguration_timestamp_ms: epoch_start_timestamp_ms
1482                .checked_add(epoch_duration_ms)
1483                .expect("Overflow calculating next_reconfiguration_timestamp_ms"),
1484            metrics: checkpoint_metrics.clone(),
1485        });
1486
1487        let certified_checkpoint_output = SendCheckpointToStateSync::new(state_sync_handle);
1488        let max_tx_per_checkpoint = max_tx_per_checkpoint(epoch_store.protocol_config());
1489        let max_checkpoint_size_bytes =
1490            epoch_store.protocol_config().max_checkpoint_size_bytes() as usize;
1491
1492        CheckpointService::build(
1493            state.clone(),
1494            checkpoint_store,
1495            epoch_store,
1496            state.get_transaction_cache_reader().clone(),
1497            global_state_hasher,
1498            checkpoint_output,
1499            Box::new(certified_checkpoint_output),
1500            checkpoint_metrics,
1501            max_tx_per_checkpoint,
1502            max_checkpoint_size_bytes,
1503        )
1504    }
1505
1506    fn construct_consensus_adapter(
1507        committee: &Committee,
1508        consensus_config: &ConsensusConfig,
1509        authority: AuthorityName,
1510        connection_monitor_status: Arc<ConnectionMonitorStatus>,
1511        prometheus_registry: &Registry,
1512        consensus_client: Arc<dyn ConsensusClient>,
1513        checkpoint_store: Arc<CheckpointStore>,
1514    ) -> ConsensusAdapter {
1515        let ca_metrics = ConsensusAdapterMetrics::new(prometheus_registry);
1516        // The consensus adapter allows the authority to send user certificates through
1517        // consensus.
1518
1519        ConsensusAdapter::new(
1520            consensus_client,
1521            checkpoint_store,
1522            authority,
1523            connection_monitor_status,
1524            consensus_config.max_pending_transactions(),
1525            consensus_config.max_pending_transactions() * 2 / committee.num_members(),
1526            consensus_config.max_submit_position,
1527            consensus_config.submit_delay_step_override(),
1528            ca_metrics,
1529            consensus_config.graduated_load_shedding_soft_limit_pct(),
1530        )
1531    }
1532
1533    async fn start_grpc_validator_service(
1534        config: &NodeConfig,
1535        state: Arc<AuthorityState>,
1536        consensus_adapter: Arc<ConsensusAdapter>,
1537        prometheus_registry: &Registry,
1538        soft_locks: Arc<PreConsensusSoftLocks>,
1539        validator_service_metrics: Arc<ValidatorServiceMetrics>,
1540        serving_rt_handle: tokio::runtime::Handle,
1541    ) -> Result<SpawnOnce> {
1542        let validator_service = ValidatorService::new(
1543            state,
1544            consensus_adapter,
1545            validator_service_metrics,
1546            config.policy_config.clone().map(|p| p.client_id_source),
1547            soft_locks,
1548        );
1549
1550        // Each service gets its own concurrency limit so that a flood of client
1551        // transaction submissions (Validator / ValidatorV2) cannot crowd the
1552        // validator-peer RPCs sharing this listener out of admission slots.
1553        // The config value is per core, so the same config scales with the
1554        // hardware; the effective limit is computed on the machine the server
1555        // actually runs on.
1556        let concurrency_limit = config.grpc_concurrency_limit_per_core.saturating_mul(
1557            NonZeroUsize::new(iota_core::runtime::available_cpu_cores())
1558                .unwrap_or(NonZeroUsize::MIN),
1559        );
1560        let load_shed = config.grpc_load_shed.unwrap_or_default();
1561
1562        let server_conf = iota_network_stack::config::Config::new();
1563        let server_builder =
1564            ServerBuilder::from_config(&server_conf, GrpcMetrics::new(prometheus_registry))
1565                .add_service_with_concurrency_limit(
1566                    ValidatorServer::new(validator_service.clone()),
1567                    concurrency_limit,
1568                    load_shed,
1569                )
1570                .add_service_with_concurrency_limit(
1571                    ValidatorV2Server::new(validator_service.clone()),
1572                    concurrency_limit,
1573                    load_shed,
1574                )
1575                .add_service_with_concurrency_limit(
1576                    ValidatorPeerServer::new(validator_service),
1577                    concurrency_limit,
1578                    load_shed,
1579                );
1580
1581        let tls_config = iota_tls::create_rustls_server_config(
1582            config.network_key_pair().copy().private(),
1583            IOTA_TLS_SERVER_NAME.to_string(),
1584        );
1585
1586        let network_address = config.network_address().clone();
1587
1588        let bind_future = async move {
1589            let server = server_builder
1590                .bind(&network_address, Some(tls_config))
1591                .await
1592                .map_err(|err| anyhow!("Failed to bind to {network_address}: {err}"))?;
1593
1594            let local_addr = server.local_addr();
1595            info!("Listening to traffic on {local_addr}");
1596
1597            Ok(server)
1598        };
1599
1600        Ok(SpawnOnce::new(bind_future, serving_rt_handle))
1601    }
1602
1603    /// Re-executes pending consensus certificates, which may not have been
1604    /// committed to disk before the node restarted. This is necessary for
1605    /// the following reasons:
1606    ///
1607    /// 1. For any transaction for which we returned signed effects to a client,
1608    ///    we must ensure that we have re-executed the transaction before we
1609    ///    begin accepting grpc requests. Otherwise we would appear to have
1610    ///    forgotten about the transaction.
1611    /// 2. While this is running, we are concurrently waiting for all previously
1612    ///    built checkpoints to be rebuilt. Since there may be dependencies in
1613    ///    either direction (from checkpointed consensus transactions to pending
1614    ///    consensus transactions, or vice versa), we must re-execute pending
1615    ///    consensus transactions to ensure that both processes can complete.
1616    /// 3. Also note that for any pending consensus transactions for which we
1617    ///    wrote a signed effects digest to disk, we must re-execute using that
1618    ///    digest as the expected effects digest, to ensure that we cannot
1619    ///    arrive at different effects than what we previously signed.
1620    async fn reexecute_pending_consensus_certs(
1621        epoch_store: &Arc<AuthorityPerEpochStore>,
1622        state: &Arc<AuthorityState>,
1623    ) {
1624        let mut pending_consensus_certificates = Vec::new();
1625        let mut additional_certs = Vec::new();
1626
1627        for tx in epoch_store.get_all_pending_consensus_transactions() {
1628            match tx.kind {
1629                // TODO: what to do with UserTransactionV1 here? It seems like this only applies to
1630                //  optimistically executed owned-object transactions that possibly didn't go
1631                //  through  consensus before the node restarted. UserTransactionsV1
1632                //  always needs to go  through consensus, so it will be replayed
1633                //  there, just like shared object  transactions.
1634                //
1635                // Shared object txns
1636                // cannot be re-executed at this  point, because we must wait for
1637                // consensus replay to assign shared  object versions.
1638                ConsensusTransactionKind::CertifiedTransaction(tx)
1639                    if !tx.contains_shared_object() =>
1640                {
1641                    let tx = *tx;
1642                    // new_unchecked is safe because we never submit a transaction to consensus
1643                    // without verifying it
1644                    let tx = VerifiedExecutableTransaction::new_from_certificate(
1645                        VerifiedCertificate::new_unchecked(tx),
1646                    );
1647                    // we only need to re-execute if we previously signed the effects (which
1648                    // indicates we returned the effects to a client).
1649                    if let Some(fx_digest) = epoch_store
1650                        .get_signed_effects_digest(tx.digest())
1651                        .expect("db error")
1652                    {
1653                        pending_consensus_certificates.push((tx, fx_digest));
1654                    } else {
1655                        additional_certs.push(tx);
1656                    }
1657                }
1658                _ => (),
1659            }
1660        }
1661
1662        let digests = pending_consensus_certificates
1663            .iter()
1664            .map(|(tx, _)| *tx.digest())
1665            .collect::<Vec<_>>();
1666
1667        info!(
1668            "reexecuting {} pending consensus certificates: {:?}",
1669            digests.len(),
1670            digests
1671        );
1672
1673        state.enqueue_with_expected_effects_digest(pending_consensus_certificates, epoch_store);
1674        state.enqueue_transactions_for_execution(additional_certs, epoch_store);
1675
1676        // If this times out, the validator will still almost certainly start up fine.
1677        // But, it is possible that it may temporarily "forget" about
1678        // transactions that it had previously executed. This could confuse
1679        // clients in some circumstances. However, the transactions are still in
1680        // pending_consensus_certificates, so we cannot lose any finality guarantees.
1681        let timeout = if cfg!(msim) { 120 } else { 60 };
1682        if tokio::time::timeout(
1683            std::time::Duration::from_secs(timeout),
1684            state
1685                .get_transaction_cache_reader()
1686                .try_notify_read_executed_effects_digests(
1687                    "IotaNode::notify_read_executed_effects_digests",
1688                    &digests,
1689                ),
1690        )
1691        .await
1692        .is_err()
1693        {
1694            // Log all the digests that were not executed to help debugging.
1695            if let Ok(executed_effects_digests) = state
1696                .get_transaction_cache_reader()
1697                .try_multi_get_executed_effects_digests(&digests)
1698            {
1699                let pending_digests = digests
1700                    .iter()
1701                    .zip(executed_effects_digests.iter())
1702                    .filter_map(|(digest, executed_effects_digest)| {
1703                        if executed_effects_digest.is_none() {
1704                            Some(digest)
1705                        } else {
1706                            None
1707                        }
1708                    })
1709                    .collect::<Vec<_>>();
1710                debug_fatal!(
1711                    "Timed out waiting for effects digests to be executed: {:?}",
1712                    pending_digests
1713                );
1714            } else {
1715                debug_fatal!(
1716                    "Timed out waiting for effects digests to be executed, digests not found"
1717                );
1718            }
1719        }
1720    }
1721
1722    pub fn state(&self) -> Arc<AuthorityState> {
1723        self.state.clone()
1724    }
1725
1726    // Only used for testing because of how epoch store is loaded.
1727    pub fn reference_gas_price_for_testing(&self) -> Result<u64, anyhow::Error> {
1728        self.state.reference_gas_price_for_testing()
1729    }
1730
1731    pub fn clone_committee_store(&self) -> Arc<CommitteeStore> {
1732        self.state.committee_store().clone()
1733    }
1734
1735    // pub fn clone_authority_store(&self) -> Arc<AuthorityStore> {
1736    // self.state.db()
1737    // }
1738
1739    /// Clone an AuthorityAggregator from the transaction orchestrator, if
1740    /// this is a fullnode. The snapshot goes stale after an epoch change;
1741    /// call again for a fresh one.
1742    pub fn clone_authority_aggregator(
1743        &self,
1744    ) -> Option<Arc<AuthorityAggregator<NetworkAuthorityClient>>> {
1745        self.transaction_orchestrator
1746            .as_ref()
1747            .map(|to| to.clone_authority_aggregator())
1748    }
1749
1750    pub fn transaction_orchestrator(
1751        &self,
1752    ) -> Option<Arc<TransactionOrchestrator<NetworkAuthorityClient>>> {
1753        self.transaction_orchestrator.clone()
1754    }
1755
1756    /// Read-only client for the SDK's `TransactionBuilder` backed by this
1757    /// node's local state instead of a remote endpoint.
1758    pub fn transaction_builder_ledger_client(&self) -> NodeTransactionBuilderLedgerClient {
1759        let reader = Arc::new(GrpcReadStore::new(
1760            self.state.clone(),
1761            self.state_sync_store.clone(),
1762        ));
1763        NodeTransactionBuilderLedgerClient::new(reader)
1764    }
1765
1766    /// Subscribe to the quorum driver's effects stream; errors while the
1767    /// quorum driver is not the currently served flow on this node.
1768    pub fn subscribe_to_transaction_orchestrator_effects(
1769        &self,
1770    ) -> Result<tokio::sync::broadcast::Receiver<QuorumDriverEffectsQueueResult>> {
1771        self.transaction_orchestrator
1772            .as_ref()
1773            .ok_or_else(|| {
1774                anyhow::anyhow!("Transaction Orchestrator is not enabled in this node.")
1775            })?
1776            .subscribe_to_effects_queue()
1777            .ok_or_else(|| {
1778                anyhow::anyhow!(
1779                    "Effects queue is not available: the quorum driver is not the currently \
1780                     served flow on this node."
1781                )
1782            })
1783    }
1784
1785    /// This function awaits the completion of checkpoint execution of the
1786    /// current epoch, after which it initiates reconfiguration of the
1787    /// entire system. This function also handles role changes for the node when
1788    /// epoch changes and, if the node is a validator, advertises capabilities
1789    /// and submits the local deny rule proposal to consensus.
1790    pub async fn monitor_reconfiguration(
1791        self: Arc<Self>,
1792        mut epoch_store: Arc<AuthorityPerEpochStore>,
1793    ) -> Result<()> {
1794        let checkpoint_executor_metrics =
1795            CheckpointExecutorMetrics::new(&self.registry_service.default_registry());
1796
1797        loop {
1798            let mut hasher_guard = self.global_state_hasher.lock().await;
1799            let hasher = hasher_guard.take().unwrap();
1800            info!(
1801                "Creating checkpoint executor for epoch {}",
1802                epoch_store.epoch()
1803            );
1804
1805            // Create closures that handle gRPC type conversion
1806            let data_sender = if let Ok(guard) = self.grpc_server_handle.try_lock() {
1807                guard.as_ref().map(|handle| {
1808                    let tx = handle.checkpoint_data_broadcaster().clone();
1809                    Box::new(move |data: &CheckpointData| {
1810                        tx.send_traced(data);
1811                    }) as Box<dyn Fn(&CheckpointData) + Send + Sync>
1812                })
1813            } else {
1814                None
1815            };
1816
1817            let checkpoint_executor = CheckpointExecutor::new(
1818                epoch_store.clone(),
1819                self.checkpoint_store.clone(),
1820                self.state.clone(),
1821                hasher.clone(),
1822                self.backpressure_manager.clone(),
1823                self.config.checkpoint_executor_config.clone(),
1824                checkpoint_executor_metrics.clone(),
1825                data_sender,
1826                Some(self.checkpoint_progress_tracker.clone()),
1827            );
1828
1829            let run_with_range = self.config.run_with_range;
1830
1831            let cur_epoch_store = self.state.load_epoch_store_one_call_per_task();
1832
1833            // Update the current protocol version metric.
1834            self.metrics
1835                .current_protocol_version
1836                .set(cur_epoch_store.protocol_config().version.as_u64() as i64);
1837
1838            // Advertise capabilities to committee, if we are a validator.
1839            if let Some(components) = &*self.validator_components.lock().await {
1840                // TODO: without this sleep, the consensus message is not delivered reliably.
1841                tokio::time::sleep(Duration::from_millis(1)).await;
1842
1843                let config = cur_epoch_store.protocol_config();
1844                let binary_config = to_binary_config(config);
1845                let transaction = ConsensusTransaction::new_capability_notification_v1(
1846                    AuthorityCapabilitiesV1::new(
1847                        self.state.name,
1848                        cur_epoch_store.get_chain(),
1849                        self.config
1850                            .supported_protocol_versions
1851                            .expect("Supported versions should be populated")
1852                            // no need to send digests of versions less than the current version
1853                            .truncate_below(config.version),
1854                        self.state
1855                            .get_available_system_packages(&binary_config)
1856                            .await,
1857                    ),
1858                );
1859                info!(?transaction, "submitting capabilities to consensus");
1860                components
1861                    .consensus_adapter
1862                    .submit(transaction, None, &cur_epoch_store)?;
1863
1864                // Announce the local deny rules. Recorded proposals are
1865                // epoch-scoped, so this re-announces on every epoch change.
1866                // The empty set is announced too: every committee member
1867                // attests its configuration each epoch, so silence means
1868                // offline rather than "no rules".
1869                if config.deny_rule_governance() {
1870                    let proposed_rules = self.config.transaction_deny_config.to_deny_rule_set();
1871                    let recorded = cur_epoch_store.recorded_deny_rule_proposal(&self.state.name);
1872                    let transaction = ConsensusTransaction::new_transaction_deny_rule_proposal(
1873                        TransactionDenyRuleProposal::new(
1874                            self.state.name,
1875                            proposed_rules,
1876                            recorded.map(|p| p.generation),
1877                        ),
1878                    );
1879                    info!(
1880                        tracking_id = ?transaction.get_tracking_id(),
1881                        "submitting deny rule proposal to consensus"
1882                    );
1883                    components
1884                        .consensus_adapter
1885                        .submit(transaction, None, &cur_epoch_store)?;
1886                }
1887            } else if self.state.is_active_validator(&cur_epoch_store)
1888                && cur_epoch_store
1889                    .protocol_config()
1890                    .track_non_committee_eligible_validators()
1891            {
1892                // Send signed capabilities to committee validators if we are a non-committee
1893                // validator in a separate task to not block the caller. Sending is done only if
1894                // the feature flag supporting it is enabled.
1895                let epoch_store = cur_epoch_store.clone();
1896                let node_clone = self.clone();
1897                spawn_monitored_task!(epoch_store.clone().within_alive_epoch(async move {
1898                    node_clone
1899                        .send_signed_capability_notification_to_committee_with_retry(&epoch_store)
1900                        .instrument(trace_span!(
1901                            "send_signed_capability_notification_to_committee_with_retry"
1902                        ))
1903                        .await;
1904                }));
1905            }
1906
1907            let stop_condition = checkpoint_executor.run_epoch(run_with_range).await;
1908
1909            if stop_condition == StopReason::RunWithRangeCondition {
1910                IotaNode::shutdown(&self).await;
1911                self.shutdown_channel_tx
1912                    .send(run_with_range)
1913                    .expect("RunWithRangeCondition met but failed to send shutdown message");
1914                return Ok(());
1915            }
1916
1917            // Safe to call because we are in the middle of reconfiguration.
1918            let latest_system_state = self
1919                .state
1920                .get_object_cache_reader()
1921                .try_get_iota_system_state_object_unsafe()
1922                .expect("Read IOTA System State object cannot fail");
1923
1924            #[cfg(msim)]
1925            if !self
1926                .sim_state
1927                .sim_safe_mode_expected
1928                .load(Ordering::Relaxed)
1929            {
1930                debug_assert!(!latest_system_state.safe_mode());
1931            }
1932
1933            #[cfg(not(msim))]
1934            debug_assert!(!latest_system_state.safe_mode());
1935
1936            if let Err(err) = self.end_of_epoch_channel.send(latest_system_state.clone()) {
1937                if self.state.is_fullnode(&cur_epoch_store) {
1938                    warn!(
1939                        "Failed to send end of epoch notification to subscriber: {:?}",
1940                        err
1941                    );
1942                }
1943            }
1944
1945            cur_epoch_store.record_is_safe_mode_metric(latest_system_state.safe_mode());
1946            let new_epoch_start_state = latest_system_state.into_epoch_start_state();
1947
1948            self.auth_agg.store(Arc::new(
1949                self.auth_agg
1950                    .load()
1951                    .recreate_with_new_epoch_start_state(&new_epoch_start_state),
1952            ));
1953
1954            let next_epoch_committee = new_epoch_start_state.get_iota_committee();
1955            let next_epoch = next_epoch_committee.epoch();
1956            assert_eq!(cur_epoch_store.epoch() + 1, next_epoch);
1957
1958            info!(
1959                next_epoch,
1960                "Finished executing all checkpoints in epoch. About to reconfigure the system."
1961            );
1962
1963            fail_point_async!("reconfig_delay");
1964
1965            // We save the connection monitor status map regardless of validator / fullnode
1966            // status so that we don't need to restart the connection monitor
1967            // every epoch. Update the mappings that will be used by the
1968            // consensus adapter if it exists or is about to be created.
1969            let authority_names_to_peer_ids =
1970                new_epoch_start_state.get_authority_names_to_peer_ids();
1971            self.connection_monitor_status
1972                .update_mapping_for_epoch(authority_names_to_peer_ids);
1973
1974            cur_epoch_store.record_epoch_reconfig_start_time_metric();
1975
1976            send_trusted_peer_change(
1977                &self.config,
1978                &self.trusted_peer_change_tx,
1979                &new_epoch_start_state,
1980            );
1981
1982            let mut validator_components_lock_guard = self.validator_components.lock().await;
1983
1984            // The following code handles 4 different cases, depending on whether the node
1985            // was a validator in the previous epoch, and whether the node is a validator
1986            // in the new epoch.
1987            let new_epoch_store = self
1988                .reconfigure_state(
1989                    &self.state,
1990                    &cur_epoch_store,
1991                    next_epoch_committee.clone(),
1992                    new_epoch_start_state,
1993                    hasher.clone(),
1994                )
1995                .await?;
1996
1997            let new_validator_components = if let Some(ValidatorComponents {
1998                validator_server_handle,
1999                validator_overload_monitor_handle,
2000                consensus_queue_overload_monitor_handle,
2001                soft_lock_sweep_handle,
2002                overload_notifier_handle,
2003                consensus_manager,
2004                consensus_store_pruner,
2005                consensus_adapter,
2006                soft_locks,
2007                mut checkpoint_service_tasks,
2008                checkpoint_metrics,
2009                iota_tx_validator_metrics,
2010                validator_registry_id,
2011            }) = validator_components_lock_guard.take()
2012            {
2013                info!("Reconfiguring the validator.");
2014                // Cancel the old overload notifier task so a new one can be
2015                // started for the next epoch.
2016                if let Some(handle) = overload_notifier_handle {
2017                    handle.abort();
2018                }
2019                // Cancel the old checkpoint service tasks.
2020                // Waiting for checkpoint builder to finish gracefully is not possible, because
2021                // it may wait on transactions while consensus on peers have
2022                // already shut down.
2023                checkpoint_service_tasks.abort_all();
2024                while let Some(result) = checkpoint_service_tasks.join_next().await {
2025                    if let Err(err) = result {
2026                        if err.is_panic() {
2027                            std::panic::resume_unwind(err.into_panic());
2028                        }
2029                        warn!("Error in checkpoint service task: {:?}", err);
2030                    }
2031                }
2032                info!("Checkpoint service has shut down.");
2033
2034                consensus_manager.shutdown().await;
2035                info!("Consensus has shut down.");
2036
2037                info!("Epoch store finished reconfiguration.");
2038
2039                // No other components should be holding a strong reference to state hasher
2040                // at this point. Confirm here before we swap in the new hasher.
2041                let global_state_hasher_metrics = Arc::into_inner(hasher)
2042                    .expect("Object state hasher should have no other references at this point")
2043                    .metrics();
2044                let new_hasher = Arc::new(GlobalStateHasher::new(
2045                    self.state.get_global_state_hash_store().clone(),
2046                    global_state_hasher_metrics,
2047                ));
2048                let weak_hasher = Arc::downgrade(&new_hasher);
2049                *hasher_guard = Some(new_hasher);
2050
2051                consensus_store_pruner.prune(next_epoch).await;
2052
2053                if self.state.is_committee_validator(&new_epoch_store) {
2054                    // Only restart consensus if this node is still a validator in the new epoch.
2055                    Some(
2056                        Self::start_epoch_specific_validator_components(
2057                            &self.config,
2058                            self.state.clone(),
2059                            consensus_adapter,
2060                            self.checkpoint_store.clone(),
2061                            new_epoch_store.clone(),
2062                            self.state_sync_handle.clone(),
2063                            self.randomness_handle.clone(),
2064                            consensus_manager,
2065                            consensus_store_pruner,
2066                            weak_hasher,
2067                            self.backpressure_manager.clone(),
2068                            soft_locks,
2069                            validator_server_handle,
2070                            validator_overload_monitor_handle,
2071                            consensus_queue_overload_monitor_handle,
2072                            soft_lock_sweep_handle,
2073                            checkpoint_metrics,
2074                            iota_tx_validator_metrics,
2075                            validator_registry_id,
2076                        )
2077                        .await?,
2078                    )
2079                } else {
2080                    info!("This node is no longer a validator after reconfiguration");
2081                    if self.registry_service.remove(validator_registry_id) {
2082                        debug!("Removed validator metrics registry");
2083                    } else {
2084                        warn!("Failed to remove validator metrics registry");
2085                    }
2086                    validator_server_handle.shutdown();
2087                    debug!("Validator grpc server shutdown triggered");
2088
2089                    None
2090                }
2091            } else {
2092                // No other components should be holding a strong reference to state hasher
2093                // at this point. Confirm here before we swap in the new hasher.
2094                let global_state_hasher_metrics = Arc::into_inner(hasher)
2095                    .expect("Object state hasher should have no other references at this point")
2096                    .metrics();
2097                let new_hasher = Arc::new(GlobalStateHasher::new(
2098                    self.state.get_global_state_hash_store().clone(),
2099                    global_state_hasher_metrics,
2100                ));
2101                let weak_hasher = Arc::downgrade(&new_hasher);
2102                *hasher_guard = Some(new_hasher);
2103
2104                if self.state.is_committee_validator(&new_epoch_store) {
2105                    info!("Promoting the node from fullnode to validator, starting grpc server");
2106
2107                    let mut components = Self::construct_validator_components(
2108                        self.config.clone(),
2109                        self.state.clone(),
2110                        Arc::new(next_epoch_committee.clone()),
2111                        new_epoch_store.clone(),
2112                        self.checkpoint_store.clone(),
2113                        self.state_sync_handle.clone(),
2114                        self.randomness_handle.clone(),
2115                        weak_hasher,
2116                        self.backpressure_manager.clone(),
2117                        self.connection_monitor_status.clone(),
2118                        &self.registry_service,
2119                        self.serving_rt_handle.clone(),
2120                    )
2121                    .await?;
2122
2123                    components.validator_server_handle =
2124                        components.validator_server_handle.start().await;
2125
2126                    Some(components)
2127                } else {
2128                    None
2129                }
2130            };
2131            *validator_components_lock_guard = new_validator_components;
2132
2133            // Force releasing current epoch store DB handle, because the
2134            // Arc<AuthorityPerEpochStore> may linger.
2135            cur_epoch_store.release_db_handles();
2136
2137            // Drop the old epoch store to free its in-memory structures
2138            // (ConsensusOutputCache, ConsensusQuarantine, DashMaps, etc.).
2139            // The DB tables were already released above.
2140            drop(cur_epoch_store);
2141
2142            // Prune old epoch databases after each epoch transition to prevent
2143            // accumulation of RocksDB instances during fast catch-up sync
2144            // (e.g. syncing from genesis).
2145            self.state.epoch_db_pruner().prune_old_epoch_dbs().await;
2146
2147            if cfg!(msim)
2148                && !matches!(
2149                    self.config
2150                        .authority_store_pruning_config
2151                        .num_epochs_to_retain_for_checkpoints(),
2152                    None | Some(u64::MAX) | Some(0)
2153                )
2154            {
2155                self.state
2156                    .prune_checkpoints_for_eligible_epochs_for_testing(
2157                        self.config.clone(),
2158                        iota_core::authority::authority_store_pruner::AuthorityStorePruningMetrics::new_for_test(),
2159                    )
2160                    .await?;
2161            }
2162
2163            epoch_store = new_epoch_store;
2164            info!("Reconfiguration finished");
2165        }
2166    }
2167
2168    async fn shutdown(&self) {
2169        if let Some(validator_components) = &*self.validator_components.lock().await {
2170            validator_components.consensus_manager.shutdown().await;
2171        }
2172
2173        // Shutdown the gRPC server if it's running
2174        if let Some(grpc_handle) = self.grpc_server_handle.lock().await.take() {
2175            info!("Shutting down gRPC server");
2176            if let Err(e) = grpc_handle.shutdown().await {
2177                warn!("Failed to gracefully shutdown gRPC server: {e}");
2178            }
2179        }
2180    }
2181
2182    /// Asynchronously reconfigures the state of the authority node for the next
2183    /// epoch.
2184    async fn reconfigure_state(
2185        &self,
2186        state: &Arc<AuthorityState>,
2187        cur_epoch_store: &AuthorityPerEpochStore,
2188        next_epoch_committee: Committee,
2189        next_epoch_start_system_state: EpochStartSystemState,
2190        global_state_hasher: Arc<GlobalStateHasher>,
2191    ) -> IotaResult<Arc<AuthorityPerEpochStore>> {
2192        let next_epoch = next_epoch_committee.epoch();
2193
2194        let last_checkpoint = self
2195            .checkpoint_store
2196            .get_epoch_last_checkpoint(cur_epoch_store.epoch())
2197            .expect("Error loading last checkpoint for current epoch")
2198            .expect("Could not load last checkpoint for current epoch");
2199        let epoch_supply_change = last_checkpoint
2200            .end_of_epoch_data
2201            .as_ref()
2202            .ok_or_else(|| {
2203                IotaError::from("last checkpoint in epoch should contain end of epoch data")
2204            })?
2205            .epoch_supply_change;
2206
2207        let last_checkpoint_seq = last_checkpoint.sequence_number();
2208
2209        assert_eq!(
2210            Some(last_checkpoint_seq),
2211            self.checkpoint_store
2212                .get_highest_executed_checkpoint_seq_number()
2213                .expect("Error loading highest executed checkpoint sequence number")
2214        );
2215
2216        let epoch_start_configuration = EpochStartConfiguration::new(
2217            next_epoch_start_system_state,
2218            *last_checkpoint.digest(),
2219            state.get_object_store().as_ref(),
2220            EpochFlag::default_flags_for_new_epoch(&state.config),
2221        )
2222        .expect("EpochStartConfiguration construction cannot fail");
2223
2224        let new_epoch_store = self
2225            .state
2226            .reconfigure(
2227                cur_epoch_store,
2228                self.config.supported_protocol_versions.unwrap(),
2229                next_epoch_committee,
2230                epoch_start_configuration,
2231                global_state_hasher,
2232                &self.config.expensive_safety_check_config,
2233                epoch_supply_change,
2234                last_checkpoint_seq,
2235            )
2236            .await
2237            .expect("Reconfigure authority state cannot fail");
2238        info!(next_epoch, "Node State has been reconfigured");
2239        assert_eq!(next_epoch, new_epoch_store.epoch());
2240        self.state.get_reconfig_api().update_epoch_flags_metrics(
2241            cur_epoch_store.epoch_start_config().flags(),
2242            new_epoch_store.epoch_start_config().flags(),
2243        );
2244
2245        Ok(new_epoch_store)
2246    }
2247
2248    pub fn get_config(&self) -> &NodeConfig {
2249        &self.config
2250    }
2251
2252    async fn execute_transaction_immediately_at_zero_epoch(
2253        state: &Arc<AuthorityState>,
2254        epoch_store: &Arc<AuthorityPerEpochStore>,
2255        tx: &TransactionEnvelope,
2256        span: tracing::Span,
2257    ) {
2258        let _guard = span.enter();
2259        let transaction =
2260            iota_types::executable_transaction::VerifiedExecutableTransaction::new_unchecked(
2261                iota_types::executable_transaction::ExecutableTransaction::new_from_data_and_sig(
2262                    tx.data().clone(),
2263                    iota_types::executable_transaction::CertificateProof::Checkpoint(0, 0),
2264                ),
2265            );
2266        state
2267            .try_execute_immediately(&transaction, None, epoch_store)
2268            .unwrap();
2269    }
2270
2271    pub fn randomness_handle(&self) -> randomness::Handle {
2272        self.randomness_handle.clone()
2273    }
2274
2275    /// Returns the registry service holding the node's Prometheus registries
2276    /// and their shared exposure filter.
2277    pub(crate) fn registry_service(&self) -> &RegistryService {
2278        &self.registry_service
2279    }
2280
2281    /// Sends signed capability notification to committee validators for
2282    /// non-committee validators. This method implements retry logic to handle
2283    /// failed attempts to send the notification. It will retry sending the
2284    /// notification with an increasing interval until it receives a successful
2285    /// response from a f+1 committee members or 2f+1 non-retryable errors.
2286    async fn send_signed_capability_notification_to_committee_with_retry(
2287        &self,
2288        epoch_store: &Arc<AuthorityPerEpochStore>,
2289    ) {
2290        const INITIAL_RETRY_INTERVAL_SECS: u64 = 5;
2291        const RETRY_INTERVAL_INCREMENT_SECS: u64 = 5;
2292        const MAX_RETRY_INTERVAL_SECS: u64 = 300; // 5 minutes
2293
2294        // Create the capability notification once
2295        let config = epoch_store.protocol_config();
2296        let binary_config = to_binary_config(config);
2297
2298        // Create the capability notification
2299        let capabilities = AuthorityCapabilitiesV1::new(
2300            self.state.name,
2301            epoch_store.get_chain(),
2302            self.config
2303                .supported_protocol_versions
2304                .expect("Supported versions should be populated")
2305                .truncate_below(config.version),
2306            self.state
2307                .get_available_system_packages(&binary_config)
2308                .await,
2309        );
2310
2311        // Sign the capabilities using the authority key pair from config
2312        let signature = AuthoritySignature::new_secure(
2313            &IntentMessage::new(
2314                Intent::iota_app(IntentScope::AuthorityCapabilities),
2315                &capabilities,
2316            ),
2317            &epoch_store.epoch(),
2318            self.config.authority_key_pair(),
2319        );
2320
2321        let request = HandleCapabilityNotificationRequestV1 {
2322            message: SignedAuthorityCapabilitiesV1::new_from_data_and_sig(capabilities, signature),
2323        };
2324
2325        let mut retry_interval = Duration::from_secs(INITIAL_RETRY_INTERVAL_SECS);
2326
2327        loop {
2328            let auth_agg = self.auth_agg.load();
2329            match auth_agg
2330                .send_capability_notification_to_quorum(request.clone())
2331                .await
2332            {
2333                Ok(_) => {
2334                    info!("Successfully sent capability notification to committee");
2335                    break;
2336                }
2337                Err(err) => {
2338                    match &err {
2339                        AggregatorSendCapabilityNotificationError::RetryableNotification {
2340                            errors,
2341                        } => {
2342                            warn!(
2343                                "Failed to send capability notification to committee (retryable error), will retry in {:?}: {:?}",
2344                                retry_interval, errors
2345                            );
2346                        }
2347                        AggregatorSendCapabilityNotificationError::NonRetryableNotification {
2348                            errors,
2349                        } => {
2350                            error!(
2351                                "Failed to send capability notification to committee (non-retryable error): {:?}",
2352                                errors
2353                            );
2354                            break;
2355                        }
2356                    };
2357
2358                    // Wait before retrying
2359                    tokio::time::sleep(retry_interval).await;
2360
2361                    // Increase retry interval for the next attempt, capped at max
2362                    retry_interval = std::cmp::min(
2363                        retry_interval + Duration::from_secs(RETRY_INTERVAL_INCREMENT_SECS),
2364                        Duration::from_secs(MAX_RETRY_INTERVAL_SECS),
2365                    );
2366                }
2367            }
2368        }
2369    }
2370}
2371
2372#[cfg(msim)]
2373impl IotaNode {
2374    pub fn get_sim_node_id(&self) -> iota_simulator::task::NodeId {
2375        self.sim_state.sim_node.id()
2376    }
2377
2378    pub fn set_safe_mode_expected(&self, new_value: bool) {
2379        info!("Setting safe mode expected to {}", new_value);
2380        self.sim_state
2381            .sim_safe_mode_expected
2382            .store(new_value, Ordering::Relaxed);
2383    }
2384}
2385
2386enum SpawnOnce {
2387    // Mutex is only needed to make SpawnOnce Sync
2388    Unstarted(
2389        Mutex<BoxFuture<'static, Result<iota_network_stack::server::Server>>>,
2390        tokio::runtime::Handle,
2391    ),
2392    #[allow(unused)]
2393    Started(iota_http::ServerHandle),
2394}
2395
2396impl SpawnOnce {
2397    pub fn new(
2398        future: impl Future<Output = Result<iota_network_stack::server::Server>> + Send + 'static,
2399        serving_rt_handle: tokio::runtime::Handle,
2400    ) -> Self {
2401        Self::Unstarted(Mutex::new(Box::pin(future)), serving_rt_handle)
2402    }
2403
2404    pub async fn start(self) -> Self {
2405        match self {
2406            Self::Unstarted(future, serving_rt_handle) => {
2407                // bind() and serve() must execute on the serving runtime:
2408                // iota_http::Builder::serve captures Handle::current() there for
2409                // the accept loop and every request handler.
2410                let (handle_tx, handle_rx) = tokio::sync::oneshot::channel();
2411                serving_rt_handle.spawn(async move {
2412                    let server = future.into_inner().await.unwrap_or_else(|err| {
2413                        panic!("Failed to start validator gRPC server: {err}")
2414                    });
2415                    if handle_tx.send(server.handle().clone()).is_err() {
2416                        return;
2417                    }
2418                    if let Err(err) = server.serve().await {
2419                        info!("Server stopped: {err}");
2420                    }
2421                    info!("Server stopped");
2422                });
2423                let handle = handle_rx
2424                    .await
2425                    .expect("validator gRPC server exited before returning its handle");
2426                Self::Started(handle)
2427            }
2428            Self::Started(_) => self,
2429        }
2430    }
2431
2432    pub fn shutdown(self) {
2433        if let SpawnOnce::Started(handle) = self {
2434            handle.trigger_shutdown();
2435        }
2436    }
2437}
2438
2439/// Notify [`DiscoveryEventLoop`] that a new list of trusted peers are now
2440/// available.
2441fn send_trusted_peer_change(
2442    config: &NodeConfig,
2443    sender: &watch::Sender<TrustedPeerChangeEvent>,
2444    new_epoch_start_state: &EpochStartSystemState,
2445) {
2446    let new_committee =
2447        new_epoch_start_state.get_validator_as_p2p_peers(config.authority_public_key());
2448
2449    sender.send_modify(|event| {
2450        core::mem::swap(&mut event.new_committee, &mut event.old_committee);
2451        event.new_committee = new_committee;
2452    })
2453}
2454
2455fn build_kv_store(
2456    state: &Arc<AuthorityState>,
2457    config: &NodeConfig,
2458    registry: &Registry,
2459) -> Result<Arc<TransactionKeyValueStore>> {
2460    let metrics = KeyValueStoreMetrics::new(registry);
2461    let db_store = TransactionKeyValueStore::new("rocksdb", metrics.clone(), state.clone());
2462
2463    let base_url = &config.transaction_kv_store_read_config.base_url;
2464
2465    if base_url.is_empty() {
2466        info!("no http kv store url provided, using local db only");
2467        return Ok(Arc::new(db_store));
2468    }
2469
2470    base_url.parse::<url::Url>().tap_err(|e| {
2471        error!(
2472            "failed to parse config.transaction_kv_store_config.base_url ({:?}) as url: {}",
2473            base_url, e
2474        )
2475    })?;
2476
2477    let http_store = HttpKVStore::new_kv(
2478        base_url,
2479        config.transaction_kv_store_read_config.cache_size,
2480        metrics.clone(),
2481    )?;
2482    info!("using local key-value store with fallback to http key-value store");
2483    Ok(Arc::new(FallbackTransactionKVStore::new_kv(
2484        db_store,
2485        http_store,
2486        metrics,
2487        "json_rpc_fallback",
2488    )))
2489}
2490
2491/// Builds and starts the gRPC server for the IOTA node based on the node's
2492/// configuration.
2493///
2494/// This function performs the following tasks:
2495/// 1. Checks if the node is a validator by inspecting the consensus
2496///    configuration; if so, it returns early as validators do not expose gRPC
2497///    APIs.
2498/// 2. Checks if gRPC is enabled in the configuration.
2499/// 3. Creates broadcast channels for checkpoint streaming.
2500/// 4. Initializes the gRPC checkpoint service.
2501/// 5. Spawns the gRPC server to listen for incoming connections.
2502///
2503/// Returns a tuple of optional broadcast channels for checkpoint summary and
2504/// data.
2505async fn build_grpc_server(
2506    config: &NodeConfig,
2507    state: Arc<AuthorityState>,
2508    state_sync_store: RocksDbStore,
2509    executor: Option<Arc<dyn iota_types::transaction_executor::TransactionExecutor>>,
2510    prometheus_registry: &Registry,
2511    server_version: ServerVersion,
2512) -> Result<Option<GrpcServerHandle>> {
2513    // Validators do not expose gRPC APIs
2514    if config.consensus_config().is_some() || !config.enable_grpc_api {
2515        return Ok(None);
2516    }
2517
2518    let Some(grpc_config) = &config.grpc_api_config else {
2519        return Err(anyhow!("gRPC API is enabled but no configuration provided"));
2520    };
2521
2522    // Get chain identifier from state directly
2523    let chain_id = state.get_chain_identifier();
2524
2525    let grpc_read_store = Arc::new(GrpcReadStore::new(state.clone(), state_sync_store));
2526
2527    // Create cancellation token for proper shutdown hierarchy
2528    let shutdown_token = CancellationToken::new();
2529
2530    // Create GrpcReader
2531    let grpc_reader = Arc::new(GrpcReader::new(
2532        grpc_read_store,
2533        Some(server_version.to_string()),
2534    ));
2535
2536    // Create gRPC server metrics
2537    let grpc_server_metrics = iota_grpc_server::GrpcServerMetrics::new(prometheus_registry);
2538    let client_id_source = config
2539        .policy_config
2540        .as_ref()
2541        .map(|p| p.client_id_source.clone());
2542
2543    let handle = start_grpc_server(
2544        grpc_reader,
2545        executor,
2546        grpc_config.clone(),
2547        shutdown_token,
2548        chain_id,
2549        Some(grpc_server_metrics),
2550        state.traffic_controller.clone(),
2551        client_id_source,
2552    )
2553    .await?;
2554
2555    Ok(Some(handle))
2556}
2557
2558/// Builds and starts the HTTP server for the IOTA node, exposing the JSON-RPC
2559/// API based on the node's configuration.
2560///
2561/// This function performs the following tasks:
2562/// 1. Checks if the node is a validator by inspecting the consensus
2563///    configuration; if so, it returns early as validators do not expose these
2564///    APIs.
2565/// 2. Creates an Axum router to handle HTTP requests.
2566/// 3. Initializes the JSON-RPC server and registers various RPC modules based
2567///    on the node's state and configuration, including CoinApi,
2568///    TransactionBuilderApi, GovernanceApi, TransactionExecutionApi, and
2569///    IndexerApi.
2570/// 4. Binds the server to the specified JSON-RPC address and starts listening
2571///    for incoming connections.
2572pub async fn build_http_server(
2573    state: Arc<AuthorityState>,
2574    transaction_orchestrator: &Option<Arc<TransactionOrchestrator<NetworkAuthorityClient>>>,
2575    config: &NodeConfig,
2576    prometheus_registry: &Registry,
2577) -> Result<Option<iota_http::ServerHandle>> {
2578    // Validators do not expose these APIs
2579    if config.consensus_config().is_some() {
2580        return Ok(None);
2581    }
2582
2583    let mut router = axum::Router::new();
2584
2585    let json_rpc_router = {
2586        let traffic_controller = state.traffic_controller.clone();
2587        let mut server = JsonRpcServerBuilder::new(
2588            env!("CARGO_PKG_VERSION"),
2589            prometheus_registry,
2590            traffic_controller,
2591            config.policy_config.clone(),
2592        );
2593
2594        let kv_store = build_kv_store(&state, config, prometheus_registry)?;
2595
2596        let metrics = Arc::new(JsonRpcMetrics::new(prometheus_registry));
2597        server.register_module(ReadApi::new(
2598            state.clone(),
2599            kv_store.clone(),
2600            metrics.clone(),
2601        ))?;
2602        server.register_module(CoinReadApi::new(
2603            state.clone(),
2604            kv_store.clone(),
2605            metrics.clone(),
2606        )?)?;
2607
2608        // if run_with_range is enabled we want to prevent any transactions
2609        // run_with_range = None is normal operating conditions
2610        if config.run_with_range.is_none() {
2611            server.register_module(TransactionBuilderApi::new(state.clone()))?;
2612        }
2613        server.register_module(GovernanceReadApi::new(state.clone(), metrics.clone()))?;
2614
2615        if let Some(transaction_orchestrator) = transaction_orchestrator {
2616            server.register_module(TransactionExecutionApi::new(
2617                state.clone(),
2618                transaction_orchestrator.clone(),
2619                metrics.clone(),
2620            ))?;
2621        }
2622
2623        let iota_names_config = config
2624            .iota_names_config
2625            .clone()
2626            .unwrap_or_else(|| IotaNamesConfig::from_chain(&state.get_chain_identifier().chain()));
2627
2628        server.register_module(IndexerApi::new(
2629            state.clone(),
2630            ReadApi::new(state.clone(), kv_store.clone(), metrics.clone()),
2631            kv_store,
2632            metrics,
2633            iota_names_config,
2634            config.indexer_max_subscriptions,
2635        ))?;
2636        server.register_module(MoveUtils::new(state.clone()))?;
2637
2638        let server_type = config.jsonrpc_server_type();
2639
2640        server.to_router(server_type).await?
2641    };
2642
2643    router = router.merge(json_rpc_router);
2644
2645    router = router
2646        .route("/health", axum::routing::get(health_check_handler))
2647        .route_layer(axum::Extension(state));
2648
2649    let layers = ServiceBuilder::new()
2650        .map_request(|mut request: axum::http::Request<_>| {
2651            if let Some(connect_info) = request.extensions().get::<iota_http::ConnectInfo>() {
2652                let axum_connect_info = axum::extract::ConnectInfo(connect_info.remote_addr);
2653                request.extensions_mut().insert(axum_connect_info);
2654            }
2655            request
2656        })
2657        .layer(axum::middleware::from_fn(server_timing_middleware));
2658
2659    router = router.layer(layers);
2660
2661    let handle = iota_http::Builder::new()
2662        .serve(&config.json_rpc_address, router)
2663        .map_err(|e| anyhow::anyhow!("{e}"))?;
2664    info!(local_addr =? handle.local_addr(), "IOTA JSON-RPC server listening on {}", handle.local_addr());
2665
2666    Ok(Some(handle))
2667}
2668
2669#[derive(Debug, serde::Serialize, serde::Deserialize)]
2670pub struct Threshold {
2671    pub threshold_seconds: Option<u32>,
2672}
2673
2674async fn health_check_handler(
2675    axum::extract::Query(Threshold { threshold_seconds }): axum::extract::Query<Threshold>,
2676    axum::Extension(state): axum::Extension<Arc<AuthorityState>>,
2677) -> impl axum::response::IntoResponse {
2678    if let Some(threshold_seconds) = threshold_seconds {
2679        // Attempt to get the latest checkpoint
2680        let summary = match state
2681            .get_checkpoint_store()
2682            .get_highest_executed_checkpoint()
2683        {
2684            Ok(Some(summary)) => summary,
2685            Ok(None) => {
2686                warn!("Highest executed checkpoint not found");
2687                return (axum::http::StatusCode::SERVICE_UNAVAILABLE, "down");
2688            }
2689            Err(err) => {
2690                warn!("Failed to retrieve highest executed checkpoint: {:?}", err);
2691                return (axum::http::StatusCode::SERVICE_UNAVAILABLE, "down");
2692            }
2693        };
2694
2695        // Calculate the threshold time based on the provided threshold_seconds
2696        let latest_chain_time = summary.timestamp();
2697        let threshold =
2698            std::time::SystemTime::now() - Duration::from_secs(threshold_seconds as u64);
2699
2700        // Check if the latest checkpoint is within the threshold
2701        if latest_chain_time < threshold {
2702            warn!(
2703                ?latest_chain_time,
2704                ?threshold,
2705                "failing health check due to checkpoint lag"
2706            );
2707            return (axum::http::StatusCode::SERVICE_UNAVAILABLE, "down");
2708        }
2709    }
2710    // if health endpoint is responding and no threshold is given, respond success
2711    (axum::http::StatusCode::OK, "up")
2712}
2713
2714#[cfg(not(test))]
2715fn max_tx_per_checkpoint(protocol_config: &ProtocolConfig) -> usize {
2716    protocol_config.max_transactions_per_checkpoint() as usize
2717}
2718
2719#[cfg(test)]
2720fn max_tx_per_checkpoint(_: &ProtocolConfig) -> usize {
2721    2
2722}
2723
2724// Not msim: this test asserts routing across real OS worker-thread pools by
2725// name, which the deterministic simulator collapses onto a single thread.
2726#[cfg(all(test, not(msim)))]
2727mod runtime_split_tests {
2728    use std::{
2729        sync::mpsc,
2730        time::{Duration, Instant},
2731    };
2732
2733    use anyhow::anyhow;
2734
2735    use super::SpawnOnce;
2736
2737    /// A single-worker-thread runtime whose worker thread carries `name`, so a
2738    /// task can tell which runtime it is running on via `current_pool()`.
2739    fn runtime(name: &'static str) -> tokio::runtime::Runtime {
2740        tokio::runtime::Builder::new_multi_thread()
2741            .worker_threads(1)
2742            .thread_name(name)
2743            .enable_all()
2744            .build()
2745            .unwrap()
2746    }
2747
2748    /// Name of the runtime whose worker thread is executing this code.
2749    fn current_pool() -> String {
2750        std::thread::current()
2751            .name()
2752            .unwrap_or("<unnamed>")
2753            .to_string()
2754    }
2755
2756    /// Regression guard for the runtime split. `SpawnOnce::start()` is invoked
2757    /// on the node-core runtime (as `IotaNode::start_async` does), but it
2758    /// must run the server *bind* on the serving runtime:
2759    /// `iota_http::Builder::serve` captures `Handle::current()` there for
2760    /// the accept loop and every request handler.
2761    ///
2762    /// The test records the runtime `start()` runs on and the runtime the bind
2763    /// runs on, and asserts the former is node-core and the latter is
2764    /// serving (so they differ). With the pre-fix inline bind the bind ran
2765    /// on the caller (node-core) runtime, and this test fails.
2766    #[test]
2767    fn spawn_once_binds_on_serving_not_the_core_runtime() {
2768        let node = runtime("node-core");
2769        let serving = runtime("serving");
2770        let (tx, rx) = mpsc::channel::<(&'static str, String)>();
2771
2772        // The "bind" future records where it runs, then binds a minimal real
2773        // server (health service only) on an ephemeral port.
2774        let bind_tx = tx.clone();
2775        let bind_future = async move {
2776            let _ = bind_tx.send(("bind", current_pool()));
2777            let addr = "/ip4/127.0.0.1/tcp/0/http".parse().unwrap();
2778            let server = iota_network_stack::config::Config::new()
2779                .server_builder()
2780                .bind(&addr, None)
2781                .await
2782                .map_err(|e| anyhow!("bind failed: {e}"))?;
2783            Ok(server)
2784        };
2785        let once = SpawnOnce::new(bind_future, serving.handle().clone());
2786
2787        // Drive start() ON the node-core runtime and record the runtime it runs on.
2788        let caller_tx = tx.clone();
2789        node.spawn(async move {
2790            let _ = caller_tx.send(("caller", current_pool()));
2791            let _ = once.start().await;
2792        });
2793
2794        // Collect both readings.
2795        let (mut caller_pool, mut bind_pool) = (None, None);
2796        let deadline = Instant::now() + Duration::from_secs(10);
2797        while (caller_pool.is_none() || bind_pool.is_none()) && Instant::now() < deadline {
2798            if let Ok((which, pool)) = rx.recv_timeout(Duration::from_millis(200)) {
2799                match which {
2800                    "caller" => caller_pool = Some(pool),
2801                    "bind" => bind_pool = Some(pool),
2802                    _ => {}
2803                }
2804            }
2805        }
2806        let caller_pool = caller_pool.expect("start() never ran");
2807        let bind_pool = bind_pool.expect("bind future never ran");
2808
2809        assert!(
2810            caller_pool.starts_with("node-core"),
2811            "start() should run on the node-core runtime, ran on: {caller_pool}"
2812        );
2813        assert!(
2814            bind_pool.starts_with("serving"),
2815            "server bind must run on the serving runtime, ran on: {bind_pool}"
2816        );
2817        assert_ne!(
2818            caller_pool, bind_pool,
2819            "the fix must move the bind off the caller (node-core) runtime onto serving"
2820        );
2821    }
2822}