Skip to main content

iota_core/
authority.rs

1// Copyright (c) 2021, Facebook, Inc. and its affiliates
2// Copyright (c) Mysten Labs, Inc.
3// Modifications Copyright (c) 2024 IOTA Stiftung
4// SPDX-License-Identifier: Apache-2.0
5
6use std::{
7    collections::{BTreeMap, HashMap, HashSet},
8    fs,
9    fs::File,
10    io::Write,
11    path::{Path, PathBuf},
12    pin::Pin,
13    sync::{Arc, atomic::Ordering},
14    time::{Duration, SystemTime, UNIX_EPOCH},
15    vec,
16};
17
18use anyhow::bail;
19use arc_swap::{ArcSwap, Guard};
20use async_trait::async_trait;
21use authority_per_epoch_store::TxLockGuard;
22pub use authority_store::{AuthorityStore, ResolverWrapper, UpdateType};
23use fastcrypto::{
24    encoding::{Base58, Encoding},
25    hash::MultisetHash,
26};
27use iota_archival::reader::ArchiveReaderBalancer;
28use iota_common::{debug_fatal, fatal};
29use iota_config::{
30    NodeConfig,
31    genesis::Genesis,
32    node::{
33        AuthorityOverloadConfig, DBCheckpointConfig, ExpensiveSafetyCheckConfig,
34        StateDebugDumpConfig,
35    },
36};
37use iota_framework::{BuiltInFramework, SystemPackage as FrameworkSystemPackage};
38use iota_json_rpc_types::{
39    DevInspectResults, DryRunTransactionBlockResponse, EventFilter, IotaEvent, IotaMoveValue,
40    IotaObjectDataFilter, IotaTransactionBlockData, IotaTransactionBlockEffects,
41    IotaTransactionBlockEvents, TransactionFilter,
42};
43use iota_macros::{fail_point, fail_point_async, fail_point_if};
44use iota_metrics::{
45    TX_TYPE_SHARED_OBJ_TX, TX_TYPE_SINGLE_WRITER_TX, monitored_scope, spawn_monitored_task,
46};
47use iota_sdk_types::{
48    Address, CheckpointContentsDigest, CheckpointDigest, Digest, EndOfEpochTransactionKind, Event,
49    ExecutionStatus, GasPayment, ObjectDigest, ObjectId, ObjectReference, Owner, RandomnessRound,
50    StructTag, SystemPackage, TransactionDigest, TransactionEffectsDigest, TransactionExpiration,
51    TransactionKind, TypeTag, Version,
52    crypto::{Intent, IntentAppId, IntentMessage, IntentScope, IntentVersion},
53    gas::GasCostSummary,
54};
55use iota_storage::{
56    key_value_store::{
57        KVStoreTransactionData, TransactionKeyValueStore, TransactionKeyValueStoreTrait,
58    },
59    key_value_store_metrics::KeyValueStoreMetrics,
60};
61#[cfg(msim)]
62use iota_types::committee::CommitteeTrait;
63use iota_types::{
64    account_abstraction::authenticator_function::{
65        AuthenticatorFunctionRef, AuthenticatorFunctionRefForExecution,
66        authenticator_function_ref_v1_from_dynamic_field_object,
67        derive_authenticator_function_ref_v1_dynamic_field_id, extract_auth_fun_refs,
68    },
69    auth_context::AuthContextData,
70    base_types::{AuthorityName, ConciseableName, ObjectInfo, ObjectType, VersionNumber},
71    committee::{Committee, EpochId, ProtocolVersion},
72    crypto::{AuthorityPublicKey, AuthoritySignInfo, AuthoritySignature, Signer},
73    deny_list_v1::check_coin_deny_list_v1,
74    digests::ChainIdentifier,
75    dynamic_field::{DynamicFieldInfo, DynamicFieldName, visitor as DFV},
76    effects::{
77        InputSharedObject, SignedTransactionEffects, TransactionEffects, TransactionEffectsAPI,
78        TransactionEffectsExt, TransactionEvents, VerifiedSignedTransactionEffects,
79    },
80    error::{ExecutionError, IotaError, IotaResult, UserInputError},
81    event::{EventID, SystemEpochInfoEvent},
82    executable_transaction::VerifiedExecutableTransaction,
83    execution_config_utils::to_binary_config,
84    fp_ensure,
85    gas::IotaGasStatus,
86    gas_coin::{SIMULATION_GAS_COIN_VALUE, mock_simulation_gas_coin},
87    inner_temporary_store::{
88        InnerTemporaryStore, ObjectMap, PackageStoreWithFallback, TemporaryModuleResolver, TxCoins,
89        WrittenObjects,
90    },
91    iota_sdk_types_conversions::type_tag_core_to_sdk,
92    iota_system_state::{
93        IotaSystemState, IotaSystemStateTrait,
94        epoch_start_iota_system_state::EpochStartSystemStateTrait, get_iota_system_state,
95    },
96    layout_resolver::{LayoutResolver, into_struct_layout},
97    message_envelope::Message,
98    messages_checkpoint::{
99        CertifiedCheckpointSummary, CheckpointCommitment, CheckpointContents,
100        CheckpointContentsExt, CheckpointRequest, CheckpointResponse, CheckpointSequenceNumber,
101        CheckpointSummary, CheckpointSummaryResponse, CheckpointTimestamp, ECMHLiveObjectSetDigest,
102        VerifiedCheckpoint,
103    },
104    messages_consensus::AuthorityCapabilitiesV1,
105    messages_grpc::{
106        HandleTransactionResponse, LayoutGenerationOption, ObjectInfoRequest,
107        ObjectInfoRequestKind, ObjectInfoResponse, TransactionInfoRequest, TransactionInfoResponse,
108        TransactionStatus,
109    },
110    metrics::{BytecodeVerifierMetrics, LimitsMetrics},
111    move_authenticator::{MoveAuthenticator, MoveAuthenticatorExt},
112    object::{
113        MoveObject, MoveObjectExt, OBJECT_START_VERSION, Object, ObjectRead, PastObjectRead,
114        bounded_visitor::BoundedVisitor,
115    },
116    storage::{
117        BackingPackageStore, BackingStore, ObjectKey, ObjectOrTombstone, ObjectStore, WriteKind,
118    },
119    supported_protocol_versions::{
120        ProtocolConfig, SupportedProtocolVersions, SupportedProtocolVersionsWithHashes,
121    },
122    traffic_control::{PolicyConfig, RemoteFirewallConfig, TrafficControlReconfigParams},
123    transaction::*,
124    transaction_executor::{SimulateTransactionResult, VmChecks},
125};
126use itertools::Itertools;
127use move_binary_format::{CompiledModule, binary_config::BinaryConfig};
128use move_core_types::{
129    account_address::AccountAddress, annotated_value::MoveStructLayout, language_storage::ModuleId,
130};
131use parking_lot::Mutex;
132use prometheus_filtered::{
133    Histogram, HistogramVec, IntCounter, IntCounterVec, IntGauge, IntGaugeVec, MetricLevel,
134    Registry, register_histogram_vec_with_registry, register_histogram_with_registry,
135    register_int_counter_vec_with_registry, register_int_counter_with_registry,
136    register_int_gauge_vec_with_registry, register_int_gauge_with_registry,
137};
138use serde::{Deserialize, Serialize, de::DeserializeOwned};
139use tap::TapFallible;
140use tokio::{
141    sync::{RwLock, mpsc, mpsc::unbounded_channel, oneshot},
142    task::JoinHandle,
143};
144use tracing::{debug, error, info, instrument, trace, warn};
145use typed_store::TypedStoreError;
146
147use self::{
148    authority_store::ExecutionLockWriteGuard, authority_store_pruner::AuthorityStorePruningMetrics,
149};
150#[cfg(msim)]
151pub use crate::checkpoints::checkpoint_executor::utils::{
152    CheckpointTimeoutConfig, init_checkpoint_timeout_config,
153};
154use crate::{
155    authority::{
156        authority_per_epoch_store::{AuthorityPerEpochStore, TxGuard},
157        authority_per_epoch_store_pruner::AuthorityPerEpochStorePruner,
158        authority_store::{ExecutionLockReadGuard, ObjectLockStatus},
159        authority_store_pruner::{AuthorityStorePruner, EPOCH_DURATION_MS_FOR_TESTING},
160        authority_store_tables::AuthorityPrunerTables,
161        epoch_start_configuration::{EpochStartConfigTrait, EpochStartConfiguration},
162    },
163    authority_client::NetworkAuthorityClient,
164    checkpoint_progress_tracker::CheckpointProgressTracker,
165    checkpoints::CheckpointStore,
166    congestion_tracker::CongestionTracker,
167    consensus_adapter::ConsensusAdapter,
168    epoch::committee_store::CommitteeStore,
169    execution_cache::{
170        CheckpointCache, ExecutionCacheCommit, ExecutionCacheReconfigAPI,
171        ExecutionCacheTraitPointers, ExecutionCacheWrite, ObjectCacheRead, StateSyncAPI,
172        TransactionCacheRead,
173    },
174    execution_driver::execution_process,
175    global_state_hasher::{GlobalStateHashStore, GlobalStateHasher},
176    grpc_indexes::{GRPC_INDEXES_DIR, GrpcIndexesStore},
177    jsonrpc_index::{CoinInfo, IndexStore, ObjectIndexChanges},
178    metrics::{LatencyObserver, RateTracker},
179    module_cache_metrics::ResolverMetrics,
180    overload_monitor::{
181        AuthorityOverloadInfo, compute_graduated_load_shedding_percentage,
182        overload_monitor_accept_tx,
183    },
184    stake_aggregator::StakeAggregator,
185    subscription_handler::SubscriptionHandler,
186    traffic_controller::{TrafficController, metrics::TrafficControllerMetrics},
187    transaction_input_loader::TransactionInputLoader,
188    transaction_manager::TransactionManager,
189    transaction_outputs::TransactionOutputs,
190    validator_tx_finalizer::ValidatorTxFinalizer,
191    verify_indexes::verify_indexes,
192};
193
194#[cfg(test)]
195#[path = "unit_tests/authority_tests.rs"]
196pub mod authority_tests;
197
198#[cfg(test)]
199#[path = "unit_tests/transaction_tests.rs"]
200pub mod transaction_tests;
201
202#[cfg(test)]
203#[path = "unit_tests/batch_transaction_tests.rs"]
204mod batch_transaction_tests;
205
206#[cfg(test)]
207#[path = "unit_tests/move_integration_tests.rs"]
208pub mod move_integration_tests;
209
210#[cfg(test)]
211#[path = "unit_tests/gas_tests.rs"]
212mod gas_tests;
213
214#[cfg(test)]
215#[path = "unit_tests/batch_verification_tests.rs"]
216mod batch_verification_tests;
217
218#[cfg(test)]
219#[path = "unit_tests/coin_deny_list_tests.rs"]
220mod coin_deny_list_tests;
221
222#[cfg(test)]
223#[path = "unit_tests/auth_unit_test_utils.rs"]
224pub mod auth_unit_test_utils;
225
226#[cfg(any(test, feature = "test-utils"))]
227pub mod authority_test_utils;
228
229pub mod authority_per_epoch_store;
230pub mod authority_per_epoch_store_pruner;
231
232mod authority_store_migrations;
233pub mod authority_store_pruner;
234pub mod authority_store_tables;
235pub mod authority_store_types;
236pub mod epoch_start_configuration;
237pub mod shared_object_congestion_tracker;
238pub mod shared_object_version_manager;
239pub mod suggested_gas_price_calculator;
240#[cfg(any(test, feature = "test-utils"))]
241pub mod test_authority_builder;
242pub mod transaction_deferral;
243
244pub(crate) mod authority_store;
245pub mod backpressure;
246pub(crate) mod dropped_tx_status_cache;
247
248/// Prometheus metrics which can be displayed in Grafana, queried and alerted on
249pub struct AuthorityMetrics {
250    tx_orders: IntCounter,
251    total_certs: IntCounter,
252    total_cert_attempts: IntCounter,
253    total_effects: IntCounter,
254    pub shared_obj_tx: IntCounter,
255    sponsored_tx: IntCounter,
256    tx_already_processed: IntCounter,
257    num_input_objs: Histogram,
258    num_shared_objects: Histogram,
259    batch_size: Histogram,
260
261    authority_state_handle_transaction_latency: Histogram,
262
263    execute_certificate_latency_single_writer: Histogram,
264    execute_certificate_latency_shared_object: Histogram,
265
266    internal_execution_latency: Histogram,
267    execution_load_input_objects_latency: Histogram,
268    prepare_certificate_latency: Histogram,
269    commit_certificate_latency: Histogram,
270    db_checkpoint_latency: Histogram,
271
272    pub(crate) transaction_manager_num_enqueued_certificates: IntCounterVec,
273    pub(crate) transaction_manager_num_missing_objects: IntGauge,
274    pub(crate) transaction_manager_num_pending_certificates: IntGauge,
275    pub(crate) transaction_manager_num_executing_certificates: IntGauge,
276    pub(crate) transaction_manager_num_ready: IntGauge,
277    pub(crate) transaction_manager_object_cache_size: IntGauge,
278    pub(crate) transaction_manager_object_cache_hits: IntCounter,
279    pub(crate) transaction_manager_object_cache_misses: IntCounter,
280    pub(crate) transaction_manager_object_cache_evictions: IntCounter,
281    pub(crate) transaction_manager_package_cache_size: IntGauge,
282    pub(crate) transaction_manager_package_cache_hits: IntCounter,
283    pub(crate) transaction_manager_package_cache_misses: IntCounter,
284    pub(crate) transaction_manager_package_cache_evictions: IntCounter,
285    pub(crate) transaction_manager_transaction_queue_age_s: Histogram,
286
287    pub(crate) execution_driver_executed_transactions: IntCounter,
288    pub(crate) execution_driver_dispatch_queue: IntGauge,
289    pub(crate) execution_queueing_delay_s: Histogram,
290    pub(crate) prepare_cert_gas_latency_ratio: Histogram,
291    pub(crate) execution_gas_latency_ratio: Histogram,
292
293    pub(crate) skipped_consensus_txns: IntCounter,
294    pub(crate) skipped_consensus_txns_cache_hit: IntCounter,
295
296    pub(crate) authority_overload_status: IntGauge,
297    /// Percentage of transactions shed due to consensus queue length.
298    pub(crate) consensus_queue_load_shedding_percentage: IntGauge,
299    /// This authority's locally computed load shedding percentage, taken as the
300    /// max of its latency/rate-based, transaction-manager-queue-based, and
301    /// writeback-cache-backpressure signals.
302    pub(crate) local_post_consensus_load_shedding_percentage: IntGauge,
303
304    pub(crate) transaction_overload_sources: IntCounterVec,
305
306    // Post processing metrics
307    post_processing_total_events_emitted: IntCounter,
308    post_processing_total_tx_indexed: IntCounter,
309    post_processing_total_tx_had_event_processed: IntCounter,
310    post_processing_total_failures: IntCounter,
311
312    // Consensus handler metrics
313    pub consensus_handler_processed: IntCounterVec,
314    pub consensus_handler_transaction_sizes: HistogramVec,
315    pub consensus_handler_num_low_scoring_authorities: IntGauge,
316    pub consensus_handler_scores: IntGaugeVec,
317    pub consensus_handler_deferred_transactions: IntCounter,
318    pub consensus_handler_congested_transactions: IntCounter,
319    pub consensus_handler_cancelled_transactions: IntCounter,
320    /// Number of user transactions dropped during a consensus commit because
321    /// post-consensus conflict/lock validation rejected them. Distinct from
322    /// `consensus_handler_load_shedding_dropped_transactions`.
323    pub consensus_handler_validation_dropped_transactions: IntCounter,
324    /// Number of user transactions dropped during a consensus commit by
325    /// post-consensus load shedding, i.e. probabilistically rejected at the
326    /// quorum `consensus_handler_load_shedding_percentage` rate.
327    pub consensus_handler_load_shedding_dropped_transactions: IntCounter,
328    /// Stake-weighted quorum (2f+1) load shedding percentage enforced on user
329    /// transactions in the most recent consensus commit. This is the cluster
330    /// value actually applied post-consensus, as opposed to this authority's
331    /// own `authority_load_shedding_percentage`. 0 when the P-COOL flow is
332    /// disabled.
333    pub consensus_handler_load_shedding_percentage: IntGauge,
334    pub consensus_handler_max_object_costs: IntGaugeVec,
335    pub consensus_committed_subdags: IntCounterVec,
336    pub consensus_committed_messages: IntGaugeVec,
337    pub consensus_committed_user_transactions: IntGaugeVec,
338    pub consensus_handler_leader_round: IntGauge,
339    pub consensus_calculated_throughput: IntGauge,
340    pub consensus_calculated_throughput_profile: IntGauge,
341
342    pub validator_scoreboard_scores: IntGaugeVec,
343    pub invalid_misbehavior_reports_by_authority: IntGaugeVec,
344
345    pub limits_metrics: Arc<LimitsMetrics>,
346
347    /// bytecode verifier metrics for tracking timeouts
348    pub bytecode_verifier_metrics: Arc<BytecodeVerifierMetrics>,
349
350    /// Count of multisig signatures
351    pub multisig_sig_count: IntCounter,
352
353    // Tracks recent average txn queueing delay between when it is ready for execution
354    // until it starts executing.
355    pub execution_queueing_latency: LatencyObserver,
356
357    // Tracks the rate of transactions become ready for execution in transaction manager.
358    // The need for the Mutex is that the tracker is updated in transaction manager and read
359    // in the overload_monitor. There should be low mutex contention because
360    // transaction manager is single threaded and the read rate in overload_monitor is
361    // low. In the case where transaction manager becomes multi-threaded, we can
362    // create one rate tracker per thread.
363    pub txn_ready_rate_tracker: Arc<Mutex<RateTracker>>,
364
365    // Tracks the rate of transactions starts execution in execution driver.
366    // Similar reason for using a Mutex here as to `txn_ready_rate_tracker`.
367    pub execution_rate_tracker: Arc<Mutex<RateTracker>>,
368}
369
370// Override default Prom buckets for positive numbers in 0-10M range
371const POSITIVE_INT_BUCKETS: &[f64] = &[
372    1., 2., 5., 7., 10., 20., 50., 70., 100., 200., 500., 700., 1000., 2000., 5000., 7000., 10000.,
373    20000., 50000., 70000., 100000., 200000., 500000., 700000., 1000000., 2000000., 5000000.,
374    7000000., 10000000.,
375];
376
377const LATENCY_SEC_BUCKETS: &[f64] = &[
378    0.0005, 0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1., 2., 3., 4., 5., 6., 7., 8., 9.,
379    10., 20., 30., 60., 90.,
380];
381
382// Buckets for low latency samples. Starts from 10us.
383const LOW_LATENCY_SEC_BUCKETS: &[f64] = &[
384    0.00001, 0.00002, 0.00005, 0.0001, 0.0002, 0.0005, 0.001, 0.002, 0.005, 0.01, 0.02, 0.05, 0.1,
385    0.2, 0.5, 1., 2., 5., 10., 20., 50., 100.,
386];
387
388const GAS_LATENCY_RATIO_BUCKETS: &[f64] = &[
389    10.0, 50.0, 100.0, 200.0, 300.0, 400.0, 500.0, 600.0, 700.0, 800.0, 900.0, 1000.0, 2000.0,
390    3000.0, 4000.0, 5000.0, 6000.0, 7000.0, 8000.0, 9000.0, 10000.0, 50000.0, 100000.0, 1000000.0,
391];
392
393impl AuthorityMetrics {
394    pub fn new(registry: &prometheus_filtered::Registry) -> AuthorityMetrics {
395        let execute_certificate_latency = register_histogram_vec_with_registry!(
396            "authority_state_execute_certificate_latency",
397            "Latency of executing certificates, including waiting for inputs",
398            &["tx_type"],
399            LATENCY_SEC_BUCKETS.to_vec(),
400            registry;
401            MetricLevel::Info,
402        )
403        .unwrap();
404
405        let execute_certificate_latency_single_writer =
406            execute_certificate_latency.with_label_values(&[TX_TYPE_SINGLE_WRITER_TX]);
407        let execute_certificate_latency_shared_object =
408            execute_certificate_latency.with_label_values(&[TX_TYPE_SHARED_OBJ_TX]);
409
410        Self {
411            tx_orders: register_int_counter_with_registry!(
412                "total_transaction_orders",
413                "Total number of transaction orders",
414                registry;
415                MetricLevel::Warn,
416            )
417                .unwrap(),
418            total_certs: register_int_counter_with_registry!(
419                "total_transaction_certificates",
420                "Total number of transaction certificates handled",
421                registry;
422                MetricLevel::Warn,
423            )
424                .unwrap(),
425            total_cert_attempts: register_int_counter_with_registry!(
426                "total_handle_certificate_attempts",
427                "Number of calls to handle_certificate",
428                registry,
429            )
430                .unwrap(),
431            // total_effects == total transactions finished
432            total_effects: register_int_counter_with_registry!(
433                "total_transaction_effects",
434                "Total number of transaction effects produced",
435                registry;
436                MetricLevel::Warn,
437            )
438                .unwrap(),
439
440            shared_obj_tx: register_int_counter_with_registry!(
441                "num_shared_obj_tx",
442                "Number of transactions involving shared objects",
443                registry;
444                MetricLevel::Warn,
445            )
446                .unwrap(),
447
448            sponsored_tx: register_int_counter_with_registry!(
449                "num_sponsored_tx",
450                "Number of sponsored transactions",
451                registry,
452            )
453                .unwrap(),
454
455            tx_already_processed: register_int_counter_with_registry!(
456                "num_tx_already_processed",
457                "Number of transaction orders already processed previously",
458                registry,
459            )
460                .unwrap(),
461            num_input_objs: register_histogram_with_registry!(
462                "num_input_objects",
463                "Distribution of number of input TX objects per TX",
464                POSITIVE_INT_BUCKETS.to_vec(),
465                registry;
466                MetricLevel::Warn,
467            )
468                .unwrap(),
469            num_shared_objects: register_histogram_with_registry!(
470                "num_shared_objects",
471                "Number of shared input objects per TX",
472                POSITIVE_INT_BUCKETS.to_vec(),
473                registry,
474            )
475                .unwrap(),
476            batch_size: register_histogram_with_registry!(
477                "batch_size",
478                "Distribution of size of transaction batch",
479                POSITIVE_INT_BUCKETS.to_vec(),
480                registry,
481            )
482                .unwrap(),
483            authority_state_handle_transaction_latency: register_histogram_with_registry!(
484                "authority_state_handle_transaction_latency",
485                "Latency of handling transactions",
486                LATENCY_SEC_BUCKETS.to_vec(),
487                registry,
488            )
489                .unwrap(),
490            execute_certificate_latency_single_writer,
491            execute_certificate_latency_shared_object,
492            internal_execution_latency: register_histogram_with_registry!(
493                "authority_state_internal_execution_latency",
494                "Latency of actual certificate executions",
495                LATENCY_SEC_BUCKETS.to_vec(),
496                registry,
497            )
498                .unwrap(),
499            execution_load_input_objects_latency: register_histogram_with_registry!(
500                "authority_state_execution_load_input_objects_latency",
501                "Latency of loading input objects for execution",
502                LOW_LATENCY_SEC_BUCKETS.to_vec(),
503                registry,
504            )
505                .unwrap(),
506            prepare_certificate_latency: register_histogram_with_registry!(
507                "authority_state_prepare_certificate_latency",
508                "Latency of executing certificates, before committing the results",
509                LATENCY_SEC_BUCKETS.to_vec(),
510                registry,
511            )
512                .unwrap(),
513            commit_certificate_latency: register_histogram_with_registry!(
514                "authority_state_commit_certificate_latency",
515                "Latency of committing certificate execution results",
516                LATENCY_SEC_BUCKETS.to_vec(),
517                registry,
518            )
519                .unwrap(),
520            db_checkpoint_latency: register_histogram_with_registry!(
521                "db_checkpoint_latency",
522                "Latency of checkpointing dbs",
523                LATENCY_SEC_BUCKETS.to_vec(),
524                registry,
525            ).unwrap(),
526            transaction_manager_num_enqueued_certificates: register_int_counter_vec_with_registry!(
527                "transaction_manager_num_enqueued_certificates",
528                "Current number of certificates enqueued to TransactionManager",
529                &["result"],
530                registry,
531            )
532                .unwrap(),
533            transaction_manager_num_missing_objects: register_int_gauge_with_registry!(
534                "transaction_manager_num_missing_objects",
535                "Current number of missing objects in TransactionManager",
536                registry,
537            )
538                .unwrap(),
539            transaction_manager_num_pending_certificates: register_int_gauge_with_registry!(
540                "transaction_manager_num_pending_certificates",
541                "Number of certificates pending in TransactionManager, with at least 1 missing input object",
542                registry;
543                MetricLevel::Warn,
544            )
545                .unwrap(),
546            transaction_manager_num_executing_certificates: register_int_gauge_with_registry!(
547                "transaction_manager_num_executing_certificates",
548                "Number of executing certificates, including queued and actually running certificates",
549                registry;
550                MetricLevel::Warn,
551            )
552                .unwrap(),
553            transaction_manager_num_ready: register_int_gauge_with_registry!(
554                "transaction_manager_num_ready",
555                "Number of ready transactions in TransactionManager",
556                registry,
557            )
558                .unwrap(),
559            transaction_manager_object_cache_size: register_int_gauge_with_registry!(
560                "transaction_manager_object_cache_size",
561                "Current size of object-availability cache in TransactionManager",
562                registry,
563            )
564                .unwrap(),
565            transaction_manager_object_cache_hits: register_int_counter_with_registry!(
566                "transaction_manager_object_cache_hits",
567                "Number of object-availability cache hits in TransactionManager",
568                registry,
569            )
570                .unwrap(),
571            authority_overload_status: register_int_gauge_with_registry!(
572                "authority_overload_status",
573                "Whether authority is current experiencing overload and enters load shedding mode.",
574                registry;
575                MetricLevel::Warn,)
576                .unwrap(),
577            local_post_consensus_load_shedding_percentage: register_int_gauge_with_registry!(
578                "authority_load_shedding_percentage",
579                "This authority's locally computed load shedding percentage. In the P-COOL flow this is the value broadcast to peers, not necessarily the rate enforced (see consensus_handler_load_shedding_percentage).",
580                registry;
581                MetricLevel::Info,)
582                .unwrap(),
583            consensus_queue_load_shedding_percentage: register_int_gauge_with_registry!(
584                "consensus_queue_load_shedding_percentage",
585                "Percentage of transactions shed due to consensus queue length. Separate admission-control signal, not an input to authority_load_shedding_percentage.",
586                registry)
587                .unwrap(),
588            transaction_manager_object_cache_misses: register_int_counter_with_registry!(
589                "transaction_manager_object_cache_misses",
590                "Number of object-availability cache misses in TransactionManager",
591                registry,
592            )
593                .unwrap(),
594            transaction_manager_object_cache_evictions: register_int_counter_with_registry!(
595                "transaction_manager_object_cache_evictions",
596                "Number of object-availability cache evictions in TransactionManager",
597                registry,
598            )
599                .unwrap(),
600            transaction_manager_package_cache_size: register_int_gauge_with_registry!(
601                "transaction_manager_package_cache_size",
602                "Current size of package-availability cache in TransactionManager",
603                registry,
604            )
605                .unwrap(),
606            transaction_manager_package_cache_hits: register_int_counter_with_registry!(
607                "transaction_manager_package_cache_hits",
608                "Number of package-availability cache hits in TransactionManager",
609                registry,
610            )
611                .unwrap(),
612            transaction_manager_package_cache_misses: register_int_counter_with_registry!(
613                "transaction_manager_package_cache_misses",
614                "Number of package-availability cache misses in TransactionManager",
615                registry,
616            )
617                .unwrap(),
618            transaction_manager_package_cache_evictions: register_int_counter_with_registry!(
619                "transaction_manager_package_cache_evictions",
620                "Number of package-availability cache evictions in TransactionManager",
621                registry,
622            )
623                .unwrap(),
624            transaction_manager_transaction_queue_age_s: register_histogram_with_registry!(
625                "transaction_manager_transaction_queue_age_s",
626                "Time spent in waiting for transaction in the queue",
627                LATENCY_SEC_BUCKETS.to_vec(),
628                registry;
629                MetricLevel::Warn,
630            )
631                .unwrap(),
632            transaction_overload_sources: register_int_counter_vec_with_registry!(
633                "transaction_overload_sources",
634                "Number of times each source indicates transaction overload.",
635                &["source"],
636                registry)
637                .unwrap(),
638            execution_driver_executed_transactions: register_int_counter_with_registry!(
639                "execution_driver_executed_transactions",
640                "Cumulative number of transaction executed by execution driver",
641                registry;
642                MetricLevel::Warn,
643            )
644                .unwrap(),
645            execution_driver_dispatch_queue: register_int_gauge_with_registry!(
646                "execution_driver_dispatch_queue",
647                "Number of transaction pending in execution driver dispatch queue",
648                registry,
649            )
650                .unwrap(),
651            execution_queueing_delay_s: register_histogram_with_registry!(
652                "execution_queueing_delay_s",
653                "Queueing delay between a transaction is ready for execution until it starts executing.",
654                LATENCY_SEC_BUCKETS.to_vec(),
655                registry
656            )
657                .unwrap(),
658            prepare_cert_gas_latency_ratio: register_histogram_with_registry!(
659                "prepare_cert_gas_latency_ratio",
660                "The ratio of computation gas divided by VM execution latency.",
661                GAS_LATENCY_RATIO_BUCKETS.to_vec(),
662                registry
663            )
664                .unwrap(),
665            execution_gas_latency_ratio: register_histogram_with_registry!(
666                "execution_gas_latency_ratio",
667                "The ratio of computation gas divided by certificate execution latency, include committing certificate.",
668                GAS_LATENCY_RATIO_BUCKETS.to_vec(),
669                registry
670            )
671                .unwrap(),
672            skipped_consensus_txns: register_int_counter_with_registry!(
673                "skipped_consensus_txns",
674                "Total number of consensus transactions skipped",
675                registry,
676            )
677                .unwrap(),
678            skipped_consensus_txns_cache_hit: register_int_counter_with_registry!(
679                "skipped_consensus_txns_cache_hit",
680                "Total number of consensus transactions skipped because of local cache hit",
681                registry,
682            )
683                .unwrap(),
684            post_processing_total_events_emitted: register_int_counter_with_registry!(
685                "post_processing_total_events_emitted",
686                "Total number of events emitted in post processing",
687                registry,
688            )
689                .unwrap(),
690            post_processing_total_tx_indexed: register_int_counter_with_registry!(
691                "post_processing_total_tx_indexed",
692                "Total number of txes indexed in post processing",
693                registry,
694            )
695                .unwrap(),
696            post_processing_total_tx_had_event_processed: register_int_counter_with_registry!(
697                "post_processing_total_tx_had_event_processed",
698                "Total number of txes finished event processing in post processing",
699                registry,
700            )
701                .unwrap(),
702            post_processing_total_failures: register_int_counter_with_registry!(
703                "post_processing_total_failures",
704                "Total number of failure in post processing",
705                registry,
706            )
707                .unwrap(),
708            consensus_handler_processed: register_int_counter_vec_with_registry!(
709                "consensus_handler_processed",
710                "Number of transactions processed by consensus handler",
711                &["class"],
712                registry
713            ).unwrap(),
714            consensus_handler_transaction_sizes: register_histogram_vec_with_registry!(
715                "consensus_handler_transaction_sizes",
716                "Sizes of each type of transactions processed by consensus handler",
717                &["class"],
718                POSITIVE_INT_BUCKETS.to_vec(),
719                registry;
720                MetricLevel::Warn,
721            ).unwrap(),
722            consensus_handler_num_low_scoring_authorities: register_int_gauge_with_registry!(
723                "consensus_handler_num_low_scoring_authorities",
724                "Number of low scoring authorities based on reputation scores from consensus",
725                registry
726            ).unwrap(),
727            consensus_handler_scores: register_int_gauge_vec_with_registry!(
728                "consensus_handler_scores",
729                "scores from consensus for each authority",
730                &["authority"],
731                registry,
732            ).unwrap(),
733            validator_scoreboard_scores: register_int_gauge_vec_with_registry!(
734                "validator_scoreboard_scores",
735                "Per-authority validator scores published by the local Scoreboard after each consensus commit. Range [0, MAX_SCORE].",
736                &["authority"],
737                registry;
738                MetricLevel::Warn,
739            ).unwrap(),
740            invalid_misbehavior_reports_by_authority: register_int_gauge_vec_with_registry!(
741                "invalid_misbehavior_reports_by_authority",
742                "Cumulative count of invalid misbehavior reports received from each reporting authority in the current epoch. Bumped when a `MisbehaviorReport` consensus transaction fails sender/authority match or payload validation. Snapshot republished after each consensus commit.",
743                &["authority"],
744                registry;
745                MetricLevel::Warn,
746            ).unwrap(),
747            consensus_handler_deferred_transactions: register_int_counter_with_registry!(
748                "consensus_handler_deferred_transactions",
749                "Number of transactions deferred by consensus handler",
750                registry,
751            ).unwrap(),
752            consensus_handler_congested_transactions: register_int_counter_with_registry!(
753                "consensus_handler_congested_transactions",
754                "Number of transactions deferred by consensus handler due to congestion",
755                registry,
756            ).unwrap(),
757            consensus_handler_cancelled_transactions: register_int_counter_with_registry!(
758                "consensus_handler_cancelled_transactions",
759                "Number of transactions cancelled by consensus handler",
760                registry,
761            ).unwrap(),
762            consensus_handler_validation_dropped_transactions: register_int_counter_with_registry!(
763                "consensus_handler_validation_dropped_transactions",
764                "Number of UserTransactionV1 transactions dropped by post-consensus validation",
765                registry,
766            ).unwrap(),
767            consensus_handler_load_shedding_dropped_transactions: register_int_counter_with_registry!(
768                "consensus_handler_load_shedding_dropped_transactions",
769                "Number of user transactions dropped by post-consensus load shedding, based on the quorum load shedding percentage",
770                registry,
771            ).unwrap(),
772            consensus_handler_load_shedding_percentage: register_int_gauge_with_registry!(
773                "consensus_handler_load_shedding_percentage",
774                "Stake-weighted quorum (2f+1) load shedding percentage enforced on user transactions in the most recent consensus commit. 0 when the P-COOL flow is disabled.",
775                registry,
776            ).unwrap(),
777            consensus_handler_max_object_costs: register_int_gauge_vec_with_registry!(
778                "consensus_handler_max_congestion_control_object_costs",
779                "Max object costs for congestion control in the current consensus commit",
780                &["commit_type"],
781                registry,
782            ).unwrap(),
783            consensus_committed_subdags: register_int_counter_vec_with_registry!(
784                "consensus_committed_subdags",
785                "Number of committed subdags, sliced by leader",
786                &["authority"],
787                registry,
788            ).unwrap(),
789            consensus_committed_messages: register_int_gauge_vec_with_registry!(
790                "consensus_committed_messages",
791                "Total number of committed consensus messages, sliced by author",
792                &["authority"],
793                registry;
794                MetricLevel::Warn,
795            ).unwrap(),
796            consensus_committed_user_transactions: register_int_gauge_vec_with_registry!(
797                "consensus_committed_user_transactions",
798                "Number of committed user transactions, sliced by submitter",
799                &["authority"],
800                registry,
801            ).unwrap(),
802            consensus_handler_leader_round: register_int_gauge_with_registry!(
803                "consensus_handler_leader_round",
804                "The leader round of the current consensus output being processed in the consensus handler",
805                registry;
806                MetricLevel::Warn,
807            ).unwrap(),
808            limits_metrics: Arc::new(LimitsMetrics::new(registry)),
809            bytecode_verifier_metrics: Arc::new(BytecodeVerifierMetrics::new(registry)),
810            multisig_sig_count: register_int_counter_with_registry!(
811                "multisig_sig_count",
812                "Count of multisig signatures",
813                registry,
814            )
815                .unwrap(),
816            consensus_calculated_throughput: register_int_gauge_with_registry!(
817                "consensus_calculated_throughput",
818                "The calculated throughput from consensus output. Result is calculated based on unique transactions.",
819                registry,
820            ).unwrap(),
821            consensus_calculated_throughput_profile: register_int_gauge_with_registry!(
822                "consensus_calculated_throughput_profile",
823                "The current active calculated throughput profile",
824                registry
825            ).unwrap(),
826            execution_queueing_latency: LatencyObserver::new(),
827            txn_ready_rate_tracker: Arc::new(Mutex::new(RateTracker::new(Duration::from_secs(10)))),
828            execution_rate_tracker: Arc::new(Mutex::new(RateTracker::new(Duration::from_secs(10)))),
829        }
830    }
831
832    /// Reset metrics that contain `hostname` as one of the labels. This is
833    /// needed to avoid retaining metrics for long-gone committee members and
834    /// only exposing metrics for the committee in the current epoch.
835    pub fn reset_on_reconfigure(&self) {
836        self.consensus_committed_messages.reset();
837        self.consensus_handler_scores.reset();
838        self.validator_scoreboard_scores.reset();
839        self.invalid_misbehavior_reports_by_authority.reset();
840        self.consensus_committed_user_transactions.reset();
841    }
842}
843
844/// a Trait object for `Signer` that is:
845/// - Pin, i.e. confined to one place in memory (we don't want to copy private
846///   keys).
847/// - Sync, i.e. can be safely shared between threads.
848///
849/// Typically instantiated with Box::pin(keypair) where keypair is a `KeyPair`
850pub type StableSyncAuthoritySigner = Pin<Arc<dyn Signer<AuthoritySignature> + Send + Sync>>;
851
852pub struct AuthorityState {
853    // Fixed size, static, identity of the authority
854    /// The name of this authority.
855    pub name: AuthorityName,
856    /// The signature key of the authority.
857    pub secret: StableSyncAuthoritySigner,
858
859    /// The database
860    input_loader: TransactionInputLoader,
861    execution_cache_trait_pointers: ExecutionCacheTraitPointers,
862
863    epoch_store: ArcSwap<AuthorityPerEpochStore>,
864
865    /// This lock denotes current 'execution epoch'.
866    /// Execution acquires read lock, checks transaction epoch and holds it
867    /// until all writes are complete. Reconfiguration acquires write lock,
868    /// changes the epoch and revert all transactions from previous epoch
869    /// that are executed but did not make into checkpoint.
870    execution_lock: RwLock<EpochId>,
871
872    pub indexes: Option<Arc<IndexStore>>,
873    pub grpc_indexes_store: Option<Arc<GrpcIndexesStore>>,
874
875    pub subscription_handler: Arc<SubscriptionHandler>,
876    pub checkpoint_store: Arc<CheckpointStore>,
877
878    committee_store: Arc<CommitteeStore>,
879
880    /// Manages pending transactions and their missing input objects.
881    transaction_manager: Arc<TransactionManager>,
882
883    /// Shuts down the execution task. Used only in testing.
884    #[cfg_attr(not(test), expect(unused))]
885    tx_execution_shutdown: Mutex<Option<oneshot::Sender<()>>>,
886
887    pub metrics: Arc<AuthorityMetrics>,
888    /// The store pruner. The checkpoint executor uses it to nudge the pruner
889    /// after each checkpoint.
890    pruner: AuthorityStorePruner,
891    authority_per_epoch_pruner: AuthorityPerEpochStorePruner,
892    checkpoint_progress_tracker: Option<Arc<CheckpointProgressTracker>>,
893
894    /// Take db checkpoints of different dbs
895    db_checkpoint_config: DBCheckpointConfig,
896
897    pub config: NodeConfig,
898
899    /// Current overload status in this authority. Updated periodically.
900    pub overload_info: AuthorityOverloadInfo,
901
902    pub validator_tx_finalizer: Option<Arc<ValidatorTxFinalizer<NetworkAuthorityClient>>>,
903
904    /// The chain identifier is derived from the digest of the genesis
905    /// checkpoint.
906    chain_identifier: ChainIdentifier,
907
908    pub(crate) congestion_tracker: Arc<CongestionTracker>,
909
910    /// Traffic controller for IOTA core servers (json-rpc, validator service)
911    pub traffic_controller: Option<Arc<TrafficController>>,
912}
913
914/// The authority state encapsulates all state, drives execution, and ensures
915/// safety.
916///
917/// Note the authority operations can be accessed through a read ref (&) and do
918/// not require &mut. Internally a database is synchronized through a mutex
919/// lock.
920///
921/// Repeating valid commands should produce no changes and return no error.
922impl AuthorityState {
923    pub fn is_committee_validator(&self, epoch_store: &AuthorityPerEpochStore) -> bool {
924        epoch_store.committee().authority_exists(&self.name)
925    }
926
927    pub fn is_active_validator(&self, epoch_store: &AuthorityPerEpochStore) -> bool {
928        epoch_store
929            .active_validators()
930            .iter()
931            .any(|a| AuthorityName::from(a) == self.name)
932    }
933
934    pub fn is_fullnode(&self, epoch_store: &AuthorityPerEpochStore) -> bool {
935        !self.is_committee_validator(epoch_store)
936    }
937
938    pub fn committee_store(&self) -> &Arc<CommitteeStore> {
939        &self.committee_store
940    }
941
942    pub fn clone_committee_store(&self) -> Arc<CommitteeStore> {
943        self.committee_store.clone()
944    }
945
946    pub fn overload_config(&self) -> &AuthorityOverloadConfig {
947        &self.config.authority_overload_config
948    }
949
950    pub fn get_epoch_state_commitments(
951        &self,
952        epoch: EpochId,
953    ) -> IotaResult<Option<Vec<CheckpointCommitment>>> {
954        self.checkpoint_store.get_epoch_state_commitments(epoch)
955    }
956
957    /// Runs deny list, input object validation, gas checks, coin deny list, and
958    /// MoveAuthenticator checks. Returns the owned object refs for optional
959    /// version validation. Does NOT acquire locks or sign the transaction.
960    ///
961    /// `epoch_gated_coin_deny_list` selects how the coin deny list is read:
962    /// `false` reads the latest value, so denials apply immediately - for
963    /// validator-local admission (signing); `true` reads the value settled
964    /// before the current epoch, which is deterministic across validators
965    /// regardless of each validator's execution progress - required
966    /// post-consensus, where the verdict decides whether the transaction
967    /// stays in the committed set. The two read modes intentionally disagree
968    /// about deny-list changes made in the current epoch, in both directions:
969    /// - An entry added this epoch is enforced at admission right away, while
970    ///   the epoch-gated layers enforce it only from the next epoch. Since
971    ///   execution and post-consensus must read epoch-gated to stay
972    ///   deterministic, admission is the only layer that can react to a new
973    ///   denial or global pause before the epoch boundary.
974    /// - An entry removed this epoch is admitted right away but still denied by
975    ///   the epoch-gated post-consensus read, so such transactions are
976    ///   sequenced by consensus and then deterministically dropped (no
977    ///   execution, no gas charged) until the removal settles at the next epoch
978    ///   boundary. The wasted consensus slot is accepted: post-consensus must
979    ///   handle deterministic drops regardless (owned-object double-spend
980    ///   losers, for example), and validators that skip admission can put such
981    ///   transactions into their blocks anyway, so no admission policy can
982    ///   limit how many deterministically-dropped transactions reach consensus.
983    #[instrument(level = "trace", skip_all, fields(tx_digest = ?transaction.digest()))]
984    pub(crate) async fn handle_transaction_validation_checks(
985        &self,
986        transaction: &VerifiedTransaction,
987        epoch_store: &Arc<AuthorityPerEpochStore>,
988        epoch_gated_coin_deny_list: bool,
989    ) -> IotaResult<Vec<ObjectReference>> {
990        let protocol_config = epoch_store.protocol_config();
991        let reference_gas_price = epoch_store.reference_gas_price();
992
993        let epoch = epoch_store.epoch();
994
995        let tx_data = transaction.data().transaction_data();
996
997        // Note: the deny checks may do redundant package loads but:
998        // - they only load packages when there is an active package deny map
999        // - the loads are cached anyway
1000        iota_transaction_checks::deny::check_transaction_for_validation(
1001            tx_data,
1002            transaction.tx_signatures(),
1003            &transaction.input_objects()?,
1004            &tx_data.receiving_objects(),
1005            &self.config.transaction_deny_config,
1006            self.get_backing_package_store().as_ref(),
1007        )?;
1008
1009        // Load all transaction-related input objects including ones for every
1010        // `MoveAuthenticator`. Loading all objects eagerly means that any invalid
1011        // reference — missing object, wrong version, inaccessible object — causes a
1012        // pre-consensus rejection.
1013        let (tx_input_objects, tx_receiving_objects, per_authenticator_inputs) =
1014            self.read_objects_for_validation(transaction, epoch)?;
1015
1016        let move_authenticators = transaction.move_authenticators();
1017
1018        // Check the inputs for signing.
1019        // If there are `MoveAuthenticator` signatures, their input objects and the
1020        // account objects are also checked and must be provided.
1021        // It is also checked if there is enough gas to execute the transaction and its
1022        // authenticators.
1023        let (gas_status, tx_checked_input_objects, per_authenticator_checked_inputs) = self
1024            .check_transaction_inputs_for_validation(
1025                protocol_config,
1026                reference_gas_price,
1027                tx_data,
1028                tx_input_objects,
1029                &tx_receiving_objects,
1030                &move_authenticators,
1031                per_authenticator_inputs,
1032            )?;
1033
1034        // Get the input objects for the authenticators, if there are
1035        // `MoveAuthenticator`s.
1036        let per_authenticator_checked_input_objects = per_authenticator_checked_inputs
1037            .iter()
1038            .map(|i| &i.0)
1039            .collect();
1040
1041        // Check if any of the sender, the transaction input objects, the receiving
1042        // objects and the authenticator input objects are in the coin deny
1043        // list, which would prevent the transaction from being signed.
1044        check_coin_deny_list_v1(
1045            tx_data.sender(),
1046            &tx_checked_input_objects,
1047            &tx_receiving_objects,
1048            &per_authenticator_checked_input_objects,
1049            &self.get_object_store(),
1050            epoch_gated_coin_deny_list.then_some(epoch),
1051        )?;
1052
1053        let (kind, signer, gas_data) = tx_data.execution_parts();
1054
1055        let (sender_authenticator_function_ref, sponsor_authenticator_function_ref) =
1056            extract_auth_fun_refs(signer, gas_data.owner, |address| {
1057                move_authenticators
1058                    .iter()
1059                    .zip(per_authenticator_checked_inputs.iter())
1060                    .find(|(move_authenticator, _)| move_authenticator.address() == address)
1061                    .map(|(_, (_, auth_fun_ref))| auth_fun_ref.clone())
1062            });
1063
1064        // Filter the authenticators and their checked inputs down to those that must
1065        // be executed pre-consensus. This is done *after* the deny-list check so
1066        // that all MoveAuthenticator input objects are covered by that check regardless
1067        // of deferral.
1068        let pre_consensus_move_authenticators =
1069            pre_consensus_move_authenticators(transaction, protocol_config);
1070        let (move_authenticators, per_authenticator_checked_inputs): (Vec<_>, Vec<_>) =
1071            move_authenticators
1072                .into_iter()
1073                .zip(per_authenticator_checked_inputs)
1074                .filter(|(a, _)| pre_consensus_move_authenticators.contains(a))
1075                .unzip();
1076        let per_authenticator_checked_input_objects: Vec<_> = per_authenticator_checked_inputs
1077            .iter()
1078            .map(|i| &i.0)
1079            .collect();
1080
1081        // If there are `MoveAuthenticator` signatures, execute them and check if they
1082        // all succeed.
1083        if !move_authenticators.is_empty() {
1084            let aggregated_authenticator_input_objects =
1085                iota_transaction_checks::aggregate_authenticator_input_objects(
1086                    &per_authenticator_checked_input_objects,
1087                )?;
1088
1089            debug_assert_eq!(
1090                move_authenticators.len(),
1091                per_authenticator_checked_inputs.len(),
1092                "Move authenticators amount must match the number of checked authenticator inputs"
1093            );
1094
1095            let move_authenticators = move_authenticators
1096                .into_iter()
1097                .zip(per_authenticator_checked_inputs)
1098                .map(
1099                    |(
1100                        move_authenticator,
1101                        (authenticator_checked_input_objects, authenticator_function_ref),
1102                    )| {
1103                        (
1104                            move_authenticator.to_owned(),
1105                            authenticator_function_ref,
1106                            authenticator_checked_input_objects,
1107                        )
1108                    },
1109                )
1110                .collect();
1111
1112            // It is supposed that `MoveAuthenticator` availability is checked in
1113            // `SenderSignedData::validity_check`.
1114
1115            // Serialize the TransactionData for the auth context before decomposing.
1116            let tx_data_bytes =
1117                bcs::to_bytes(&tx_data).expect("TransactionData serialization cannot fail");
1118
1119            let (sender_auth_digest, sponsor_auth_digest) =
1120                transaction.data().compute_auth_digests()?;
1121
1122            let auth_context_data = AuthContextData {
1123                transaction_data_bytes: tx_data_bytes,
1124                sender_auth_digest,
1125                sponsor_auth_digest,
1126                sender_authenticator_function_ref,
1127                sponsor_authenticator_function_ref,
1128            };
1129
1130            // Execute the Move authenticators.
1131            let validation_result = epoch_store.executor().authenticate_transaction(
1132                self.get_backing_store().as_ref(),
1133                protocol_config,
1134                self.metrics.limits_metrics.clone(),
1135                &epoch_store.epoch_start_config().epoch_data().epoch_id(),
1136                epoch_store
1137                    .epoch_start_config()
1138                    .epoch_data()
1139                    .epoch_start_timestamp(),
1140                gas_data,
1141                gas_status,
1142                move_authenticators,
1143                aggregated_authenticator_input_objects,
1144                kind,
1145                signer,
1146                transaction.digest().to_owned(),
1147                auth_context_data,
1148                &mut None,
1149            );
1150
1151            if let Err(validation_error) = validation_result {
1152                return Err(IotaError::MoveAuthenticatorExecutionFailure {
1153                    error: validation_error.to_string(),
1154                });
1155            }
1156        }
1157
1158        Ok(tx_checked_input_objects.inner().filter_owned_objects())
1159    }
1160
1161    /// This is a private method and should be kept that way. It doesn't check
1162    /// whether the provided transaction is a system transaction, and hence
1163    /// can only be called internally.
1164    async fn handle_transaction_impl(
1165        &self,
1166        transaction: VerifiedTransaction,
1167        epoch_store: &Arc<AuthorityPerEpochStore>,
1168    ) -> IotaResult<VerifiedSignedTransaction> {
1169        // Ensure that validator cannot reconfigure while we are signing the tx
1170        let _execution_lock = self.execution_lock_for_signing()?;
1171
1172        let owned_objects = self
1173            .handle_transaction_validation_checks(
1174                &transaction,
1175                epoch_store,
1176                // Latest-value coin deny-list read: admission is validator-local,
1177                // and denials should take effect immediately. Unlike the P-COOL
1178                // submission path, no post-consensus re-check follows - this is
1179                // the only sender-side coin deny check in the certificate flow.
1180                false,
1181            )
1182            .await?;
1183
1184        let epoch = epoch_store.epoch();
1185        let signed_transaction =
1186            VerifiedSignedTransaction::new(epoch, transaction, self.name, &*self.secret);
1187
1188        // Check and write locks, to signed transaction, into the database
1189        // The call to self.set_transaction_lock checks the lock is not conflicting,
1190        // and returns ConflictingTransaction error in case there is a lock on a
1191        // different existing transaction.
1192        self.get_cache_writer().try_acquire_transaction_locks(
1193            epoch_store,
1194            &owned_objects,
1195            signed_transaction.clone(),
1196        )?;
1197
1198        Ok(signed_transaction)
1199    }
1200
1201    /// Initiate a new transaction.
1202    #[instrument(name = "handle_transaction", level = "trace", skip_all, fields(tx_digest = ?transaction.digest(), sender = transaction.data().transaction_data().gas_owner().to_string()
1203    ))]
1204    pub async fn handle_transaction(
1205        &self,
1206        epoch_store: &Arc<AuthorityPerEpochStore>,
1207        transaction: VerifiedTransaction,
1208    ) -> IotaResult<HandleTransactionResponse> {
1209        let tx_digest = *transaction.digest();
1210        debug!("handle_transaction");
1211
1212        // Ensure an idempotent answer.
1213        if let Some((_, status)) = self.get_transaction_status(&tx_digest, epoch_store)? {
1214            return Ok(HandleTransactionResponse { status });
1215        }
1216
1217        let _metrics_guard = self
1218            .metrics
1219            .authority_state_handle_transaction_latency
1220            .start_timer();
1221        self.metrics.tx_orders.inc();
1222
1223        let signed = self.handle_transaction_impl(transaction, epoch_store).await;
1224        match signed {
1225            Ok(s) => {
1226                if self.is_committee_validator(epoch_store) {
1227                    if let Some(validator_tx_finalizer) = &self.validator_tx_finalizer {
1228                        let tx = s.clone();
1229                        let validator_tx_finalizer = validator_tx_finalizer.clone();
1230                        let cache_reader = self.get_transaction_cache_reader().clone();
1231                        let epoch_store = epoch_store.clone();
1232                        spawn_monitored_task!(epoch_store.within_alive_epoch(
1233                            validator_tx_finalizer.track_signed_tx(cache_reader, &epoch_store, tx)
1234                        ));
1235                    }
1236                }
1237                Ok(HandleTransactionResponse {
1238                    status: TransactionStatus::Signed(s.into_inner().into_sig()),
1239                })
1240            }
1241            // It happens frequently that while we are checking the validity of the transaction, it
1242            // has just been executed.
1243            // In that case, we could still return Ok to avoid showing confusing errors.
1244            Err(err) => Ok(HandleTransactionResponse {
1245                status: self
1246                    .get_transaction_status(&tx_digest, epoch_store)?
1247                    .ok_or(err)?
1248                    .1,
1249            }),
1250        }
1251    }
1252
1253    pub fn check_system_overload_at_signing(&self) -> bool {
1254        self.config
1255            .authority_overload_config
1256            .check_system_overload_at_signing
1257    }
1258
1259    pub fn check_system_overload_at_execution(&self) -> bool {
1260        self.config
1261            .authority_overload_config
1262            .check_system_overload_at_execution
1263    }
1264
1265    /// Checks system overload conditions before accepting a transaction.
1266    ///
1267    /// In certificate-less (P-COOL) mode: only checks consensus
1268    /// queue overload, since execution-based overload will be handled
1269    /// post-consensus.
1270    ///
1271    /// In certificate mode: runs all checks — authority overload
1272    /// (execution latency), transaction manager (execution queue),
1273    /// consensus adapter (queue limit), and writeback cache backpressure.
1274    pub(crate) fn check_system_overload(
1275        &self,
1276        consensus_adapter: &Arc<ConsensusAdapter>,
1277        tx_data: &SenderSignedData,
1278        do_authority_overload_check: bool,
1279        pcool_flow_enabled: bool,
1280    ) -> IotaResult {
1281        if pcool_flow_enabled {
1282            // Graduated shedding: 0% to 100% as consensus queue fills from soft
1283            // to hard limit.
1284            self.check_consensus_queue_graduated_limits(consensus_adapter, tx_data)
1285                .tap_err(|_| {
1286                    self.update_overload_metrics("consensus");
1287                })?;
1288
1289            // NOTE: graduated shedding at 100% already rejects everything at or above
1290            // `max_pending_transactions`, so the queue-length part of the check below
1291            // is redundant but harmless. But `check_consensus_overload()` should be
1292            // kept here because it also verifies that `submit_semaphore` has permits
1293            // (see `check_consensus_hard_limits` in consensus_adapter.rs), which is a
1294            // separate concurrency limit not covered by the graduated shedding.
1295            consensus_adapter.check_consensus_overload().tap_err(|_| {
1296                self.update_overload_metrics("consensus");
1297            })?;
1298        } else {
1299            if do_authority_overload_check {
1300                self.check_authority_overload(tx_data).tap_err(|_| {
1301                    self.update_overload_metrics("execution_queue");
1302                })?;
1303            }
1304            self.transaction_manager
1305                .check_execution_overload(self.overload_config(), tx_data)
1306                .tap_err(|_| {
1307                    self.update_overload_metrics("execution_pending");
1308                })?;
1309            consensus_adapter.check_consensus_overload().tap_err(|_| {
1310                self.update_overload_metrics("consensus");
1311            })?;
1312
1313            let pending_tx_count = self
1314                .get_cache_commit()
1315                .approximate_pending_transaction_count();
1316            if pending_tx_count
1317                > self
1318                    .config
1319                    .execution_cache_config
1320                    .writeback_cache
1321                    .backpressure_threshold_for_rpc()
1322            {
1323                return Err(IotaError::ValidatorOverloadedRetryAfter {
1324                    retry_after_secs: 10,
1325                });
1326            }
1327        }
1328
1329        Ok(())
1330    }
1331
1332    /// Rejects `tx_data` via graduated shedding based on consensus queue
1333    /// length. Scales from 0% at the soft limit to 100% at
1334    /// `max_pending_transactions`. Returns `ValidatorOverloadedRetryAfter`
1335    /// for probabilistic rejection (shedding percentage < 100%, via
1336    /// `overload_monitor_accept_tx`) or `TooManyTransactionsPendingConsensus`
1337    /// for unconditional rejection (shedding percentage >= 100%). Updates
1338    /// `consensus_queue_load_shedding_percentage` metric.
1339    fn check_consensus_queue_graduated_limits(
1340        &self,
1341        consensus_adapter: &Arc<ConsensusAdapter>,
1342        tx_data: &SenderSignedData,
1343    ) -> IotaResult {
1344        let num_inflight_txs = consensus_adapter.num_inflight_transactions() as usize;
1345
1346        let shedding_pct = compute_graduated_load_shedding_percentage(
1347            num_inflight_txs,
1348            consensus_adapter.max_pending_transactions(),
1349            consensus_adapter.graduated_load_shedding_soft_limit_pct(),
1350        );
1351
1352        self.metrics
1353            .consensus_queue_load_shedding_percentage
1354            .set(shedding_pct as i64);
1355
1356        if shedding_pct == 0 {
1357            return Ok(());
1358        }
1359
1360        // At/above the hard limit, rejection is unconditional (not
1361        // probabilistic), so the seed-rotation retry hint of
1362        // `ValidatorOverloadedRetryAfter` doesn't apply - return the
1363        // capacity-bound error instead.
1364        if shedding_pct >= 100 {
1365            return Err(IotaError::TooManyTransactionsPendingConsensus);
1366        }
1367
1368        overload_monitor_accept_tx(shedding_pct, tx_data.digest())
1369    }
1370
1371    fn check_authority_overload(&self, tx_data: &SenderSignedData) -> IotaResult {
1372        if !self.overload_info.is_overload.load(Ordering::Relaxed) {
1373            return Ok(());
1374        }
1375
1376        let load_shedding_percentage = self
1377            .overload_info
1378            .local_load_shedding_percentage
1379            .load(Ordering::Relaxed);
1380        overload_monitor_accept_tx(load_shedding_percentage, tx_data.digest())
1381    }
1382
1383    fn update_overload_metrics(&self, source: &str) {
1384        self.metrics
1385            .transaction_overload_sources
1386            .with_label_values(&[source])
1387            .inc();
1388    }
1389
1390    /// Wait for a certificate to be executed.
1391    /// For consensus transactions, it needs to be sequenced by the consensus.
1392    /// For owned object transactions, this function will enqueue the
1393    /// transaction for execution.
1394    #[instrument(level = "trace", skip_all)]
1395    pub async fn wait_for_certificate_execution(
1396        &self,
1397        certificate: &VerifiedCertificate,
1398        epoch_store: &Arc<AuthorityPerEpochStore>,
1399    ) -> IotaResult<TransactionEffects> {
1400        let _metrics_guard = if certificate.contains_shared_object() {
1401            self.metrics
1402                .execute_certificate_latency_shared_object
1403                .start_timer()
1404        } else {
1405            self.metrics
1406                .execute_certificate_latency_single_writer
1407                .start_timer()
1408        };
1409        trace!("wait_for_certificate_execution");
1410
1411        self.metrics.total_cert_attempts.inc();
1412
1413        if !certificate.contains_shared_object() {
1414            // Shared object transactions need to be sequenced by the consensus before
1415            // enqueueing for execution, done in
1416            // AuthorityPerEpochStore::handle_consensus_transaction(). For owned
1417            // object transactions, they can be enqueued for execution immediately.
1418            self.enqueue_certificates_for_execution(vec![certificate.clone()], epoch_store);
1419        }
1420
1421        // tx could be reverted when epoch ends, so we must be careful not to return a
1422        // result here after the epoch ends.
1423        epoch_store
1424            .within_alive_epoch(self.notify_read_effects(certificate))
1425            .await
1426            .map_err(|_| IotaError::EpochEnded(epoch_store.epoch()))
1427            .and_then(|r| r)
1428    }
1429
1430    /// Internal logic to execute a transaction.
1431    ///
1432    /// Guarantees that
1433    /// - If input objects are available, return no permanent failure.
1434    /// - Execution and output commit are atomic. i.e. outputs are only written
1435    ///   to storage,
1436    /// on successful execution; crashed execution has no observable effect and
1437    /// can be retried.
1438    ///
1439    /// It is caller's responsibility to ensure input objects are available and
1440    /// locks are set. If this cannot be satisfied by the caller,
1441    /// `wait_for_certificate_execution()` should be called instead.
1442    ///
1443    /// Should only be called within iota-core.
1444    #[instrument(level = "trace", skip_all, fields(tx_digest = ?transaction.digest()))]
1445    pub fn try_execute_immediately(
1446        &self,
1447        transaction: &VerifiedExecutableTransaction,
1448        expected_effects_digest: Option<TransactionEffectsDigest>,
1449        epoch_store: &Arc<AuthorityPerEpochStore>,
1450    ) -> IotaResult<(TransactionEffects, Option<ExecutionError>)> {
1451        let _scope = monitored_scope("Execution::try_execute_immediately");
1452        let _metrics_guard = self.metrics.internal_execution_latency.start_timer();
1453
1454        let tx_digest = transaction.digest();
1455
1456        // Acquire a lock to prevent concurrent executions of the same transaction.
1457        let tx_guard = epoch_store.acquire_tx_guard(transaction)?;
1458
1459        // The transaction could have been processed by a concurrent attempt of the
1460        // same transaction, so check if the effects have already been written.
1461        if let Some(effects) = self
1462            .get_transaction_cache_reader()
1463            .try_get_executed_effects(tx_digest)?
1464        {
1465            if let Some(expected_effects_digest_inner) = expected_effects_digest {
1466                assert_eq!(
1467                    effects.digest(),
1468                    expected_effects_digest_inner,
1469                    "Unexpected effects digest for transaction {tx_digest}"
1470                );
1471            }
1472            tx_guard.release();
1473            return Ok((effects, None));
1474        }
1475
1476        let (tx_input_objects, per_authenticator_inputs) =
1477            self.read_objects_for_execution(tx_guard.as_lock_guard(), transaction, epoch_store)?;
1478
1479        // If no expected_effects_digest was provided, try to get it from storage.
1480        // We could be re-executing a previously executed but uncommitted transaction,
1481        // perhaps after restarting with a new binary. In this situation, if
1482        // we have published an effects signature, we must be sure not to
1483        // equivocate.
1484        let expected_effects_digest =
1485            expected_effects_digest.or(epoch_store.get_signed_effects_digest(tx_digest)?);
1486
1487        self.process_transaction(
1488            tx_guard,
1489            transaction,
1490            tx_input_objects,
1491            per_authenticator_inputs,
1492            expected_effects_digest,
1493            epoch_store,
1494        )
1495        .tap_err(|e| info!(?tx_digest, "process_transaction failed: {e}"))
1496        .tap_ok(
1497            |(fx, _)| debug!(?tx_digest, fx_digest=?fx.digest(), "process_transaction succeeded"),
1498        )
1499    }
1500
1501    pub fn read_objects_for_execution(
1502        &self,
1503        tx_lock: &TxLockGuard,
1504        transaction: &VerifiedExecutableTransaction,
1505        epoch_store: &Arc<AuthorityPerEpochStore>,
1506    ) -> IotaResult<(InputObjects, Vec<(InputObjects, ObjectReadResult)>)> {
1507        let _scope = monitored_scope("Execution::load_input_objects");
1508        let _metrics_guard = self
1509            .metrics
1510            .execution_load_input_objects_latency
1511            .start_timer();
1512
1513        let input_objects = transaction.collect_all_input_object_kind_for_reading()?;
1514
1515        let input_objects = self.input_loader.read_objects_for_execution(
1516            epoch_store,
1517            &transaction.key(),
1518            tx_lock,
1519            &input_objects,
1520            epoch_store.epoch(),
1521        )?;
1522
1523        transaction.split_input_objects_into_groups_for_reading(input_objects)
1524    }
1525
1526    /// Test only wrapper for `try_execute_immediately()` above, useful for
1527    /// checking errors if the pre-conditions are not satisfied, and
1528    /// executing change epoch transactions.
1529    pub fn try_execute_for_test(
1530        &self,
1531        certificate: &VerifiedCertificate,
1532    ) -> IotaResult<(VerifiedSignedTransactionEffects, Option<ExecutionError>)> {
1533        let epoch_store = self.epoch_store_for_testing();
1534        let (effects, execution_error_opt) = self.try_execute_immediately(
1535            &VerifiedExecutableTransaction::new_from_certificate(certificate.clone()),
1536            None,
1537            &epoch_store,
1538        )?;
1539        let signed_effects = self.sign_effects(effects, &epoch_store)?;
1540        Ok((signed_effects, execution_error_opt))
1541    }
1542
1543    /// Non-fallible version of `try_execute_for_test()`.
1544    pub fn execute_for_test(
1545        &self,
1546        certificate: &VerifiedCertificate,
1547    ) -> (VerifiedSignedTransactionEffects, Option<ExecutionError>) {
1548        self.try_execute_for_test(certificate)
1549            .expect("try_execute_for_test should not fail")
1550    }
1551
1552    pub async fn notify_read_effects(
1553        &self,
1554        certificate: &VerifiedCertificate,
1555    ) -> IotaResult<TransactionEffects> {
1556        self.get_transaction_cache_reader()
1557            .try_notify_read_executed_effects(&[*certificate.digest()])
1558            .await
1559            .map(|mut r| r.pop().expect("must return correct number of effects"))
1560    }
1561
1562    fn check_owned_locks(&self, owned_object_refs: &[ObjectReference]) -> IotaResult {
1563        self.get_object_cache_reader()
1564            .try_check_owned_objects_are_live(owned_object_refs)
1565    }
1566
1567    /// This function captures the required state to debug a forked transaction.
1568    /// The dump is written to a file in dir `path`, with name prefixed by the
1569    /// transaction digest. NOTE: Since this info escapes the validator
1570    /// context, make sure not to leak any private info here
1571    pub(crate) fn debug_dump_transaction_state(
1572        &self,
1573        tx_digest: &TransactionDigest,
1574        effects: &TransactionEffects,
1575        expected_effects_digest: TransactionEffectsDigest,
1576        inner_temporary_store: &InnerTemporaryStore,
1577        transaction: &VerifiedExecutableTransaction,
1578        debug_dump_config: &StateDebugDumpConfig,
1579    ) -> IotaResult<PathBuf> {
1580        // Fall back to the OS temp directory if no dump directory is configured.
1581        // This is safe: dump files are named by transaction digest, so no collisions.
1582        let dump_dir = debug_dump_config
1583            .dump_file_directory
1584            .as_ref()
1585            .cloned()
1586            .unwrap_or(std::env::temp_dir());
1587        let epoch_store = self.load_epoch_store_one_call_per_task();
1588
1589        NodeStateDump::new(
1590            tx_digest,
1591            effects,
1592            expected_effects_digest,
1593            self.get_object_store().as_ref(),
1594            &epoch_store,
1595            inner_temporary_store,
1596            transaction,
1597        )?
1598        .write_to_file(&dump_dir)
1599        .map_err(|e| IotaError::FileIO(e.to_string()))
1600    }
1601
1602    #[instrument(name = "process_certificate", level = "trace", skip_all, fields(tx_digest = ?transaction.digest(), sender = ?transaction.data().transaction_data().gas_owner().to_string()))]
1603    pub(crate) fn process_transaction(
1604        &self,
1605        tx_guard: TxGuard,
1606        transaction: &VerifiedExecutableTransaction,
1607        tx_input_objects: InputObjects,
1608        per_authenticator_inputs: Vec<(InputObjects, ObjectReadResult)>,
1609        expected_effects_digest: Option<TransactionEffectsDigest>,
1610        epoch_store: &Arc<AuthorityPerEpochStore>,
1611    ) -> IotaResult<(TransactionEffects, Option<ExecutionError>)> {
1612        let process_transaction_start_time = tokio::time::Instant::now();
1613        let digest = *transaction.digest();
1614
1615        let _scope = monitored_scope("Execution::process_certificate");
1616
1617        fail_point_if!("correlated-crash-process-transaction", || {
1618            if iota_simulator::random::deterministic_probability_once(digest, 0.01) {
1619                iota_simulator::task::kill_current_node(None);
1620            }
1621        });
1622
1623        let execution_guard = self.execution_lock_for_executable_transaction(transaction);
1624        // Any caller that verifies the signatures on the transaction will have already
1625        // checked the epoch. But paths that don't verify sigs (e.g. execution
1626        // from checkpoint, reading from db) present the possibility of an epoch
1627        // mismatch. If this transaction is not finalized in previous epoch, then it's
1628        // invalid.
1629        let execution_guard = match execution_guard {
1630            Ok(execution_guard) => execution_guard,
1631            Err(err) => {
1632                tx_guard.release();
1633                return Err(err);
1634            }
1635        };
1636        // Since we obtain a reference to the epoch store before taking the execution
1637        // lock, it's possible that reconfiguration has happened and they no
1638        // longer match.
1639        if *execution_guard != epoch_store.epoch() {
1640            tx_guard.release();
1641            info!("The epoch of the execution_guard doesn't match the epoch store");
1642            return Err(IotaError::WrongEpoch {
1643                expected_epoch: epoch_store.epoch(),
1644                actual_epoch: *execution_guard,
1645            });
1646        }
1647
1648        // Errors originating from `execute_transaction` may be transient (failure to
1649        // read locks) or non-transient (transaction input is invalid, move vm
1650        // errors). However, all errors from this function occur before we have
1651        // written anything to the db, so we commit the tx guard and rely on the
1652        // client to retry the tx (if it was transient).
1653        let (inner_temporary_store, effects, execution_error_opt) = match self.execute_transaction(
1654            &execution_guard,
1655            transaction,
1656            tx_input_objects,
1657            per_authenticator_inputs,
1658            epoch_store,
1659        ) {
1660            Err(e) => {
1661                info!(name = ?self.name, ?digest, "Error preparing transaction: {e}");
1662                tx_guard.release();
1663                return Err(e);
1664            }
1665            Ok(res) => res,
1666        };
1667
1668        if let Some(expected_effects_digest) = expected_effects_digest {
1669            if effects.digest() != expected_effects_digest {
1670                // We dont want to mask the original error, so we log it and continue.
1671                match self.debug_dump_transaction_state(
1672                    &digest,
1673                    &effects,
1674                    expected_effects_digest,
1675                    &inner_temporary_store,
1676                    transaction,
1677                    &self.config.state_debug_dump_config,
1678                ) {
1679                    Ok(out_path) => {
1680                        info!(
1681                            "Dumped node state for transaction {} to {}",
1682                            digest,
1683                            out_path.as_path().display().to_string()
1684                        );
1685                    }
1686                    Err(e) => {
1687                        error!("Error dumping state for transaction {}: {e}", digest);
1688                    }
1689                }
1690                error!(
1691                    tx_digest = ?digest,
1692                    ?expected_effects_digest,
1693                    actual_effects = ?effects,
1694                    "fork detected!"
1695                );
1696                panic!(
1697                    "Transaction {} is expected to have effects digest {}, but got {}!",
1698                    digest,
1699                    expected_effects_digest,
1700                    effects.digest(),
1701                );
1702            }
1703        }
1704
1705        fail_point!("crash");
1706
1707        self.commit_transaction(
1708            transaction,
1709            inner_temporary_store,
1710            &effects,
1711            tx_guard,
1712            execution_guard,
1713            epoch_store,
1714        )?;
1715
1716        let elapsed = process_transaction_start_time.elapsed().as_micros() as f64;
1717        if elapsed > 0.0 {
1718            self.metrics
1719                .execution_gas_latency_ratio
1720                .observe(effects.gas_cost_summary().computation_cost as f64 / elapsed);
1721        };
1722        Ok((effects, execution_error_opt))
1723    }
1724
1725    pub async fn reconfigure_traffic_control(
1726        &self,
1727        params: TrafficControlReconfigParams,
1728    ) -> Result<TrafficControlReconfigParams, IotaError> {
1729        if let Some(traffic_controller) = self.traffic_controller.as_ref() {
1730            traffic_controller.admin_reconfigure(params).await
1731        } else {
1732            Err(IotaError::InvalidAdminRequest(
1733                "Traffic controller is not configured on this node".to_string(),
1734            ))
1735        }
1736    }
1737
1738    #[instrument(level = "trace", skip_all)]
1739    fn commit_transaction(
1740        &self,
1741        transaction: &VerifiedExecutableTransaction,
1742        inner_temporary_store: InnerTemporaryStore,
1743        effects: &TransactionEffects,
1744        tx_guard: TxGuard,
1745        _execution_guard: ExecutionLockReadGuard<'_>,
1746        epoch_store: &Arc<AuthorityPerEpochStore>,
1747    ) -> IotaResult {
1748        let _scope: Option<iota_metrics::MonitoredScopeGuard> =
1749            monitored_scope("Execution::commit_certificate");
1750        let _metrics_guard = self.metrics.commit_certificate_latency.start_timer();
1751
1752        let tx_key = transaction.key();
1753        let tx_digest = transaction.digest();
1754        let input_object_count = inner_temporary_store.input_objects.len();
1755        let shared_object_count = effects.input_shared_objects().len();
1756
1757        let output_keys = inner_temporary_store.get_output_keys(effects);
1758
1759        // index transaction
1760        let _ = self
1761            .post_process_one_tx(transaction, effects, &inner_temporary_store, epoch_store)
1762            .tap_err(|e| {
1763                self.metrics.post_processing_total_failures.inc();
1764                error!(?tx_digest, "tx post processing failed: {e}");
1765            });
1766
1767        // The insertion to epoch_store is not atomic with the insertion to the
1768        // perpetual store. This is OK because we insert to the epoch store
1769        // first. And during lookups we always look up in the perpetual store first.
1770        epoch_store.insert_tx_key_and_digest(&tx_key, tx_digest)?;
1771
1772        // Allow testing what happens if we crash here.
1773        fail_point!("crash");
1774
1775        let transaction_outputs = TransactionOutputs::build_transaction_outputs(
1776            transaction.clone().into_unsigned(),
1777            effects.clone(),
1778            inner_temporary_store,
1779        );
1780        self.get_cache_writer()
1781            .try_write_transaction_outputs(epoch_store.epoch(), transaction_outputs.into())?;
1782
1783        if transaction.transaction_data().is_end_of_epoch_tx() {
1784            // At the end of epoch, since system packages may have been upgraded, force
1785            // reload them in the cache.
1786            self.get_object_cache_reader()
1787                .force_reload_system_packages(&BuiltInFramework::all_package_ids());
1788        }
1789
1790        // `commit_transaction()` finished, the tx is fully committed to the store.
1791        tx_guard.commit_tx();
1792
1793        // Notifies transaction manager about transaction and output objects committed.
1794        // This provides necessary information to transaction manager to start executing
1795        // additional ready transactions.
1796        self.transaction_manager
1797            .notify_commit(tx_digest, output_keys, epoch_store);
1798
1799        self.update_metrics(transaction, input_object_count, shared_object_count);
1800
1801        Ok(())
1802    }
1803
1804    fn update_metrics(
1805        &self,
1806        transaction: &VerifiedExecutableTransaction,
1807        input_object_count: usize,
1808        shared_object_count: usize,
1809    ) {
1810        // count signature by scheme, for multisig
1811        if transaction.has_upgraded_multisig() {
1812            self.metrics.multisig_sig_count.inc();
1813        }
1814
1815        self.metrics.total_effects.inc();
1816        self.metrics.total_certs.inc();
1817
1818        if shared_object_count > 0 {
1819            self.metrics.shared_obj_tx.inc();
1820        }
1821
1822        if transaction.is_sponsored_tx() {
1823            self.metrics.sponsored_tx.inc();
1824        }
1825
1826        self.metrics
1827            .num_input_objs
1828            .observe(input_object_count as f64);
1829        self.metrics
1830            .num_shared_objects
1831            .observe(shared_object_count as f64);
1832        self.metrics.batch_size.observe(
1833            transaction
1834                .data()
1835                .intent_message()
1836                .value
1837                .kind()
1838                .num_commands() as f64,
1839        );
1840    }
1841
1842    /// `execute_transaction()` validates the transaction input, and executes
1843    /// the transaction, returning effects, output objects, events, etc.
1844    ///
1845    /// It reads state from the db (both owned and shared locks), but it has no
1846    /// side effects.
1847    ///
1848    /// It can be generally understood that a failure of `execute_transaction`
1849    /// indicates a non-transient error, e.g. the transaction input is
1850    /// somehow invalid, the correct locks are not held, etc. However, this
1851    /// is not entirely true, as a transient db read error may also cause
1852    /// this function to fail.
1853    #[instrument(level = "trace", skip_all)]
1854    fn execute_transaction(
1855        &self,
1856        _execution_guard: &ExecutionLockReadGuard<'_>,
1857        transaction: &VerifiedExecutableTransaction,
1858        tx_input_objects: InputObjects,
1859        per_authenticator_inputs: Vec<(InputObjects, ObjectReadResult)>,
1860        epoch_store: &Arc<AuthorityPerEpochStore>,
1861    ) -> IotaResult<(
1862        InnerTemporaryStore,
1863        TransactionEffects,
1864        Option<ExecutionError>,
1865    )> {
1866        let _scope = monitored_scope("Execution::execute_certificate");
1867        let _metrics_guard = self.metrics.prepare_certificate_latency.start_timer();
1868        let prepare_transaction_start_time = tokio::time::Instant::now();
1869
1870        let protocol_config = epoch_store.protocol_config();
1871
1872        let reference_gas_price = epoch_store.reference_gas_price();
1873
1874        let epoch_id = epoch_store.epoch_start_config().epoch_data().epoch_id();
1875        let epoch_start_timestamp = epoch_store
1876            .epoch_start_config()
1877            .epoch_data()
1878            .epoch_start_timestamp();
1879
1880        let backing_store = self.get_backing_store().as_ref();
1881
1882        let tx_digest = *transaction.digest();
1883
1884        // TODO: We need to move this to a more appropriate place to avoid redundant
1885        // checks.
1886        let tx_data = transaction.data().transaction_data();
1887        tx_data.validity_check(protocol_config)?;
1888
1889        let (kind, signer, gas_data) = tx_data.execution_parts();
1890
1891        let move_authenticators = transaction.move_authenticators();
1892
1893        #[cfg_attr(not(any(msim, fail_points)), expect(unused_mut))]
1894        let (inner_temp_store, _, mut effects, execution_error_opt) = if move_authenticators
1895            .is_empty()
1896        {
1897            // No Move authentication required, proceed to execute the transaction directly.
1898
1899            // The cost of partially re-auditing a transaction before execution is
1900            // tolerated.
1901            let (tx_gas_status, tx_checked_input_objects) =
1902                iota_transaction_checks::check_certificate_input(
1903                    transaction,
1904                    tx_input_objects,
1905                    protocol_config,
1906                    reference_gas_price,
1907                )?;
1908
1909            let owned_object_refs = tx_checked_input_objects.inner().filter_owned_objects();
1910            self.check_owned_locks(&owned_object_refs)?;
1911            epoch_store.executor().execute_transaction_to_effects(
1912                backing_store,
1913                protocol_config,
1914                self.metrics.limits_metrics.clone(),
1915                // TODO: would be nice to pass the whole NodeConfig here, but it creates a
1916                // cyclic dependency w/ iota-adapter
1917                self.config
1918                    .expensive_safety_check_config
1919                    .enable_deep_per_tx_iota_conservation_check(),
1920                self.config.certificate_deny_config.certificate_deny_set(),
1921                &epoch_id,
1922                epoch_start_timestamp,
1923                tx_checked_input_objects,
1924                gas_data,
1925                tx_gas_status,
1926                kind,
1927                signer,
1928                tx_digest,
1929                &mut None,
1930            )
1931        } else {
1932            // One or more `MoveAuthenticator` signatures present — authenticate each and
1933            // then execute the transaction.
1934            // It is supposed that `MoveAuthenticator` availability is checked in
1935            // `SenderSignedData::validity_check`.
1936
1937            debug_assert_eq!(
1938                move_authenticators.len(),
1939                per_authenticator_inputs.len(),
1940                "Move authenticators amount must match the number of authenticator inputs"
1941            );
1942
1943            let per_authenticator_inputs = move_authenticators
1944                .iter()
1945                .zip(per_authenticator_inputs)
1946                .map(
1947                    |(move_authenticator, (authenticator_input_objects, account_object))| {
1948                        // Check basic `object_to_authenticate` preconditions and get its
1949                        // components.
1950                        let (
1951                            auth_account_object_id,
1952                            auth_account_object_seq_number,
1953                            auth_account_object_digest,
1954                        ) = move_authenticator.object_to_authenticate_components()?;
1955
1956                        let signer = move_authenticator.address();
1957
1958                        let authenticator_function_ref_for_execution = self.check_move_account(
1959                            auth_account_object_id,
1960                            auth_account_object_seq_number,
1961                            auth_account_object_digest,
1962                            account_object,
1963                            &signer,
1964                        )?;
1965
1966                        Ok((
1967                            authenticator_input_objects,
1968                            authenticator_function_ref_for_execution,
1969                        ))
1970                    },
1971                )
1972                .collect::<IotaResult<Vec<_>>>()?;
1973
1974            let per_authenticator_input_objects = per_authenticator_inputs
1975                .iter()
1976                .map(|(authenticator_input_objects, _)| authenticator_input_objects.clone())
1977                .collect::<Vec<_>>();
1978
1979            // Serialize the TransactionData for the auth context.
1980            let tx_data_bytes =
1981                bcs::to_bytes(tx_data).expect("TransactionData serialization cannot fail");
1982
1983            let (sender_auth_digest, sponsor_auth_digest) =
1984                transaction.data().compute_auth_digests()?;
1985
1986            // Check the `MoveAuthenticator` input objects.
1987            // The `MoveAuthenticator` receiving objects are checked on the signing step.
1988            // `max_auth_gas` is used here as a Move authenticator gas budget until it is
1989            // not a part of the transaction data.
1990            let authenticator_gas_budget = protocol_config.max_auth_gas();
1991            let (
1992                gas_status,
1993                per_authenticator_checked_input_objects,
1994                authenticator_and_tx_checked_input_objects,
1995            ) = iota_transaction_checks::check_certificate_and_move_authenticator_input(
1996                transaction,
1997                tx_input_objects,
1998                per_authenticator_input_objects,
1999                authenticator_gas_budget,
2000                protocol_config,
2001                reference_gas_price,
2002            )?;
2003
2004            debug_assert_eq!(
2005                move_authenticators.len(),
2006                per_authenticator_checked_input_objects.len(),
2007                "Move authenticators amount must match the number of checked authenticator inputs"
2008            );
2009
2010            let move_authenticators = move_authenticators
2011                .into_iter()
2012                .zip(per_authenticator_inputs)
2013                .zip(per_authenticator_checked_input_objects)
2014                .map(
2015                    |(
2016                        (move_authenticator, (_, authenticator_function_ref_for_execution)),
2017                        authenticator_checked_input_objects,
2018                    )| {
2019                        (
2020                            move_authenticator.to_owned(),
2021                            authenticator_function_ref_for_execution,
2022                            authenticator_checked_input_objects,
2023                        )
2024                    },
2025                )
2026                .collect::<Vec<_>>();
2027
2028            let owned_object_refs = authenticator_and_tx_checked_input_objects
2029                .inner()
2030                .filter_owned_objects();
2031            self.check_owned_locks(&owned_object_refs)?;
2032
2033            let (sender_authenticator_function_ref, sponsor_authenticator_function_ref) =
2034                extract_auth_fun_refs(signer, gas_data.owner, |address| {
2035                    move_authenticators
2036                        .iter()
2037                        .find(|t| t.0.address() == address)
2038                        .map(|t| t.1.authenticator_function_ref.clone())
2039                });
2040
2041            let auth_context_data = AuthContextData {
2042                transaction_data_bytes: tx_data_bytes,
2043                sender_auth_digest,
2044                sponsor_auth_digest,
2045                sender_authenticator_function_ref,
2046                sponsor_authenticator_function_ref,
2047            };
2048
2049            epoch_store
2050                .executor()
2051                .authenticate_then_execute_transaction_to_effects(
2052                    backing_store,
2053                    protocol_config,
2054                    self.metrics.limits_metrics.clone(),
2055                    self.config
2056                        .expensive_safety_check_config
2057                        .enable_deep_per_tx_iota_conservation_check(),
2058                    self.config.certificate_deny_config.certificate_deny_set(),
2059                    &epoch_id,
2060                    epoch_start_timestamp,
2061                    gas_data,
2062                    gas_status,
2063                    move_authenticators,
2064                    authenticator_and_tx_checked_input_objects,
2065                    kind,
2066                    signer,
2067                    tx_digest,
2068                    auth_context_data,
2069                    &mut None,
2070                )
2071        };
2072
2073        fail_point_if!("cp_execution_nondeterminism", || {
2074            #[cfg(msim)]
2075            self.create_fail_state(transaction, epoch_store, &mut effects);
2076        });
2077
2078        let elapsed = prepare_transaction_start_time.elapsed().as_micros() as f64;
2079        if elapsed > 0.0 {
2080            self.metrics
2081                .prepare_cert_gas_latency_ratio
2082                .observe(effects.gas_cost_summary().computation_cost as f64 / elapsed);
2083        }
2084
2085        Ok((inner_temp_store, effects, execution_error_opt.err()))
2086    }
2087
2088    pub fn prepare_transaction_for_benchmark(
2089        &self,
2090        transaction: &VerifiedExecutableTransaction,
2091        input_objects: InputObjects,
2092        epoch_store: &Arc<AuthorityPerEpochStore>,
2093    ) -> IotaResult<(
2094        InnerTemporaryStore,
2095        TransactionEffects,
2096        Option<ExecutionError>,
2097    )> {
2098        let lock = RwLock::new(epoch_store.epoch());
2099        let execution_guard = lock.try_read().unwrap();
2100
2101        self.execute_transaction(
2102            &execution_guard,
2103            transaction,
2104            input_objects,
2105            vec![],
2106            epoch_store,
2107        )
2108    }
2109
2110    /// TO BE DEPRECATED SOON: Use `simulate_transaction` with
2111    /// `VmChecks::Enabled` instead.
2112    #[instrument("dry_exec_tx", level = "trace", skip_all)]
2113    #[allow(clippy::type_complexity)]
2114    pub fn dry_exec_transaction(
2115        &self,
2116        transaction: TransactionData,
2117        transaction_digest: TransactionDigest,
2118    ) -> IotaResult<(
2119        DryRunTransactionBlockResponse,
2120        BTreeMap<ObjectId, (ObjectReference, Object, WriteKind)>,
2121        TransactionEffects,
2122        Option<ObjectId>,
2123    )> {
2124        let epoch_store = self.load_epoch_store_one_call_per_task();
2125        if !self.is_fullnode(&epoch_store) {
2126            return Err(IotaError::UnsupportedFeature {
2127                error: "dry-exec is only supported on fullnodes".to_string(),
2128            });
2129        }
2130
2131        if transaction.kind().is_system() {
2132            return Err(IotaError::UnsupportedFeature {
2133                error: "dry-exec does not support system transactions".to_string(),
2134            });
2135        }
2136
2137        self.dry_exec_transaction_impl(&epoch_store, transaction, transaction_digest)
2138    }
2139
2140    #[allow(clippy::type_complexity)]
2141    pub fn dry_exec_transaction_for_benchmark(
2142        &self,
2143        transaction: TransactionData,
2144        transaction_digest: TransactionDigest,
2145    ) -> IotaResult<(
2146        DryRunTransactionBlockResponse,
2147        BTreeMap<ObjectId, (ObjectReference, Object, WriteKind)>,
2148        TransactionEffects,
2149        Option<ObjectId>,
2150    )> {
2151        let epoch_store = self.load_epoch_store_one_call_per_task();
2152        self.dry_exec_transaction_impl(&epoch_store, transaction, transaction_digest)
2153    }
2154
2155    #[instrument(level = "trace", skip_all)]
2156    #[allow(clippy::type_complexity)]
2157    fn dry_exec_transaction_impl(
2158        &self,
2159        epoch_store: &AuthorityPerEpochStore,
2160        transaction: TransactionData,
2161        transaction_digest: TransactionDigest,
2162    ) -> IotaResult<(
2163        DryRunTransactionBlockResponse,
2164        BTreeMap<ObjectId, (ObjectReference, Object, WriteKind)>,
2165        TransactionEffects,
2166        Option<ObjectId>,
2167    )> {
2168        // Cheap validity checks for a transaction, including input size limits.
2169        transaction.validity_check_no_gas_check(epoch_store.protocol_config())?;
2170
2171        let input_object_kinds = transaction.input_objects()?;
2172        let receiving_object_refs = transaction.receiving_objects();
2173
2174        iota_transaction_checks::deny::check_transaction_for_validation(
2175            &transaction,
2176            &[],
2177            &input_object_kinds,
2178            &receiving_object_refs,
2179            &self.config.transaction_deny_config,
2180            self.get_backing_package_store().as_ref(),
2181        )?;
2182
2183        let (input_objects, receiving_objects) = self.input_loader.read_objects_for_signing(
2184            // We don't want to cache this transaction since it's a dry run.
2185            None,
2186            &input_object_kinds,
2187            &receiving_object_refs,
2188            epoch_store.epoch(),
2189        )?;
2190
2191        // make a gas object if one was not provided
2192        let mut transaction = transaction;
2193        let reference_gas_price = epoch_store.reference_gas_price();
2194        let ((gas_status, checked_input_objects), mock_gas) = if transaction.gas().is_empty() {
2195            let sender = transaction.gas_owner();
2196            let gas_object_id = ObjectId::random();
2197            let gas_object = Object::new_move(
2198                MoveObject::new_gas_coin(
2199                    OBJECT_START_VERSION,
2200                    gas_object_id,
2201                    SIMULATION_GAS_COIN_VALUE,
2202                ),
2203                Owner::Address(sender),
2204                TransactionDigest::GENESIS_MARKER,
2205            );
2206            let gas_object_ref = gas_object.object_ref();
2207            // Add gas object to transaction gas payment
2208            transaction.gas_data_mut().objects = vec![gas_object_ref];
2209            (
2210                iota_transaction_checks::check_transaction_input_with_given_gas(
2211                    epoch_store.protocol_config(),
2212                    reference_gas_price,
2213                    &transaction,
2214                    input_objects,
2215                    receiving_objects,
2216                    gas_object,
2217                    &self.metrics.bytecode_verifier_metrics,
2218                    &self.config.verifier_signing_config,
2219                )?,
2220                Some(gas_object_id),
2221            )
2222        } else {
2223            // `MoveAuthenticator`s are not supported in dry runs, so we set the
2224            // `authenticator_gas_budget` to 0.
2225            let authenticator_gas_budget = 0;
2226
2227            (
2228                iota_transaction_checks::check_transaction_input(
2229                    epoch_store.protocol_config(),
2230                    reference_gas_price,
2231                    &transaction,
2232                    input_objects,
2233                    &receiving_objects,
2234                    &self.metrics.bytecode_verifier_metrics,
2235                    &self.config.verifier_signing_config,
2236                    authenticator_gas_budget,
2237                )?,
2238                None,
2239            )
2240        };
2241
2242        let protocol_config = epoch_store.protocol_config();
2243        let (kind, signer, gas_data) = transaction.execution_parts();
2244
2245        let silent = true;
2246        let executor = iota_execution::executor(protocol_config, silent, None)
2247            .expect("Creating an executor should not fail here");
2248
2249        let expensive_checks = false;
2250        let (inner_temp_store, _, effects, execution_error) = executor
2251            .execute_transaction_to_effects(
2252                self.get_backing_store().as_ref(),
2253                protocol_config,
2254                self.metrics.limits_metrics.clone(),
2255                expensive_checks,
2256                self.config.certificate_deny_config.certificate_deny_set(),
2257                &epoch_store.epoch_start_config().epoch_data().epoch_id(),
2258                epoch_store
2259                    .epoch_start_config()
2260                    .epoch_data()
2261                    .epoch_start_timestamp(),
2262                checked_input_objects,
2263                gas_data,
2264                gas_status,
2265                kind,
2266                signer,
2267                transaction_digest,
2268                &mut None,
2269            );
2270        let tx_digest = *effects.transaction_digest();
2271
2272        let module_cache =
2273            TemporaryModuleResolver::new(&inner_temp_store, epoch_store.module_cache().clone());
2274
2275        let mut layout_resolver =
2276            epoch_store
2277                .executor()
2278                .type_layout_resolver(Box::new(PackageStoreWithFallback::new(
2279                    &inner_temp_store,
2280                    self.get_backing_package_store(),
2281                )));
2282        // Returning empty vector here because we recalculate changes in the rpc layer.
2283        let object_changes = Vec::new();
2284
2285        // Returning empty vector here because we recalculate changes in the rpc layer.
2286        let balance_changes = Vec::new();
2287
2288        let written_with_kind = effects
2289            .created()
2290            .into_iter()
2291            .map(|(oref, _)| (oref, WriteKind::Create))
2292            .chain(
2293                effects
2294                    .unwrapped()
2295                    .into_iter()
2296                    .map(|(oref, _)| (oref, WriteKind::Unwrap)),
2297            )
2298            .chain(
2299                effects
2300                    .mutated()
2301                    .into_iter()
2302                    .map(|(oref, _)| (oref, WriteKind::Mutate)),
2303            )
2304            .map(|(oref, kind)| {
2305                let obj = inner_temp_store.written.get(&oref.object_id).unwrap();
2306                // TODO: Avoid clones.
2307                (oref.object_id, (oref, obj.clone(), kind))
2308            })
2309            .collect();
2310
2311        let execution_error_source = execution_error
2312            .as_ref()
2313            .err()
2314            .and_then(|e| e.source().as_ref().map(|e| e.to_string()));
2315
2316        Ok((
2317            DryRunTransactionBlockResponse {
2318                // to avoid cloning `transaction`, fields are populated in this order
2319                suggested_gas_price: self
2320                    .congestion_tracker
2321                    .get_prediction_suggested_gas_price(&transaction),
2322                input: IotaTransactionBlockData::try_from_with_module_cache(
2323                    transaction,
2324                    &module_cache,
2325                    tx_digest,
2326                )
2327                .map_err(|e| IotaError::TransactionSerialization {
2328                    error: format!(
2329                        "Failed to convert transaction to IotaTransactionBlockData: {e}",
2330                    ),
2331                })?, // TODO: replace the underlying try_from to IotaError. This one goes deep
2332                effects: effects.clone().try_into()?,
2333                events: IotaTransactionBlockEvents::try_from(
2334                    inner_temp_store.events.clone(),
2335                    tx_digest,
2336                    None,
2337                    layout_resolver.as_mut(),
2338                )?,
2339                object_changes,
2340                balance_changes,
2341                execution_error_source,
2342            },
2343            written_with_kind,
2344            effects,
2345            mock_gas,
2346        ))
2347    }
2348
2349    pub fn simulate_transaction(
2350        &self,
2351        mut transaction: TransactionData,
2352        checks: VmChecks,
2353    ) -> IotaResult<SimulateTransactionResult> {
2354        if transaction.kind().is_system() {
2355            return Err(IotaError::UnsupportedFeature {
2356                error: "simulate does not support system transactions".to_string(),
2357            });
2358        }
2359
2360        let epoch_store = self.load_epoch_store_one_call_per_task();
2361        if !self.is_fullnode(&epoch_store) {
2362            return Err(IotaError::UnsupportedFeature {
2363                error: "simulate is only supported on fullnodes".to_string(),
2364            });
2365        }
2366
2367        // Cheap validity checks for a transaction, including input size limits.
2368        // This does not check if gas objects are missing since we may create a
2369        // mock gas object. It checks for other transaction input validity.
2370        transaction.validity_check_no_gas_check(epoch_store.protocol_config())?;
2371
2372        let input_object_kinds = transaction.input_objects()?;
2373        let receiving_object_refs = transaction.receiving_objects();
2374
2375        // Since we need to simulate a validator signing the transaction, the first step
2376        // is to check if some transaction elements are denied.
2377        iota_transaction_checks::deny::check_transaction_for_validation(
2378            &transaction,
2379            &[],
2380            &input_object_kinds,
2381            &receiving_object_refs,
2382            &self.config.transaction_deny_config,
2383            self.get_backing_package_store().as_ref(),
2384        )?;
2385
2386        // Load input and receiving objects
2387        let (mut input_objects, receiving_objects) = self.input_loader.read_objects_for_signing(
2388            // We don't want to cache this transaction since it's a simulation.
2389            None,
2390            &input_object_kinds,
2391            &receiving_object_refs,
2392            epoch_store.epoch(),
2393        )?;
2394
2395        // Create a mock gas object if one was not provided
2396        let mock_gas_id = if transaction.gas().is_empty() {
2397            let mock_gas_object = mock_simulation_gas_coin(transaction.gas_data().owner);
2398            let mock_gas_object_ref = mock_gas_object.object_ref();
2399            transaction.gas_data_mut().objects = vec![mock_gas_object_ref];
2400            input_objects.push(ObjectReadResult::new_from_gas_object(&mock_gas_object));
2401            Some(mock_gas_object.id())
2402        } else {
2403            None
2404        };
2405
2406        let protocol_config = epoch_store.protocol_config();
2407
2408        // `MoveAuthenticator`s are not supported in simulation, so we set the
2409        // `authenticator_gas_budget` to 0.
2410        let authenticator_gas_budget = 0;
2411
2412        // Checks enabled -> DRY-RUN, it means we are simulating a real TX
2413        // Checks disabled -> DEV-INSPECT, more relaxed Move VM checks
2414        let (gas_status, checked_input_objects) = if checks.enabled() {
2415            iota_transaction_checks::check_transaction_input(
2416                protocol_config,
2417                epoch_store.reference_gas_price(),
2418                &transaction,
2419                input_objects,
2420                &receiving_objects,
2421                &self.metrics.bytecode_verifier_metrics,
2422                &self.config.verifier_signing_config,
2423                authenticator_gas_budget,
2424            )?
2425        } else {
2426            let checked_input_objects = iota_transaction_checks::check_dev_inspect_input(
2427                protocol_config,
2428                transaction.kind(),
2429                input_objects,
2430                receiving_objects,
2431            )?;
2432            let gas_status = IotaGasStatus::new(
2433                transaction.gas_budget(),
2434                transaction.gas_price(),
2435                epoch_store.reference_gas_price(),
2436                protocol_config,
2437            )?;
2438
2439            (gas_status, checked_input_objects)
2440        };
2441
2442        // Create a new executor for the simulation
2443        let executor = iota_execution::executor(
2444            protocol_config,
2445            true, // silent
2446            None,
2447        )
2448        .expect("Creating an executor should not fail here");
2449
2450        // Execute the simulation
2451        let (kind, signer, gas_data) = transaction.execution_parts();
2452        let (inner_temp_store, _, effects, execution_result) = executor.dev_inspect_transaction(
2453            self.get_backing_store().as_ref(),
2454            protocol_config,
2455            self.metrics.limits_metrics.clone(),
2456            false, // expensive_checks
2457            self.config.certificate_deny_config.certificate_deny_set(),
2458            &epoch_store.epoch_start_config().epoch_data().epoch_id(),
2459            epoch_store
2460                .epoch_start_config()
2461                .epoch_data()
2462                .epoch_start_timestamp(),
2463            checked_input_objects,
2464            gas_data,
2465            gas_status,
2466            kind,
2467            signer,
2468            transaction.digest(),
2469            checks.disabled(),
2470        );
2471
2472        // In the case of a dev inspect, the execution_result could be filled with some
2473        // values. Else, execution_result is empty in the case of a dry run.
2474        Ok(SimulateTransactionResult {
2475            input_objects: inner_temp_store.input_objects,
2476            output_objects: inner_temp_store.written,
2477            events: effects.events_digest().map(|_| inner_temp_store.events),
2478            effects,
2479            execution_result,
2480            suggested_gas_price: self
2481                .congestion_tracker
2482                .get_prediction_suggested_gas_price(&transaction),
2483            mock_gas_id,
2484        })
2485    }
2486
2487    /// TO BE DEPRECATED SOON: Use `simulate_transaction` with
2488    /// `VmChecks::DISABLED` instead.
2489    /// The object ID for gas can be any
2490    /// object ID, even for an uncreated object
2491    #[instrument("dev_inspect_tx", level = "trace", skip_all)]
2492    pub async fn dev_inspect_transaction_block(
2493        &self,
2494        sender: Address,
2495        transaction_kind: TransactionKind,
2496        gas_price: Option<u64>,
2497        gas_budget: Option<u64>,
2498        gas_sponsor: Option<Address>,
2499        gas_objects: Option<Vec<ObjectReference>>,
2500        show_raw_txn_data_and_effects: Option<bool>,
2501        skip_checks: Option<bool>,
2502    ) -> IotaResult<DevInspectResults> {
2503        let epoch_store = self.load_epoch_store_one_call_per_task();
2504
2505        if !self.is_fullnode(&epoch_store) {
2506            return Err(IotaError::UnsupportedFeature {
2507                error: "dev-inspect is only supported on fullnodes".to_string(),
2508            });
2509        }
2510
2511        if transaction_kind.is_system() {
2512            return Err(IotaError::UnsupportedFeature {
2513                error: "system transactions are not supported".to_string(),
2514            });
2515        }
2516
2517        let show_raw_txn_data_and_effects = show_raw_txn_data_and_effects.unwrap_or(false);
2518        let skip_checks = skip_checks.unwrap_or(true);
2519        let reference_gas_price = epoch_store.reference_gas_price();
2520        let protocol_config = epoch_store.protocol_config();
2521        let max_tx_gas = protocol_config.max_tx_gas();
2522
2523        let price = gas_price.unwrap_or(reference_gas_price);
2524        let budget = gas_budget.unwrap_or(max_tx_gas);
2525        let owner = gas_sponsor.unwrap_or(sender);
2526        // Payment might be empty here, but it's fine we'll have to deal with it later
2527        // after reading all the input objects.
2528        let payment = gas_objects.unwrap_or_default();
2529        let mut transaction = TransactionData::V1(TransactionDataV1 {
2530            kind: transaction_kind.clone(),
2531            sender,
2532            gas_payment: GasPayment {
2533                objects: payment,
2534                owner,
2535                price,
2536                budget,
2537            },
2538            expiration: TransactionExpiration::None,
2539        });
2540
2541        let raw_txn_data = if show_raw_txn_data_and_effects {
2542            bcs::to_bytes(&transaction).map_err(|_| IotaError::TransactionSerialization {
2543                error: "Failed to serialize transaction during dev inspect".to_string(),
2544            })?
2545        } else {
2546            vec![]
2547        };
2548
2549        transaction.validity_check_no_gas_check(protocol_config)?;
2550
2551        let input_object_kinds = transaction.input_objects()?;
2552        let receiving_object_refs = transaction.receiving_objects();
2553
2554        iota_transaction_checks::deny::check_transaction_for_validation(
2555            &transaction,
2556            &[],
2557            &input_object_kinds,
2558            &receiving_object_refs,
2559            &self.config.transaction_deny_config,
2560            self.get_backing_package_store().as_ref(),
2561        )?;
2562
2563        let (mut input_objects, receiving_objects) = self.input_loader.read_objects_for_signing(
2564            // We don't want to cache this transaction since it's a dev inspect.
2565            None,
2566            &input_object_kinds,
2567            &receiving_object_refs,
2568            epoch_store.epoch(),
2569        )?;
2570
2571        let (gas_status, checked_input_objects) = if skip_checks {
2572            // If we are skipping checks, then we call the check_dev_inspect_input function
2573            // which will perform only lightweight checks on the transaction
2574            // input. And if the gas field is empty, that means we will
2575            // use the dummy gas object so we need to add it to the input objects vector.
2576            if transaction.gas().is_empty() {
2577                // Create and use a dummy gas object if there is no gas object provided.
2578                let dummy_gas_object = Object::new_gas_with_balance_and_owner_for_testing(
2579                    SIMULATION_GAS_COIN_VALUE,
2580                    transaction.gas_owner(),
2581                );
2582                let gas_object_ref = dummy_gas_object.object_ref();
2583                transaction.gas_data_mut().objects = vec![gas_object_ref];
2584                input_objects.push(ObjectReadResult::new(
2585                    InputObjectKind::ImmOrOwnedMoveObject(gas_object_ref),
2586                    dummy_gas_object.into(),
2587                ));
2588            }
2589            let checked_input_objects = iota_transaction_checks::check_dev_inspect_input(
2590                protocol_config,
2591                &transaction_kind,
2592                input_objects,
2593                receiving_objects,
2594            )?;
2595            let gas_status = IotaGasStatus::new(
2596                max_tx_gas,
2597                transaction.gas_price(),
2598                reference_gas_price,
2599                protocol_config,
2600            )?;
2601
2602            (gas_status, checked_input_objects)
2603        } else {
2604            // If we are not skipping checks, then we call the check_transaction_input
2605            // function and its dummy gas variant which will perform full
2606            // fledged checks just like a real transaction execution.
2607            if transaction.gas().is_empty() {
2608                // Create and use a dummy gas object if there is no gas object provided.
2609                let dummy_gas_object = Object::new_gas_with_balance_and_owner_for_testing(
2610                    SIMULATION_GAS_COIN_VALUE,
2611                    transaction.gas_owner(),
2612                );
2613                let gas_object_ref = dummy_gas_object.object_ref();
2614                transaction.gas_data_mut().objects = vec![gas_object_ref];
2615                iota_transaction_checks::check_transaction_input_with_given_gas(
2616                    epoch_store.protocol_config(),
2617                    reference_gas_price,
2618                    &transaction,
2619                    input_objects,
2620                    receiving_objects,
2621                    dummy_gas_object,
2622                    &self.metrics.bytecode_verifier_metrics,
2623                    &self.config.verifier_signing_config,
2624                )?
2625            } else {
2626                // `MoveAuthenticator`s are not supported in dev inspects, so we set the
2627                // `authenticator_gas_budget` to 0.
2628                let authenticator_gas_budget = 0;
2629
2630                iota_transaction_checks::check_transaction_input(
2631                    epoch_store.protocol_config(),
2632                    reference_gas_price,
2633                    &transaction,
2634                    input_objects,
2635                    &receiving_objects,
2636                    &self.metrics.bytecode_verifier_metrics,
2637                    &self.config.verifier_signing_config,
2638                    authenticator_gas_budget,
2639                )?
2640            }
2641        };
2642
2643        let executor = iota_execution::executor(protocol_config, /* silent */ true, None)
2644            .expect("Creating an executor should not fail here");
2645        let gas_data = transaction.gas_data().clone();
2646        let intent_msg = IntentMessage::new(
2647            Intent {
2648                version: IntentVersion::V0,
2649                scope: IntentScope::TransactionData,
2650                app_id: IntentAppId::Iota,
2651            },
2652            transaction,
2653        );
2654        let transaction_digest = TransactionDigest::new(intent_msg.value.digest().into_inner());
2655        let (inner_temp_store, _, effects, execution_result) = executor.dev_inspect_transaction(
2656            self.get_backing_store().as_ref(),
2657            protocol_config,
2658            self.metrics.limits_metrics.clone(),
2659            // expensive checks
2660            false,
2661            self.config.certificate_deny_config.certificate_deny_set(),
2662            &epoch_store.epoch_start_config().epoch_data().epoch_id(),
2663            epoch_store
2664                .epoch_start_config()
2665                .epoch_data()
2666                .epoch_start_timestamp(),
2667            checked_input_objects,
2668            gas_data,
2669            gas_status,
2670            transaction_kind,
2671            sender,
2672            transaction_digest,
2673            skip_checks,
2674        );
2675
2676        let raw_effects = if show_raw_txn_data_and_effects {
2677            bcs::to_bytes(&effects).map_err(|_| IotaError::TransactionSerialization {
2678                error: "Failed to serialize transaction effects during dev inspect".to_string(),
2679            })?
2680        } else {
2681            vec![]
2682        };
2683
2684        let mut layout_resolver =
2685            epoch_store
2686                .executor()
2687                .type_layout_resolver(Box::new(PackageStoreWithFallback::new(
2688                    &inner_temp_store,
2689                    self.get_backing_package_store(),
2690                )));
2691
2692        DevInspectResults::new(
2693            effects,
2694            inner_temp_store.events.clone(),
2695            execution_result,
2696            raw_txn_data,
2697            raw_effects,
2698            layout_resolver.as_mut(),
2699        )
2700    }
2701
2702    // Only used for testing because of how epoch store is loaded.
2703    pub fn reference_gas_price_for_testing(&self) -> Result<u64, anyhow::Error> {
2704        let epoch_store = self.epoch_store_for_testing();
2705        Ok(epoch_store.reference_gas_price())
2706    }
2707
2708    #[instrument(level = "trace", skip_all)]
2709    pub fn try_is_tx_already_executed(&self, digest: &TransactionDigest) -> IotaResult<bool> {
2710        self.get_transaction_cache_reader()
2711            .try_is_tx_already_executed(digest)
2712    }
2713
2714    /// Non-fallible version of `try_is_tx_already_executed`.
2715    pub fn is_tx_already_executed(&self, digest: &TransactionDigest) -> bool {
2716        self.try_is_tx_already_executed(digest)
2717            .expect("storage access failed")
2718    }
2719
2720    /// Indexes a transaction by updating various indexes in the `IndexStore`.
2721    #[instrument(level = "debug", skip_all, err)]
2722    fn index_tx(
2723        &self,
2724        indexes: &IndexStore,
2725        digest: &TransactionDigest,
2726        // TODO: index_tx really just need the transaction data here.
2727        transaction: &VerifiedExecutableTransaction,
2728        effects: &TransactionEffects,
2729        events: &TransactionEvents,
2730        timestamp_ms: u64,
2731        tx_coins: Option<TxCoins>,
2732        written: &WrittenObjects,
2733        inner_temporary_store: &InnerTemporaryStore,
2734        epoch_store: &Arc<AuthorityPerEpochStore>,
2735    ) -> IotaResult<u64> {
2736        let changes = self
2737            .process_object_index(effects, written, inner_temporary_store, epoch_store)
2738            .tap_err(|e| warn!(tx_digest=?digest, "Failed to process object index, index_tx is skipped: {e}"))?;
2739
2740        indexes.index_tx(
2741            transaction.data().intent_message().value.sender(),
2742            transaction
2743                .data()
2744                .intent_message()
2745                .value
2746                .input_objects()?
2747                .iter()
2748                .map(|o| o.object_id()),
2749            effects
2750                .all_changed_objects()
2751                .into_iter()
2752                .map(|(obj_ref, owner, _kind)| (obj_ref, owner)),
2753            transaction
2754                .data()
2755                .intent_message()
2756                .value
2757                .move_calls()
2758                .into_iter()
2759                .map(|(package, module, function)| {
2760                    (*package, module.to_owned(), function.to_owned())
2761                }),
2762            events,
2763            changes,
2764            digest,
2765            timestamp_ms,
2766            tx_coins,
2767        )
2768    }
2769
2770    #[cfg(msim)]
2771    fn create_fail_state(
2772        &self,
2773        transaction: &VerifiedExecutableTransaction,
2774        epoch_store: &Arc<AuthorityPerEpochStore>,
2775        effects: &mut TransactionEffects,
2776    ) {
2777        use std::cell::RefCell;
2778
2779        use iota_types::effects::TransactionEffectsAPIForTesting;
2780        thread_local! {
2781            static FAIL_STATE: RefCell<(u64, HashSet<AuthorityName>)> = RefCell::new((0, HashSet::new()));
2782        }
2783        if !transaction.data().intent_message().value.is_system_tx() {
2784            let committee = epoch_store.committee();
2785            let cur_stake = (**committee).weight(&self.name);
2786            if cur_stake > 0 {
2787                FAIL_STATE.with_borrow_mut(|fail_state| {
2788                    // let (&mut failing_stake, &mut failing_validators) = fail_state;
2789                    if fail_state.0 < committee.validity_threshold() {
2790                        fail_state.0 += cur_stake;
2791                        fail_state.1.insert(self.name);
2792                    }
2793
2794                    if fail_state.1.contains(&self.name) {
2795                        info!("cp_exec failing tx");
2796                        effects.gas_cost_summary_mut_for_testing().computation_cost += 1;
2797                    }
2798                });
2799            }
2800        }
2801    }
2802
2803    fn process_object_index(
2804        &self,
2805        effects: &TransactionEffects,
2806        written: &WrittenObjects,
2807        inner_temporary_store: &InnerTemporaryStore,
2808        epoch_store: &Arc<AuthorityPerEpochStore>,
2809    ) -> IotaResult<ObjectIndexChanges> {
2810        let mut layout_resolver =
2811            epoch_store
2812                .executor()
2813                .type_layout_resolver(Box::new(PackageStoreWithFallback::new(
2814                    inner_temporary_store,
2815                    self.get_backing_package_store(),
2816                )));
2817
2818        let modified_at_version = effects
2819            .modified_at_versions()
2820            .into_iter()
2821            .collect::<HashMap<_, _>>();
2822
2823        let tx_digest = effects.transaction_digest();
2824        let mut deleted_owners = vec![];
2825        let mut deleted_dynamic_fields = vec![];
2826        for object_ref in effects.deleted().into_iter().chain(effects.wrapped()) {
2827            let old_version = modified_at_version.get(&object_ref.object_id).unwrap();
2828            // When we process the index, the latest object hasn't been written yet so
2829            // the old object must be present.
2830            match self.get_owner_at_version(&object_ref.object_id, *old_version).unwrap_or_else(
2831                |e| panic!("tx_digest={tx_digest}, error processing object owner index, cannot find owner for object {} at version {old_version:?}. Err: {e:?}", object_ref.object_id)
2832            ) {
2833                Owner::Address(addr) => deleted_owners.push((addr, object_ref.object_id)),
2834                Owner::Object(object_id) => {
2835                    deleted_dynamic_fields.push((object_id, object_ref.object_id))
2836                }
2837                _ => {}
2838            }
2839        }
2840
2841        let mut new_owners = vec![];
2842        let mut new_dynamic_fields = vec![];
2843
2844        for (oref, owner, kind) in effects.all_changed_objects() {
2845            let id = &oref.object_id;
2846            // For mutated objects, retrieve old owner and delete old index if there is a
2847            // owner change.
2848            if let WriteKind::Mutate = kind {
2849                let Some(old_version) = modified_at_version.get(id) else {
2850                    panic!(
2851                        "tx_digest={tx_digest}, error processing object owner index, cannot find modified at version for mutated object [{id}]."
2852                    );
2853                };
2854                // When we process the index, the latest object hasn't been written yet so
2855                // the old object must be present.
2856                let Some(old_object) = self
2857                    .get_object_store()
2858                    .try_get_object_by_key(id, *old_version)?
2859                else {
2860                    panic!(
2861                        "tx_digest={tx_digest}, error processing object owner index, cannot find owner for object {id} at version {old_version:?}"
2862                    );
2863                };
2864                if old_object.owner != owner {
2865                    match old_object.owner {
2866                        Owner::Address(addr) => {
2867                            deleted_owners.push((addr, *id));
2868                        }
2869                        Owner::Object(object_id) => deleted_dynamic_fields.push((object_id, *id)),
2870                        _ => {}
2871                    }
2872                }
2873            }
2874
2875            match owner {
2876                Owner::Address(addr) => {
2877                    // TODO: We can remove the object fetching after we added ObjectType to
2878                    // TransactionEffects
2879                    let new_object = written.get(id).unwrap_or_else(
2880                        || panic!("tx_digest={tx_digest}, error processing object owner index, written does not contain object {id}")
2881                    );
2882                    assert_eq!(
2883                        new_object.version(),
2884                        oref.version,
2885                        "tx_digest={} error processing object owner index, object {} from written has mismatched version. Actual: {}, expected: {}",
2886                        tx_digest,
2887                        id,
2888                        new_object.version(),
2889                        oref.version
2890                    );
2891
2892                    let type_ = new_object
2893                        .type_()
2894                        .map(|type_| ObjectType::Struct(type_.clone()))
2895                        .unwrap_or(ObjectType::Package);
2896
2897                    new_owners.push((
2898                        (addr, *id),
2899                        ObjectInfo {
2900                            object_id: *id,
2901                            version: oref.version,
2902                            digest: oref.digest,
2903                            type_,
2904                            owner,
2905                            previous_transaction: *effects.transaction_digest(),
2906                        },
2907                    ));
2908                }
2909                Owner::Object(owner) => {
2910                    let new_object = written.get(id).unwrap_or_else(
2911                        || panic!("tx_digest={tx_digest}, error processing object owner index, written does not contain object {id}")
2912                    );
2913                    assert_eq!(
2914                        new_object.version(),
2915                        oref.version,
2916                        "tx_digest={} error processing object owner index, object {} from written has mismatched version. Actual: {}, expected: {}",
2917                        tx_digest,
2918                        id,
2919                        new_object.version(),
2920                        oref.version
2921                    );
2922
2923                    let Some(df_info) = self
2924                        .try_create_dynamic_field_info(new_object, written, layout_resolver.as_mut())
2925                        .unwrap_or_else(|e| {
2926                            error!("try_create_dynamic_field_info should not fail, {}, new_object={:?}", e, new_object);
2927                            None
2928                        }
2929                        )
2930                    else {
2931                        // Skip indexing for non dynamic field objects.
2932                        continue;
2933                    };
2934                    new_dynamic_fields.push(((owner, *id), df_info))
2935                }
2936                _ => {}
2937            }
2938        }
2939
2940        Ok(ObjectIndexChanges {
2941            deleted_owners,
2942            deleted_dynamic_fields,
2943            new_owners,
2944            new_dynamic_fields,
2945        })
2946    }
2947
2948    fn try_create_dynamic_field_info(
2949        &self,
2950        o: &Object,
2951        written: &WrittenObjects,
2952        resolver: &mut dyn LayoutResolver,
2953    ) -> IotaResult<Option<DynamicFieldInfo>> {
2954        // Skip if not a move object
2955        let Some(move_object) = o.data.as_opt_struct().cloned() else {
2956            return Ok(None);
2957        };
2958
2959        // We only index dynamic field objects
2960        if !move_object.struct_tag().is_dynamic_field() {
2961            return Ok(None);
2962        }
2963
2964        let layout = match resolver.get_annotated_layout(move_object.struct_tag()) {
2965            Ok(annotated_layout) => annotated_layout.into_layout(),
2966            Err(e) => {
2967                error!(
2968                    "unable to load layout for type `{:?}`: {e}",
2969                    move_object.struct_tag()
2970                );
2971                return Ok(None);
2972            }
2973        };
2974
2975        let field =
2976            DFV::FieldVisitor::deserialize(move_object.contents(), &layout).map_err(|e| {
2977                IotaError::ObjectDeserialization {
2978                    error: e.to_string(),
2979                }
2980            })?;
2981
2982        let type_ = field.kind;
2983        let name_type: TypeTag = type_tag_core_to_sdk(&field.name_layout.into());
2984        let bcs_name = field.name_bytes.to_owned();
2985
2986        let name_value = BoundedVisitor::deserialize_value(field.name_bytes, field.name_layout)
2987            .map_err(|e| {
2988                warn!("{e}");
2989                IotaError::ObjectDeserialization {
2990                    error: e.to_string(),
2991                }
2992            })?;
2993
2994        let name = DynamicFieldName {
2995            type_: name_type,
2996            value: IotaMoveValue::from(name_value).to_json_value(),
2997        };
2998
2999        let value_metadata = field.value_metadata().map_err(|e| {
3000            warn!("{e}");
3001            IotaError::ObjectDeserialization {
3002                error: e.to_string(),
3003            }
3004        })?;
3005
3006        Ok(Some(match value_metadata {
3007            DFV::ValueMetadata::DynamicField(object_type) => DynamicFieldInfo {
3008                name,
3009                bcs_name,
3010                type_,
3011                object_type: object_type.to_canonical_string(/* with_prefix */ true),
3012                object_id: o.id(),
3013                version: o.version(),
3014                digest: o.digest(),
3015            },
3016
3017            DFV::ValueMetadata::DynamicObjectField(object_id) => {
3018                // Find the actual object from storage using the object id obtained from the
3019                // wrapper.
3020
3021                // Try to find the object in the written objects first.
3022                let (version, digest, object_type) = if let Some(object) = written.get(&object_id) {
3023                    (
3024                        object.version(),
3025                        object.digest(),
3026                        object.data.opt_object_type().unwrap().clone(),
3027                    )
3028                } else {
3029                    // If not found, try to find it in the database.
3030                    let object = self
3031                        .get_object_store()
3032                        .try_get_object_by_key(&object_id, o.version())?
3033                        .ok_or_else(|| UserInputError::ObjectNotFound {
3034                            object_id,
3035                            version: Some(o.version()),
3036                        })?;
3037                    let version = object.version();
3038                    let digest = object.digest();
3039                    let object_type = object.data.opt_object_type().unwrap().clone();
3040                    (version, digest, object_type)
3041                };
3042
3043                DynamicFieldInfo {
3044                    name,
3045                    bcs_name,
3046                    type_,
3047                    object_type: object_type.to_string(),
3048                    object_id,
3049                    version,
3050                    digest,
3051                }
3052            }
3053        }))
3054    }
3055
3056    #[instrument(level = "trace", skip_all, err)]
3057    fn post_process_one_tx(
3058        &self,
3059        transaction: &VerifiedExecutableTransaction,
3060        effects: &TransactionEffects,
3061        inner_temporary_store: &InnerTemporaryStore,
3062        epoch_store: &Arc<AuthorityPerEpochStore>,
3063    ) -> IotaResult {
3064        if self.indexes.is_none() {
3065            return Ok(());
3066        }
3067
3068        let _scope = monitored_scope("Execution::post_process_one_tx");
3069
3070        let tx_digest = transaction.digest();
3071        let timestamp_ms = Self::unixtime_now_ms();
3072        let events = &inner_temporary_store.events;
3073        let written = &inner_temporary_store.written;
3074        let tx_coins = self.fullnode_only_get_tx_coins_for_indexing(
3075            effects,
3076            inner_temporary_store,
3077            epoch_store,
3078        );
3079
3080        // Index tx
3081        if let Some(indexes) = &self.indexes {
3082            let _ = self
3083                .index_tx(
3084                    indexes.as_ref(),
3085                    tx_digest,
3086                    transaction,
3087                    effects,
3088                    events,
3089                    timestamp_ms,
3090                    tx_coins,
3091                    written,
3092                    inner_temporary_store,
3093                    epoch_store,
3094                )
3095                .tap_ok(|_| self.metrics.post_processing_total_tx_indexed.inc())
3096                .tap_err(|e| error!(?tx_digest, "Post processing - Couldn't index tx: {e}"))
3097                .expect("Indexing tx should not fail");
3098
3099            let effects: IotaTransactionBlockEffects = effects.clone().try_into()?;
3100            let events = self.make_transaction_block_events(
3101                events.clone(),
3102                *tx_digest,
3103                timestamp_ms,
3104                epoch_store,
3105                inner_temporary_store,
3106            )?;
3107            // Emit events
3108            self.subscription_handler
3109                .process_tx(transaction.data().transaction_data(), &effects, &events)
3110                .tap_ok(|_| {
3111                    self.metrics
3112                        .post_processing_total_tx_had_event_processed
3113                        .inc()
3114                })
3115                .tap_err(|e| {
3116                    warn!(
3117                        ?tx_digest,
3118                        "Post processing - Couldn't process events for tx: {}", e
3119                    )
3120                })?;
3121
3122            self.metrics
3123                .post_processing_total_events_emitted
3124                .inc_by(events.data.len() as u64);
3125        };
3126        Ok(())
3127    }
3128
3129    fn make_transaction_block_events(
3130        &self,
3131        transaction_events: TransactionEvents,
3132        digest: TransactionDigest,
3133        timestamp_ms: u64,
3134        epoch_store: &Arc<AuthorityPerEpochStore>,
3135        inner_temporary_store: &InnerTemporaryStore,
3136    ) -> IotaResult<IotaTransactionBlockEvents> {
3137        let mut layout_resolver =
3138            epoch_store
3139                .executor()
3140                .type_layout_resolver(Box::new(PackageStoreWithFallback::new(
3141                    inner_temporary_store,
3142                    self.get_backing_package_store(),
3143                )));
3144        IotaTransactionBlockEvents::try_from(
3145            transaction_events,
3146            digest,
3147            Some(timestamp_ms),
3148            layout_resolver.as_mut(),
3149        )
3150    }
3151
3152    pub fn unixtime_now_ms() -> u64 {
3153        let now = SystemTime::now()
3154            .duration_since(UNIX_EPOCH)
3155            .expect("Time went backwards")
3156            .as_millis();
3157        u64::try_from(now).expect("Travelling in time machine")
3158    }
3159
3160    #[instrument(level = "trace", skip_all)]
3161    pub async fn handle_transaction_info_request(
3162        &self,
3163        request: TransactionInfoRequest,
3164    ) -> IotaResult<TransactionInfoResponse> {
3165        let epoch_store = self.load_epoch_store_one_call_per_task();
3166        let (transaction, status) = self
3167            .get_transaction_status(&request.transaction_digest, &epoch_store)?
3168            .ok_or(IotaError::TransactionNotFound {
3169                digest: request.transaction_digest,
3170            })?;
3171        Ok(TransactionInfoResponse {
3172            transaction,
3173            status,
3174        })
3175    }
3176
3177    #[instrument(level = "trace", skip_all)]
3178    pub async fn handle_object_info_request(
3179        &self,
3180        request: ObjectInfoRequest,
3181    ) -> IotaResult<ObjectInfoResponse> {
3182        let epoch_store = self.load_epoch_store_one_call_per_task();
3183
3184        let requested_object_seq = match request.request_kind {
3185            ObjectInfoRequestKind::LatestObjectInfo => {
3186                self.try_get_object_or_tombstone(request.object_id)?
3187                    .ok_or_else(|| {
3188                        IotaError::from(UserInputError::ObjectNotFound {
3189                            object_id: request.object_id,
3190                            version: None,
3191                        })
3192                    })?
3193                    .version
3194            }
3195            ObjectInfoRequestKind::PastObjectInfoDebug(seq) => seq,
3196        };
3197
3198        let object = self
3199            .get_object_store()
3200            .try_get_object_by_key(&request.object_id, requested_object_seq)?
3201            .ok_or_else(|| {
3202                IotaError::from(UserInputError::ObjectNotFound {
3203                    object_id: request.object_id,
3204                    version: Some(requested_object_seq),
3205                })
3206            })?;
3207
3208        let layout = if let (LayoutGenerationOption::Generate, Some(move_obj)) =
3209            (request.generate_layout, object.data.as_opt_struct())
3210        {
3211            Some(into_struct_layout(
3212                epoch_store
3213                    .executor()
3214                    .type_layout_resolver(Box::new(self.get_backing_package_store().as_ref()))
3215                    .get_annotated_layout(move_obj.struct_tag())?,
3216            )?)
3217        } else {
3218            None
3219        };
3220
3221        let lock = if !object.is_address_owned() {
3222            // Only address owned objects have locks.
3223            None
3224        } else {
3225            self.get_transaction_lock(&object.object_ref(), &epoch_store)?
3226                .map(|s| s.into_inner())
3227        };
3228
3229        Ok(ObjectInfoResponse {
3230            object,
3231            layout,
3232            lock_for_debugging: lock,
3233        })
3234    }
3235
3236    #[instrument(level = "trace", skip_all)]
3237    pub fn handle_checkpoint_request(
3238        &self,
3239        request: &CheckpointRequest,
3240    ) -> IotaResult<CheckpointResponse> {
3241        let summary = if request.certified {
3242            let summary = match request.sequence_number {
3243                Some(seq) => self
3244                    .checkpoint_store
3245                    .get_checkpoint_by_sequence_number(seq)?,
3246                None => self.checkpoint_store.get_latest_certified_checkpoint()?,
3247            }
3248            .map(|v| v.into_inner());
3249            summary.map(CheckpointSummaryResponse::Certified)
3250        } else {
3251            let summary = match request.sequence_number {
3252                Some(seq) => self.checkpoint_store.get_locally_computed_checkpoint(seq)?,
3253                None => self
3254                    .checkpoint_store
3255                    .get_latest_locally_computed_checkpoint()?,
3256            };
3257            summary.map(CheckpointSummaryResponse::Pending)
3258        };
3259        let contents = match &summary {
3260            Some(s) => self
3261                .checkpoint_store
3262                .get_checkpoint_contents(&s.content_digest())?,
3263            None => None,
3264        };
3265        Ok(CheckpointResponse {
3266            checkpoint: summary,
3267            contents,
3268        })
3269    }
3270
3271    fn check_protocol_version(
3272        supported_protocol_versions: SupportedProtocolVersions,
3273        current_version: ProtocolVersion,
3274    ) {
3275        info!("current protocol version is now {:?}", current_version);
3276        info!("supported versions are: {:?}", supported_protocol_versions);
3277        if !supported_protocol_versions.is_version_supported(current_version) {
3278            let msg = format!(
3279                "Unsupported protocol version. The network is at {current_version:?}, but this IotaNode only supports: {supported_protocol_versions:?}. Shutting down.",
3280            );
3281
3282            error!("{}", msg);
3283            eprintln!("{msg}");
3284
3285            #[cfg(not(msim))]
3286            std::process::exit(1);
3287
3288            #[cfg(msim)]
3289            iota_simulator::task::shutdown_current_node();
3290        }
3291    }
3292
3293    #[expect(clippy::disallowed_methods)] // allow unbounded_channel()
3294    #[expect(clippy::too_many_arguments)]
3295    pub async fn new(
3296        name: AuthorityName,
3297        secret: StableSyncAuthoritySigner,
3298        supported_protocol_versions: SupportedProtocolVersions,
3299        store: Arc<AuthorityStore>,
3300        execution_cache_trait_pointers: ExecutionCacheTraitPointers,
3301        epoch_store: Arc<AuthorityPerEpochStore>,
3302        committee_store: Arc<CommitteeStore>,
3303        indexes: Option<Arc<IndexStore>>,
3304        grpc_indexes_store: Option<Arc<GrpcIndexesStore>>,
3305        checkpoint_store: Arc<CheckpointStore>,
3306        prometheus_registry: &Registry,
3307        genesis_objects: &[Object],
3308        db_checkpoint_config: &DBCheckpointConfig,
3309        config: NodeConfig,
3310        archive_readers: ArchiveReaderBalancer,
3311        validator_tx_finalizer: Option<Arc<ValidatorTxFinalizer<NetworkAuthorityClient>>>,
3312        chain_identifier: ChainIdentifier,
3313        pruner_db: Option<Arc<AuthorityPrunerTables>>,
3314        checkpoint_progress_tracker: Option<Arc<CheckpointProgressTracker>>,
3315        policy_config: Option<PolicyConfig>,
3316        firewall_config: Option<RemoteFirewallConfig>,
3317    ) -> Arc<Self> {
3318        Self::check_protocol_version(supported_protocol_versions, epoch_store.protocol_version());
3319
3320        let metrics = Arc::new(AuthorityMetrics::new(prometheus_registry));
3321        let (tx_ready_transactions, rx_ready_transactions) = unbounded_channel();
3322        let transaction_manager = Arc::new(TransactionManager::new(
3323            execution_cache_trait_pointers.object_cache_reader.clone(),
3324            execution_cache_trait_pointers
3325                .transaction_cache_reader
3326                .clone(),
3327            &epoch_store,
3328            tx_ready_transactions,
3329            metrics.clone(),
3330        ));
3331        let (tx_execution_shutdown, rx_execution_shutdown) = oneshot::channel();
3332
3333        let authority_per_epoch_pruner = AuthorityPerEpochStorePruner::new(
3334            epoch_store.get_parent_path(),
3335            config
3336                .authority_store_pruning_config
3337                .num_latest_epoch_dbs_to_retain,
3338        )
3339        .await;
3340        let pruner = AuthorityStorePruner::new(
3341            store.perpetual_tables.clone(),
3342            checkpoint_store.clone(),
3343            grpc_indexes_store.clone(),
3344            indexes.clone(),
3345            config.authority_store_pruning_config.clone(),
3346            epoch_store.committee().authority_exists(&name),
3347            epoch_store.epoch_start_state().epoch_duration_ms(),
3348            prometheus_registry,
3349            archive_readers,
3350            pruner_db,
3351            checkpoint_progress_tracker.clone(),
3352        );
3353        let input_loader =
3354            TransactionInputLoader::new(execution_cache_trait_pointers.object_cache_reader.clone());
3355        let epoch = epoch_store.epoch();
3356        let rgp = epoch_store.reference_gas_price();
3357        let traffic_controller_metrics =
3358            Arc::new(TrafficControllerMetrics::new(prometheus_registry));
3359        let traffic_controller = if let Some(policy_config) = policy_config {
3360            Some(Arc::new(
3361                TrafficController::init(
3362                    policy_config,
3363                    traffic_controller_metrics,
3364                    firewall_config.clone(),
3365                )
3366                .await,
3367            ))
3368        } else {
3369            None
3370        };
3371        let state = Arc::new(AuthorityState {
3372            name,
3373            secret,
3374            execution_lock: RwLock::new(epoch),
3375            epoch_store: ArcSwap::new(epoch_store.clone()),
3376            input_loader,
3377            execution_cache_trait_pointers,
3378            indexes,
3379            grpc_indexes_store,
3380            subscription_handler: Arc::new(SubscriptionHandler::new(prometheus_registry)),
3381            checkpoint_store,
3382            committee_store,
3383            transaction_manager,
3384            tx_execution_shutdown: Mutex::new(Some(tx_execution_shutdown)),
3385            metrics,
3386            pruner,
3387            authority_per_epoch_pruner,
3388            checkpoint_progress_tracker,
3389            db_checkpoint_config: db_checkpoint_config.clone(),
3390            config,
3391            overload_info: AuthorityOverloadInfo::default(),
3392            validator_tx_finalizer,
3393            chain_identifier,
3394            congestion_tracker: Arc::new(CongestionTracker::new(rgp)),
3395            traffic_controller,
3396        });
3397
3398        // Start a task to execute ready transactions.
3399        let authority_state = Arc::downgrade(&state);
3400        spawn_monitored_task!(execution_process(
3401            authority_state,
3402            rx_ready_transactions,
3403            rx_execution_shutdown,
3404        ));
3405        spawn_monitored_task!(authority_store_migrations::migrate_events(store));
3406
3407        // TODO: This doesn't belong to the constructor of AuthorityState.
3408        state
3409            .create_owner_index_if_empty(genesis_objects, &epoch_store)
3410            .expect("Error indexing genesis objects.");
3411
3412        state
3413    }
3414
3415    pub fn epoch_db_pruner(&self) -> &AuthorityPerEpochStorePruner {
3416        &self.authority_per_epoch_pruner
3417    }
3418
3419    // TODO: Consolidate our traits to reduce the number of methods here.
3420    pub fn get_object_cache_reader(&self) -> &Arc<dyn ObjectCacheRead> {
3421        &self.execution_cache_trait_pointers.object_cache_reader
3422    }
3423
3424    pub fn get_transaction_cache_reader(&self) -> &Arc<dyn TransactionCacheRead> {
3425        &self.execution_cache_trait_pointers.transaction_cache_reader
3426    }
3427
3428    pub fn get_cache_writer(&self) -> &Arc<dyn ExecutionCacheWrite> {
3429        &self.execution_cache_trait_pointers.cache_writer
3430    }
3431
3432    pub fn get_backing_store(&self) -> &Arc<dyn BackingStore + Send + Sync> {
3433        &self.execution_cache_trait_pointers.backing_store
3434    }
3435
3436    pub fn get_backing_package_store(&self) -> &Arc<dyn BackingPackageStore + Send + Sync> {
3437        &self.execution_cache_trait_pointers.backing_package_store
3438    }
3439
3440    pub fn get_object_store(&self) -> &Arc<dyn ObjectStore + Send + Sync> {
3441        &self.execution_cache_trait_pointers.object_store
3442    }
3443
3444    pub fn get_reconfig_api(&self) -> &Arc<dyn ExecutionCacheReconfigAPI> {
3445        &self.execution_cache_trait_pointers.reconfig_api
3446    }
3447
3448    pub fn get_global_state_hash_store(&self) -> &Arc<dyn GlobalStateHashStore> {
3449        &self.execution_cache_trait_pointers.global_state_hash_store
3450    }
3451
3452    pub fn get_checkpoint_cache(&self) -> &Arc<dyn CheckpointCache> {
3453        &self.execution_cache_trait_pointers.checkpoint_cache
3454    }
3455
3456    pub fn get_state_sync_store(&self) -> &Arc<dyn StateSyncAPI> {
3457        &self.execution_cache_trait_pointers.state_sync_store
3458    }
3459
3460    pub fn get_cache_commit(&self) -> &Arc<dyn ExecutionCacheCommit> {
3461        &self.execution_cache_trait_pointers.cache_commit
3462    }
3463
3464    pub fn database_for_testing(&self) -> Arc<AuthorityStore> {
3465        self.execution_cache_trait_pointers
3466            .testing_api
3467            .database_for_testing()
3468    }
3469
3470    pub async fn prune_checkpoints_for_eligible_epochs_for_testing(
3471        &self,
3472        config: NodeConfig,
3473        metrics: Arc<AuthorityStorePruningMetrics>,
3474    ) -> anyhow::Result<()> {
3475        let archive_readers =
3476            ArchiveReaderBalancer::new(config.archive_reader_config(), &Registry::default())?;
3477        AuthorityStorePruner::prune_checkpoints_for_eligible_epochs(
3478            &self.database_for_testing().perpetual_tables,
3479            &self.checkpoint_store,
3480            self.grpc_indexes_store.as_deref(),
3481            None,
3482            config.authority_store_pruning_config,
3483            metrics,
3484            archive_readers,
3485            EPOCH_DURATION_MS_FOR_TESTING,
3486            self.checkpoint_progress_tracker.as_ref(),
3487        )
3488        .await
3489    }
3490
3491    pub fn transaction_manager(&self) -> &Arc<TransactionManager> {
3492        &self.transaction_manager
3493    }
3494
3495    /// Adds transactions / certificates to transaction manager for ordered
3496    /// execution.
3497    pub fn enqueue_transactions_for_execution(
3498        &self,
3499        transactions: Vec<VerifiedExecutableTransaction>,
3500        epoch_store: &Arc<AuthorityPerEpochStore>,
3501    ) {
3502        self.transaction_manager.enqueue(transactions, epoch_store)
3503    }
3504
3505    /// Adds certificates to transaction manager for ordered execution.
3506    pub fn enqueue_certificates_for_execution(
3507        &self,
3508        certs: Vec<VerifiedCertificate>,
3509        epoch_store: &Arc<AuthorityPerEpochStore>,
3510    ) {
3511        self.transaction_manager
3512            .enqueue_certificates(certs, epoch_store)
3513    }
3514
3515    pub fn enqueue_with_expected_effects_digest(
3516        &self,
3517        transactions: Vec<(VerifiedExecutableTransaction, TransactionEffectsDigest)>,
3518        epoch_store: &AuthorityPerEpochStore,
3519    ) {
3520        self.transaction_manager
3521            .enqueue_with_expected_effects_digest(transactions, epoch_store)
3522    }
3523
3524    fn create_owner_index_if_empty(
3525        &self,
3526        genesis_objects: &[Object],
3527        epoch_store: &Arc<AuthorityPerEpochStore>,
3528    ) -> IotaResult {
3529        let Some(index_store) = &self.indexes else {
3530            return Ok(());
3531        };
3532        if !index_store.is_empty() {
3533            return Ok(());
3534        }
3535
3536        let mut new_owners = vec![];
3537        let mut new_dynamic_fields = vec![];
3538        let mut layout_resolver = epoch_store
3539            .executor()
3540            .type_layout_resolver(Box::new(self.get_backing_package_store().as_ref()));
3541        for o in genesis_objects.iter() {
3542            match o.owner {
3543                Owner::Address(addr) => {
3544                    new_owners.push(((addr, o.id()), ObjectInfo::new(&o.object_ref(), o)))
3545                }
3546                Owner::Object(object_id) => {
3547                    let id = o.id();
3548                    let info = match self.try_create_dynamic_field_info(
3549                        o,
3550                        &BTreeMap::new(),
3551                        layout_resolver.as_mut(),
3552                    ) {
3553                        Ok(Some(info)) => info,
3554                        Ok(None) => continue,
3555                        Err(IotaError::UserInput {
3556                            error:
3557                                UserInputError::ObjectNotFound {
3558                                    object_id: not_found_id,
3559                                    version,
3560                                },
3561                        }) => {
3562                            warn!(
3563                                ?not_found_id,
3564                                ?version,
3565                                object_owner=?object_id,
3566                                field=?id,
3567                                "Skipping dynamic field: referenced genesis object not found"
3568                            );
3569                            continue;
3570                        }
3571                        Err(e) => return Err(e),
3572                    };
3573                    new_dynamic_fields.push(((object_id, id), info));
3574                }
3575                _ => {}
3576            }
3577        }
3578
3579        index_store.insert_genesis_objects(ObjectIndexChanges {
3580            deleted_owners: vec![],
3581            deleted_dynamic_fields: vec![],
3582            new_owners,
3583            new_dynamic_fields,
3584        })
3585    }
3586
3587    /// Attempts to acquire execution lock for an executable transaction.
3588    /// Returns the lock if the transaction is matching current executed epoch
3589    /// Returns None otherwise
3590    pub fn execution_lock_for_executable_transaction(
3591        &self,
3592        transaction: &VerifiedExecutableTransaction,
3593    ) -> IotaResult<ExecutionLockReadGuard<'_>> {
3594        let lock = self
3595            .execution_lock
3596            .try_read()
3597            .map_err(|_| IotaError::ValidatorHaltedAtEpochEnd)?;
3598        if *lock == transaction.auth_sig().epoch() {
3599            Ok(lock)
3600        } else {
3601            Err(IotaError::WrongEpoch {
3602                expected_epoch: *lock,
3603                actual_epoch: transaction.auth_sig().epoch(),
3604            })
3605        }
3606    }
3607
3608    /// Acquires the execution lock for the duration of a transaction signing
3609    /// request. This prevents reconfiguration from starting until we are
3610    /// finished handling the signing request. Otherwise, in-memory lock
3611    /// state could be cleared (by `ObjectLocks::clear_cached_locks`)
3612    /// while we are attempting to acquire locks for the transaction.
3613    pub fn execution_lock_for_signing(&self) -> IotaResult<ExecutionLockReadGuard<'_>> {
3614        self.execution_lock
3615            .try_read()
3616            .map_err(|_| IotaError::ValidatorHaltedAtEpochEnd)
3617    }
3618
3619    pub async fn execution_lock_for_reconfiguration(&self) -> ExecutionLockWriteGuard<'_> {
3620        self.execution_lock.write().await
3621    }
3622
3623    #[instrument(level = "error", skip_all)]
3624    pub async fn reconfigure(
3625        &self,
3626        cur_epoch_store: &AuthorityPerEpochStore,
3627        supported_protocol_versions: SupportedProtocolVersions,
3628        new_committee: Committee,
3629        epoch_start_configuration: EpochStartConfiguration,
3630        state_hasher: Arc<GlobalStateHasher>,
3631        expensive_safety_check_config: &ExpensiveSafetyCheckConfig,
3632        epoch_supply_change: i64,
3633        epoch_last_checkpoint: CheckpointSequenceNumber,
3634    ) -> IotaResult<Arc<AuthorityPerEpochStore>> {
3635        Self::check_protocol_version(
3636            supported_protocol_versions,
3637            epoch_start_configuration
3638                .epoch_start_state()
3639                .protocol_version(),
3640        );
3641        self.metrics.reset_on_reconfigure();
3642        self.committee_store.insert_new_committee(&new_committee)?;
3643
3644        // Wait until no transactions are being executed.
3645        let mut execution_lock = self.execution_lock_for_reconfiguration().await;
3646
3647        // Terminate all epoch-specific tasks (those started with within_alive_epoch).
3648        cur_epoch_store.epoch_terminated().await;
3649
3650        let highest_locally_built_checkpoint_seq = self
3651            .checkpoint_store
3652            .get_latest_locally_computed_checkpoint()?
3653            .map(|c| c.sequence_number())
3654            .unwrap_or(0);
3655
3656        assert!(
3657            epoch_last_checkpoint >= highest_locally_built_checkpoint_seq,
3658            "expected {epoch_last_checkpoint} >= {highest_locally_built_checkpoint_seq}"
3659        );
3660        if highest_locally_built_checkpoint_seq == epoch_last_checkpoint
3661            || self.is_fullnode(cur_epoch_store)
3662        {
3663            // if we built the last checkpoint locally (as opposed to receiving it from a
3664            // peer), then all shared_version_assignments except the one for the
3665            // ChangeEpoch transaction should have been removed
3666            let num_shared_version_assignments = cur_epoch_store.num_shared_version_assignments();
3667            // Due to (otherwise harmless) race conditions between CheckpointExecutor and
3668            // ConsensusHandler, we actually can't guarantee that all
3669            // shared_version_assignments have been removed. However,
3670            // typically at most 2 or 3 are left over. We leave this check here in order to
3671            // catch complete failure of cleanup which would cause a memory
3672            // leak.
3673            if num_shared_version_assignments > 10 {
3674                // If this happens in prod, we have a memory leak, but not a correctness issue.
3675                debug_fatal!(
3676                    "all shared_version_assignments should have been removed \
3677                    (num_shared_version_assignments: {num_shared_version_assignments})"
3678                );
3679            }
3680        }
3681
3682        // Safe to reconfigure now. No transactions are being executed,
3683        // and no epoch-specific tasks are running.
3684
3685        // TODO: revert_uncommitted_epoch_transactions will soon be unnecessary -
3686        // clear_state_end_of_epoch() can simply drop all uncommitted transactions
3687        self.revert_uncommitted_epoch_transactions(cur_epoch_store)
3688            .await?;
3689        self.get_reconfig_api()
3690            .clear_state_end_of_epoch(&execution_lock);
3691        self.check_system_consistency(
3692            cur_epoch_store,
3693            state_hasher,
3694            expensive_safety_check_config,
3695            epoch_supply_change,
3696        )?;
3697        self.get_reconfig_api()
3698            .try_set_epoch_start_configuration(&epoch_start_configuration)?;
3699        if let Some(checkpoint_path) = &self.db_checkpoint_config.checkpoint_path {
3700            if self
3701                .db_checkpoint_config
3702                .perform_db_checkpoints_at_epoch_end
3703            {
3704                let checkpoint_indexes = self
3705                    .db_checkpoint_config
3706                    .perform_index_db_checkpoints_at_epoch_end
3707                    .unwrap_or(false);
3708                let current_epoch = cur_epoch_store.epoch();
3709                let epoch_checkpoint_path = checkpoint_path.join(format!("epoch_{current_epoch}"));
3710                self.checkpoint_all_dbs(
3711                    &epoch_checkpoint_path,
3712                    cur_epoch_store,
3713                    checkpoint_indexes,
3714                )?;
3715            }
3716        }
3717
3718        let new_epoch = new_committee.epoch;
3719        let new_epoch_store = self
3720            .reopen_epoch_db(
3721                cur_epoch_store,
3722                new_committee,
3723                epoch_start_configuration,
3724                expensive_safety_check_config,
3725                epoch_last_checkpoint,
3726            )
3727            .await?;
3728        assert_eq!(new_epoch_store.epoch(), new_epoch);
3729        self.transaction_manager.reconfigure(new_epoch);
3730        *execution_lock = new_epoch;
3731        // drop execution_lock after epoch store was updated
3732        // see also assert in AuthorityState::process_transaction
3733        // on the epoch store and execution lock epoch match
3734        Ok(new_epoch_store)
3735    }
3736
3737    /// Advance the epoch store to the next epoch for testing only.
3738    /// This only manually sets all the places where we have the epoch number.
3739    /// It doesn't properly reconfigure the node, hence should be only used for
3740    /// testing.
3741    pub async fn reconfigure_for_testing(&self) {
3742        let mut execution_lock = self.execution_lock_for_reconfiguration().await;
3743        let epoch_store = self.epoch_store_for_testing().clone();
3744        let protocol_config = epoch_store.protocol_config().clone();
3745        // The current protocol config used in the epoch store may have been overridden
3746        // and diverged from the protocol config definitions. That override may
3747        // have now been dropped when the initial guard was dropped. We reapply
3748        // the override before creating the new epoch store, to make sure that
3749        // the new epoch store has the same protocol config as the current one.
3750        // Since this is for testing only, we mostly like to keep the protocol config
3751        // the same across epochs.
3752        let _guard =
3753            ProtocolConfig::apply_overrides_for_testing(move |_, _| protocol_config.clone());
3754        let new_epoch_store = epoch_store.new_at_next_epoch_for_testing(
3755            self.get_backing_package_store().clone(),
3756            &self.config.expensive_safety_check_config,
3757            self.checkpoint_store
3758                .get_epoch_last_checkpoint(epoch_store.epoch())
3759                .unwrap()
3760                .map(|c| c.sequence_number())
3761                .unwrap_or_default(),
3762        );
3763        let new_epoch = new_epoch_store.epoch();
3764        self.transaction_manager.reconfigure(new_epoch);
3765        self.epoch_store.store(new_epoch_store);
3766        epoch_store.epoch_terminated().await;
3767        *execution_lock = new_epoch;
3768    }
3769
3770    #[instrument(level = "error", skip_all)]
3771    fn check_system_consistency(
3772        &self,
3773        cur_epoch_store: &AuthorityPerEpochStore,
3774        state_hasher: Arc<GlobalStateHasher>,
3775        expensive_safety_check_config: &ExpensiveSafetyCheckConfig,
3776        epoch_supply_change: i64,
3777    ) -> IotaResult<()> {
3778        info!(
3779            "Performing iota conservation consistency check for epoch {}",
3780            cur_epoch_store.epoch()
3781        );
3782
3783        if cfg!(debug_assertions) {
3784            cur_epoch_store.check_all_executed_transactions_in_checkpoint();
3785        }
3786
3787        self.get_reconfig_api()
3788            .try_expensive_check_iota_conservation(cur_epoch_store, Some(epoch_supply_change))?;
3789
3790        // check for root state hash consistency with live object set
3791        if expensive_safety_check_config.enable_state_consistency_check() {
3792            info!(
3793                "Performing state consistency check for epoch {}",
3794                cur_epoch_store.epoch()
3795            );
3796            self.expensive_check_is_consistent_state(
3797                state_hasher,
3798                cur_epoch_store,
3799                cfg!(debug_assertions), // panic in debug mode only
3800            );
3801        }
3802
3803        if expensive_safety_check_config.enable_secondary_index_checks() {
3804            if let Some(indexes) = self.indexes.clone() {
3805                verify_indexes(self.get_global_state_hash_store().as_ref(), indexes)
3806                    .expect("secondary indexes are inconsistent");
3807            }
3808        }
3809
3810        Ok(())
3811    }
3812
3813    fn expensive_check_is_consistent_state(
3814        &self,
3815        state_hasher: Arc<GlobalStateHasher>,
3816        cur_epoch_store: &AuthorityPerEpochStore,
3817        panic: bool,
3818    ) {
3819        let live_object_set_hash = state_hasher.digest_live_object_set();
3820
3821        let root_state_hash: ECMHLiveObjectSetDigest = self
3822            .get_global_state_hash_store()
3823            .get_root_state_hash_for_epoch(cur_epoch_store.epoch())
3824            .expect("Retrieving root state hash cannot fail")
3825            .expect("Root state hash for epoch must exist")
3826            .1
3827            .digest()
3828            .into();
3829
3830        let is_inconsistent = root_state_hash != live_object_set_hash;
3831        if is_inconsistent {
3832            if panic {
3833                panic!(
3834                    "Inconsistent state detected: root state hash: {root_state_hash:?}, live object set hash: {live_object_set_hash:?}"
3835                );
3836            } else {
3837                error!(
3838                    "Inconsistent state detected: root state hash: {:?}, live object set hash: {:?}",
3839                    root_state_hash, live_object_set_hash
3840                );
3841            }
3842        } else {
3843            info!("State consistency check passed");
3844        }
3845
3846        if !panic {
3847            state_hasher.set_inconsistent_state(is_inconsistent);
3848        }
3849    }
3850
3851    pub fn current_epoch_for_testing(&self) -> EpochId {
3852        self.epoch_store_for_testing().epoch()
3853    }
3854
3855    #[instrument(level = "error", skip_all)]
3856    pub fn checkpoint_all_dbs(
3857        &self,
3858        checkpoint_path: &Path,
3859        cur_epoch_store: &AuthorityPerEpochStore,
3860        checkpoint_indexes: bool,
3861    ) -> IotaResult {
3862        let _metrics_guard = self.metrics.db_checkpoint_latency.start_timer();
3863        let current_epoch = cur_epoch_store.epoch();
3864
3865        if checkpoint_path.exists() {
3866            info!("Skipping db checkpoint as it already exists for epoch: {current_epoch}");
3867            return Ok(());
3868        }
3869
3870        let checkpoint_path_tmp = checkpoint_path.with_extension("tmp");
3871        let store_checkpoint_path_tmp = checkpoint_path_tmp.join("store");
3872
3873        if checkpoint_path_tmp.exists() {
3874            fs::remove_dir_all(&checkpoint_path_tmp)
3875                .map_err(|e| IotaError::FileIO(e.to_string()))?;
3876        }
3877
3878        fs::create_dir_all(&checkpoint_path_tmp).map_err(|e| IotaError::FileIO(e.to_string()))?;
3879        fs::create_dir(&store_checkpoint_path_tmp).map_err(|e| IotaError::FileIO(e.to_string()))?;
3880
3881        // NOTE: Do not change the order of invoking these checkpoint calls
3882        // We want to snapshot checkpoint db first to not race with state sync
3883        self.checkpoint_store
3884            .checkpoint_db(&checkpoint_path_tmp.join("checkpoints"))?;
3885
3886        self.get_reconfig_api()
3887            .try_checkpoint_db(&store_checkpoint_path_tmp.join("perpetual"))?;
3888
3889        self.committee_store
3890            .checkpoint_db(&checkpoint_path_tmp.join("epochs"))?;
3891
3892        if checkpoint_indexes {
3893            if let Some(indexes) = self.indexes.as_ref() {
3894                indexes.checkpoint_db(&checkpoint_path_tmp.join("indexes"))?;
3895            }
3896            if let Some(grpc_indexes_store) = self.grpc_indexes_store.as_ref() {
3897                grpc_indexes_store.checkpoint_db(&checkpoint_path_tmp.join(GRPC_INDEXES_DIR))?;
3898            }
3899        }
3900
3901        fs::rename(checkpoint_path_tmp, checkpoint_path)
3902            .map_err(|e| IotaError::FileIO(e.to_string()))?;
3903        Ok(())
3904    }
3905
3906    /// Load the current epoch store. This can change during reconfiguration. To
3907    /// ensure that we never end up accessing different epoch stores in a
3908    /// single task, we need to make sure that this is called once per task.
3909    /// Each call needs to be carefully audited to ensure it is
3910    /// the case. This also means we should minimize the number of call-sites.
3911    /// Only call it when there is no way to obtain it from somewhere else.
3912    pub fn load_epoch_store_one_call_per_task(&self) -> Guard<Arc<AuthorityPerEpochStore>> {
3913        self.epoch_store.load()
3914    }
3915
3916    // Load the epoch store, should be used in tests only.
3917    pub fn epoch_store_for_testing(&self) -> Guard<Arc<AuthorityPerEpochStore>> {
3918        self.load_epoch_store_one_call_per_task()
3919    }
3920
3921    pub fn clone_committee_for_testing(&self) -> Committee {
3922        Committee::clone(self.epoch_store_for_testing().committee())
3923    }
3924
3925    #[instrument(level = "trace", skip_all)]
3926    pub fn try_get_object(&self, object_id: &ObjectId) -> IotaResult<Option<Object>> {
3927        self.get_object_store()
3928            .try_get_object(object_id)
3929            .map_err(Into::into)
3930    }
3931
3932    /// Non-fallible version of `try_get_object`.
3933    pub fn get_object(&self, object_id: &ObjectId) -> Option<Object> {
3934        self.try_get_object(object_id)
3935            .expect("storage access failed")
3936    }
3937
3938    pub fn get_iota_system_package_object_ref(&self) -> IotaResult<ObjectReference> {
3939        Ok(self
3940            .try_get_object(&ObjectId::SYSTEM)?
3941            .expect("system package should always exist")
3942            .object_ref())
3943    }
3944
3945    // This function is only used for testing.
3946    pub fn get_iota_system_state_object_for_testing(&self) -> IotaResult<IotaSystemState> {
3947        self.get_object_cache_reader()
3948            .try_get_iota_system_state_object_unsafe()
3949    }
3950
3951    #[instrument(level = "trace", skip_all)]
3952    pub fn get_checkpoint_by_sequence_number(
3953        &self,
3954        sequence_number: CheckpointSequenceNumber,
3955    ) -> IotaResult<Option<VerifiedCheckpoint>> {
3956        Ok(self
3957            .checkpoint_store
3958            .get_checkpoint_by_sequence_number(sequence_number)?)
3959    }
3960
3961    /// Wait for the given transactions to be included in a checkpoint.
3962    ///
3963    /// Returns a mapping from transaction digest to
3964    /// `(checkpoint_sequence_number, checkpoint_timestamp_ms)`.
3965    /// On timeout, returns partial results for any transactions that were
3966    /// already checkpointed.
3967    pub async fn wait_for_checkpoint_inclusion(
3968        &self,
3969        digests: &[TransactionDigest],
3970        timeout: Duration,
3971    ) -> IotaResult<BTreeMap<TransactionDigest, (CheckpointSequenceNumber, u64)>> {
3972        let epoch_store = self.load_epoch_store_one_call_per_task();
3973
3974        // Local cache so multiple transactions in the same checkpoint only
3975        // trigger a single checkpoint summary lookup.
3976        let mut checkpoint_timestamp_cache = HashMap::<CheckpointSequenceNumber, u64>::new();
3977
3978        let results = epoch_store
3979            .wait_for_transactions_in_checkpoint_with_timeout(digests, timeout, |seq| {
3980                *checkpoint_timestamp_cache.entry(seq).or_insert_with(|| {
3981                    self.get_checkpoint_by_sequence_number(seq)
3982                        .ok()
3983                        .flatten()
3984                        .map(|c| c.timestamp_ms)
3985                        .unwrap_or(0)
3986                })
3987            })
3988            .await?;
3989
3990        Ok(digests
3991            .iter()
3992            .copied()
3993            .zip(results)
3994            .filter_map(|(digest, opt)| opt.map(|seq_and_ts| (digest, seq_and_ts)))
3995            .collect())
3996    }
3997
3998    #[instrument(level = "trace", skip_all)]
3999    pub fn get_transaction_checkpoint_for_tests(
4000        &self,
4001        digest: &TransactionDigest,
4002        epoch_store: &AuthorityPerEpochStore,
4003    ) -> IotaResult<Option<VerifiedCheckpoint>> {
4004        let checkpoint = epoch_store.get_transaction_checkpoint(digest)?;
4005        let Some(checkpoint) = checkpoint else {
4006            return Ok(None);
4007        };
4008        let checkpoint = self
4009            .checkpoint_store
4010            .get_checkpoint_by_sequence_number(checkpoint)?;
4011        Ok(checkpoint)
4012    }
4013
4014    #[instrument(level = "trace", skip_all)]
4015    pub fn get_object_read(&self, object_id: &ObjectId) -> IotaResult<ObjectRead> {
4016        Ok(
4017            match self
4018                .get_object_cache_reader()
4019                .try_get_latest_object_or_tombstone(*object_id)?
4020            {
4021                Some((_, ObjectOrTombstone::Object(object))) => {
4022                    let layout = self.get_object_layout(&object)?;
4023                    ObjectRead::Exists(object.object_ref(), object, layout)
4024                }
4025                Some((_, ObjectOrTombstone::Tombstone(objref))) => ObjectRead::Deleted(objref),
4026                None => ObjectRead::NotExists(*object_id),
4027            },
4028        )
4029    }
4030
4031    /// Chain Identifier is the digest of the genesis checkpoint.
4032    pub fn get_chain_identifier(&self) -> ChainIdentifier {
4033        self.chain_identifier
4034    }
4035
4036    #[instrument(level = "trace", skip_all)]
4037    pub fn get_move_object<T>(&self, object_id: &ObjectId) -> IotaResult<T>
4038    where
4039        T: DeserializeOwned,
4040    {
4041        let o = self.get_object_read(object_id)?.into_object()?;
4042        if let Some(move_object) = o.data.as_opt_struct() {
4043            Ok(bcs::from_bytes(move_object.contents()).map_err(|e| {
4044                IotaError::ObjectDeserialization {
4045                    error: format!("{e}"),
4046                }
4047            })?)
4048        } else {
4049            Err(IotaError::ObjectDeserialization {
4050                error: format!("Provided object : [{object_id}] is not a Move object."),
4051            })
4052        }
4053    }
4054
4055    /// This function aims to serve rpc reads on past objects and
4056    /// we don't expect it to be called for other purposes.
4057    /// Depending on the object pruning policies that will be enforced in the
4058    /// future there is no software-level guarantee/SLA to retrieve an object
4059    /// with an old version even if it exists/existed.
4060    #[instrument(level = "trace", skip_all)]
4061    pub fn get_past_object_read(
4062        &self,
4063        object_id: &ObjectId,
4064        version: Version,
4065    ) -> IotaResult<PastObjectRead> {
4066        // Firstly we see if the object ever existed by getting its latest data
4067        let Some(obj_ref) = self
4068            .get_object_cache_reader()
4069            .try_get_latest_object_ref_or_tombstone(*object_id)?
4070        else {
4071            return Ok(PastObjectRead::ObjectNotExists(*object_id));
4072        };
4073
4074        if version > obj_ref.version {
4075            return Ok(PastObjectRead::VersionTooHigh {
4076                object_id: *object_id,
4077                asked_version: version,
4078                latest_version: obj_ref.version,
4079            });
4080        }
4081
4082        if version < obj_ref.version {
4083            // Read past objects
4084            return Ok(match self.read_object_at_version(object_id, version)? {
4085                Some((object, layout)) => {
4086                    let obj_ref = object.object_ref();
4087                    PastObjectRead::VersionFound(obj_ref, object, layout)
4088                }
4089
4090                None => PastObjectRead::VersionNotFound(*object_id, version),
4091            });
4092        }
4093
4094        if !obj_ref.digest.is_alive() {
4095            return Ok(PastObjectRead::ObjectDeleted(obj_ref));
4096        }
4097
4098        match self.read_object_at_version(object_id, obj_ref.version)? {
4099            Some((object, layout)) => Ok(PastObjectRead::VersionFound(obj_ref, object, layout)),
4100            None => {
4101                error!(
4102                    "Object with in parent_entry is missing from object store, datastore is \
4103                     inconsistent",
4104                );
4105                Err(UserInputError::ObjectNotFound {
4106                    object_id: *object_id,
4107                    version: Some(obj_ref.version),
4108                }
4109                .into())
4110            }
4111        }
4112    }
4113
4114    #[instrument(level = "trace", skip_all)]
4115    fn read_object_at_version(
4116        &self,
4117        object_id: &ObjectId,
4118        version: Version,
4119    ) -> IotaResult<Option<(Object, Option<MoveStructLayout>)>> {
4120        let Some(object) = self
4121            .get_object_cache_reader()
4122            .try_get_object_by_key(object_id, version)?
4123        else {
4124            return Ok(None);
4125        };
4126
4127        let layout = self.get_object_layout(&object)?;
4128        Ok(Some((object, layout)))
4129    }
4130
4131    fn get_object_layout(&self, object: &Object) -> IotaResult<Option<MoveStructLayout>> {
4132        let layout = object
4133            .data
4134            .as_opt_struct()
4135            .map(|object| {
4136                into_struct_layout(
4137                    self.load_epoch_store_one_call_per_task()
4138                        .executor()
4139                        // TODO(cache) - must read through cache
4140                        .type_layout_resolver(Box::new(self.get_backing_package_store().as_ref()))
4141                        .get_annotated_layout(object.struct_tag())?,
4142                )
4143            })
4144            .transpose()?;
4145        Ok(layout)
4146    }
4147
4148    fn get_owner_at_version(&self, object_id: &ObjectId, version: Version) -> IotaResult<Owner> {
4149        self.get_object_store()
4150            .try_get_object_by_key(object_id, version)?
4151            .ok_or_else(|| {
4152                IotaError::from(UserInputError::ObjectNotFound {
4153                    object_id: *object_id,
4154                    version: Some(version),
4155                })
4156            })
4157            .map(|o| o.owner)
4158    }
4159
4160    #[instrument(level = "trace", skip_all)]
4161    pub fn get_owner_objects(
4162        &self,
4163        owner: Address,
4164        // If `Some`, the query will start from the next item after the specified cursor
4165        cursor: Option<ObjectId>,
4166        limit: usize,
4167        filter: Option<IotaObjectDataFilter>,
4168    ) -> IotaResult<Vec<ObjectInfo>> {
4169        if let Some(indexes) = &self.indexes {
4170            indexes.get_owner_objects(owner, cursor, limit, filter)
4171        } else {
4172            Err(IotaError::IndexStoreNotAvailable)
4173        }
4174    }
4175
4176    #[instrument(level = "trace", skip_all)]
4177    pub fn get_owned_coins_iterator_with_cursor(
4178        &self,
4179        owner: Address,
4180        // If `Some`, the query will start from the next item after the specified cursor
4181        cursor: (String, ObjectId),
4182        limit: usize,
4183        one_coin_type_only: bool,
4184    ) -> IotaResult<impl Iterator<Item = (String, ObjectId, CoinInfo)> + '_> {
4185        if let Some(indexes) = &self.indexes {
4186            indexes.get_owned_coins_iterator_with_cursor(owner, cursor, limit, one_coin_type_only)
4187        } else {
4188            Err(IotaError::IndexStoreNotAvailable)
4189        }
4190    }
4191
4192    #[instrument(level = "trace", skip_all)]
4193    pub fn get_owner_objects_iterator(
4194        &self,
4195        owner: Address,
4196        // If `Some`, the query will start from the next item after the specified cursor
4197        cursor: Option<ObjectId>,
4198        filter: Option<IotaObjectDataFilter>,
4199    ) -> IotaResult<impl Iterator<Item = ObjectInfo> + '_> {
4200        let cursor_u = cursor.unwrap_or(ObjectId::ZERO);
4201        if let Some(indexes) = &self.indexes {
4202            indexes.get_owner_objects_iterator(owner, cursor_u, filter)
4203        } else {
4204            Err(IotaError::IndexStoreNotAvailable)
4205        }
4206    }
4207
4208    #[instrument(level = "trace", skip_all)]
4209    pub fn get_move_objects<T>(&self, owner: Address, tag: StructTag) -> IotaResult<Vec<T>>
4210    where
4211        T: DeserializeOwned,
4212    {
4213        let object_ids = self
4214            .get_owner_objects_iterator(owner, None, None)?
4215            .filter(|o| match &o.type_ {
4216                ObjectType::Struct(s) => *s == tag,
4217                ObjectType::Package => false,
4218            })
4219            .map(|info| ObjectKey(info.object_id, info.version))
4220            .collect::<Vec<_>>();
4221        let mut move_objects = vec![];
4222
4223        let objects = self
4224            .get_object_store()
4225            .try_multi_get_objects_by_key(&object_ids)?;
4226
4227        for (o, id) in objects.into_iter().zip(object_ids) {
4228            let object = o.ok_or_else(|| {
4229                IotaError::from(UserInputError::ObjectNotFound {
4230                    object_id: id.0,
4231                    version: Some(id.1),
4232                })
4233            })?;
4234            let move_object = object.data.as_opt_struct().ok_or_else(|| {
4235                IotaError::from(UserInputError::MovePackageAsObject { object_id: id.0 })
4236            })?;
4237            move_objects.push(bcs::from_bytes(move_object.contents()).map_err(|e| {
4238                IotaError::ObjectDeserialization {
4239                    error: format!("{e}"),
4240                }
4241            })?);
4242        }
4243        Ok(move_objects)
4244    }
4245
4246    #[instrument(level = "trace", skip_all)]
4247    pub fn get_dynamic_fields(
4248        &self,
4249        owner: ObjectId,
4250        // If `Some`, the query will start from the next item after the specified cursor
4251        cursor: Option<ObjectId>,
4252        limit: usize,
4253    ) -> IotaResult<Vec<(ObjectId, DynamicFieldInfo)>> {
4254        Ok(self
4255            .get_dynamic_fields_iterator(owner, cursor)?
4256            .take(limit)
4257            .collect::<Result<Vec<_>, _>>()?)
4258    }
4259
4260    fn get_dynamic_fields_iterator(
4261        &self,
4262        owner: ObjectId,
4263        // If `Some`, the query will start from the next item after the specified cursor
4264        cursor: Option<ObjectId>,
4265    ) -> IotaResult<impl Iterator<Item = Result<(ObjectId, DynamicFieldInfo), TypedStoreError>> + '_>
4266    {
4267        if let Some(indexes) = &self.indexes {
4268            indexes.get_dynamic_fields_iterator(owner, cursor)
4269        } else {
4270            Err(IotaError::IndexStoreNotAvailable)
4271        }
4272    }
4273
4274    #[instrument(level = "trace", skip_all)]
4275    pub fn get_dynamic_field_object_id(
4276        &self,
4277        owner: ObjectId,
4278        name_type: TypeTag,
4279        name_bcs_bytes: &[u8],
4280    ) -> IotaResult<Option<ObjectId>> {
4281        if let Some(indexes) = &self.indexes {
4282            indexes.get_dynamic_field_object_id(owner, name_type, name_bcs_bytes)
4283        } else {
4284            Err(IotaError::IndexStoreNotAvailable)
4285        }
4286    }
4287
4288    #[instrument(level = "trace", skip_all)]
4289    pub fn get_total_transaction_blocks(&self) -> IotaResult<u64> {
4290        Ok(self.get_indexes()?.next_sequence_number())
4291    }
4292
4293    #[instrument(level = "trace", skip_all)]
4294    pub async fn get_executed_transaction_and_effects(
4295        &self,
4296        digest: TransactionDigest,
4297        kv_store: Arc<TransactionKeyValueStore>,
4298    ) -> IotaResult<(Transaction, TransactionEffects)> {
4299        let transaction = kv_store.get_tx(digest).await?;
4300        let effects = kv_store.get_fx_by_tx_digest(digest).await?;
4301        Ok((transaction, effects))
4302    }
4303
4304    #[instrument(level = "trace", skip_all)]
4305    pub fn multi_get_checkpoint_by_sequence_number(
4306        &self,
4307        sequence_numbers: &[CheckpointSequenceNumber],
4308    ) -> IotaResult<Vec<Option<VerifiedCheckpoint>>> {
4309        Ok(self
4310            .checkpoint_store
4311            .multi_get_checkpoint_by_sequence_number(sequence_numbers)?)
4312    }
4313
4314    #[instrument(level = "trace", skip_all)]
4315    pub fn get_transaction_events(
4316        &self,
4317        digest: &TransactionDigest,
4318    ) -> IotaResult<TransactionEvents> {
4319        self.get_transaction_cache_reader()
4320            .try_get_events(digest)?
4321            .ok_or(IotaError::TransactionEventsNotFound { digest: *digest })
4322    }
4323
4324    pub fn get_transaction_input_objects(
4325        &self,
4326        effects: &TransactionEffects,
4327    ) -> anyhow::Result<Vec<Object>> {
4328        iota_types::storage::get_transaction_input_objects(self.get_object_store(), effects)
4329            .map_err(Into::into)
4330    }
4331
4332    pub fn get_transaction_output_objects(
4333        &self,
4334        effects: &TransactionEffects,
4335    ) -> anyhow::Result<Vec<Object>> {
4336        iota_types::storage::get_transaction_output_objects(self.get_object_store(), effects)
4337            .map_err(Into::into)
4338    }
4339
4340    fn get_indexes(&self) -> IotaResult<Arc<IndexStore>> {
4341        match &self.indexes {
4342            Some(i) => Ok(i.clone()),
4343            None => Err(IotaError::UnsupportedFeature {
4344                error: "extended object indexing is not enabled on this server".into(),
4345            }),
4346        }
4347    }
4348
4349    pub async fn get_transactions_for_tests(
4350        self: &Arc<Self>,
4351        filter: Option<TransactionFilter>,
4352        cursor: Option<TransactionDigest>,
4353        limit: Option<usize>,
4354        reverse: bool,
4355    ) -> IotaResult<Vec<TransactionDigest>> {
4356        let metrics = KeyValueStoreMetrics::new_for_tests();
4357        let kv_store = Arc::new(TransactionKeyValueStore::new(
4358            "rocksdb",
4359            metrics,
4360            self.clone(),
4361        ));
4362        self.get_transactions(&kv_store, filter, cursor, limit, reverse)
4363            .await
4364    }
4365
4366    #[instrument(level = "trace", skip_all)]
4367    pub async fn get_transactions(
4368        &self,
4369        kv_store: &Arc<TransactionKeyValueStore>,
4370        filter: Option<TransactionFilter>,
4371        // If `Some`, the query will start from the next item after the specified cursor
4372        cursor: Option<TransactionDigest>,
4373        limit: Option<usize>,
4374        reverse: bool,
4375    ) -> IotaResult<Vec<TransactionDigest>> {
4376        if let Some(TransactionFilter::Checkpoint(sequence_number)) = filter {
4377            let checkpoint_contents = kv_store.get_checkpoint_contents(sequence_number).await?;
4378            let iter = checkpoint_contents.iter().map(|c| c.transaction);
4379            if reverse {
4380                let iter = iter
4381                    .rev()
4382                    .skip_while(|d| cursor.is_some() && Some(*d) != cursor)
4383                    .skip(usize::from(cursor.is_some()));
4384                return Ok(iter.take(limit.unwrap_or(usize::MAX)).collect());
4385            } else {
4386                let iter = iter
4387                    .skip_while(|d| cursor.is_some() && Some(*d) != cursor)
4388                    .skip(usize::from(cursor.is_some()));
4389                return Ok(iter.take(limit.unwrap_or(usize::MAX)).collect());
4390            }
4391        }
4392        self.get_indexes()?
4393            .get_transactions(filter, cursor, limit, reverse)
4394    }
4395
4396    pub fn get_checkpoint_store(&self) -> &Arc<CheckpointStore> {
4397        &self.checkpoint_store
4398    }
4399
4400    /// The store pruner; the checkpoint executor uses it to nudge the pruner
4401    /// after each checkpoint.
4402    pub fn pruner(&self) -> &AuthorityStorePruner {
4403        &self.pruner
4404    }
4405
4406    pub fn get_latest_checkpoint_sequence_number(&self) -> IotaResult<CheckpointSequenceNumber> {
4407        self.get_checkpoint_store()
4408            .get_highest_executed_checkpoint_seq_number()?
4409            .ok_or(IotaError::UserInput {
4410                error: UserInputError::LatestCheckpointSequenceNumberNotFound,
4411            })
4412    }
4413
4414    #[cfg(msim)]
4415    pub fn get_highest_pruned_checkpoint_for_testing(
4416        &self,
4417    ) -> IotaResult<CheckpointSequenceNumber> {
4418        self.database_for_testing()
4419            .perpetual_tables
4420            .get_highest_pruned_checkpoint()
4421            .map(|c| c.unwrap_or(0))
4422            .map_err(Into::into)
4423    }
4424
4425    #[instrument(level = "trace", skip_all)]
4426    pub fn get_checkpoint_summary_by_sequence_number(
4427        &self,
4428        sequence_number: CheckpointSequenceNumber,
4429    ) -> IotaResult<CheckpointSummary> {
4430        let verified_checkpoint = self
4431            .get_checkpoint_store()
4432            .get_checkpoint_by_sequence_number(sequence_number)?;
4433        match verified_checkpoint {
4434            Some(verified_checkpoint) => Ok(verified_checkpoint.into_inner().into_data()),
4435            None => Err(IotaError::UserInput {
4436                error: UserInputError::VerifiedCheckpointNotFound(sequence_number),
4437            }),
4438        }
4439    }
4440
4441    #[instrument(level = "trace", skip_all)]
4442    pub fn get_checkpoint_summary_by_digest(
4443        &self,
4444        digest: CheckpointDigest,
4445    ) -> IotaResult<CheckpointSummary> {
4446        let verified_checkpoint = self
4447            .get_checkpoint_store()
4448            .get_checkpoint_by_digest(&digest)?;
4449        match verified_checkpoint {
4450            Some(verified_checkpoint) => Ok(verified_checkpoint.into_inner().into_data()),
4451            None => Err(IotaError::UserInput {
4452                error: UserInputError::VerifiedCheckpointDigestNotFound(Base58::encode(digest)),
4453            }),
4454        }
4455    }
4456
4457    #[instrument(level = "trace", skip_all)]
4458    pub fn find_publish_txn_digest(&self, package_id: ObjectId) -> IotaResult<TransactionDigest> {
4459        if package_id.is_system_package() {
4460            return self.find_genesis_txn_digest();
4461        }
4462        Ok(self
4463            .get_object_read(&package_id)?
4464            .into_object()?
4465            .previous_transaction)
4466    }
4467
4468    #[instrument(level = "trace", skip_all)]
4469    pub fn find_genesis_txn_digest(&self) -> IotaResult<TransactionDigest> {
4470        let summary = self
4471            .get_verified_checkpoint_by_sequence_number(0)?
4472            .into_message();
4473        let content = self.get_checkpoint_contents(summary.content_digest)?;
4474        let genesis_transaction = content.enumerate_transactions(&summary).next();
4475        Ok(genesis_transaction
4476            .ok_or(IotaError::UserInput {
4477                error: UserInputError::GenesisTransactionNotFound,
4478            })?
4479            .1
4480            .transaction)
4481    }
4482
4483    #[instrument(level = "trace", skip_all)]
4484    pub fn get_verified_checkpoint_by_sequence_number(
4485        &self,
4486        sequence_number: CheckpointSequenceNumber,
4487    ) -> IotaResult<VerifiedCheckpoint> {
4488        let verified_checkpoint = self
4489            .get_checkpoint_store()
4490            .get_checkpoint_by_sequence_number(sequence_number)?;
4491        match verified_checkpoint {
4492            Some(verified_checkpoint) => Ok(verified_checkpoint),
4493            None => Err(IotaError::UserInput {
4494                error: UserInputError::VerifiedCheckpointNotFound(sequence_number),
4495            }),
4496        }
4497    }
4498
4499    #[instrument(level = "trace", skip_all)]
4500    pub fn get_verified_checkpoint_summary_by_digest(
4501        &self,
4502        digest: CheckpointDigest,
4503    ) -> IotaResult<VerifiedCheckpoint> {
4504        let verified_checkpoint = self
4505            .get_checkpoint_store()
4506            .get_checkpoint_by_digest(&digest)?;
4507        match verified_checkpoint {
4508            Some(verified_checkpoint) => Ok(verified_checkpoint),
4509            None => Err(IotaError::UserInput {
4510                error: UserInputError::VerifiedCheckpointDigestNotFound(Base58::encode(digest)),
4511            }),
4512        }
4513    }
4514
4515    #[instrument(level = "trace", skip_all)]
4516    pub fn get_checkpoint_contents(
4517        &self,
4518        digest: CheckpointContentsDigest,
4519    ) -> IotaResult<CheckpointContents> {
4520        self.get_checkpoint_store()
4521            .get_checkpoint_contents(&digest)?
4522            .ok_or(IotaError::UserInput {
4523                error: UserInputError::CheckpointContentsNotFound(digest),
4524            })
4525    }
4526
4527    #[instrument(level = "trace", skip_all)]
4528    pub fn get_checkpoint_contents_by_sequence_number(
4529        &self,
4530        sequence_number: CheckpointSequenceNumber,
4531    ) -> IotaResult<CheckpointContents> {
4532        let verified_checkpoint = self
4533            .get_checkpoint_store()
4534            .get_checkpoint_by_sequence_number(sequence_number)?;
4535        match verified_checkpoint {
4536            Some(verified_checkpoint) => {
4537                let content_digest = verified_checkpoint.into_inner().content_digest;
4538                self.get_checkpoint_contents(content_digest)
4539            }
4540            None => Err(IotaError::UserInput {
4541                error: UserInputError::VerifiedCheckpointNotFound(sequence_number),
4542            }),
4543        }
4544    }
4545
4546    #[instrument(level = "trace", skip_all)]
4547    pub async fn query_events(
4548        &self,
4549        kv_store: &Arc<TransactionKeyValueStore>,
4550        query: EventFilter,
4551        // If `Some`, the query will start from the next item after the specified cursor
4552        cursor: Option<EventID>,
4553        limit: usize,
4554        descending: bool,
4555    ) -> IotaResult<Vec<IotaEvent>> {
4556        let index_store = self.get_indexes()?;
4557
4558        // Get the tx_num from tx_digest
4559        let (tx_num, event_num) = if let Some(cursor) = cursor.as_ref() {
4560            let tx_seq = index_store.get_transaction_seq(&cursor.tx_digest)?.ok_or(
4561                IotaError::TransactionNotFound {
4562                    digest: cursor.tx_digest,
4563                },
4564            )?;
4565            (tx_seq, cursor.event_seq as usize)
4566        } else if descending {
4567            (u64::MAX, usize::MAX)
4568        } else {
4569            (0, 0)
4570        };
4571
4572        let limit = limit + 1;
4573        let mut event_keys = match query {
4574            EventFilter::All(filters) => {
4575                if filters.is_empty() {
4576                    index_store.all_events(tx_num, event_num, limit, descending)?
4577                } else {
4578                    return Err(IotaError::UserInput {
4579                        error: UserInputError::Unsupported(
4580                            "This query type does not currently support filter combinations"
4581                                .to_string(),
4582                        ),
4583                    });
4584                }
4585            }
4586            EventFilter::Transaction(digest) => {
4587                index_store.events_by_transaction(&digest, tx_num, event_num, limit, descending)?
4588            }
4589            EventFilter::MoveModule { package, module } => {
4590                let module_id = ModuleId::new(
4591                    AccountAddress::new(package.into_bytes()),
4592                    move_core_types::identifier::Identifier::new(module.as_str()).unwrap(),
4593                );
4594                index_store.events_by_module_id(&module_id, tx_num, event_num, limit, descending)?
4595            }
4596            EventFilter::MoveEventType(struct_name) => index_store
4597                .events_by_move_event_struct_name(
4598                    &struct_name,
4599                    tx_num,
4600                    event_num,
4601                    limit,
4602                    descending,
4603                )?,
4604            EventFilter::Sender(sender) => {
4605                index_store.events_by_sender(&sender, tx_num, event_num, limit, descending)?
4606            }
4607            EventFilter::TimeRange {
4608                start_time,
4609                end_time,
4610            } => index_store
4611                .event_iterator(start_time, end_time, tx_num, event_num, limit, descending)?,
4612            EventFilter::MoveEventModule { package, module } => index_store
4613                .events_by_move_event_module(
4614                    &ModuleId::new(
4615                        AccountAddress::new(package.into_bytes()),
4616                        move_core_types::identifier::Identifier::new(module.as_str()).unwrap(),
4617                    ),
4618                    tx_num,
4619                    event_num,
4620                    limit,
4621                    descending,
4622                )?,
4623            // not using "_ =>" because we want to make sure we remember to add new variants here
4624            EventFilter::Package(_)
4625            | EventFilter::MoveEventField { .. }
4626            | EventFilter::Any(_)
4627            | EventFilter::And(_, _)
4628            | EventFilter::Or(_, _) => {
4629                return Err(IotaError::UserInput {
4630                    error: UserInputError::Unsupported(
4631                        "This query type is not supported by the full node.".to_string(),
4632                    ),
4633                });
4634            }
4635        };
4636
4637        // skip one event if exclusive cursor is provided,
4638        // otherwise truncate to the original limit.
4639        if cursor.is_some() {
4640            if !event_keys.is_empty() {
4641                event_keys.remove(0);
4642            }
4643        } else {
4644            event_keys.truncate(limit - 1);
4645        }
4646
4647        // get the unique set of digests from the event_keys
4648        let transaction_digests = event_keys
4649            .iter()
4650            .map(|(_, digest, _, _)| *digest)
4651            .collect::<HashSet<_>>()
4652            .into_iter()
4653            .collect::<Vec<_>>();
4654
4655        let events = kv_store
4656            .multi_get_events_by_tx_digests(&transaction_digests)
4657            .await?;
4658
4659        let events_map: HashMap<_, _> =
4660            transaction_digests.iter().zip(events.into_iter()).collect();
4661
4662        let stored_events = event_keys
4663            .into_iter()
4664            .map(|k| {
4665                (
4666                    k,
4667                    events_map
4668                        .get(&k.1)
4669                        .expect("fetched digest is missing")
4670                        .clone()
4671                        .and_then(|e| e.get(k.2).cloned()),
4672                )
4673            })
4674            .map(
4675                |((_event_digest, tx_digest, event_seq, timestamp), event)| {
4676                    event
4677                        .map(|e| (e, tx_digest, event_seq, timestamp))
4678                        .ok_or(IotaError::TransactionEventsNotFound { digest: tx_digest })
4679                },
4680            )
4681            .collect::<Result<Vec<_>, _>>()?;
4682
4683        let epoch_store = self.load_epoch_store_one_call_per_task();
4684        let backing_store = self.get_backing_package_store().as_ref();
4685        let mut layout_resolver = epoch_store
4686            .executor()
4687            .type_layout_resolver(Box::new(backing_store));
4688        let mut events = vec![];
4689        for (e, tx_digest, event_seq, timestamp) in stored_events.into_iter() {
4690            events.push(IotaEvent::try_from(
4691                e.clone(),
4692                tx_digest,
4693                event_seq as u64,
4694                Some(timestamp),
4695                layout_resolver.get_annotated_layout(&e.type_)?,
4696            )?)
4697        }
4698        Ok(events)
4699    }
4700
4701    pub fn insert_genesis_object(&self, object: Object) {
4702        self.get_reconfig_api()
4703            .try_insert_genesis_object(object)
4704            .expect("Cannot insert genesis object")
4705    }
4706
4707    pub fn insert_genesis_objects(&self, objects: &[Object]) {
4708        for o in objects {
4709            self.insert_genesis_object(o.clone());
4710        }
4711    }
4712
4713    /// Make a status response for a transaction
4714    #[instrument(level = "trace", skip_all)]
4715    pub fn get_transaction_status(
4716        &self,
4717        transaction_digest: &TransactionDigest,
4718        epoch_store: &Arc<AuthorityPerEpochStore>,
4719    ) -> IotaResult<Option<(SenderSignedData, TransactionStatus)>> {
4720        // TODO: In the case of read path, we should not have to re-sign the effects.
4721        if let Some(effects) =
4722            self.get_signed_effects_and_maybe_resign(transaction_digest, epoch_store)?
4723        {
4724            if let Some(transaction) = self
4725                .get_transaction_cache_reader()
4726                .try_get_transaction_block(transaction_digest)?
4727            {
4728                let cert_sig = epoch_store.get_transaction_cert_sig(transaction_digest)?;
4729                let events = if effects.events_digest().is_some() {
4730                    self.get_transaction_events(effects.transaction_digest())?
4731                } else {
4732                    TransactionEvents::default()
4733                };
4734                return Ok(Some((
4735                    (*transaction).clone().into_message(),
4736                    TransactionStatus::Executed(cert_sig, effects.into_inner(), events),
4737                )));
4738            } else {
4739                // The read of effects and read of transaction are not atomic. It's possible
4740                // that we reverted the transaction (during epoch change) in
4741                // between the above two reads, and we end up having effects but
4742                // not transaction. In this case, we just fall through.
4743                debug!(tx_digest=?transaction_digest, "Signed effects exist but no transaction found");
4744            }
4745        }
4746        if let Some(signed) = epoch_store.get_signed_transaction(transaction_digest)? {
4747            self.metrics.tx_already_processed.inc();
4748            let (transaction, sig) = signed.into_inner().into_data_and_sig();
4749            Ok(Some((transaction, TransactionStatus::Signed(sig))))
4750        } else {
4751            Ok(None)
4752        }
4753    }
4754
4755    /// Get the signed effects of the given transaction. If the effects was
4756    /// signed in a previous epoch, re-sign it so that the caller is able to
4757    /// form a cert of the effects in the current epoch.
4758    #[instrument(level = "trace", skip_all)]
4759    pub fn get_signed_effects_and_maybe_resign(
4760        &self,
4761        transaction_digest: &TransactionDigest,
4762        epoch_store: &Arc<AuthorityPerEpochStore>,
4763    ) -> IotaResult<Option<VerifiedSignedTransactionEffects>> {
4764        let effects = self
4765            .get_transaction_cache_reader()
4766            .try_get_executed_effects(transaction_digest)?;
4767        match effects {
4768            Some(effects) => {
4769                // If the transaction was executed in previous epochs, the validator will
4770                // re-sign the effects with new current epoch so that a client is always able to
4771                // obtain an effects certificate at the current epoch.
4772                //
4773                // Why is this necessary? Consider the following case:
4774                // - assume there are 4 validators
4775                // - Quorum driver gets 2 signed effects before reconfig halt
4776                // - The tx makes it into final checkpoint.
4777                // - 2 validators go away and are replaced in the new epoch.
4778                // - The new epoch begins.
4779                // - The quorum driver cannot complete the partial effects cert from the
4780                //   previous epoch, because it may not be able to reach either of the 2 former
4781                //   validators.
4782                // - But, if the 2 validators that stayed are willing to re-sign the effects in
4783                //   the new epoch, the QD can make a new effects cert and return it to the
4784                //   client.
4785                //
4786                // This is a considered a short-term workaround. Eventually, Quorum Driver
4787                // should be able to return either an effects certificate, -or-
4788                // a proof of inclusion in a checkpoint. In the case above, the
4789                // Quorum Driver would return a proof of inclusion in the final
4790                // checkpoint, and this code would no longer be necessary.
4791                if effects.epoch() != epoch_store.epoch() {
4792                    debug!(
4793                        tx_digest=?transaction_digest,
4794                        effects_epoch=?effects.epoch(),
4795                        epoch=?epoch_store.epoch(),
4796                        "Re-signing the effects with the current epoch"
4797                    );
4798                }
4799                Ok(Some(self.sign_effects(effects, epoch_store)?))
4800            }
4801            None => Ok(None),
4802        }
4803    }
4804
4805    #[instrument(level = "trace", skip_all)]
4806    pub(crate) fn sign_effects(
4807        &self,
4808        effects: TransactionEffects,
4809        epoch_store: &Arc<AuthorityPerEpochStore>,
4810    ) -> IotaResult<VerifiedSignedTransactionEffects> {
4811        let tx_digest = *effects.transaction_digest();
4812        let signed_effects = match epoch_store.get_effects_signature(&tx_digest)? {
4813            Some(sig) => {
4814                debug_assert!(sig.epoch == epoch_store.epoch());
4815                SignedTransactionEffects::new_from_data_and_sig(effects, sig)
4816            }
4817            _ => {
4818                let sig = AuthoritySignInfo::new(
4819                    epoch_store.epoch(),
4820                    &effects,
4821                    Intent::iota_app(IntentScope::TransactionEffects),
4822                    self.name,
4823                    &*self.secret,
4824                );
4825
4826                let effects = SignedTransactionEffects::new_from_data_and_sig(effects, sig.clone());
4827
4828                epoch_store.insert_effects_digest_and_signature(
4829                    &tx_digest,
4830                    effects.digest(),
4831                    &sig,
4832                )?;
4833
4834                effects
4835            }
4836        };
4837
4838        Ok(VerifiedSignedTransactionEffects::new_unchecked(
4839            signed_effects,
4840        ))
4841    }
4842
4843    // Returns coin objects for indexing for fullnode if indexing is enabled.
4844    #[instrument(level = "trace", skip_all)]
4845    fn fullnode_only_get_tx_coins_for_indexing(
4846        &self,
4847        effects: &TransactionEffects,
4848        inner_temporary_store: &InnerTemporaryStore,
4849        epoch_store: &Arc<AuthorityPerEpochStore>,
4850    ) -> Option<TxCoins> {
4851        if self.indexes.is_none() || self.is_committee_validator(epoch_store) {
4852            return None;
4853        }
4854        let written_coin_objects = inner_temporary_store
4855            .written
4856            .iter()
4857            .filter_map(|(k, v)| {
4858                if v.is_coin() {
4859                    Some((*k, v.clone()))
4860                } else {
4861                    None
4862                }
4863            })
4864            .collect();
4865        let mut input_coin_objects = inner_temporary_store
4866            .input_objects
4867            .iter()
4868            .filter_map(|(k, v)| {
4869                if v.is_coin() {
4870                    Some((*k, v.clone()))
4871                } else {
4872                    None
4873                }
4874            })
4875            .collect::<ObjectMap>();
4876
4877        // Check for receiving objects that were actually used and modified during
4878        // execution. Their updated version will already showup in
4879        // "written_coins" but their input isn't included in the set of input
4880        // objects in a inner_temporary_store.
4881        for (object_id, version) in effects.modified_at_versions() {
4882            if inner_temporary_store
4883                .loaded_runtime_objects
4884                .contains_key(&object_id)
4885            {
4886                if let Some(object) = self
4887                    .get_object_store()
4888                    .get_object_by_key(&object_id, version)
4889                {
4890                    if object.is_coin() {
4891                        input_coin_objects.insert(object_id, object);
4892                    }
4893                }
4894            }
4895        }
4896
4897        Some((input_coin_objects, written_coin_objects))
4898    }
4899
4900    /// Get the TransactionEnvelope that currently locks the given object, if
4901    /// any. Since object locks are only valid for one epoch, we also need
4902    /// the epoch_id in the query. Returns UserInputError::ObjectNotFound if
4903    /// no lock records for the given object can be found.
4904    /// Returns UserInputError::ObjectVersionUnavailableForConsumption if the
4905    /// object record is at a different version.
4906    /// Returns Some(VerifiedEnvelope) if the given ObjectReference is locked by
4907    /// a certain transaction. Returns None if the a lock record is
4908    /// initialized for the given ObjectReference but not yet locked by any
4909    /// transaction,     or cannot find the transaction in transaction
4910    /// table, because of data race etc.
4911    #[instrument(level = "trace", skip_all)]
4912    pub fn get_transaction_lock(
4913        &self,
4914        object_ref: &ObjectReference,
4915        epoch_store: &AuthorityPerEpochStore,
4916    ) -> IotaResult<Option<VerifiedSignedTransaction>> {
4917        let lock_info = self
4918            .get_object_cache_reader()
4919            .try_get_lock(*object_ref, epoch_store)?;
4920        let lock_info = match lock_info {
4921            ObjectLockStatus::LockedAtDifferentVersion { locked_ref } => {
4922                return Err(UserInputError::ObjectVersionUnavailableForConsumption {
4923                    provided_obj_ref: *object_ref,
4924                    current_version: locked_ref.version,
4925                }
4926                .into());
4927            }
4928            ObjectLockStatus::Initialized => {
4929                return Ok(None);
4930            }
4931            ObjectLockStatus::LockedToTx { locked_by_tx } => locked_by_tx,
4932        };
4933
4934        epoch_store.get_signed_transaction(&lock_info)
4935    }
4936
4937    pub fn try_get_objects(&self, objects: &[ObjectId]) -> IotaResult<Vec<Option<Object>>> {
4938        self.get_object_cache_reader().try_get_objects(objects)
4939    }
4940
4941    /// Non-fallible version of `try_get_objects`.
4942    pub fn get_objects(&self, objects: &[ObjectId]) -> Vec<Option<Object>> {
4943        self.try_get_objects(objects)
4944            .expect("storage access failed")
4945    }
4946
4947    pub fn try_get_object_or_tombstone(
4948        &self,
4949        object_id: ObjectId,
4950    ) -> IotaResult<Option<ObjectReference>> {
4951        self.get_object_cache_reader()
4952            .try_get_latest_object_ref_or_tombstone(object_id)
4953    }
4954
4955    /// Non-fallible version of `try_get_object_or_tombstone`.
4956    pub fn get_object_or_tombstone(&self, object_id: ObjectId) -> Option<ObjectReference> {
4957        self.try_get_object_or_tombstone(object_id)
4958            .expect("storage access failed")
4959    }
4960
4961    /// Ordinarily, protocol upgrades occur when 2f + 1 + (f *
4962    /// ProtocolConfig::buffer_stake_for_protocol_upgrade_bps) vote for the
4963    /// upgrade.
4964    ///
4965    /// This method can be used to dynamic adjust the amount of buffer. If set
4966    /// to 0, the upgrade will go through with only 2f+1 votes.
4967    ///
4968    /// IMPORTANT: If this is used, it must be used on >=2f+1 validators (all
4969    /// should have the same value), or you risk halting the chain.
4970    pub fn set_override_protocol_upgrade_buffer_stake(
4971        &self,
4972        expected_epoch: EpochId,
4973        buffer_stake_bps: u64,
4974    ) -> IotaResult {
4975        let epoch_store = self.load_epoch_store_one_call_per_task();
4976        let actual_epoch = epoch_store.epoch();
4977        if actual_epoch != expected_epoch {
4978            return Err(IotaError::WrongEpoch {
4979                expected_epoch,
4980                actual_epoch,
4981            });
4982        }
4983
4984        epoch_store.set_override_protocol_upgrade_buffer_stake(buffer_stake_bps)
4985    }
4986
4987    pub fn clear_override_protocol_upgrade_buffer_stake(
4988        &self,
4989        expected_epoch: EpochId,
4990    ) -> IotaResult {
4991        let epoch_store = self.load_epoch_store_one_call_per_task();
4992        let actual_epoch = epoch_store.epoch();
4993        if actual_epoch != expected_epoch {
4994            return Err(IotaError::WrongEpoch {
4995                expected_epoch,
4996                actual_epoch,
4997            });
4998        }
4999
5000        epoch_store.clear_override_protocol_upgrade_buffer_stake()
5001    }
5002
5003    /// Get the set of system packages that are compiled in to this build, if
5004    /// those packages are compatible with the current versions of those
5005    /// packages on-chain.
5006    pub async fn get_available_system_packages(
5007        &self,
5008        binary_config: &BinaryConfig,
5009    ) -> Vec<ObjectReference> {
5010        let mut results = vec![];
5011
5012        let system_packages = BuiltInFramework::iter_system_packages();
5013
5014        // Add extra framework packages during simtest
5015        #[cfg(msim)]
5016        let extra_packages = framework_injection::get_extra_packages(self.name);
5017        #[cfg(msim)]
5018        let system_packages = {
5019            let mut packages: Vec<_> = system_packages.collect();
5020            packages.extend(extra_packages.iter());
5021            packages
5022        };
5023
5024        for system_package in system_packages {
5025            let modules = system_package.modules().to_vec();
5026            // In simtests, we could override the current built-in framework packages.
5027            #[cfg(msim)]
5028            let modules = framework_injection::get_override_modules(&system_package.id, self.name)
5029                .unwrap_or(modules);
5030
5031            let Some(obj_ref) = iota_framework::compare_system_package(
5032                &self.get_object_store(),
5033                &system_package.id,
5034                &modules,
5035                system_package.dependencies.to_vec(),
5036                binary_config,
5037            )
5038            .await
5039            else {
5040                return vec![];
5041            };
5042            results.push(obj_ref);
5043        }
5044
5045        results
5046    }
5047
5048    /// Return the new versions, module bytes, and dependencies for the packages
5049    /// that have been committed to for a framework upgrade, in
5050    /// `system_packages`.  Loads the module contents from the binary, and
5051    /// performs the following checks:
5052    ///
5053    /// - Whether its contents matches what is on-chain already, in which case
5054    ///   no upgrade is required, and its contents are omitted from the output.
5055    /// - Whether the contents in the binary can form a package whose digest
5056    ///   matches the input, meaning the framework will be upgraded, and this
5057    ///   authority can satisfy that upgrade, in which case the contents are
5058    ///   included in the output.
5059    ///
5060    /// If the current version of the framework can't be loaded, the binary does
5061    /// not contain the bytes for that framework ID, or the resulting
5062    /// package fails the digest check, `None` is returned indicating that
5063    /// this authority cannot run the upgrade that the network voted on.
5064    async fn get_system_package_bytes(
5065        &self,
5066        system_packages: Vec<ObjectReference>,
5067        binary_config: &BinaryConfig,
5068    ) -> Option<Vec<SystemPackage>> {
5069        let ids: Vec<_> = system_packages
5070            .iter()
5071            .map(|object_ref| object_ref.object_id)
5072            .collect();
5073        let objects = self.get_objects(&ids);
5074
5075        let mut res = Vec::with_capacity(system_packages.len());
5076        for (system_package_ref, object) in system_packages.into_iter().zip(objects.iter()) {
5077            let prev_transaction = match object {
5078                Some(cur_object) if cur_object.object_ref() == system_package_ref => {
5079                    // Skip this one because it doesn't need to be upgraded.
5080                    info!(
5081                        "Framework {} does not need updating",
5082                        system_package_ref.object_id
5083                    );
5084                    continue;
5085                }
5086
5087                Some(cur_object) => cur_object.previous_transaction,
5088                None => TransactionDigest::GENESIS_MARKER,
5089            };
5090
5091            #[cfg(msim)]
5092            let FrameworkSystemPackage {
5093                id: _,
5094                bytes,
5095                dependencies,
5096            } = framework_injection::get_override_system_package(
5097                &system_package_ref.object_id,
5098                self.name,
5099            )
5100            .unwrap_or_else(|| {
5101                BuiltInFramework::get_package_by_id(&system_package_ref.object_id).clone()
5102            });
5103
5104            #[cfg(not(msim))]
5105            let FrameworkSystemPackage {
5106                id: _,
5107                bytes,
5108                dependencies,
5109            } = BuiltInFramework::get_package_by_id(&system_package_ref.object_id).clone();
5110
5111            let modules: Vec<_> = bytes
5112                .iter()
5113                .map(|m| CompiledModule::deserialize_with_config(m, binary_config).unwrap())
5114                .collect();
5115
5116            let new_object = Object::new_system_package(
5117                &modules,
5118                system_package_ref.version,
5119                dependencies.clone(),
5120                prev_transaction,
5121            );
5122
5123            let new_ref = new_object.object_ref();
5124            if new_ref != system_package_ref {
5125                error!(
5126                    "Framework mismatch -- binary: {new_ref:?}\n  upgrade: {system_package_ref:?}"
5127                );
5128                return None;
5129            }
5130
5131            res.push(SystemPackage {
5132                version: system_package_ref.version,
5133                modules: bytes,
5134                dependencies,
5135            });
5136        }
5137
5138        Some(res)
5139    }
5140
5141    /// Returns the new protocol version and system packages that the network
5142    /// has voted to upgrade to. If the proposed protocol version is not
5143    /// supported, None is returned.
5144    fn is_protocol_version_supported_v1(
5145        proposed_protocol_version: ProtocolVersion,
5146        committee: &Committee,
5147        capabilities: Vec<AuthorityCapabilitiesV1>,
5148        mut buffer_stake_bps: u64,
5149    ) -> Option<(ProtocolVersion, Digest, Vec<ObjectReference>)> {
5150        if buffer_stake_bps > 10000 {
5151            warn!("clamping buffer_stake_bps to 10000");
5152            buffer_stake_bps = 10000;
5153        }
5154
5155        // For each validator, gather the protocol version and system packages that it
5156        // would like to upgrade to in the next epoch.
5157        let mut desired_upgrades: Vec<_> = capabilities
5158            .into_iter()
5159            .filter_map(|mut cap| {
5160                // A validator that lists no packages is voting against any change at all.
5161                if cap.available_system_packages.is_empty() {
5162                    return None;
5163                }
5164
5165                cap.available_system_packages.sort();
5166
5167                info!(
5168                    "validator {:?} supports {:?} with system packages: {:?}",
5169                    cap.authority.concise(),
5170                    cap.supported_protocol_versions,
5171                    cap.available_system_packages,
5172                );
5173
5174                // A validator that only supports the current protocol version is also voting
5175                // against any change, because framework upgrades always require a protocol
5176                // version bump.
5177                cap.supported_protocol_versions
5178                    .get_version_digest(proposed_protocol_version)
5179                    .map(|digest| (digest, cap.available_system_packages, cap.authority))
5180            })
5181            .collect();
5182
5183        // There can only be one set of votes that have a majority, find one if it
5184        // exists.
5185        desired_upgrades.sort();
5186        desired_upgrades
5187            .into_iter()
5188            .chunk_by(|(digest, packages, _authority)| (*digest, packages.clone()))
5189            .into_iter()
5190            .find_map(|((digest, packages), group)| {
5191                // should have been filtered out earlier.
5192                assert!(!packages.is_empty());
5193
5194                let mut stake_aggregator: StakeAggregator<(), true> =
5195                    StakeAggregator::new(Arc::new(committee.clone()));
5196
5197                for (_, _, authority) in group {
5198                    stake_aggregator.insert_generic(authority, ());
5199                }
5200
5201                let total_votes = stake_aggregator.total_votes();
5202                let quorum_threshold = committee.quorum_threshold();
5203                let effective_threshold = committee.effective_threshold(buffer_stake_bps);
5204
5205                info!(
5206                    protocol_config_digest = ?digest,
5207                    ?total_votes,
5208                    ?quorum_threshold,
5209                    ?buffer_stake_bps,
5210                    ?effective_threshold,
5211                    ?proposed_protocol_version,
5212                    ?packages,
5213                    "support for upgrade"
5214                );
5215
5216                let has_support = total_votes >= effective_threshold;
5217                has_support.then_some((proposed_protocol_version, digest, packages))
5218            })
5219    }
5220
5221    /// Selects the highest supported protocol version and system packages that
5222    /// the network has voted to upgrade to. If no upgrade is supported,
5223    /// returns the current protocol version and system packages.
5224    fn choose_protocol_version_and_system_packages_v1(
5225        current_protocol_version: ProtocolVersion,
5226        current_protocol_digest: Digest,
5227        committee: &Committee,
5228        capabilities: Vec<AuthorityCapabilitiesV1>,
5229        buffer_stake_bps: u64,
5230    ) -> (ProtocolVersion, Digest, Vec<ObjectReference>) {
5231        let mut next_protocol_version = current_protocol_version;
5232        let mut system_packages = vec![];
5233        let mut protocol_version_digest = current_protocol_digest;
5234
5235        // Finds the highest supported protocol version and system packages by
5236        // incrementing the proposed protocol version by one until no further
5237        // upgrades are supported.
5238        while let Some((version, digest, packages)) = Self::is_protocol_version_supported_v1(
5239            next_protocol_version + 1,
5240            committee,
5241            capabilities.clone(),
5242            buffer_stake_bps,
5243        ) {
5244            next_protocol_version = version;
5245            protocol_version_digest = digest;
5246            system_packages = packages;
5247        }
5248
5249        (
5250            next_protocol_version,
5251            protocol_version_digest,
5252            system_packages,
5253        )
5254    }
5255
5256    /// Returns the indices of validators that support the given protocol
5257    /// version and digest. This includes both committee and non-committee
5258    /// validators based on their capabilities. Uses active validators
5259    /// instead of committee indices.
5260    fn get_validators_supporting_protocol_version(
5261        target_protocol_version: ProtocolVersion,
5262        target_digest: Digest,
5263        active_validators: &[AuthorityPublicKey],
5264        capabilities: &[AuthorityCapabilitiesV1],
5265    ) -> Vec<u64> {
5266        let mut eligible_validators = Vec::new();
5267
5268        for capability in capabilities {
5269            // Check if this validator supports the target protocol version and digest
5270            if let Some(digest) = capability
5271                .supported_protocol_versions
5272                .get_version_digest(target_protocol_version)
5273            {
5274                if digest == target_digest {
5275                    // Find the validator's index in the active validators list
5276                    if let Some(index) = active_validators
5277                        .iter()
5278                        .position(|name| AuthorityName::from(name) == capability.authority)
5279                    {
5280                        eligible_validators.push(index as u64);
5281                    }
5282                }
5283            }
5284        }
5285
5286        // Sort indices for deterministic behavior
5287        eligible_validators.sort();
5288        eligible_validators
5289    }
5290
5291    /// Calculates the sum of weights for eligible validators that are part of
5292    /// the committee. Takes the indices from
5293    /// get_validators_supporting_protocol_version and maps them back
5294    /// to committee members to get their weights.
5295    fn calculate_eligible_validators_weight(
5296        eligible_validator_indices: &[u64],
5297        active_validators: &[AuthorityPublicKey],
5298        committee: &Committee,
5299    ) -> u64 {
5300        let mut total_weight = 0u64;
5301
5302        for &index in eligible_validator_indices {
5303            let authority_pubkey = &active_validators[index as usize];
5304            // Check if this validator is in the committee and get their weight
5305            if let Some((_, weight)) = committee
5306                .members()
5307                .find(|(name, _)| *name == AuthorityName::from(authority_pubkey))
5308            {
5309                total_weight += weight;
5310            }
5311        }
5312
5313        total_weight
5314    }
5315
5316    /// Creates and execute the advance epoch transaction to effects without
5317    /// committing it to the database. The effects of the change epoch tx
5318    /// are only written to the database after a certified checkpoint has been
5319    /// formed and executed by CheckpointExecutor.
5320    ///
5321    /// When a framework upgraded has been decided on, but the validator does
5322    /// not have the new versions of the packages locally, the validator
5323    /// cannot form the ChangeEpochTx. In this case it returns Err,
5324    /// indicating that the checkpoint builder should give up trying to make the
5325    /// final checkpoint. As long as the network is able to create a certified
5326    /// checkpoint (which should be ensured by the capabilities vote), it
5327    /// will arrive via state sync and be executed by CheckpointExecutor.
5328    #[instrument(level = "error", skip_all)]
5329    pub async fn create_and_execute_advance_epoch_tx(
5330        &self,
5331        epoch_store: &Arc<AuthorityPerEpochStore>,
5332        gas_cost_summary: &GasCostSummary,
5333        checkpoint: CheckpointSequenceNumber,
5334        epoch_start_timestamp_ms: CheckpointTimestamp,
5335        scores: Vec<u64>,
5336    ) -> anyhow::Result<(
5337        IotaSystemState,
5338        Option<SystemEpochInfoEvent>,
5339        TransactionEffects,
5340    )> {
5341        let mut txns = Vec::new();
5342
5343        let next_epoch = epoch_store.epoch() + 1;
5344
5345        let buffer_stake_bps = epoch_store.get_effective_buffer_stake_bps();
5346        let authority_capabilities = epoch_store
5347            .get_capabilities_v1()
5348            .expect("read capabilities from db cannot fail");
5349        let (next_epoch_protocol_version, next_epoch_protocol_digest, next_epoch_system_packages) =
5350            Self::choose_protocol_version_and_system_packages_v1(
5351                epoch_store.protocol_version(),
5352                SupportedProtocolVersionsWithHashes::protocol_config_digest(
5353                    epoch_store.protocol_config(),
5354                ),
5355                epoch_store.committee(),
5356                authority_capabilities.clone(),
5357                buffer_stake_bps,
5358            );
5359
5360        // since system packages are created during the current epoch, they should abide
5361        // by the rules of the current epoch, including the current epoch's max
5362        // Move binary format version
5363        let config = epoch_store.protocol_config();
5364        let binary_config = to_binary_config(config);
5365        let Some(next_epoch_system_package_bytes) = self
5366            .get_system_package_bytes(next_epoch_system_packages.clone(), &binary_config)
5367            .await
5368        else {
5369            error!(
5370                "upgraded system packages {:?} are not locally available, cannot create \
5371                ChangeEpochTx. validator binary must be upgraded to the correct version!",
5372                next_epoch_system_packages
5373            );
5374            // the checkpoint builder will keep retrying forever when it hits this error.
5375            // Eventually, one of two things will happen:
5376            // - The operator will upgrade this binary to one that has the new packages
5377            //   locally, and this function will succeed.
5378            // - The final checkpoint will be certified by other validators, we will receive
5379            //   it via state sync, and execute it. This will upgrade the framework
5380            //   packages, reconfigure, and most likely shut down in the new epoch (this
5381            //   validator likely doesn't support the new protocol version, or else it
5382            //   should have had the packages.)
5383            bail!("missing system packages: cannot form ChangeEpochTx");
5384        };
5385
5386        // Use ChangeEpochV3 or ChangeEpochV4 when the feature flags are enabled and
5387        // ChangeEpochV2 requirements are met
5388        if config.select_committee_from_eligible_validators() {
5389            // Get the list of eligible validators that support the target protocol version
5390            let active_validators = epoch_store.epoch_start_state().get_active_validators();
5391
5392            let mut eligible_active_validators = (0..active_validators.len() as u64).collect();
5393
5394            // Use validators supporting the target protocol version as eligible validators
5395            // in the next version if select_committee_supporting_next_epoch_version feature
5396            // flag is set to true.
5397            if config.select_committee_supporting_next_epoch_version() {
5398                eligible_active_validators = Self::get_validators_supporting_protocol_version(
5399                    next_epoch_protocol_version,
5400                    next_epoch_protocol_digest,
5401                    &active_validators,
5402                    &authority_capabilities,
5403                );
5404
5405                // Calculate the total weight of eligible validators in the committee
5406                let eligible_validators_weight = Self::calculate_eligible_validators_weight(
5407                    &eligible_active_validators,
5408                    &active_validators,
5409                    epoch_store.committee(),
5410                );
5411
5412                // Safety check: ensure eligible validators have enough stake
5413                // Use the same effective threshold calculation that was used to decide the
5414                // protocol version
5415                let committee = epoch_store.committee();
5416                let effective_threshold = committee.effective_threshold(buffer_stake_bps);
5417
5418                if eligible_validators_weight < effective_threshold {
5419                    error!(
5420                        "Eligible validators weight {eligible_validators_weight} is less than effective threshold {effective_threshold}. \
5421                        This could indicate a bug in validator selection logic or inconsistency with protocol version decision.",
5422                    );
5423                    // Pass all active validator indices as eligible validators
5424                    // to perform selection among all of them.
5425                    eligible_active_validators = (0..active_validators.len() as u64).collect();
5426                }
5427            }
5428
5429            // Use ChangeEpochV4 when the pass_validator_scores_to_advance_epoch feature
5430            // flag is enabled.
5431            if config.pass_validator_scores_to_advance_epoch() {
5432                txns.push(EndOfEpochTransactionKind::new_change_epoch_v4(
5433                    next_epoch,
5434                    next_epoch_protocol_version.as_u64(),
5435                    gas_cost_summary.storage_cost,
5436                    gas_cost_summary.computation_cost,
5437                    gas_cost_summary.computation_cost_burned,
5438                    gas_cost_summary.storage_rebate,
5439                    gas_cost_summary.non_refundable_storage_fee,
5440                    epoch_start_timestamp_ms,
5441                    next_epoch_system_package_bytes,
5442                    eligible_active_validators,
5443                    scores,
5444                    config.adjust_rewards_by_score(),
5445                ));
5446            } else {
5447                txns.push(EndOfEpochTransactionKind::new_change_epoch_v3(
5448                    next_epoch,
5449                    next_epoch_protocol_version.as_u64(),
5450                    gas_cost_summary.storage_cost,
5451                    gas_cost_summary.computation_cost,
5452                    gas_cost_summary.computation_cost_burned,
5453                    gas_cost_summary.storage_rebate,
5454                    gas_cost_summary.non_refundable_storage_fee,
5455                    epoch_start_timestamp_ms,
5456                    next_epoch_system_package_bytes,
5457                    eligible_active_validators,
5458                ));
5459            }
5460        } else if config.protocol_defined_base_fee()
5461            && config.max_committee_members_count_as_option().is_some()
5462        {
5463            txns.push(EndOfEpochTransactionKind::new_change_epoch_v2(
5464                next_epoch,
5465                next_epoch_protocol_version.as_u64(),
5466                gas_cost_summary.storage_cost,
5467                gas_cost_summary.computation_cost,
5468                gas_cost_summary.computation_cost_burned,
5469                gas_cost_summary.storage_rebate,
5470                gas_cost_summary.non_refundable_storage_fee,
5471                epoch_start_timestamp_ms,
5472                next_epoch_system_package_bytes,
5473            ));
5474        } else {
5475            txns.push(EndOfEpochTransactionKind::new_change_epoch(
5476                next_epoch,
5477                next_epoch_protocol_version.as_u64(),
5478                gas_cost_summary.storage_cost,
5479                gas_cost_summary.computation_cost,
5480                gas_cost_summary.storage_rebate,
5481                gas_cost_summary.non_refundable_storage_fee,
5482                epoch_start_timestamp_ms,
5483                next_epoch_system_package_bytes,
5484            ));
5485        }
5486
5487        let tx = VerifiedTransaction::new_end_of_epoch_transaction(txns);
5488
5489        let executable_tx = VerifiedExecutableTransaction::new_from_checkpoint(
5490            tx.clone(),
5491            epoch_store.epoch(),
5492            checkpoint,
5493        );
5494
5495        let tx_digest = executable_tx.digest();
5496
5497        info!(
5498            ?next_epoch,
5499            ?next_epoch_protocol_version,
5500            ?next_epoch_system_packages,
5501            computation_cost=?gas_cost_summary.computation_cost,
5502            computation_cost_burned=?gas_cost_summary.computation_cost_burned,
5503            storage_cost=?gas_cost_summary.storage_cost,
5504            storage_rebate=?gas_cost_summary.storage_rebate,
5505            non_refundable_storage_fee=?gas_cost_summary.non_refundable_storage_fee,
5506            ?tx_digest,
5507            "Creating advance epoch transaction"
5508        );
5509
5510        fail_point_async!("change_epoch_tx_delay");
5511        let tx_lock = epoch_store.acquire_tx_lock(tx_digest);
5512
5513        // The tx could have been executed by state sync already - if so simply return
5514        // an error. The checkpoint builder will shortly be terminated by
5515        // reconfiguration anyway.
5516        if self
5517            .get_transaction_cache_reader()
5518            .try_is_tx_already_executed(tx_digest)?
5519        {
5520            warn!("change epoch tx has already been executed via state sync");
5521            bail!("change epoch tx has already been executed via state sync",);
5522        }
5523
5524        let execution_guard = self.execution_lock_for_executable_transaction(&executable_tx)?;
5525
5526        // We must manually assign the shared object versions to the transaction before
5527        // executing it. This is because we do not sequence end-of-epoch
5528        // transactions through consensus.
5529        epoch_store.assign_shared_object_versions_idempotent(
5530            self.get_object_cache_reader().as_ref(),
5531            std::slice::from_ref(&executable_tx),
5532        )?;
5533
5534        let (input_objects, _) =
5535            self.read_objects_for_execution(&tx_lock, &executable_tx, epoch_store)?;
5536
5537        let (temporary_store, effects, _execution_error_opt) = self.execute_transaction(
5538            &execution_guard,
5539            &executable_tx,
5540            input_objects,
5541            vec![],
5542            epoch_store,
5543        )?;
5544        let system_obj = get_iota_system_state(&temporary_store.written)
5545            .expect("change epoch tx must write to system object");
5546        // Find the SystemEpochInfoEvent emitted by the advance_epoch transaction.
5547        let system_epoch_info_event = temporary_store
5548            .events
5549            .0
5550            .into_iter()
5551            .find(|event| event.is_system_epoch_info_event())
5552            .map(SystemEpochInfoEvent::from);
5553        // The system epoch info event can be `None` in case if the `advance_epoch`
5554        // Move function call failed and was executed in the safe mode.
5555        assert!(system_epoch_info_event.is_some() || system_obj.safe_mode());
5556
5557        // We must write tx and effects to the state sync tables so that state sync is
5558        // able to deliver to the transaction to CheckpointExecutor after it is
5559        // included in a certified checkpoint.
5560        self.get_state_sync_store()
5561            .try_insert_transaction_and_effects(&tx, &effects)
5562            .map_err(|err| {
5563                let err: anyhow::Error = err.into();
5564                err
5565            })?;
5566
5567        info!(
5568            "Effects summary of the change epoch transaction: {:?}",
5569            effects.summary_for_debug()
5570        );
5571        epoch_store.record_checkpoint_builder_is_safe_mode_metric(system_obj.safe_mode());
5572        // The change epoch transaction cannot fail to execute.
5573        assert!(effects.status().is_success());
5574        Ok((system_obj, system_epoch_info_event, effects))
5575    }
5576
5577    /// This function is called at the very end of the epoch.
5578    /// This step is required before updating new epoch in the db and calling
5579    /// reopen_epoch_db.
5580    #[instrument(level = "error", skip_all)]
5581    async fn revert_uncommitted_epoch_transactions(
5582        &self,
5583        epoch_store: &AuthorityPerEpochStore,
5584    ) -> IotaResult {
5585        {
5586            let state = epoch_store.get_reconfig_state_write_lock_guard();
5587            if state.should_accept_user_certs() {
5588                // Need to change this so that consensus adapter do not accept certificates from
5589                // user. This can happen if our local validator did not initiate
5590                // epoch change locally, but 2f+1 nodes already concluded the
5591                // epoch.
5592                //
5593                // This lock is essentially a barrier (in the certificate mode only) for
5594                // `epoch_store.pending_consensus_certificates` table we are reading on the line
5595                // after this block
5596                epoch_store.close_user_certs(state);
5597            }
5598            // lock is dropped here
5599        }
5600
5601        // In the P-COOL flow, the list of pending consensus certificates is
5602        // always empty, so the reverting below is only for the certificate mode.
5603        if !epoch_store.protocol_config().enable_pcool_flow() {
5604            let pending_certificates = epoch_store.pending_consensus_certificates();
5605            info!(
5606                "Reverting {} locally executed transactions that was not included in the epoch: \
5607                    {:?}",
5608                pending_certificates.len(),
5609                pending_certificates,
5610            );
5611            for digest in pending_certificates {
5612                if epoch_store.is_transaction_executed_in_checkpoint(&digest)? {
5613                    info!(
5614                        "Not reverting pending consensus transaction {:?} - it was included in \
5615                            checkpoint",
5616                        digest
5617                    );
5618                    continue;
5619                }
5620                info!("Reverting {:?} at the end of epoch", digest);
5621                epoch_store.revert_executed_transaction(&digest)?;
5622                self.get_reconfig_api().try_revert_state_update(&digest)?;
5623            }
5624            info!("All uncommitted local transactions reverted");
5625        } else {
5626            info!("P-COOL mode: skipping revert of uncommitted epoch transactions");
5627        }
5628
5629        Ok(())
5630    }
5631
5632    #[instrument(level = "error", skip_all)]
5633    async fn reopen_epoch_db(
5634        &self,
5635        cur_epoch_store: &AuthorityPerEpochStore,
5636        new_committee: Committee,
5637        epoch_start_configuration: EpochStartConfiguration,
5638        expensive_safety_check_config: &ExpensiveSafetyCheckConfig,
5639        epoch_last_checkpoint: CheckpointSequenceNumber,
5640    ) -> IotaResult<Arc<AuthorityPerEpochStore>> {
5641        let new_epoch = new_committee.epoch;
5642        info!(new_epoch = ?new_epoch, "re-opening AuthorityEpochTables for new epoch");
5643        assert_eq!(
5644            epoch_start_configuration.epoch_start_state().epoch(),
5645            new_committee.epoch
5646        );
5647        fail_point!("before-open-new-epoch-store");
5648        let new_epoch_store = cur_epoch_store.new_at_next_epoch(
5649            self.name,
5650            new_committee,
5651            epoch_start_configuration,
5652            self.get_backing_package_store().clone(),
5653            expensive_safety_check_config,
5654            epoch_last_checkpoint,
5655        )?;
5656        self.epoch_store.store(new_epoch_store.clone());
5657        Ok(new_epoch_store)
5658    }
5659
5660    /// Checks if `authenticator` unlocks a valid Move account and returns the
5661    /// account-related `AuthenticatorFunctionRef` object.
5662    fn check_move_account(
5663        &self,
5664        auth_account_object_id: ObjectId,
5665        auth_account_object_seq_number: Option<Version>,
5666        auth_account_object_digest: Option<ObjectDigest>,
5667        account_object: ObjectReadResult,
5668        signer: &Address,
5669    ) -> IotaResult<AuthenticatorFunctionRefForExecution> {
5670        let account_object = match account_object.object {
5671            ObjectReadResultKind::Object(object) => Ok(object),
5672            ObjectReadResultKind::DeletedSharedObject(version, digest) => {
5673                Err(UserInputError::AccountObjectDeleted {
5674                    account_id: account_object.id(),
5675                    account_version: version,
5676                    transaction_digest: digest,
5677                })
5678            }
5679            // It is impossible to check the account object because it is used in a canceled
5680            // transaction and is not loaded.
5681            ObjectReadResultKind::CancelledTransactionSharedObject(version) => {
5682                Err(UserInputError::AccountObjectInCanceledTransaction {
5683                    account_id: account_object.id(),
5684                    account_version: version,
5685                })
5686            }
5687        }?;
5688
5689        let account_object_addr = Address::from(auth_account_object_id);
5690
5691        fp_ensure!(
5692            signer == &account_object_addr,
5693            UserInputError::IncorrectUserSignature {
5694                error: format!("Move authenticator is trying to unlock {account_object_addr:?}, but given signer address is {signer:?}")
5695            }
5696            .into()
5697        );
5698
5699        fp_ensure!(
5700            account_object.is_shared() || account_object.is_immutable(),
5701            UserInputError::AccountObjectNotSupported {
5702                object_id: auth_account_object_id
5703            }
5704            .into()
5705        );
5706
5707        let auth_account_object_seq_number =
5708            if let Some(auth_account_object_seq_number) = auth_account_object_seq_number {
5709                let account_object_version = account_object.version();
5710
5711                fp_ensure!(
5712                    account_object_version == auth_account_object_seq_number,
5713                    UserInputError::AccountObjectVersionMismatch {
5714                        object_id: auth_account_object_id,
5715                        expected_version: auth_account_object_seq_number,
5716                        actual_version: account_object_version,
5717                    }
5718                    .into()
5719                );
5720
5721                auth_account_object_seq_number
5722            } else {
5723                account_object.version()
5724            };
5725
5726        if let Some(auth_account_object_digest) = auth_account_object_digest {
5727            let expected_digest = account_object.digest();
5728            fp_ensure!(
5729                expected_digest == auth_account_object_digest,
5730                UserInputError::InvalidAccountObjectDigest {
5731                    object_id: auth_account_object_id,
5732                    expected_digest,
5733                    actual_digest: auth_account_object_digest,
5734                }
5735                .into()
5736            );
5737        }
5738
5739        let authenticator_function_ref_field_id =
5740            derive_authenticator_function_ref_v1_dynamic_field_id(auth_account_object_id)?;
5741
5742        let authenticator_function_ref_field = self
5743            .get_object_cache_reader()
5744            .try_find_object_lt_or_eq_version(
5745                authenticator_function_ref_field_id,
5746                auth_account_object_seq_number,
5747            )?;
5748
5749        if let Some(authenticator_function_ref_field_obj) = authenticator_function_ref_field {
5750            Ok(authenticator_function_ref_v1_from_dynamic_field_object(
5751                auth_account_object_id,
5752                &authenticator_function_ref_field_obj,
5753            )?)
5754        } else {
5755            Err(UserInputError::MoveAuthenticatorNotFound {
5756                authenticator_function_ref_id: authenticator_function_ref_field_id,
5757                account_object_id: auth_account_object_id,
5758                account_object_version: auth_account_object_seq_number,
5759            }
5760            .into())
5761        }
5762    }
5763
5764    #[allow(clippy::type_complexity)]
5765    fn read_objects_for_validation(
5766        &self,
5767        transaction: &VerifiedTransaction,
5768        epoch: u64,
5769    ) -> IotaResult<(
5770        InputObjects,
5771        ReceivingObjects,
5772        Vec<(InputObjects, ObjectReadResult)>,
5773    )> {
5774        let (input_objects, tx_receiving_objects) = self.input_loader.read_objects_for_signing(
5775            Some(transaction.digest()),
5776            &transaction.collect_all_input_object_kind_for_reading()?,
5777            &transaction.data().transaction_data().receiving_objects(),
5778            epoch,
5779        )?;
5780
5781        transaction
5782            .split_input_objects_into_groups_for_reading(input_objects)
5783            .map(|(tx_input_objects, per_authenticator_inputs)| {
5784                (
5785                    tx_input_objects,
5786                    tx_receiving_objects,
5787                    per_authenticator_inputs,
5788                )
5789            })
5790    }
5791
5792    #[allow(clippy::type_complexity)]
5793    fn check_transaction_inputs_for_validation(
5794        &self,
5795        protocol_config: &ProtocolConfig,
5796        reference_gas_price: u64,
5797        tx_data: &TransactionData,
5798        tx_input_objects: InputObjects,
5799        tx_receiving_objects: &ReceivingObjects,
5800        move_authenticators: &Vec<&MoveAuthenticator>,
5801        per_authenticator_inputs: Vec<(InputObjects, ObjectReadResult)>,
5802    ) -> IotaResult<(
5803        IotaGasStatus,
5804        CheckedInputObjects,
5805        Vec<(CheckedInputObjects, AuthenticatorFunctionRef)>,
5806    )> {
5807        let authenticator_gas_budget = if move_authenticators.is_empty() {
5808            0
5809        } else {
5810            // `max_auth_gas` is used here as a Move authenticator gas budget until it is
5811            // not a part of the transaction data.
5812            protocol_config.max_auth_gas()
5813        };
5814
5815        debug_assert_eq!(
5816            move_authenticators.len(),
5817            per_authenticator_inputs.len(),
5818            "Move authenticators amount must match the number of authenticator inputs"
5819        );
5820
5821        let per_authenticator_checked_inputs = move_authenticators
5822            .iter()
5823            .zip(per_authenticator_inputs)
5824            .map(
5825                |(move_authenticator, (authenticator_input_objects, account_object))| {
5826                    // Check basic `object_to_authenticate` preconditions and get its components.
5827                    let (
5828                        auth_account_object_id,
5829                        auth_account_object_seq_number,
5830                        auth_account_object_digest,
5831                    ) = move_authenticator.object_to_authenticate_components()?;
5832
5833                    let signer = move_authenticator.address();
5834
5835                    // Make sure the signer is a Move account.
5836                    let AuthenticatorFunctionRefForExecution {
5837                        authenticator_function_ref,
5838                        ..
5839                    } = self.check_move_account(
5840                        auth_account_object_id,
5841                        auth_account_object_seq_number,
5842                        auth_account_object_digest,
5843                        account_object,
5844                        &signer,
5845                    )?;
5846
5847                    // Check the MoveAuthenticator input objects.
5848                    let authenticator_checked_input_objects =
5849                        iota_transaction_checks::check_move_authenticator_input_for_validation(
5850                            authenticator_input_objects,
5851                        )?;
5852
5853                    Ok((
5854                        authenticator_checked_input_objects,
5855                        authenticator_function_ref,
5856                    ))
5857                },
5858            )
5859            .collect::<IotaResult<Vec<_>>>()?;
5860
5861        // Check the transaction inputs.
5862        let (gas_status, tx_checked_input_objects) =
5863            iota_transaction_checks::check_transaction_input(
5864                protocol_config,
5865                reference_gas_price,
5866                tx_data,
5867                tx_input_objects,
5868                tx_receiving_objects,
5869                &self.metrics.bytecode_verifier_metrics,
5870                &self.config.verifier_signing_config,
5871                authenticator_gas_budget,
5872            )?;
5873
5874        Ok((
5875            gas_status,
5876            tx_checked_input_objects,
5877            per_authenticator_checked_inputs,
5878        ))
5879    }
5880
5881    #[cfg(test)]
5882    pub(crate) fn iter_live_object_set_for_testing(
5883        &self,
5884    ) -> impl Iterator<Item = authority_store_tables::LiveObject> + '_ {
5885        self.get_global_state_hash_store()
5886            .iter_cached_live_object_set_for_testing()
5887    }
5888
5889    #[cfg(test)]
5890    pub(crate) fn shutdown_execution_for_test(&self) {
5891        self.tx_execution_shutdown
5892            .lock()
5893            .take()
5894            .unwrap()
5895            .send(())
5896            .unwrap();
5897    }
5898
5899    /// NOTE: this function is only to be used for fuzzing and testing. Never
5900    /// use in prod
5901    pub async fn insert_objects_unsafe_for_testing_only(&self, objects: &[Object]) {
5902        self.get_reconfig_api().bulk_insert_genesis_objects(objects);
5903        self.get_object_cache_reader()
5904            .force_reload_system_packages(&BuiltInFramework::all_package_ids());
5905        self.get_reconfig_api()
5906            .clear_state_end_of_epoch(&self.execution_lock_for_reconfiguration().await);
5907    }
5908}
5909
5910pub struct RandomnessRoundReceiver {
5911    authority_state: Arc<AuthorityState>,
5912    randomness_rx: mpsc::Receiver<(EpochId, RandomnessRound, Vec<u8>)>,
5913}
5914
5915impl RandomnessRoundReceiver {
5916    pub fn spawn(
5917        authority_state: Arc<AuthorityState>,
5918        randomness_rx: mpsc::Receiver<(EpochId, RandomnessRound, Vec<u8>)>,
5919    ) -> JoinHandle<()> {
5920        let rrr = RandomnessRoundReceiver {
5921            authority_state,
5922            randomness_rx,
5923        };
5924        spawn_monitored_task!(rrr.run())
5925    }
5926
5927    async fn run(mut self) {
5928        info!("RandomnessRoundReceiver event loop started");
5929
5930        loop {
5931            tokio::select! {
5932                maybe_recv = self.randomness_rx.recv() => {
5933                    if let Some((epoch, round, bytes)) = maybe_recv {
5934                        self.handle_new_randomness(epoch, round, bytes).await;
5935                    } else {
5936                        break;
5937                    }
5938                },
5939            }
5940        }
5941
5942        info!("RandomnessRoundReceiver event loop ended");
5943    }
5944
5945    #[instrument(level = "debug", skip_all, fields(?epoch, ?round))]
5946    async fn handle_new_randomness(&self, epoch: EpochId, round: RandomnessRound, bytes: Vec<u8>) {
5947        fail_point_async!("randomness-delay");
5948
5949        let epoch_store = self.authority_state.load_epoch_store_one_call_per_task();
5950        if epoch_store.epoch() != epoch {
5951            warn!(
5952                "dropping randomness for epoch {epoch}, round {round}, because we are in epoch {}",
5953                epoch_store.epoch()
5954            );
5955            return;
5956        }
5957        let transaction = VerifiedTransaction::new_randomness_state_update(
5958            epoch,
5959            round,
5960            bytes,
5961            epoch_store
5962                .epoch_start_config()
5963                .randomness_obj_initial_shared_version(),
5964        );
5965        debug!(
5966            "created randomness state update transaction with digest: {:?}",
5967            transaction.digest()
5968        );
5969        let transaction = VerifiedExecutableTransaction::new_system(transaction, epoch);
5970        let digest = *transaction.digest();
5971
5972        // Randomness state updates contain the full bls signature for the random round,
5973        // which cannot necessarily be reconstructed again later. Therefore we must
5974        // immediately persist this transaction. If we crash before its outputs
5975        // are committed, this ensures we will be able to re-execute it.
5976        self.authority_state
5977            .get_cache_commit()
5978            .persist_transaction(&transaction);
5979
5980        // Send transaction to TransactionManager for execution.
5981        self.authority_state
5982            .transaction_manager()
5983            .enqueue(vec![transaction], &epoch_store);
5984
5985        let authority_state = self.authority_state.clone();
5986        spawn_monitored_task!(async move {
5987            // Wait for transaction execution in a separate task, to avoid deadlock in case
5988            // of out-of-order randomness generation. (Each
5989            // RandomnessStateUpdate depends on the output of the
5990            // RandomnessStateUpdate from the previous round.)
5991            //
5992            // We set a very long timeout so that in case this gets stuck for some reason,
5993            // the validator will eventually crash rather than continuing in a
5994            // zombie mode.
5995            const RANDOMNESS_STATE_UPDATE_EXECUTION_TIMEOUT: Duration = Duration::from_secs(300);
5996            let result = tokio::time::timeout(
5997                RANDOMNESS_STATE_UPDATE_EXECUTION_TIMEOUT,
5998                authority_state
5999                    .get_transaction_cache_reader()
6000                    .try_notify_read_executed_effects(&[digest]),
6001            )
6002            .await;
6003            let result = match result {
6004                Ok(result) => result,
6005                Err(_) => {
6006                    if cfg!(debug_assertions) {
6007                        // Crash on randomness update execution timeout in debug builds.
6008                        panic!(
6009                            "randomness state update transaction execution timed out at epoch {epoch}, round {round}"
6010                        );
6011                    }
6012                    warn!(
6013                        "randomness state update transaction execution timed out at epoch {epoch}, round {round}"
6014                    );
6015                    // Continue waiting as long as necessary in non-debug builds.
6016                    authority_state
6017                        .get_transaction_cache_reader()
6018                        .try_notify_read_executed_effects(&[digest])
6019                        .await
6020                }
6021            };
6022
6023            let mut effects = result.unwrap_or_else(|_| panic!("failed to get effects for randomness state update transaction at epoch {epoch}, round {round}"));
6024            let effects = effects.pop().expect("should return effects");
6025            if *effects.status() != ExecutionStatus::Success {
6026                fatal!(
6027                    "failed to execute randomness state update transaction at epoch {epoch}, round {round}: {effects:?}"
6028                );
6029            }
6030            debug!(
6031                "successfully executed randomness state update transaction at epoch {epoch}, round {round}"
6032            );
6033        });
6034    }
6035}
6036
6037#[async_trait]
6038impl TransactionKeyValueStoreTrait for AuthorityState {
6039    async fn multi_get(
6040        &self,
6041        transaction_keys: &[TransactionDigest],
6042        effects_keys: &[TransactionDigest],
6043    ) -> IotaResult<KVStoreTransactionData> {
6044        let txns = if !transaction_keys.is_empty() {
6045            self.get_transaction_cache_reader()
6046                .try_multi_get_transaction_blocks(transaction_keys)?
6047                .into_iter()
6048                .map(|t| t.map(|t| (*t).clone().into_inner()))
6049                .collect()
6050        } else {
6051            vec![]
6052        };
6053
6054        let fx = if !effects_keys.is_empty() {
6055            self.get_transaction_cache_reader()
6056                .try_multi_get_executed_effects(effects_keys)?
6057        } else {
6058            vec![]
6059        };
6060
6061        Ok((txns, fx))
6062    }
6063
6064    async fn multi_get_checkpoints(
6065        &self,
6066        checkpoint_summaries: &[CheckpointSequenceNumber],
6067        checkpoint_contents: &[CheckpointSequenceNumber],
6068        checkpoint_summaries_by_digest: &[CheckpointDigest],
6069    ) -> IotaResult<(
6070        Vec<Option<CertifiedCheckpointSummary>>,
6071        Vec<Option<CheckpointContents>>,
6072        Vec<Option<CertifiedCheckpointSummary>>,
6073    )> {
6074        // TODO: use multi-get methods if it ever becomes important (unlikely)
6075        let mut summaries = Vec::with_capacity(checkpoint_summaries.len());
6076        let store = self.get_checkpoint_store();
6077        for seq in checkpoint_summaries {
6078            let checkpoint = store
6079                .get_checkpoint_by_sequence_number(*seq)?
6080                .map(|c| c.into_inner());
6081
6082            summaries.push(checkpoint);
6083        }
6084
6085        let mut contents = Vec::with_capacity(checkpoint_contents.len());
6086        for seq in checkpoint_contents {
6087            let checkpoint = store
6088                .get_checkpoint_by_sequence_number(*seq)?
6089                .and_then(|summary| {
6090                    store
6091                        .get_checkpoint_contents(&summary.content_digest)
6092                        .expect("db read cannot fail")
6093                });
6094            contents.push(checkpoint);
6095        }
6096
6097        let mut summaries_by_digest = Vec::with_capacity(checkpoint_summaries_by_digest.len());
6098        for digest in checkpoint_summaries_by_digest {
6099            let checkpoint = store
6100                .get_checkpoint_by_digest(digest)?
6101                .map(|c| c.into_inner());
6102            summaries_by_digest.push(checkpoint);
6103        }
6104
6105        Ok((summaries, contents, summaries_by_digest))
6106    }
6107
6108    async fn get_transaction_perpetual_checkpoint(
6109        &self,
6110        digest: TransactionDigest,
6111    ) -> IotaResult<Option<CheckpointSequenceNumber>> {
6112        self.get_checkpoint_cache()
6113            .try_get_transaction_perpetual_checkpoint(&digest)
6114            .map(|res| res.map(|(_epoch, checkpoint)| checkpoint))
6115    }
6116
6117    async fn get_object(
6118        &self,
6119        object_id: ObjectId,
6120        version: VersionNumber,
6121    ) -> IotaResult<Option<Object>> {
6122        self.get_object_cache_reader()
6123            .try_get_object_by_key(&object_id, version)
6124    }
6125
6126    #[instrument(skip_all)]
6127    async fn multi_get_objects(
6128        &self,
6129        object_keys: &[ObjectKey],
6130    ) -> IotaResult<Vec<Option<Object>>> {
6131        Ok(self
6132            .get_object_cache_reader()
6133            .multi_get_objects_by_key(object_keys))
6134    }
6135
6136    async fn multi_get_transactions_perpetual_checkpoints(
6137        &self,
6138        digests: &[TransactionDigest],
6139    ) -> IotaResult<Vec<Option<CheckpointSequenceNumber>>> {
6140        let res = self
6141            .get_checkpoint_cache()
6142            .try_multi_get_transactions_perpetual_checkpoints(digests)?;
6143
6144        Ok(res
6145            .into_iter()
6146            .map(|maybe| maybe.map(|(_epoch, checkpoint)| checkpoint))
6147            .collect())
6148    }
6149
6150    #[instrument(skip(self, digests), fields(digests = digests.iter().map(|d| d.to_string()).collect::<Vec<String>>().join(", ")))]
6151    async fn multi_get_events_by_tx_digests(
6152        &self,
6153        digests: &[TransactionDigest],
6154    ) -> IotaResult<Vec<Option<TransactionEvents>>> {
6155        if digests.is_empty() {
6156            return Ok(vec![]);
6157        }
6158
6159        Ok(self
6160            .get_transaction_cache_reader()
6161            .multi_get_events(digests))
6162    }
6163}
6164
6165#[cfg(msim)]
6166pub mod framework_injection {
6167    use std::{
6168        cell::RefCell,
6169        collections::{BTreeMap, BTreeSet},
6170    };
6171
6172    use iota_framework::{BuiltInFramework, SystemPackage};
6173    use iota_sdk_types::ObjectId;
6174    use iota_types::base_types::AuthorityName;
6175    use move_binary_format::CompiledModule;
6176
6177    type FrameworkOverrideConfig = BTreeMap<ObjectId, PackageOverrideConfig>;
6178
6179    // Thread local cache because all simtests run in a single unique thread.
6180    thread_local! {
6181        static OVERRIDE: RefCell<FrameworkOverrideConfig> = RefCell::new(FrameworkOverrideConfig::default());
6182    }
6183
6184    type Framework = Vec<CompiledModule>;
6185
6186    pub type PackageUpgradeCallback =
6187        Box<dyn Fn(AuthorityName) -> Option<Framework> + Send + Sync + 'static>;
6188
6189    enum PackageOverrideConfig {
6190        Global(Framework),
6191        PerValidator(PackageUpgradeCallback),
6192    }
6193
6194    fn compiled_modules_to_bytes(modules: &[CompiledModule]) -> Vec<Vec<u8>> {
6195        modules
6196            .iter()
6197            .map(|m| {
6198                let mut buf = Vec::new();
6199                m.serialize_with_version(m.version, &mut buf).unwrap();
6200                buf
6201            })
6202            .collect()
6203    }
6204
6205    pub fn set_override(package_id: ObjectId, modules: Vec<CompiledModule>) {
6206        OVERRIDE.with(|bs| {
6207            bs.borrow_mut()
6208                .insert(package_id, PackageOverrideConfig::Global(modules))
6209        });
6210    }
6211
6212    pub fn set_override_cb(package_id: ObjectId, func: PackageUpgradeCallback) {
6213        OVERRIDE.with(|bs| {
6214            bs.borrow_mut()
6215                .insert(package_id, PackageOverrideConfig::PerValidator(func))
6216        });
6217    }
6218
6219    pub fn get_override_bytes(package_id: &ObjectId, name: AuthorityName) -> Option<Vec<Vec<u8>>> {
6220        OVERRIDE.with(|cfg| {
6221            cfg.borrow().get(package_id).and_then(|entry| match entry {
6222                PackageOverrideConfig::Global(framework) => {
6223                    Some(compiled_modules_to_bytes(framework))
6224                }
6225                PackageOverrideConfig::PerValidator(func) => {
6226                    func(name).map(|fw| compiled_modules_to_bytes(&fw))
6227                }
6228            })
6229        })
6230    }
6231
6232    pub fn get_override_modules(
6233        package_id: &ObjectId,
6234        name: AuthorityName,
6235    ) -> Option<Vec<CompiledModule>> {
6236        OVERRIDE.with(|cfg| {
6237            cfg.borrow().get(package_id).and_then(|entry| match entry {
6238                PackageOverrideConfig::Global(framework) => Some(framework.clone()),
6239                PackageOverrideConfig::PerValidator(func) => func(name),
6240            })
6241        })
6242    }
6243
6244    pub fn get_override_system_package(
6245        package_id: &ObjectId,
6246        name: AuthorityName,
6247    ) -> Option<SystemPackage> {
6248        let bytes = get_override_bytes(package_id, name)?;
6249        let dependencies = if package_id.is_system_package() {
6250            BuiltInFramework::get_package_by_id(package_id)
6251                .dependencies
6252                .to_vec()
6253        } else {
6254            // Assume that entirely new injected packages depend on all existing system
6255            // packages.
6256            BuiltInFramework::all_package_ids()
6257        };
6258        Some(SystemPackage {
6259            id: *package_id,
6260            bytes,
6261            dependencies,
6262        })
6263    }
6264
6265    pub fn get_extra_packages(name: AuthorityName) -> Vec<SystemPackage> {
6266        let built_in = BTreeSet::from_iter(BuiltInFramework::all_package_ids());
6267        let extra: Vec<ObjectId> = OVERRIDE.with(|cfg| {
6268            cfg.borrow()
6269                .keys()
6270                .filter_map(|package| (!built_in.contains(package)).then_some(*package))
6271                .collect()
6272        });
6273
6274        extra
6275            .into_iter()
6276            .map(|package| SystemPackage {
6277                id: package,
6278                bytes: get_override_bytes(&package, name).unwrap(),
6279                dependencies: BuiltInFramework::all_package_ids(),
6280            })
6281            .collect()
6282    }
6283}
6284
6285#[derive(Debug, Serialize, Deserialize, Clone)]
6286pub struct ObjDumpFormat {
6287    pub id: ObjectId,
6288    pub version: VersionNumber,
6289    pub digest: ObjectDigest,
6290    pub object: Object,
6291}
6292
6293impl ObjDumpFormat {
6294    fn new(object: Object) -> Self {
6295        let oref = object.object_ref();
6296        Self {
6297            id: oref.object_id,
6298            version: oref.version,
6299            digest: oref.digest,
6300            object,
6301        }
6302    }
6303}
6304
6305#[derive(Debug, Serialize, Deserialize, Clone)]
6306pub struct NodeStateDump {
6307    pub tx_digest: TransactionDigest,
6308    pub sender_signed_data: SenderSignedData,
6309    pub executed_epoch: u64,
6310    pub reference_gas_price: u64,
6311    pub protocol_version: u64,
6312    pub epoch_start_timestamp_ms: u64,
6313    pub computed_effects: TransactionEffects,
6314    pub expected_effects_digest: TransactionEffectsDigest,
6315    pub relevant_system_packages: Vec<ObjDumpFormat>,
6316    pub shared_objects: Vec<ObjDumpFormat>,
6317    pub loaded_child_objects: Vec<ObjDumpFormat>,
6318    pub modified_at_versions: Vec<ObjDumpFormat>,
6319    pub runtime_reads: Vec<ObjDumpFormat>,
6320    pub input_objects: Vec<ObjDumpFormat>,
6321}
6322
6323impl NodeStateDump {
6324    pub fn new(
6325        tx_digest: &TransactionDigest,
6326        effects: &TransactionEffects,
6327        expected_effects_digest: TransactionEffectsDigest,
6328        object_store: &dyn ObjectStore,
6329        epoch_store: &Arc<AuthorityPerEpochStore>,
6330        inner_temporary_store: &InnerTemporaryStore,
6331        transaction: &VerifiedExecutableTransaction,
6332    ) -> IotaResult<Self> {
6333        // Epoch info
6334        let executed_epoch = epoch_store.epoch();
6335        let reference_gas_price = epoch_store.reference_gas_price();
6336        let epoch_start_config = epoch_store.epoch_start_config();
6337        let protocol_version = epoch_store.protocol_version().as_u64();
6338        let epoch_start_timestamp_ms = epoch_start_config.epoch_data().epoch_start_timestamp();
6339
6340        // Record all system packages at this version
6341        let mut relevant_system_packages = Vec::new();
6342        for sys_package_id in BuiltInFramework::all_package_ids() {
6343            if let Some(w) = object_store.try_get_object(&sys_package_id)? {
6344                relevant_system_packages.push(ObjDumpFormat::new(w))
6345            }
6346        }
6347
6348        // Record all the shared objects
6349        let mut shared_objects = Vec::new();
6350        for kind in effects.input_shared_objects() {
6351            match kind {
6352                InputSharedObject::Mutate(obj_ref) | InputSharedObject::ReadOnly(obj_ref) => {
6353                    if let Some(w) =
6354                        object_store.try_get_object_by_key(&obj_ref.object_id, obj_ref.version)?
6355                    {
6356                        shared_objects.push(ObjDumpFormat::new(w))
6357                    }
6358                }
6359                InputSharedObject::ReadDeleted(..)
6360                | InputSharedObject::MutateDeleted(..)
6361                | InputSharedObject::Cancelled(..) => (), /* TODO: consider record congested
6362                                                           * objects. */
6363            }
6364        }
6365
6366        // Record all loaded child objects
6367        // Child objects which are read but not mutated are not tracked anywhere else
6368        let mut loaded_child_objects = Vec::new();
6369        for (id, meta) in &inner_temporary_store.loaded_runtime_objects {
6370            if let Some(w) = object_store.try_get_object_by_key(id, meta.version)? {
6371                loaded_child_objects.push(ObjDumpFormat::new(w))
6372            }
6373        }
6374
6375        // Record all modified objects
6376        let mut modified_at_versions = Vec::new();
6377        for (id, ver) in effects.modified_at_versions() {
6378            if let Some(w) = object_store.try_get_object_by_key(&id, ver)? {
6379                modified_at_versions.push(ObjDumpFormat::new(w))
6380            }
6381        }
6382
6383        // Packages read at runtime, which were not previously loaded into the temoorary
6384        // store Some packages may be fetched at runtime and wont show up in
6385        // input objects
6386        let mut runtime_reads = Vec::new();
6387        for obj in inner_temporary_store
6388            .runtime_packages_loaded_from_db
6389            .values()
6390        {
6391            runtime_reads.push(ObjDumpFormat::new(obj.object().clone()));
6392        }
6393
6394        // All other input objects should already be in `inner_temporary_store.objects`
6395
6396        Ok(Self {
6397            tx_digest: *tx_digest,
6398            executed_epoch,
6399            reference_gas_price,
6400            epoch_start_timestamp_ms,
6401            protocol_version,
6402            relevant_system_packages,
6403            shared_objects,
6404            loaded_child_objects,
6405            modified_at_versions,
6406            runtime_reads,
6407            sender_signed_data: transaction.clone().into_message(),
6408            input_objects: inner_temporary_store
6409                .input_objects
6410                .values()
6411                .map(|o| ObjDumpFormat::new(o.clone()))
6412                .collect(),
6413            computed_effects: effects.clone(),
6414            expected_effects_digest,
6415        })
6416    }
6417
6418    pub fn all_objects(&self) -> Vec<ObjDumpFormat> {
6419        let mut objects = Vec::new();
6420        objects.extend(self.relevant_system_packages.clone());
6421        objects.extend(self.shared_objects.clone());
6422        objects.extend(self.loaded_child_objects.clone());
6423        objects.extend(self.modified_at_versions.clone());
6424        objects.extend(self.runtime_reads.clone());
6425        objects.extend(self.input_objects.clone());
6426        objects
6427    }
6428
6429    pub fn write_to_file(&self, path: &Path) -> Result<PathBuf, anyhow::Error> {
6430        let file_name = format!(
6431            "{}_{}_NODE_DUMP.json",
6432            self.tx_digest,
6433            AuthorityState::unixtime_now_ms()
6434        );
6435        let mut path = path.to_path_buf();
6436        path.push(&file_name);
6437        let mut file = File::create(path.clone())?;
6438        file.write_all(serde_json::to_string_pretty(self)?.as_bytes())?;
6439        Ok(path)
6440    }
6441
6442    pub fn read_from_file(path: &PathBuf) -> Result<Self, anyhow::Error> {
6443        let file = File::open(path)?;
6444        serde_json::from_reader(file).map_err(|e| anyhow::anyhow!(e))
6445    }
6446}
6447
6448/// Returns the [`MoveAuthenticator`]s to execute during the pre-consensus
6449/// phase.
6450///
6451/// When `pre_consensus_sponsor_only_move_authentication` is enabled:
6452/// - For sponsored transactions: only the sponsor's [`MoveAuthenticator`] is
6453///   returned (empty if the sponsor does not use one).
6454/// - For non-sponsored transactions: all [`MoveAuthenticator`]s are returned
6455///   (currently only the sender's).
6456///
6457/// When the flag is not set, all [`MoveAuthenticator`]s are returned for
6458/// compatibility.
6459fn pre_consensus_move_authenticators<'a>(
6460    tx: &'a VerifiedTransaction,
6461    protocol_config: &ProtocolConfig,
6462) -> Vec<&'a MoveAuthenticator> {
6463    if protocol_config.pre_consensus_sponsor_only_move_authentication() {
6464        if tx.transaction_data().is_sponsored_tx() {
6465            if let Some(sponsor_move_authenticator) = tx.sponsor_move_authenticator() {
6466                vec![sponsor_move_authenticator]
6467            } else {
6468                vec![]
6469            }
6470        } else {
6471            tx.move_authenticators()
6472        }
6473    } else {
6474        tx.move_authenticators()
6475    }
6476}