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