Skip to main content

iota_core/
authority.rs

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