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