Skip to main content

sui_core/
authority.rs

1// Copyright (c) 2021, Facebook, Inc. and its affiliates
2// Copyright (c) Mysten Labs, Inc.
3// SPDX-License-Identifier: Apache-2.0
4
5use crate::accumulators::coin_reservations::CachingCoinReservationResolver;
6use crate::accumulators::funds_read::AccountFundsRead;
7use crate::accumulators::object_funds_checker::ObjectFundsCheckerDEPRECATED;
8use crate::accumulators::object_funds_checker::metrics::ObjectFundsCheckerMetrics;
9use crate::accumulators::transaction_rewriting::rewrite_transaction_for_coin_reservations;
10use crate::accumulators::unsettled_object_withdrawals::UnsettledObjectWithdrawals;
11use crate::accumulators::{self, AccumulatorSettlementTxBuilder};
12use crate::checkpoints::CheckpointBuilderError;
13use crate::checkpoints::CheckpointBuilderResult;
14use crate::congestion_tracker::CongestionTracker;
15use crate::execution_cache::ExecutionCacheTraitPointers;
16use crate::execution_cache::TransactionCacheRead;
17use crate::execution_cache::writeback_cache::WritebackCache;
18use crate::execution_scheduler::ExecutionScheduler;
19use crate::execution_scheduler::funds_withdraw_scheduler::FundsSettlement;
20use crate::gasless_rate_limiter::ConsensusGaslessCounter;
21use crate::traffic_controller::TrafficController;
22use crate::traffic_controller::metrics::TrafficControllerMetrics;
23use crate::transaction_deny_config_manager::TransactionDenyConfigManager;
24use crate::transaction_outputs::TransactionOutputs;
25use arc_swap::{ArcSwap, ArcSwapOption, Guard};
26use authority_per_epoch_store::CertLockGuard;
27use fastcrypto::encoding::Base58;
28use fastcrypto::encoding::Encoding;
29use fastcrypto::hash::MultisetHash;
30use itertools::Itertools;
31use move_binary_format::CompiledModule;
32use move_binary_format::binary_config::BinaryConfig;
33use move_core_types::annotated_value::MoveStructLayout;
34use move_core_types::language_storage::ModuleId;
35use mysten_common::ZipDebugEqIteratorExt;
36use mysten_common::{assert_reachable, fatal};
37use parking_lot::Mutex;
38use prometheus::{
39    Gauge, Histogram, HistogramVec, IntCounter, IntCounterVec, IntGauge, IntGaugeVec, Registry,
40    register_gauge_with_registry, register_histogram_vec_with_registry,
41    register_histogram_with_registry, register_int_counter_vec_with_registry,
42    register_int_counter_with_registry, register_int_gauge_vec_with_registry,
43    register_int_gauge_with_registry,
44};
45use serde::{Deserialize, Serialize};
46use shared_object_version_manager::AssignedVersions;
47use shared_object_version_manager::Schedulable;
48use std::collections::BTreeMap;
49use std::collections::BTreeSet;
50use std::fs::File;
51use std::io::Write;
52use std::path::{Path, PathBuf};
53use std::sync::atomic::Ordering;
54use std::time::Duration;
55use std::time::Instant;
56use std::time::SystemTime;
57use std::time::UNIX_EPOCH;
58use std::{
59    collections::{HashMap, HashSet},
60    fs,
61    pin::Pin,
62    str::FromStr,
63    sync::Arc,
64    vec,
65};
66use sui_config::NodeConfig;
67use sui_config::node::{AuthorityOverloadConfig, StateDebugDumpConfig};
68use sui_config::transaction_deny_config::TransactionDenyConfig;
69use sui_execution::Executor;
70use sui_package_resolver::{PackageStoreWithLruCache, SyncResolver};
71use sui_protocol_config::PerObjectCongestionControlMode;
72use sui_protocol_config::assert_reachable_gated;
73use sui_types::accumulator_root::AccumulatorObjId;
74use sui_types::accumulator_root::UnsettledObjectFundsRead;
75use sui_types::base_types::SystemObjectVersions;
76use sui_types::execution::ExecutionOutput;
77use sui_types::execution::ExecutionTimeObservationKey;
78use sui_types::execution::ExecutionTiming;
79use sui_types::execution_params::ExecutionOrEarlyError;
80use sui_types::execution_params::FundsWithdrawStatus;
81use sui_types::execution_params::get_early_execution_error;
82use sui_types::layout_resolver::{LayoutResolver, into_struct_layout};
83use sui_types::messages_consensus::AuthorityCapabilitiesV2;
84use sui_types::node_role::NodeRole;
85use sui_types::storage::InputKey;
86use sui_types::storage::RuntimeObjectResolver;
87use sui_types::storage::TrackingBackingStore;
88use sui_types::traffic_control::{
89    PolicyConfig, RemoteFirewallConfig, TrafficControlReconfigParams,
90};
91use sui_types::transaction_executor::SimulateTransactionResult;
92use sui_types::transaction_executor::TransactionChecks;
93use sui_types::{SUI_ACCUMULATOR_ROOT_OBJECT_ID, accumulator_metadata};
94use tap::TapFallible;
95use tokio::sync::RwLock;
96use tokio::sync::mpsc::unbounded_channel;
97use tokio::sync::oneshot;
98use tokio::sync::watch::error::RecvError;
99use tokio::time::timeout;
100use tracing::{debug, error, info, instrument, warn};
101
102use self::authority_store::ExecutionLockWriteGuard;
103use self::authority_store_pruner::{AuthorityStorePruningMetrics, PrunerWatermarks};
104pub use authority_store::{AuthorityStore, ResolverWrapper};
105use mysten_metrics::{monitored_scope, spawn_monitored_task};
106
107use mysten_common::debug_fatal;
108use shared_crypto::intent::{Intent, IntentScope};
109use sui_config::genesis::Genesis;
110use sui_config::node::{DBCheckpointConfig, ExpensiveSafetyCheckConfig};
111use sui_framework::{BuiltInFramework, SystemPackage};
112use sui_macros::{fail_point, fail_point_arg, fail_point_async, fail_point_if};
113use sui_rpc_store::Store as RpcStore;
114use sui_types::authenticator_state::get_authenticator_state;
115use sui_types::coin_reservation::CoinReservationResolverTrait;
116use sui_types::committee::{EpochId, ProtocolVersion};
117use sui_types::crypto::{AuthoritySignInfo, Signer};
118use sui_types::deny_list_v1::check_coin_deny_list_v1;
119use sui_types::digests::ChainIdentifier;
120use sui_types::effects::{
121    InputConsensusObject, SignedTransactionEffects, TransactionEffects, TransactionEffectsAPI,
122    TransactionEvents, VerifiedSignedTransactionEffects,
123};
124use sui_types::error::{ExecutionError, SuiErrorKind, UserInputError};
125use sui_types::executable_transaction::VerifiedExecutableTransaction;
126use sui_types::execution_status::ExecutionStatus;
127use sui_types::gas::{GasCostSummary, GasUsageReport};
128use sui_types::inner_temporary_store::InnerTemporaryStore;
129use sui_types::message_envelope::Message;
130use sui_types::messages_checkpoint::{
131    CheckpointCommitment, CheckpointContents, CheckpointContentsDigest, CheckpointDigest,
132    CheckpointRequest, CheckpointRequestV2, CheckpointResponse, CheckpointResponseV2,
133    CheckpointSequenceNumber, CheckpointSummary, CheckpointSummaryResponse, CheckpointTimestamp,
134    ECMHLiveObjectSetDigest, VerifiedCheckpoint,
135};
136use sui_types::messages_grpc::{
137    LayoutGenerationOption, ObjectInfoRequest, ObjectInfoRequestKind, ObjectInfoResponse,
138    TransactionInfoRequest, TransactionInfoResponse, TransactionStatus,
139};
140use sui_types::metrics::{BytecodeVerifierMetrics, ExecutionMetrics};
141#[cfg(test)]
142use sui_types::object::MoveObject;
143use sui_types::object::{OBJECT_START_VERSION, Owner, PastObjectRead};
144use sui_types::signature::GenericSignature;
145use sui_types::storage::{
146    BackingPackageStore, BackingStore, ObjectKey, ObjectOrTombstone, ObjectStore,
147};
148use sui_types::sui_system_state::SuiSystemStateTrait;
149use sui_types::sui_system_state::epoch_start_sui_system_state::EpochStartSystemStateTrait;
150use sui_types::sui_system_state::{SuiSystemState, get_sui_system_state};
151use sui_types::supported_protocol_versions::{ProtocolConfig, SupportedProtocolVersions};
152use sui_types::{
153    SUI_SYSTEM_ADDRESS,
154    base_types::*,
155    committee::Committee,
156    crypto::AuthoritySignature,
157    error::{SuiError, SuiResult},
158    object::{Object, ObjectRead},
159    transaction::*,
160};
161use sui_types::{TypeTag, is_system_package};
162use typed_store::TypedStoreError;
163
164use crate::authority::authority_per_epoch_store::{AuthorityPerEpochStore, CertTxGuard};
165use crate::authority::authority_per_epoch_store_pruner::AuthorityPerEpochStorePruner;
166use crate::authority::authority_store::ExecutionLockReadGuard;
167use crate::authority::authority_store_pruner::{
168    AuthorityStorePruner, EPOCH_DURATION_MS_FOR_TESTING,
169};
170use crate::authority::epoch_start_configuration::EpochStartConfigTrait;
171use crate::authority::epoch_start_configuration::EpochStartConfiguration;
172use crate::checkpoints::CheckpointStore;
173use crate::epoch::committee_store::CommitteeStore;
174use crate::execution_cache::{
175    CheckpointCache, ExecutionCacheCommit, ExecutionCacheReconfigAPI, ExecutionCacheWrite,
176    ObjectCacheRead, StateSyncAPI,
177};
178use crate::execution_driver::execution_process;
179use crate::global_state_hasher::{GlobalStateHashStore, GlobalStateHasher, WrappedObject};
180use crate::metrics::LatencyObserver;
181use crate::metrics::RateTracker;
182use crate::module_cache_metrics::ResolverMetrics;
183use crate::overload_monitor::{AuthorityOverloadInfo, overload_monitor_accept_tx};
184use crate::stake_aggregator::StakeAggregator;
185use crate::transaction_input_loader::TransactionInputLoader;
186
187#[cfg(msim)]
188pub use crate::checkpoints::checkpoint_executor::utils::{
189    CheckpointTimeoutConfig, init_checkpoint_timeout_config,
190};
191
192#[cfg(msim)]
193use sui_types::committee::CommitteeTrait;
194use sui_types::deny_list_v2::check_coin_deny_list_v2_during_signing;
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/gas_data_tests.rs"]
218mod gas_data_tests;
219
220#[cfg(test)]
221#[path = "unit_tests/batch_verification_tests.rs"]
222mod batch_verification_tests;
223
224#[cfg(test)]
225#[path = "unit_tests/coin_deny_list_tests.rs"]
226mod coin_deny_list_tests;
227
228#[cfg(test)]
229#[path = "unit_tests/auth_unit_test_utils.rs"]
230pub mod auth_unit_test_utils;
231
232pub mod authority_test_utils;
233
234pub mod authority_per_epoch_store;
235pub mod authority_per_epoch_store_pruner;
236
237pub mod authority_store_pruner;
238pub mod authority_store_tables;
239pub mod authority_store_types;
240pub mod congestion_log;
241pub mod consensus_tx_status_cache;
242pub(crate) mod epoch_marker_key;
243pub mod epoch_start_configuration;
244pub mod execution_time_estimator;
245pub mod finalized_transactions_cache;
246pub mod shared_object_congestion_tracker;
247pub mod shared_object_version_manager;
248pub mod submitted_transaction_cache;
249pub mod test_authority_builder;
250pub mod transaction_deferral;
251pub mod transaction_reject_reason_cache;
252mod weighted_moving_average;
253
254pub(crate) mod authority_store;
255pub mod backpressure;
256
257/// Prometheus metrics which can be displayed in Grafana, queried and alerted on
258pub struct AuthorityMetrics {
259    tx_orders: IntCounter,
260    total_certs: IntCounter,
261    total_effects: IntCounter,
262    // TODO: this tracks consensus object tx, not just shared. Consider renaming.
263    pub shared_obj_tx: IntCounter,
264    sponsored_tx: IntCounter,
265    num_input_objs: Histogram,
266    // TODO: this tracks consensus object count, not just shared. Consider renaming.
267    num_shared_objects: Histogram,
268    batch_size: Histogram,
269
270    authority_state_handle_vote_transaction_latency: Histogram,
271
272    internal_execution_latency: Histogram,
273    /// Number of times the validator refused to report effects (signed or unsigned, labeled by
274    /// RPC surface) because it had previously signed different effects for the same transaction.
275    signed_effects_equivocation_prevented: IntCounterVec,
276    execution_load_input_objects_latency: Histogram,
277    prepare_certificate_latency: Histogram,
278    commit_certificate_latency: Histogram,
279    db_checkpoint_latency: Histogram,
280
281    // TODO: Rename these metrics.
282    pub(crate) transaction_manager_num_enqueued_certificates: IntCounterVec,
283    pub(crate) transaction_manager_num_pending_certificates: IntGauge,
284    pub(crate) transaction_manager_num_executing_certificates: IntGauge,
285    pub(crate) transaction_manager_transaction_queue_age_s: Histogram,
286
287    pub(crate) execution_driver_executed_transactions: IntCounter,
288    pub(crate) execution_driver_paused_transactions: IntCounter,
289    pub(crate) execution_driver_dispatch_queue: IntGauge,
290    pub(crate) execution_queueing_delay_s: Histogram,
291    pub(crate) prepare_cert_gas_latency_ratio: Histogram,
292    pub(crate) execution_gas_latency_ratio: Histogram,
293
294    pub(crate) skipped_consensus_txns: IntCounter,
295    pub(crate) skipped_consensus_txns_cache_hit: IntCounter,
296    pub(crate) consensus_handler_duplicate_tx_count: Histogram,
297    pub(crate) staggered_submission_excess_copies: Histogram,
298    pub(crate) staggered_submission_signal_band: IntGauge,
299    pub(crate) staggered_submission_active: IntGauge,
300    pub(crate) staggered_submission_signal_transitions: IntCounterVec,
301    pub(crate) staggered_submission_commit_copies: IntCounterVec,
302    pub(crate) staggered_submission_band_duration_commits: HistogramVec,
303    pub(crate) staggered_submission_duplication_ratio: Gauge,
304
305    pub(crate) authority_overload_status: IntGauge,
306    pub(crate) authority_load_shedding_percentage: IntGauge,
307
308    pub(crate) transaction_overload_sources: IntCounterVec,
309
310    /// Post processing metrics
311    /// Consensus commit and transaction handler metrics
312    pub consensus_handler_processed: IntCounterVec,
313    pub consensus_handler_processed_user_transactions: IntCounterVec,
314    pub consensus_handler_transaction_sizes: HistogramVec,
315    pub consensus_handler_max_transaction_size: IntGaugeVec,
316    pub consensus_handler_deferred_transactions: IntCounter,
317    pub consensus_handler_congested_transactions: IntCounter,
318    pub consensus_handler_unpaid_amplification_deferrals: IntCounter,
319    pub consensus_handler_double_spend_deferrals: IntCounter,
320    pub consensus_handler_double_spend_conflict_count: HistogramVec,
321    pub consensus_handler_double_spend_conflicting_authority: IntCounterVec,
322    pub consensus_handler_cancelled_transactions: IntCounter,
323    pub consensus_handler_dropped_transactions: IntCounterVec,
324    pub consensus_handler_max_object_costs: IntGaugeVec,
325    pub consensus_committed_subdags: IntCounterVec,
326    pub accumulator_deposits: IntCounter,
327    pub accumulator_withdrawals: IntCounter,
328    pub consensus_committed_messages: IntGaugeVec,
329    pub consensus_committed_user_transactions: IntGaugeVec,
330    pub consensus_finalized_user_transactions: IntGaugeVec,
331    pub consensus_rejected_user_transactions: IntGaugeVec,
332    pub consensus_dropped_user_transactions: IntGaugeVec,
333    pub consensus_calculated_throughput: IntGauge,
334    pub consensus_calculated_throughput_profile: IntGauge,
335    pub consensus_block_handler_block_processed: IntCounter,
336    pub consensus_block_handler_txn_processed: IntCounterVec,
337    pub consensus_block_handler_fastpath_executions: IntCounter,
338    pub consensus_timestamp_bias: Histogram,
339
340    pub execution_metrics: Arc<ExecutionMetrics>,
341
342    /// bytecode verifier metrics for tracking timeouts
343    pub bytecode_verifier_metrics: Arc<BytecodeVerifierMetrics>,
344
345    /// Count of zklogin signatures
346    pub zklogin_sig_count: IntCounter,
347    /// Count of multisig signatures
348    pub multisig_sig_count: IntCounter,
349
350    // Tracks recent average txn queueing delay between when it is ready for execution
351    // until it starts executing.
352    pub execution_queueing_latency: LatencyObserver,
353
354    // Tracks the rate of transactions become ready for execution in transaction manager.
355    // The need for the Mutex is that the tracker is updated in transaction manager and read
356    // in the overload_monitor. There should be low mutex contention because
357    // transaction manager is single threaded and the read rate in overload_monitor is
358    // low. In the case where transaction manager becomes multi-threaded, we can
359    // create one rate tracker per thread.
360    pub txn_ready_rate_tracker: Arc<Mutex<RateTracker>>,
361
362    // Tracks the rate of transactions starts execution in execution driver.
363    // Similar reason for using a Mutex here as to `txn_ready_rate_tracker`.
364    pub execution_rate_tracker: Arc<Mutex<RateTracker>>,
365}
366
367// Override default Prom buckets for positive numbers in 0-10M range
368const POSITIVE_INT_BUCKETS: &[f64] = &[
369    1., 2., 5., 7., 10., 20., 50., 70., 100., 200., 500., 700., 1000., 2000., 5000., 7000., 10000.,
370    20000., 50000., 70000., 100000., 200000., 500000., 700000., 1000000., 2000000., 5000000.,
371    7000000., 10000000.,
372];
373
374const CONSENSUS_TRANSACTION_SIZE_BUCKETS: &[f64] = &[
375    1., 2., 5., 7., 10., 20., 50., 70., 100., 200., 500., 700., 1000., 2000., 5000., 7000., 10000.,
376    20000., 50000., 70000., 100000., 150000., 200000., 250000., 300000., 500000., 700000.,
377    1000000., 2000000., 5000000., 7000000., 10000000.,
378];
379
380const LATENCY_SEC_BUCKETS: &[f64] = &[
381    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.,
382    10., 20., 30., 60., 90.,
383];
384
385// Buckets for low latency samples. Starts from 10us.
386const LOW_LATENCY_SEC_BUCKETS: &[f64] = &[
387    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,
388    0.2, 0.5, 1., 2., 5., 10., 20., 50., 100.,
389];
390
391// Buckets for consensus timestamp bias in seconds.
392// We expect 200-300ms, so we cluster the buckets more tightly in that range.
393const TIMESTAMP_BIAS_SEC_BUCKETS: &[f64] = &[
394    -2.0, 0.0, 0.2, 0.22, 0.24, 0.26, 0.28, 0.30, 0.32, 0.34, 0.36, 0.38, 0.40, 0.45, 0.50, 0.80,
395    2.0, 10.0, 30.0,
396];
397
398const GAS_LATENCY_RATIO_BUCKETS: &[f64] = &[
399    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,
400    3000.0, 4000.0, 5000.0, 6000.0, 7000.0, 8000.0, 9000.0, 10000.0, 50000.0, 100000.0, 1000000.0,
401];
402
403pub const DEV_INSPECT_GAS_COIN_VALUE: u64 = 1_000_000_000_000_000_000;
404
405// Transaction author should have observed the input objects as finalized output,
406// so usually the wait does not need to be long.
407// When submitted by TransactionDriver, it will retry quickly if there is no return from this validator too.
408pub const WAIT_FOR_FASTPATH_INPUT_TIMEOUT: Duration = Duration::from_secs(2);
409
410impl AuthorityMetrics {
411    pub fn new(registry: &prometheus::Registry) -> AuthorityMetrics {
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_effects == total transactions finished
426            total_effects: register_int_counter_with_registry!(
427                "total_transaction_effects",
428                "Total number of transaction effects produced",
429                registry,
430            )
431            .unwrap(),
432
433            shared_obj_tx: register_int_counter_with_registry!(
434                "num_shared_obj_tx",
435                "Number of transactions involving shared objects",
436                registry,
437            )
438            .unwrap(),
439
440            sponsored_tx: register_int_counter_with_registry!(
441                "num_sponsored_tx",
442                "Number of sponsored transactions",
443                registry,
444            )
445            .unwrap(),
446
447            num_input_objs: register_histogram_with_registry!(
448                "num_input_objects",
449                "Distribution of number of input TX objects per TX",
450                POSITIVE_INT_BUCKETS.to_vec(),
451                registry,
452            )
453            .unwrap(),
454            num_shared_objects: register_histogram_with_registry!(
455                "num_shared_objects",
456                "Number of shared input objects per TX",
457                POSITIVE_INT_BUCKETS.to_vec(),
458                registry,
459            )
460            .unwrap(),
461            batch_size: register_histogram_with_registry!(
462                "batch_size",
463                "Distribution of size of transaction batch",
464                POSITIVE_INT_BUCKETS.to_vec(),
465                registry,
466            )
467            .unwrap(),
468            authority_state_handle_vote_transaction_latency: register_histogram_with_registry!(
469                "authority_state_handle_vote_transaction_latency",
470                "Latency of voting on transactions without signing",
471                LATENCY_SEC_BUCKETS.to_vec(),
472                registry,
473            )
474            .unwrap(),
475            internal_execution_latency: register_histogram_with_registry!(
476                "authority_state_internal_execution_latency",
477                "Latency of actual certificate executions",
478                LATENCY_SEC_BUCKETS.to_vec(),
479                registry,
480            )
481            .unwrap(),
482            signed_effects_equivocation_prevented: register_int_counter_vec_with_registry!(
483                "authority_state_signed_effects_equivocation_prevented",
484                "Number of times the validator refused to report effects that differ from previously signed effects for the same transaction, by RPC surface",
485                &["surface"],
486                registry,
487            )
488            .unwrap(),
489            execution_load_input_objects_latency: register_histogram_with_registry!(
490                "authority_state_execution_load_input_objects_latency",
491                "Latency of loading input objects for execution",
492                LOW_LATENCY_SEC_BUCKETS.to_vec(),
493                registry,
494            )
495            .unwrap(),
496            prepare_certificate_latency: register_histogram_with_registry!(
497                "authority_state_prepare_certificate_latency",
498                "Latency of executing certificates, before committing the results",
499                LATENCY_SEC_BUCKETS.to_vec(),
500                registry,
501            )
502            .unwrap(),
503            commit_certificate_latency: register_histogram_with_registry!(
504                "authority_state_commit_certificate_latency",
505                "Latency of committing certificate execution results",
506                LATENCY_SEC_BUCKETS.to_vec(),
507                registry,
508            )
509            .unwrap(),
510            db_checkpoint_latency: register_histogram_with_registry!(
511                "db_checkpoint_latency",
512                "Latency of checkpointing dbs",
513                LATENCY_SEC_BUCKETS.to_vec(),
514                registry,
515            ).unwrap(),
516            transaction_manager_num_enqueued_certificates: register_int_counter_vec_with_registry!(
517                "transaction_manager_num_enqueued_certificates",
518                "Current number of certificates enqueued to ExecutionScheduler",
519                &["result"],
520                registry,
521            )
522            .unwrap(),
523            transaction_manager_num_pending_certificates: register_int_gauge_with_registry!(
524                "transaction_manager_num_pending_certificates",
525                "Number of certificates pending in ExecutionScheduler, with at least 1 missing input object",
526                registry,
527            )
528            .unwrap(),
529            transaction_manager_num_executing_certificates: register_int_gauge_with_registry!(
530                "transaction_manager_num_executing_certificates",
531                "Number of executing certificates, including queued and actually running certificates",
532                registry,
533            )
534            .unwrap(),
535            authority_overload_status: register_int_gauge_with_registry!(
536                "authority_overload_status",
537                "Whether authority is current experiencing overload and enters load shedding mode.",
538                registry)
539            .unwrap(),
540            authority_load_shedding_percentage: register_int_gauge_with_registry!(
541                "authority_load_shedding_percentage",
542                "The percentage of transactions is shed when the authority is in load shedding mode.",
543                registry)
544            .unwrap(),
545            transaction_manager_transaction_queue_age_s: register_histogram_with_registry!(
546                "transaction_manager_transaction_queue_age_s",
547                "Time spent in waiting for transaction in the queue",
548                LATENCY_SEC_BUCKETS.to_vec(),
549                registry,
550            )
551            .unwrap(),
552            transaction_overload_sources: register_int_counter_vec_with_registry!(
553                "transaction_overload_sources",
554                "Number of times each source indicates transaction overload.",
555                &["source"],
556                registry)
557            .unwrap(),
558            execution_driver_executed_transactions: register_int_counter_with_registry!(
559                "execution_driver_executed_transactions",
560                "Cumulative number of transaction executed by execution driver",
561                registry,
562            )
563            .unwrap(),
564            execution_driver_paused_transactions: register_int_counter_with_registry!(
565                "execution_driver_paused_transactions",
566                "Cumulative number of transactions paused by execution driver",
567                registry,
568            )
569            .unwrap(),
570            execution_driver_dispatch_queue: register_int_gauge_with_registry!(
571                "execution_driver_dispatch_queue",
572                "Number of transaction pending in execution driver dispatch queue",
573                registry,
574            )
575            .unwrap(),
576            execution_queueing_delay_s: register_histogram_with_registry!(
577                "execution_queueing_delay_s",
578                "Queueing delay between a transaction is ready for execution until it starts executing.",
579                LATENCY_SEC_BUCKETS.to_vec(),
580                registry
581            )
582            .unwrap(),
583            prepare_cert_gas_latency_ratio: register_histogram_with_registry!(
584                "prepare_cert_gas_latency_ratio",
585                "The ratio of computation gas divided by VM execution latency.",
586                GAS_LATENCY_RATIO_BUCKETS.to_vec(),
587                registry
588            )
589            .unwrap(),
590            execution_gas_latency_ratio: register_histogram_with_registry!(
591                "execution_gas_latency_ratio",
592                "The ratio of computation gas divided by certificate execution latency, include committing certificate.",
593                GAS_LATENCY_RATIO_BUCKETS.to_vec(),
594                registry
595            )
596            .unwrap(),
597            skipped_consensus_txns: register_int_counter_with_registry!(
598                "skipped_consensus_txns",
599                "Total number of consensus transactions skipped",
600                registry,
601            )
602            .unwrap(),
603            skipped_consensus_txns_cache_hit: register_int_counter_with_registry!(
604                "skipped_consensus_txns_cache_hit",
605                "Total number of consensus transactions skipped because of local cache hit",
606                registry,
607            )
608            .unwrap(),
609            consensus_handler_duplicate_tx_count: register_histogram_with_registry!(
610                "consensus_handler_duplicate_tx_count",
611                "Number of times each transaction appears in its first consensus commit",
612                POSITIVE_INT_BUCKETS.to_vec(),
613                registry,
614            )
615            .unwrap(),
616            staggered_submission_excess_copies: register_histogram_with_registry!(
617                "staggered_submission_excess_copies",
618                "Excess copies per commit of transactions without allowed proposers. Copies seen in earlier commits count while the transaction is cached.",
619                POSITIVE_INT_BUCKETS.to_vec(),
620                registry,
621            )
622            .unwrap(),
623            staggered_submission_signal_band: register_int_gauge_with_registry!(
624                "staggered_submission_signal_band",
625                "Current band of the duplication signal. 0 is off and higher bands hold submissions longer. Staggering follows the band only when both the protocol flag and the node config enable it.",
626                registry,
627            )
628            .unwrap(),
629            staggered_submission_active: register_int_gauge_with_registry!(
630                "staggered_submission_active",
631                "1 if this validator staggers submissions of transactions without allowed proposers, else 0. It stays 0 while the signal runs in dry run.",
632                registry,
633            )
634            .unwrap(),
635            staggered_submission_signal_transitions: register_int_counter_vec_with_registry!(
636                "staggered_submission_signal_transitions",
637                "Number of duplication-signal transitions, labeled by the band entered",
638                &["state"],
639                registry,
640            )
641            .unwrap(),
642            staggered_submission_commit_copies: register_int_counter_vec_with_registry!(
643                "staggered_submission_commit_copies",
644                "User transaction copies in commits, by kind. unique counts first copies. excess counts copies past the paid allowance. paid_duplicate counts copies within the allowance. restricted_duplicate counts copies of transactions with allowed proposers.",
645                &["kind"],
646                registry,
647            )
648            .unwrap(),
649            staggered_submission_band_duration_commits: register_histogram_vec_with_registry!(
650                "staggered_submission_band_duration_commits",
651                "Commits the duplication signal spent in a band before leaving it, by band left",
652                &["band"],
653                prometheus::exponential_buckets(1.0, 2.0, 18).unwrap(),
654                registry,
655            )
656            .unwrap(),
657            staggered_submission_duplication_ratio: register_gauge_with_registry!(
658                "staggered_submission_duplication_ratio",
659                "Amplification measured by the duplication signal: excess duplicate copies as a fraction of unique user transactions over the signal window, compared against the band enter/exit ratios",
660                registry,
661            )
662            .unwrap(),
663            consensus_handler_processed: register_int_counter_vec_with_registry!(
664                "consensus_handler_processed",
665                "Number of transactions processed by consensus handler, sliced by class and commit outcome (accepted/rejected)",
666                &["class", "outcome"],
667                registry
668            ).unwrap(),
669            consensus_handler_processed_user_transactions: register_int_counter_vec_with_registry!(
670                "consensus_handler_processed_user_transactions",
671                "Number of user transactions processed by consensus handler, sliced by commit outcome (accepted/rejected) and block author",
672                &["outcome", "authority"],
673                registry
674            ).unwrap(),
675            consensus_handler_transaction_sizes: register_histogram_vec_with_registry!(
676                "consensus_handler_transaction_sizes",
677                "Sizes of each type of transactions processed by consensus handler, sliced by class and commit outcome (accepted/rejected)",
678                &["class", "outcome"],
679                CONSENSUS_TRANSACTION_SIZE_BUCKETS.to_vec(),
680                registry
681            ).unwrap(),
682            consensus_handler_max_transaction_size: register_int_gauge_vec_with_registry!(
683                "consensus_handler_max_transaction_size",
684                "Maximum transaction size in bytes received by the consensus handler for each class",
685                &["class"],
686                registry,
687            ).unwrap(),
688            consensus_handler_deferred_transactions: register_int_counter_with_registry!(
689                "consensus_handler_deferred_transactions",
690                "Number of transactions deferred by consensus handler",
691                registry,
692            ).unwrap(),
693            consensus_handler_congested_transactions: register_int_counter_with_registry!(
694                "consensus_handler_congested_transactions",
695                "Number of transactions deferred by consensus handler due to congestion",
696                registry,
697            ).unwrap(),
698            consensus_handler_unpaid_amplification_deferrals: register_int_counter_with_registry!(
699                "consensus_handler_unpaid_amplification_deferrals",
700                "Number of transactions deferred due to unpaid consensus amplification",
701                registry,
702            ).unwrap(),
703            consensus_handler_double_spend_deferrals: register_int_counter_with_registry!(
704                "consensus_handler_double_spend_deferrals",
705                "Number of transactions deferred due to owned object double-spend contention",
706                registry,
707            ).unwrap(),
708            consensus_handler_double_spend_conflict_count: register_histogram_vec_with_registry!(
709                "consensus_handler_double_spend_conflict_count",
710                "Number of conflicting transactions per double-spend winner, by object type",
711                &["object_type"],
712                POSITIVE_INT_BUCKETS.to_vec(),
713                registry,
714            ).unwrap(),
715            consensus_handler_double_spend_conflicting_authority: register_int_counter_vec_with_registry!(
716                "consensus_handler_double_spend_conflicting_authority",
717                "Number of transactions involved in owned object double-spend contention, by the \
718                 block authority that sequenced the transaction and its role in the conflict \
719                 (winner = won the lock, loser = dropped)",
720                &["authority", "role"],
721                registry,
722            ).unwrap(),
723            consensus_handler_cancelled_transactions: register_int_counter_with_registry!(
724                "consensus_handler_cancelled_transactions",
725                "Number of transactions cancelled by consensus handler",
726                registry,
727            ).unwrap(),
728            consensus_handler_dropped_transactions: register_int_counter_vec_with_registry!(
729                "consensus_handler_dropped_transactions",
730                "Number of transactions dropped by consensus handler, by drop reason",
731                &["reason"],
732                registry,
733            ).unwrap(),
734            consensus_handler_max_object_costs: register_int_gauge_vec_with_registry!(
735                "consensus_handler_max_congestion_control_object_costs",
736                "Max object costs for congestion control in the current consensus commit",
737                &["commit_type"],
738                registry,
739            ).unwrap(),
740            consensus_committed_subdags: register_int_counter_vec_with_registry!(
741                "consensus_committed_subdags",
742                "Number of committed subdags, sliced by author",
743                &["authority"],
744                registry,
745            ).unwrap(),
746            accumulator_deposits: register_int_counter_with_registry!(
747                "accumulator_deposits",
748                "Total accumulator deposit (merge) events processed in settlement",
749                registry,
750            ).unwrap(),
751            accumulator_withdrawals: register_int_counter_with_registry!(
752                "accumulator_withdrawals",
753                "Total accumulator withdrawal (split) events processed in settlement",
754                registry,
755            ).unwrap(),
756            consensus_committed_messages: register_int_gauge_vec_with_registry!(
757                "consensus_committed_messages",
758                "Total number of committed consensus messages, sliced by author",
759                &["authority"],
760                registry,
761            ).unwrap(),
762            consensus_committed_user_transactions: register_int_gauge_vec_with_registry!(
763                "consensus_committed_user_transactions",
764                "Number of certified & user transactions committed, sliced by submitter and persisted across restarts within each epoch",
765                &["authority"],
766                registry,
767            ).unwrap(),
768            consensus_finalized_user_transactions: register_int_gauge_vec_with_registry!(
769                "consensus_finalized_user_transactions",
770                "Number of user transactions finalized, sliced by submitter",
771                &["authority"],
772                registry,
773            ).unwrap(),
774            consensus_rejected_user_transactions: register_int_gauge_vec_with_registry!(
775                "consensus_rejected_user_transactions",
776                "Number of user transactions rejected, sliced by submitter",
777                &["authority"],
778                registry,
779            ).unwrap(),
780            consensus_dropped_user_transactions: register_int_gauge_vec_with_registry!(
781                "consensus_dropped_user_transactions",
782                "Number of user transactions dropped post-consensus, sliced by submitter",
783                &["authority"],
784                registry,
785            ).unwrap(),
786            execution_metrics: Arc::new(ExecutionMetrics::new(registry)),
787            bytecode_verifier_metrics: Arc::new(BytecodeVerifierMetrics::new(registry)),
788            zklogin_sig_count: register_int_counter_with_registry!(
789                "zklogin_sig_count",
790                "Count of zkLogin signatures",
791                registry,
792            )
793            .unwrap(),
794            multisig_sig_count: register_int_counter_with_registry!(
795                "multisig_sig_count",
796                "Count of zkLogin signatures",
797                registry,
798            )
799            .unwrap(),
800            consensus_calculated_throughput: register_int_gauge_with_registry!(
801                "consensus_calculated_throughput",
802                "The calculated throughput from consensus output. Result is calculated based on unique transactions.",
803                registry,
804            ).unwrap(),
805            consensus_calculated_throughput_profile: register_int_gauge_with_registry!(
806                "consensus_calculated_throughput_profile",
807                "The current active calculated throughput profile",
808                registry
809            ).unwrap(),
810            consensus_block_handler_block_processed: register_int_counter_with_registry!(
811                "consensus_block_handler_block_processed",
812                "Number of blocks processed by consensus block handler.",
813                registry
814            ).unwrap(),
815            consensus_block_handler_txn_processed: register_int_counter_vec_with_registry!(
816                "consensus_block_handler_txn_processed",
817                "Number of transactions processed by consensus block handler, by whether they are certified or rejected.",
818                &["outcome"],
819                registry
820            ).unwrap(),
821            consensus_block_handler_fastpath_executions: register_int_counter_with_registry!(
822                "consensus_block_handler_fastpath_executions",
823                "Number of fastpath transactions sent for execution by consensus transaction handler",
824                registry,
825            ).unwrap(),
826            consensus_timestamp_bias: register_histogram_with_registry!(
827                "consensus_timestamp_bias",
828                "Bias/delay from consensus timestamp to system time",
829                TIMESTAMP_BIAS_SEC_BUCKETS.to_vec(),
830                registry
831            ).unwrap(),
832            execution_queueing_latency: LatencyObserver::new(),
833            txn_ready_rate_tracker: Arc::new(Mutex::new(RateTracker::new(Duration::from_secs(10)))),
834            execution_rate_tracker: Arc::new(Mutex::new(RateTracker::new(Duration::from_secs(10)))),
835        }
836    }
837
838    pub(crate) fn observe_consensus_handler_transaction_size(
839        &self,
840        class: &str,
841        outcome: &str,
842        size: usize,
843    ) {
844        self.consensus_handler_transaction_sizes
845            .with_label_values(&[class, outcome])
846            .observe(size as f64);
847
848        let max_transaction_size = self
849            .consensus_handler_max_transaction_size
850            .with_label_values(&[class]);
851        max_transaction_size.set(max_transaction_size.get().max(size as i64));
852    }
853}
854
855/// a Trait object for `Signer` that is:
856/// - Pin, i.e. confined to one place in memory (we don't want to copy private keys).
857/// - Sync, i.e. can be safely shared between threads.
858///
859/// Typically instantiated with Box::pin(keypair) where keypair is a `KeyPair`
860///
861pub type StableSyncAuthoritySigner = Pin<Arc<dyn Signer<AuthoritySignature> + Send + Sync>>;
862
863/// The expected effects digest of a transaction, when the effects are known before execution,
864/// tagged with where the expectation came from.
865#[derive(Debug, Clone, Copy, PartialEq, Eq)]
866pub enum ExpectedEffectsDigest {
867    /// Read from the contents of the certified checkpoint at `checkpoint_seq`.
868    Certified {
869        digest: TransactionEffectsDigest,
870        checkpoint_seq: CheckpointSequenceNumber,
871    },
872    /// Known but not network-certified: this validator's own previously signed effects, or an
873    /// operator override.
874    Uncertified(TransactionEffectsDigest),
875}
876
877impl ExpectedEffectsDigest {
878    pub fn digest(&self) -> TransactionEffectsDigest {
879        match self {
880            Self::Certified { digest, .. } => *digest,
881            Self::Uncertified(digest) => *digest,
882        }
883    }
884
885    pub fn checkpoint_seq(&self) -> Option<CheckpointSequenceNumber> {
886        match self {
887            Self::Certified { checkpoint_seq, .. } => Some(*checkpoint_seq),
888            Self::Uncertified(_) => None,
889        }
890    }
891}
892
893/// Execution env contains the "environment" for the transaction to be executed in, that is,
894/// all the information necessary for execution that is not specified by the transaction itself.
895#[derive(Debug, Clone)]
896pub struct ExecutionEnv {
897    /// The assigned version of each shared object for the transaction.
898    pub assigned_versions: AssignedVersions,
899    /// The expected digest of the effects of the transaction, if executing from checkpoint or
900    /// other sources where the effects are known in advance.
901    pub expected_effects_digest: Option<ExpectedEffectsDigest>,
902    /// Status of the address funds withdraw scheduling of the transaction,
903    /// including both address and object funds withdraws.
904    pub funds_withdraw_status: FundsWithdrawStatus,
905    /// Transactions that must finish before this transaction can be executed.
906    /// Used to schedule barrier transactions after non-exclusive writes.
907    pub barrier_dependencies: Vec<TransactionDigest>,
908    /// The transaction's position in causal order, assigned by the ExecutionScheduler
909    /// at enqueue time and used by the execution driver for admission. The driver
910    /// retires the index when the transaction finishes executing or is dropped as no
911    /// longer needed. None at the driver means the transaction is admitted
912    /// unconditionally (settlement transactions - see
913    /// `execution_scheduler::causal_admission`).
914    pub(crate) causal_index: Option<u64>,
915}
916
917impl Default for ExecutionEnv {
918    fn default() -> Self {
919        Self {
920            assigned_versions: AssignedVersions::empty(),
921            expected_effects_digest: None,
922            funds_withdraw_status: FundsWithdrawStatus::MaybeSufficient,
923            barrier_dependencies: Default::default(),
924            causal_index: None,
925        }
926    }
927}
928
929impl ExecutionEnv {
930    pub fn new() -> Self {
931        Default::default()
932    }
933
934    pub fn with_expected_effects(mut self, expected: ExpectedEffectsDigest) -> Self {
935        self.expected_effects_digest = Some(expected);
936        self
937    }
938
939    pub fn with_assigned_versions(mut self, assigned_versions: AssignedVersions) -> Self {
940        self.assigned_versions = assigned_versions;
941        self
942    }
943
944    pub fn with_insufficient_funds(mut self) -> Self {
945        self.funds_withdraw_status = FundsWithdrawStatus::Insufficient;
946        self
947    }
948
949    /// For tests that drive scheduler-internal paths directly, standing in for the
950    /// index the ExecutionScheduler assigns at enqueue time.
951    #[cfg(test)]
952    pub(crate) fn with_causal_index(mut self, index: u64) -> Self {
953        self.causal_index = Some(index);
954        self
955    }
956
957    pub fn with_barrier_dependencies(
958        mut self,
959        barrier_dependencies: BTreeSet<TransactionDigest>,
960    ) -> Self {
961        self.barrier_dependencies = barrier_dependencies.into_iter().collect();
962        self
963    }
964}
965
966#[derive(Debug)]
967pub struct ForkRecoveryState {
968    /// Transaction digest to effects digest overrides
969    transaction_overrides:
970        parking_lot::RwLock<HashMap<TransactionDigest, TransactionEffectsDigest>>,
971}
972
973impl Default for ForkRecoveryState {
974    fn default() -> Self {
975        Self {
976            transaction_overrides: parking_lot::RwLock::new(HashMap::new()),
977        }
978    }
979}
980
981impl ForkRecoveryState {
982    pub fn new(config: Option<&sui_config::node::ForkRecoveryConfig>) -> Result<Self, SuiError> {
983        let Some(config) = config else {
984            return Ok(Self::default());
985        };
986
987        let mut transaction_overrides = HashMap::new();
988        for (tx_digest_str, effects_digest_str) in &config.transaction_overrides {
989            let tx_digest = TransactionDigest::from_str(tx_digest_str).map_err(|_| {
990                SuiErrorKind::Unknown(format!("Invalid transaction digest: {}", tx_digest_str))
991            })?;
992            let effects_digest =
993                TransactionEffectsDigest::from_str(effects_digest_str).map_err(|_| {
994                    SuiErrorKind::Unknown(format!("Invalid effects digest: {}", effects_digest_str))
995                })?;
996            transaction_overrides.insert(tx_digest, effects_digest);
997        }
998
999        Ok(Self {
1000            transaction_overrides: parking_lot::RwLock::new(transaction_overrides),
1001        })
1002    }
1003
1004    pub fn get_transaction_override(
1005        &self,
1006        tx_digest: &TransactionDigest,
1007    ) -> Option<TransactionEffectsDigest> {
1008        self.transaction_overrides.read().get(tx_digest).copied()
1009    }
1010}
1011
1012pub struct AuthorityState {
1013    // Fixed size, static, identity of the authority
1014    /// The name of this authority.
1015    pub name: AuthorityName,
1016    /// The signature key of the authority.
1017    pub secret: StableSyncAuthoritySigner,
1018
1019    /// The database
1020    input_loader: TransactionInputLoader,
1021    execution_cache_trait_pointers: ExecutionCacheTraitPointers,
1022    coin_reservation_resolver: Arc<CachingCoinReservationResolver>,
1023
1024    epoch_store: ArcSwap<AuthorityPerEpochStore>,
1025
1026    /// This lock denotes current 'execution epoch'.
1027    /// Execution acquires read lock, checks certificate epoch and holds it until all writes are complete.
1028    /// Reconfiguration acquires write lock, changes the epoch and revert all transactions
1029    /// from previous epoch that are executed but did not make into checkpoint.
1030    execution_lock: RwLock<EpochId>,
1031
1032    pub checkpoint_store: Arc<CheckpointStore>,
1033
1034    committee_store: Arc<CommitteeStore>,
1035
1036    /// Schedules transaction execution.
1037    execution_scheduler: Arc<ExecutionScheduler>,
1038
1039    /// Shuts down the execution task. Used only in testing.
1040    #[allow(unused)]
1041    tx_execution_shutdown: Mutex<Option<oneshot::Sender<()>>>,
1042
1043    pub metrics: Arc<AuthorityMetrics>,
1044    _pruner: AuthorityStorePruner,
1045    _authority_per_epoch_pruner: AuthorityPerEpochStorePruner,
1046
1047    /// Take db checkpoints of different dbs
1048    db_checkpoint_config: DBCheckpointConfig,
1049
1050    pub config: NodeConfig,
1051
1052    /// Current overload status in this authority. Updated periodically.
1053    pub overload_info: AuthorityOverloadInfo,
1054
1055    /// The chain identifier is derived from the digest of the genesis checkpoint.
1056    chain_identifier: ChainIdentifier,
1057
1058    pub(crate) congestion_tracker: Arc<CongestionTracker>,
1059
1060    /// Consumed by gasless tx rate limiter.
1061    pub(crate) consensus_gasless_counter: Arc<ConsensusGaslessCounter>,
1062
1063    /// Traffic controller for the validator service.
1064    pub traffic_controller: Option<Arc<TrafficController>>,
1065
1066    /// Fork recovery state for handling equivocation after forks
1067    fork_recovery_state: Option<ForkRecoveryState>,
1068
1069    /// Notification channel for reconfiguration
1070    notify_epoch: tokio::sync::watch::Sender<EpochId>,
1071
1072    pub(crate) object_funds_checker: ArcSwapOption<ObjectFundsCheckerDEPRECATED>,
1073    object_funds_checker_metrics: Arc<ObjectFundsCheckerMetrics>,
1074    pub(crate) unsettled_object_withdrawals: Arc<UnsettledObjectWithdrawals>,
1075
1076    /// Created once per process, then re-attached to each new `AuthorityPerEpochStore`
1077    /// at reconfiguration.
1078    transaction_deny_config_manager: Arc<TransactionDenyConfigManager>,
1079}
1080
1081/// The authority state encapsulates all state, drives execution, and ensures safety.
1082///
1083/// Note the authority operations can be accessed through a read ref (&) and do not
1084/// require &mut. Internally a database is synchronized through a mutex lock.
1085///
1086/// Repeating valid commands should produce no changes and return no error.
1087impl AuthorityState {
1088    pub fn node_role(&self, epoch_store: &AuthorityPerEpochStore) -> NodeRole {
1089        epoch_store.node_role()
1090    }
1091
1092    pub fn is_validator(&self, epoch_store: &AuthorityPerEpochStore) -> bool {
1093        epoch_store.node_role().is_validator()
1094    }
1095
1096    pub fn is_fullnode(&self, epoch_store: &AuthorityPerEpochStore) -> bool {
1097        epoch_store.node_role().is_fullnode()
1098    }
1099
1100    pub fn committee_store(&self) -> &Arc<CommitteeStore> {
1101        &self.committee_store
1102    }
1103
1104    pub fn clone_committee_store(&self) -> Arc<CommitteeStore> {
1105        self.committee_store.clone()
1106    }
1107
1108    pub fn overload_config(&self) -> &AuthorityOverloadConfig {
1109        &self.config.authority_overload_config
1110    }
1111
1112    pub fn get_epoch_state_commitments(
1113        &self,
1114        epoch: EpochId,
1115    ) -> SuiResult<Option<Vec<CheckpointCommitment>>> {
1116        self.checkpoint_store.get_epoch_state_commitments(epoch)
1117    }
1118
1119    fn handle_transaction_deny_checks(
1120        &self,
1121        transaction: &VerifiedTransaction,
1122        epoch_store: &Arc<AuthorityPerEpochStore>,
1123    ) -> SuiResult<CheckedInputObjects> {
1124        let tx_digest = transaction.digest();
1125        let tx_data = transaction.data().transaction_data();
1126
1127        let input_object_kinds = tx_data.input_objects()?;
1128        let receiving_objects_refs = tx_data.receiving_objects();
1129
1130        let transaction_deny_config = self
1131            .transaction_deny_config_manager
1132            .effective_config()
1133            .load();
1134        pre_object_load_checks(
1135            tx_data,
1136            transaction.tx_signatures(),
1137            &input_object_kinds,
1138            &receiving_objects_refs,
1139            epoch_store.protocol_config(),
1140            transaction_deny_config.as_ref(),
1141            self.get_backing_package_store().as_ref(),
1142            self.chain_identifier,
1143            self.coin_reservation_resolver.as_ref(),
1144            self.get_account_funds_read().as_ref(),
1145        )?;
1146
1147        let (input_objects, receiving_objects) = self.input_loader.read_objects_for_signing(
1148            Some(tx_digest),
1149            &input_object_kinds,
1150            &receiving_objects_refs,
1151            epoch_store.epoch(),
1152        )?;
1153
1154        let checked_input_objects = sui_transaction_checks::check_transaction_input(
1155            epoch_store.protocol_config(),
1156            epoch_store.reference_gas_price(),
1157            tx_data,
1158            input_objects,
1159            &receiving_objects,
1160            &self.metrics.bytecode_verifier_metrics,
1161            &self.config.verifier_signing_config,
1162        )?;
1163
1164        self.handle_coin_deny_list_checks(
1165            tx_data,
1166            &checked_input_objects,
1167            &receiving_objects,
1168            epoch_store,
1169        )?;
1170
1171        Ok(checked_input_objects)
1172    }
1173
1174    fn handle_coin_deny_list_checks(
1175        &self,
1176        tx_data: &TransactionData,
1177        checked_input_objects: &CheckedInputObjects,
1178        receiving_objects: &ReceivingObjects,
1179        epoch_store: &Arc<AuthorityPerEpochStore>,
1180    ) -> SuiResult<()> {
1181        use sui_types::balance::Balance;
1182
1183        let declared_withdrawals = tx_data.process_funds_withdrawals_for_signing(
1184            self.chain_identifier,
1185            self.coin_reservation_resolver.as_ref(),
1186        )?;
1187
1188        let funds_withdrawals = declared_withdrawals
1189            .values()
1190            .filter_map(|(_, type_tag, funder)| {
1191                Balance::maybe_get_balance_type_param(type_tag)
1192                    .map(|ty| (*funder, ty.to_canonical_string(false)))
1193            })
1194            .collect::<BTreeSet<_>>();
1195
1196        if epoch_store.coin_deny_list_v1_enabled() {
1197            check_coin_deny_list_v1(
1198                tx_data.sender(),
1199                checked_input_objects,
1200                receiving_objects,
1201                funds_withdrawals.clone(),
1202                &self.get_object_store(),
1203            )?;
1204        }
1205
1206        if epoch_store.protocol_config().enable_coin_deny_list_v2() {
1207            check_coin_deny_list_v2_during_signing(
1208                tx_data.sender(),
1209                checked_input_objects,
1210                receiving_objects,
1211                funds_withdrawals,
1212                &self.get_object_store(),
1213            )?;
1214        }
1215
1216        Ok(())
1217    }
1218
1219    /// Vote for a transaction, either when validator receives a submit_transaction request,
1220    /// or sees a transaction from consensus. Performs the same types of checks as
1221    /// transaction signing, but does not explicitly sign the transaction.
1222    /// Note that if the transaction has been executed, we still go through the
1223    /// same checks, which fail if the transaction consumed owned input versions.
1224    /// TODO: Assess whether we want to optimize the case when the transaction
1225    /// has already been executed.
1226    #[instrument(level = "trace", skip_all, fields(tx_digest = ?transaction.digest()))]
1227    pub fn handle_vote_transaction(
1228        &self,
1229        epoch_store: &Arc<AuthorityPerEpochStore>,
1230        transaction: VerifiedTransaction,
1231    ) -> SuiResult<()> {
1232        debug!("handle_vote_transaction");
1233
1234        let _metrics_guard = self
1235            .metrics
1236            .authority_state_handle_vote_transaction_latency
1237            .start_timer();
1238        self.metrics.tx_orders.inc();
1239
1240        // The should_accept_user_certs check here is best effort, because
1241        // between a validator signs a tx and a cert is formed, the validator
1242        // could close the window.
1243        if !epoch_store
1244            .get_reconfig_state_read_lock_guard()
1245            .should_accept_user_certs()
1246        {
1247            return Err(SuiErrorKind::ValidatorHaltedAtEpochEnd.into());
1248        }
1249
1250        // Accept finalized transactions, instead of voting to reject them.
1251        // Checking executed transactions is limited to the current epoch.
1252        // Otherwise there can be a race where the transaction is accepted because it has executed,
1253        // but the executed effects are pruned post consensus, leading to failures.
1254        let tx_digest = *transaction.digest();
1255        if epoch_store.is_recently_finalized(&tx_digest)
1256            || epoch_store.transactions_executed_in_cur_epoch(&[tx_digest])[0]
1257        {
1258            assert_reachable!("transaction recently executed");
1259            return Ok(());
1260        }
1261
1262        if self
1263            .get_transaction_cache_reader()
1264            .transaction_executed_in_last_epoch(transaction.digest(), epoch_store.epoch())
1265        {
1266            return Err(SuiErrorKind::TransactionAlreadyExecuted {
1267                digest: (*transaction.digest()),
1268            }
1269            .into());
1270        }
1271
1272        // Ensure that validator cannot reconfigure while we are validating the transaction.
1273        let _execution_lock = self.execution_lock_for_validation()?;
1274
1275        let checked_input_objects =
1276            self.handle_transaction_deny_checks(&transaction, epoch_store)?;
1277
1278        let owned_objects = checked_input_objects.inner().filter_owned_objects();
1279
1280        // Validate owned object versions without acquiring locks. Locking happens post-consensus
1281        // in the consensus handler. Validation still runs to prevent spam transactions with
1282        // invalid object versions, and is necessary to handle recently created objects.
1283        self.get_cache_writer()
1284            .validate_owned_object_versions(&owned_objects)
1285    }
1286
1287    /// Used for early client validation check for transactions before submission to server.
1288    /// Performs the same validation checks as handle_vote_transaction without acquiring locks.
1289    /// This allows for fast failure feedback to clients for non-retriable errors.
1290    ///
1291    /// The key addition is checking that owned object versions match live object versions.
1292    /// This is necessary because handle_transaction_deny_checks fetches objects at their
1293    /// requested version (which may exist in storage as historical versions), whereas
1294    /// validators check against the live/current version during locking (verify_live_object).
1295    pub fn check_transaction_validity(
1296        &self,
1297        epoch_store: &Arc<AuthorityPerEpochStore>,
1298        transaction: &VerifiedTransaction,
1299        enforce_live_input_objects: bool,
1300    ) -> SuiResult<()> {
1301        if !epoch_store
1302            .get_reconfig_state_read_lock_guard()
1303            .should_accept_user_certs()
1304        {
1305            return Err(SuiErrorKind::ValidatorHaltedAtEpochEnd.into());
1306        }
1307
1308        transaction.validity_check(&epoch_store.tx_validity_check_context())?;
1309
1310        let checked_input_objects =
1311            self.handle_transaction_deny_checks(transaction, epoch_store)?;
1312
1313        // Check that owned object versions match live objects
1314        let owned_objects = checked_input_objects.inner().filter_owned_objects();
1315        let cache_reader = self.get_object_cache_reader();
1316
1317        for obj_ref in &owned_objects {
1318            if let Some(live_object) = cache_reader.get_object(&obj_ref.0) {
1319                // Only reject if transaction references an old version. Allow newer
1320                // versions that may exist on validators but not yet synced to fullnode.
1321                if obj_ref.1 < live_object.version() {
1322                    return Err(SuiErrorKind::UserInputError {
1323                        error: UserInputError::ObjectVersionUnavailableForConsumption {
1324                            provided_obj_ref: *obj_ref,
1325                            current_version: live_object.version(),
1326                        },
1327                    }
1328                    .into());
1329                }
1330
1331                if enforce_live_input_objects && live_object.version() < obj_ref.1 {
1332                    // Returns a non-retriable error when the input object version is required to be live.
1333                    return Err(SuiErrorKind::UserInputError {
1334                        error: UserInputError::ObjectVersionUnavailableForConsumption {
1335                            provided_obj_ref: *obj_ref,
1336                            current_version: live_object.version(),
1337                        },
1338                    }
1339                    .into());
1340                }
1341
1342                // If version matches, verify digest also matches
1343                if obj_ref.1 == live_object.version() && obj_ref.2 != live_object.digest() {
1344                    return Err(SuiErrorKind::UserInputError {
1345                        error: UserInputError::InvalidObjectDigest {
1346                            object_id: obj_ref.0,
1347                            expected_digest: live_object.digest(),
1348                        },
1349                    }
1350                    .into());
1351                }
1352            }
1353        }
1354
1355        Ok(())
1356    }
1357
1358    pub fn check_system_overload_at_signing(&self) -> bool {
1359        self.config
1360            .authority_overload_config
1361            .check_system_overload_at_signing
1362    }
1363
1364    pub(crate) fn check_system_overload(
1365        &self,
1366        tx_data: &SenderSignedData,
1367        do_authority_overload_check: bool,
1368    ) -> SuiResult {
1369        if do_authority_overload_check {
1370            self.check_authority_overload(tx_data).tap_err(|_| {
1371                self.update_overload_metrics("execution_queue");
1372            })?;
1373        }
1374        self.execution_scheduler
1375            .check_execution_overload(self.overload_config(), tx_data)
1376            .tap_err(|_| {
1377                self.update_overload_metrics("execution_pending");
1378            })?;
1379        // Consensus overload is handled by the admission queue in authority_server.rs.
1380
1381        let pending_tx_count = self
1382            .get_cache_commit()
1383            .approximate_pending_transaction_count();
1384        if pending_tx_count > self.config.execution_cache.backpressure_threshold_for_rpc() {
1385            return Err(SuiErrorKind::ValidatorOverloadedRetryAfter {
1386                retry_after_secs: 10,
1387            }
1388            .into());
1389        }
1390
1391        Ok(())
1392    }
1393
1394    fn check_authority_overload(&self, tx_data: &SenderSignedData) -> SuiResult {
1395        if !self.overload_info.is_overload.load(Ordering::Relaxed) {
1396            return Ok(());
1397        }
1398
1399        let load_shedding_percentage = self
1400            .overload_info
1401            .load_shedding_percentage
1402            .load(Ordering::Relaxed);
1403        overload_monitor_accept_tx(load_shedding_percentage, tx_data.digest())
1404    }
1405
1406    pub(crate) fn update_overload_metrics(&self, source: &str) {
1407        self.metrics
1408            .transaction_overload_sources
1409            .with_label_values(&[source])
1410            .inc();
1411    }
1412
1413    /// Waits for fastpath (owned, package) dependency objects to become available.
1414    /// Returns true if a chosen set of fastpath dependency objects are available,
1415    /// returns false otherwise after an internal timeout.
1416    pub(crate) async fn wait_for_fastpath_dependency_objects(
1417        &self,
1418        transaction: &VerifiedTransaction,
1419        epoch: EpochId,
1420    ) -> SuiResult<bool> {
1421        let txn_data = transaction.data().transaction_data();
1422        let (move_objects, packages, receiving_objects) = txn_data.fastpath_dependency_objects()?;
1423
1424        // Gather and filter input objects to wait for.
1425        let fastpath_dependency_objects: Vec<_> = move_objects
1426            .into_iter()
1427            .filter_map(|obj_ref| self.should_wait_for_dependency_object(obj_ref))
1428            .chain(
1429                packages
1430                    .into_iter()
1431                    .map(|package_id| InputKey::Package { id: package_id }),
1432            )
1433            .collect();
1434        let receiving_keys: HashSet<_> = receiving_objects
1435            .into_iter()
1436            .filter_map(|receiving_obj_ref| {
1437                self.should_wait_for_dependency_object(receiving_obj_ref)
1438            })
1439            .collect();
1440        if fastpath_dependency_objects.is_empty() && receiving_keys.is_empty() {
1441            return Ok(true);
1442        }
1443
1444        // Use shorter wait timeout in simtests to exercise server-side error paths and
1445        // client-side retry logic.
1446        let max_wait = if cfg!(msim) {
1447            Duration::from_millis(200)
1448        } else {
1449            WAIT_FOR_FASTPATH_INPUT_TIMEOUT
1450        };
1451
1452        match timeout(
1453            max_wait,
1454            self.get_object_cache_reader().notify_read_input_objects(
1455                &fastpath_dependency_objects,
1456                &receiving_keys,
1457                epoch,
1458            ),
1459        )
1460        .await
1461        {
1462            Ok(()) => Ok(true),
1463            // Maybe return an error for unavailable input objects,
1464            // and allow the caller to skip the rest of input checks?
1465            Err(_) => Ok(false),
1466        }
1467    }
1468
1469    /// Returns Some(inputKey) if the object reference should be waited on until it is
1470    /// finalized, before proceeding to input checks.
1471    ///
1472    /// Incorrect decisions here should only affect user experience, not safety:
1473    /// - Waiting unnecessarily adds latency to transaction signing and submission.
1474    /// - Not waiting when needed may cause the transaction to be rejected because input object is unavailable.
1475    fn should_wait_for_dependency_object(&self, obj_ref: ObjectRef) -> Option<InputKey> {
1476        let (obj_id, cur_version, _digest) = obj_ref;
1477        let Some(latest_obj_ref) = self
1478            .get_object_cache_reader()
1479            .get_latest_object_ref_or_tombstone(obj_id)
1480        else {
1481            // Object might not have been created.
1482            return Some(InputKey::VersionedObject {
1483                id: FullObjectID::new(obj_id, None),
1484                version: cur_version,
1485            });
1486        };
1487        let latest_digest = latest_obj_ref.2;
1488        if latest_digest == ObjectDigest::OBJECT_DIGEST_DELETED {
1489            // Do not wait for deleted object and rely on input check instead.
1490            return None;
1491        }
1492        let latest_version = latest_obj_ref.1;
1493        if cur_version <= latest_version {
1494            // Do not wait for version that already exists or has been consumed.
1495            // Let the input check to handle them and return the proper error.
1496            return None;
1497        }
1498        // Wait for the object version to become available.
1499        Some(InputKey::VersionedObject {
1500            id: FullObjectID::new(obj_id, None),
1501            version: cur_version,
1502        })
1503    }
1504
1505    /// Wait for a transaction to be executed. Transactions need to be sequenced by consensus
1506    /// before being enqueued for execution.
1507    ///
1508    /// Only use this in tests.
1509    #[instrument(level = "trace", skip_all)]
1510    pub async fn wait_for_transaction_execution_for_testing(
1511        &self,
1512        transaction: &VerifiedExecutableTransaction,
1513    ) -> TransactionEffects {
1514        self.notify_read_effects_for_testing(
1515            "AuthorityState::wait_for_transaction_execution_for_testing",
1516            *transaction.digest(),
1517        )
1518        .await
1519    }
1520
1521    /// Internal logic to execute a certificate.
1522    ///
1523    /// Guarantees that
1524    /// - If input objects are available, return no permanent failure.
1525    /// - Execution and output commit are atomic. i.e. outputs are only written to storage,
1526    /// on successful execution; crashed execution has no observable effect and can be retried.
1527    ///
1528    /// It is caller's responsibility to ensure input objects are available and locks are set.
1529    /// If this cannot be satisfied by the caller, execute_certificate() should be called instead.
1530    ///
1531    /// Should only be called within sui-core.
1532    #[instrument(level = "trace", skip_all)]
1533    pub fn try_execute_immediately(
1534        &self,
1535        certificate: &VerifiedExecutableTransaction,
1536        mut execution_env: ExecutionEnv,
1537        epoch_store: &Arc<AuthorityPerEpochStore>,
1538    ) -> ExecutionOutput<(TransactionEffects, Option<ExecutionError>)> {
1539        let _scope = monitored_scope("Execution::try_execute_immediately");
1540        let _metrics_guard = self.metrics.internal_execution_latency.start_timer();
1541
1542        let tx_digest = certificate.digest();
1543
1544        if let Some(fork_recovery) = &self.fork_recovery_state
1545            && let Some(override_digest) = fork_recovery.get_transaction_override(tx_digest)
1546        {
1547            warn!(
1548                ?tx_digest,
1549                original_digest = ?execution_env.expected_effects_digest,
1550                override_digest = ?override_digest,
1551                "Applying fork recovery override for transaction effects digest"
1552            );
1553            execution_env.expected_effects_digest =
1554                Some(ExpectedEffectsDigest::Uncertified(override_digest));
1555        }
1556
1557        // prevent concurrent executions of the same tx.
1558        let tx_guard = epoch_store.acquire_tx_guard(certificate);
1559
1560        let tx_cache_reader = self.get_transaction_cache_reader();
1561        if let Some(effects) = tx_cache_reader.get_executed_effects(tx_digest) {
1562            if let Some(expected_effects_digest) = execution_env.expected_effects_digest {
1563                assert_eq!(
1564                    effects.digest(),
1565                    expected_effects_digest.digest(),
1566                    "Unexpected effects digest for transaction {:?}",
1567                    tx_digest
1568                );
1569            }
1570            tx_guard.release();
1571            return ExecutionOutput::Success((effects, None));
1572        }
1573
1574        let execution_start_time = Instant::now();
1575
1576        // Any caller that verifies the signatures on the certificate will have already checked the
1577        // epoch. But paths that don't verify sigs (e.g. execution from checkpoint, reading from db)
1578        // present the possibility of an epoch mismatch. If this cert is not finalzied in previous
1579        // epoch, then it's invalid.
1580        let Some(execution_guard) = self.execution_lock_for_executable_transaction(certificate)
1581        else {
1582            tx_guard.release();
1583            return ExecutionOutput::EpochEnded;
1584        };
1585        // Since we obtain a reference to the epoch store before taking the execution lock, it's
1586        // possible that reconfiguration has happened and they no longer match.
1587        // TODO: We may not need the following check anymore since the scheduler
1588        // should have checked that the certificate is from the same epoch as epoch_store.
1589        if *execution_guard != epoch_store.epoch() {
1590            tx_guard.release();
1591            info!("The epoch of the execution_guard doesn't match the epoch store");
1592            return ExecutionOutput::EpochEnded;
1593        }
1594
1595        let accumulator_version = execution_env.assigned_versions.accumulator_version();
1596
1597        let (transaction_outputs, timings, execution_error_opt) = match self.process_certificate(
1598            &tx_guard,
1599            &execution_guard,
1600            certificate,
1601            execution_env,
1602            epoch_store,
1603        ) {
1604            ExecutionOutput::Success(result) => result,
1605            output => return output.unwrap_err(),
1606        };
1607        let transaction_outputs = Arc::new(transaction_outputs);
1608
1609        fail_point!("crash");
1610
1611        let effects = transaction_outputs.effects.clone();
1612        debug!(
1613            ?tx_digest,
1614            fx_digest=?effects.digest(),
1615            "process_certificate succeeded in {:.3}ms",
1616            (execution_start_time.elapsed().as_micros() as f64) / 1000.0
1617        );
1618
1619        self.commit_certificate(certificate, transaction_outputs, epoch_store);
1620
1621        if let TransactionKind::AuthenticatorStateUpdate(auth_state) =
1622            certificate.data().transaction_data().kind()
1623        {
1624            if let Some(err) = &execution_error_opt {
1625                debug_fatal!("Authenticator state update failed: {:?}", err);
1626            }
1627            epoch_store.update_authenticator_state(auth_state);
1628
1629            // double check that the signature verifier always matches the authenticator state
1630            if cfg!(debug_assertions) {
1631                let authenticator_state = get_authenticator_state(self.get_object_store())
1632                    .expect("Read cannot fail")
1633                    .expect("Authenticator state must exist");
1634
1635                let mut sys_jwks: Vec<_> = authenticator_state
1636                    .active_jwks
1637                    .into_iter()
1638                    .map(|jwk| (jwk.jwk_id, jwk.jwk))
1639                    .collect();
1640                let mut active_jwks: Vec<_> = epoch_store
1641                    .signature_verifier
1642                    .get_jwks()
1643                    .into_iter()
1644                    .collect();
1645                sys_jwks.sort();
1646                active_jwks.sort();
1647
1648                assert_eq!(sys_jwks, active_jwks);
1649            }
1650        }
1651
1652        if certificate
1653            .transaction_data()
1654            .kind()
1655            .is_accumulator_barrier_settle_tx()
1656        {
1657            let object_funds_checker = self.object_funds_checker.load();
1658            if let Some(object_funds_checker) = object_funds_checker.as_ref() {
1659                // unwrap safe because we assign accumulator version for every transaction
1660                // when accumulator is enabled.
1661                let next_accumulator_version = accumulator_version.unwrap().next();
1662                object_funds_checker.settle_accumulator_version(next_accumulator_version);
1663            }
1664        }
1665
1666        tx_guard.commit_tx();
1667
1668        let elapsed = execution_start_time.elapsed();
1669        epoch_store.record_local_execution_time(
1670            certificate.data().transaction_data(),
1671            &effects,
1672            timings,
1673            elapsed,
1674        );
1675
1676        let elapsed_us = elapsed.as_micros() as f64;
1677        if elapsed_us > 0.0 {
1678            self.metrics
1679                .execution_gas_latency_ratio
1680                .observe(effects.gas_cost_summary().computation_cost as f64 / elapsed_us);
1681        };
1682        ExecutionOutput::Success((effects, execution_error_opt))
1683    }
1684
1685    pub fn read_objects_for_execution(
1686        &self,
1687        tx_lock: &CertLockGuard,
1688        certificate: &VerifiedExecutableTransaction,
1689        assigned_shared_object_versions: &AssignedVersions,
1690        epoch_store: &Arc<AuthorityPerEpochStore>,
1691    ) -> SuiResult<InputObjects> {
1692        let _scope = monitored_scope("Execution::load_input_objects");
1693        let _metrics_guard = self
1694            .metrics
1695            .execution_load_input_objects_latency
1696            .start_timer();
1697        let input_objects = &certificate.data().transaction_data().input_objects()?;
1698        self.input_loader.read_objects_for_execution(
1699            &certificate.key(),
1700            tx_lock,
1701            input_objects,
1702            assigned_shared_object_versions,
1703            epoch_store.epoch(),
1704        )
1705    }
1706
1707    pub async fn try_execute_executable_for_test(
1708        &self,
1709        executable: &VerifiedExecutableTransaction,
1710        execution_env: ExecutionEnv,
1711    ) -> (VerifiedSignedTransactionEffects, Option<ExecutionError>) {
1712        let epoch_store = self.epoch_store_for_testing();
1713        let (effects, execution_error_opt) = self
1714            .try_execute_immediately(executable, execution_env, &epoch_store)
1715            .unwrap();
1716        let signed_effects = self.sign_effects(effects, &epoch_store).unwrap();
1717        (signed_effects, execution_error_opt)
1718    }
1719
1720    /// Wait until the effects of the given transaction are available and return them.
1721    /// Panics if the effects are not found.
1722    ///
1723    /// Only use this in tests where effects are expected to exist.
1724    pub async fn notify_read_effects_for_testing(
1725        &self,
1726        task_name: &'static str,
1727        digest: TransactionDigest,
1728    ) -> TransactionEffects {
1729        self.get_transaction_cache_reader()
1730            .notify_read_executed_effects(task_name, &[digest])
1731            .await
1732            .pop()
1733            .expect("must return correct number of effects")
1734    }
1735
1736    /// This function captures the required state to debug a forked transaction.
1737    /// The dump is written to a file in dir `path`, with name prefixed by the transaction digest.
1738    /// NOTE: Since this info escapes the validator context,
1739    /// make sure not to leak any private info here
1740    pub(crate) fn debug_dump_transaction_state(
1741        &self,
1742        tx_digest: &TransactionDigest,
1743        effects: &TransactionEffects,
1744        expected_effects_digest: TransactionEffectsDigest,
1745        inner_temporary_store: &InnerTemporaryStore,
1746        certificate: &VerifiedExecutableTransaction,
1747        debug_dump_config: &StateDebugDumpConfig,
1748    ) -> SuiResult<PathBuf> {
1749        let dump_dir = debug_dump_config
1750            .dump_file_directory
1751            .as_ref()
1752            .cloned()
1753            .unwrap_or(std::env::temp_dir());
1754        let epoch_store = self.load_epoch_store_one_call_per_task();
1755
1756        NodeStateDump::new(
1757            tx_digest,
1758            effects,
1759            expected_effects_digest,
1760            self.get_object_store().as_ref(),
1761            &epoch_store,
1762            inner_temporary_store,
1763            certificate,
1764        )?
1765        .write_to_file(&dump_dir)
1766        .map_err(|e| SuiErrorKind::FileIOError(e.to_string()).into())
1767    }
1768
1769    #[instrument(level = "trace", skip_all)]
1770    pub(crate) fn process_certificate(
1771        &self,
1772        tx_guard: &CertTxGuard,
1773        execution_guard: &ExecutionLockReadGuard<'_>,
1774        certificate: &VerifiedExecutableTransaction,
1775        execution_env: ExecutionEnv,
1776        epoch_store: &Arc<AuthorityPerEpochStore>,
1777    ) -> ExecutionOutput<(
1778        TransactionOutputs,
1779        Vec<ExecutionTiming>,
1780        Option<ExecutionError>,
1781    )> {
1782        let _scope = monitored_scope("Execution::process_certificate");
1783
1784        let input_objects = match self.read_objects_for_execution(
1785            tx_guard.as_lock_guard(),
1786            certificate,
1787            &execution_env.assigned_versions,
1788            epoch_store,
1789        ) {
1790            Ok(objects) => objects,
1791            Err(e) => return ExecutionOutput::Fatal(e),
1792        };
1793
1794        let expected_effects_digest = execution_env.expected_effects_digest;
1795
1796        fail_point_if!("correlated-crash-process-certificate", || {
1797            if sui_simulator::random::deterministic_probability_once(certificate.digest(), 0.01) {
1798                sui_simulator::task::kill_current_node(None);
1799            }
1800        });
1801
1802        // Errors originating from prepare_certificate may be transient (failure to read locks) or
1803        // non-transient (transaction input is invalid, move vm errors). However, all errors from
1804        // this function occur before we have written anything to the db, so we commit the tx
1805        // guard and rely on the client to retry the tx (if it was transient).
1806        self.execute_certificate(
1807            execution_guard,
1808            certificate,
1809            input_objects,
1810            expected_effects_digest,
1811            execution_env,
1812            epoch_store,
1813        )
1814    }
1815
1816    pub async fn reconfigure_traffic_control(
1817        &self,
1818        params: TrafficControlReconfigParams,
1819    ) -> Result<TrafficControlReconfigParams, SuiError> {
1820        if let Some(traffic_controller) = self.traffic_controller.as_ref() {
1821            traffic_controller.admin_reconfigure(params).await
1822        } else {
1823            Err(SuiErrorKind::InvalidAdminRequest(
1824                "Traffic controller is not configured on this node".to_string(),
1825            )
1826            .into())
1827        }
1828    }
1829
1830    #[instrument(level = "trace", skip_all)]
1831    fn commit_certificate(
1832        &self,
1833        certificate: &VerifiedExecutableTransaction,
1834        transaction_outputs: Arc<TransactionOutputs>,
1835        epoch_store: &Arc<AuthorityPerEpochStore>,
1836    ) {
1837        let _scope: Option<mysten_metrics::MonitoredScopeGuard> =
1838            monitored_scope("Execution::commit_certificate");
1839        let _metrics_guard = self.metrics.commit_certificate_latency.start_timer();
1840
1841        let tx_digest = certificate.digest();
1842
1843        // The insertion to epoch_store is not atomic with the insertion to the perpetual store. This is OK because
1844        // we insert to the epoch store first. And during lookups we always look up in the perpetual store first.
1845        epoch_store.insert_executed_in_epoch(tx_digest);
1846        let key = certificate.key();
1847        if !matches!(key, TransactionKey::Digest(_)) {
1848            epoch_store.insert_tx_key(key, *tx_digest);
1849        }
1850
1851        // Allow testing what happens if we crash here.
1852        fail_point!("crash");
1853
1854        self.get_cache_writer()
1855            .write_transaction_outputs(epoch_store.epoch(), transaction_outputs);
1856
1857        // Fire an in-memory-only notification so the scheduler can detect that this
1858        // barrier transaction has been executed (e.g. by the checkpoint executor) and
1859        // stop waiting for the checkpoint builder.  We intentionally do NOT persist
1860        // this to the DB to avoid stale entries surviving a crash while effects may not.
1861        if let Some(settlement_key) = certificate
1862            .transaction_data()
1863            .kind()
1864            .accumulator_barrier_settlement_key()
1865        {
1866            epoch_store.notify_barrier_executed(settlement_key, *tx_digest);
1867        }
1868
1869        if certificate.transaction_data().is_end_of_epoch_tx() {
1870            // At the end of epoch, since system packages may have been upgraded, force
1871            // reload them in the cache.
1872            self.get_object_cache_reader()
1873                .force_reload_system_packages(&BuiltInFramework::all_package_ids());
1874        }
1875    }
1876
1877    fn update_metrics(
1878        &self,
1879        certificate: &VerifiedExecutableTransaction,
1880        inner_temporary_store: &InnerTemporaryStore,
1881        effects: &TransactionEffects,
1882    ) {
1883        // count signature by scheme, for zklogin and multisig
1884        if certificate.has_zklogin_sig() {
1885            self.metrics.zklogin_sig_count.inc();
1886        } else if certificate.has_upgraded_multisig() {
1887            self.metrics.multisig_sig_count.inc();
1888        }
1889
1890        self.metrics.total_effects.inc();
1891        self.metrics.total_certs.inc();
1892
1893        let consensus_object_count = effects.accessed_consensus_objects().len();
1894        if consensus_object_count > 0 {
1895            self.metrics.shared_obj_tx.inc();
1896        }
1897
1898        if certificate.is_sponsored_tx() {
1899            self.metrics.sponsored_tx.inc();
1900        }
1901
1902        let input_object_count = inner_temporary_store.input_objects.len();
1903        self.metrics
1904            .num_input_objs
1905            .observe(input_object_count as f64);
1906        self.metrics
1907            .num_shared_objects
1908            .observe(consensus_object_count as f64);
1909        self.metrics.batch_size.observe(
1910            certificate
1911                .data()
1912                .intent_message()
1913                .value
1914                .kind()
1915                .num_commands() as f64,
1916        );
1917    }
1918
1919    /// Runs the executor on an already-prepared transaction; the caller is responsible for any
1920    /// coin reservation rewriting.
1921    fn execute_transaction_to_effects(
1922        &self,
1923        executor: &dyn Executor,
1924        store: &dyn BackingStore,
1925        protocol_config: &ProtocolConfig,
1926        enable_expensive_checks: bool,
1927        execution_params: ExecutionOrEarlyError,
1928        epoch_id: &EpochId,
1929        epoch_timestamp_ms: u64,
1930        input_objects: CheckedInputObjects,
1931        system_object_versions: SystemObjectVersions,
1932        unsettled_object_funds: &dyn UnsettledObjectFundsRead,
1933        gas_data: GasData,
1934        reference_gas_price: u64,
1935        kind: TransactionKind,
1936        rewritten_inputs: Option<Vec<bool>>,
1937        signer: SuiAddress,
1938        tx_digest: TransactionDigest,
1939    ) -> (
1940        InnerTemporaryStore,
1941        GasUsageReport,
1942        TransactionEffects,
1943        Vec<ExecutionTiming>,
1944        Result<(), ExecutionError>,
1945    ) {
1946        let (inner_temp_store, gas_report, effects, timings, execution_error) = executor
1947            // TODO only run this function on FullNodes, use `execute_transaction_to_effects` on validators.
1948            .execute_transaction_to_effects_and_execution_error(
1949                store,
1950                protocol_config,
1951                self.metrics.execution_metrics.clone(),
1952                enable_expensive_checks,
1953                execution_params,
1954                epoch_id,
1955                epoch_timestamp_ms,
1956                input_objects,
1957                system_object_versions,
1958                unsettled_object_funds,
1959                gas_data,
1960                reference_gas_price,
1961                kind,
1962                rewritten_inputs,
1963                signer,
1964                tx_digest,
1965                &mut None,
1966            );
1967
1968        (
1969            inner_temp_store,
1970            gas_report,
1971            effects,
1972            timings,
1973            execution_error,
1974        )
1975    }
1976
1977    /// execute_certificate validates the transaction input, and executes the certificate,
1978    /// returning transaction outputs.
1979    ///
1980    /// It reads state from the db (both owned and shared locks), but it has no side effects.
1981    ///
1982    /// Executes a certificate and returns an ExecutionOutput.
1983    /// The function can fail with Fatal errors (e.g., the transaction input is invalid,
1984    /// locks are not held correctly, etc.) or transient errors (e.g., db read errors).
1985    #[instrument(level = "trace", skip_all)]
1986    fn execute_certificate(
1987        &self,
1988        _execution_guard: &ExecutionLockReadGuard<'_>,
1989        certificate: &VerifiedExecutableTransaction,
1990        input_objects: InputObjects,
1991        expected_effects_digest: Option<ExpectedEffectsDigest>,
1992        execution_env: ExecutionEnv,
1993        epoch_store: &Arc<AuthorityPerEpochStore>,
1994    ) -> ExecutionOutput<(
1995        TransactionOutputs,
1996        Vec<ExecutionTiming>,
1997        Option<ExecutionError>,
1998    )> {
1999        let _scope = monitored_scope("Execution::prepare_certificate");
2000        let _metrics_guard = self.metrics.prepare_certificate_latency.start_timer();
2001        let prepare_certificate_start_time = tokio::time::Instant::now();
2002
2003        // TODO: We need to move this to a more appropriate place to avoid redundant checks.
2004        let tx_data = certificate.data().transaction_data();
2005
2006        if let Err(e) = tx_data.validity_check(&epoch_store.tx_validity_check_context()) {
2007            return ExecutionOutput::Fatal(e);
2008        }
2009
2010        // The cost of partially re-auditing a transaction before execution is tolerated.
2011        // This step is required for correctness because, for example, ConsensusAddressOwner
2012        // object owner may have changed between signing and execution.
2013        let input_objects = match sui_transaction_checks::check_certificate_input(
2014            certificate,
2015            input_objects,
2016            epoch_store.protocol_config(),
2017            epoch_store.reference_gas_price(),
2018        ) {
2019            Ok(result) => result,
2020            Err(e) => return ExecutionOutput::Fatal(e),
2021        };
2022
2023        let tx_digest = *certificate.digest();
2024        let protocol_config = epoch_store.protocol_config();
2025        let transaction_data = &certificate.data().intent_message().value;
2026        let sender = transaction_data.sender();
2027        let (mut kind, signer, gas_data) = transaction_data.execution_parts();
2028        let early_execution_error = get_early_execution_error(
2029            &tx_digest,
2030            &input_objects,
2031            self.config.certificate_deny_config.certificate_deny_set(),
2032            &execution_env.funds_withdraw_status,
2033        );
2034        let accumulator_version = execution_env.assigned_versions.accumulator_version();
2035        let system_object_versions = execution_env
2036            .assigned_versions
2037            .system_object_versions
2038            .clone();
2039        let execution_params = match early_execution_error {
2040            None => ExecutionOrEarlyError::ok(accumulator_version),
2041            Some(errors) => ExecutionOrEarlyError::failed(errors, accumulator_version),
2042        };
2043
2044        // Skip on early error: the tx will fail anyway and rewriting may fail if the accumulator
2045        // was deleted.
2046        let rewritten_inputs = if execution_params.is_ok() {
2047            rewrite_transaction_for_coin_reservations(
2048                self.chain_identifier,
2049                &*self.coin_reservation_resolver,
2050                sender,
2051                &mut kind,
2052                execution_env.assigned_versions.accumulator_version(),
2053            )
2054            .expect("rewriting must succeed for a certified transaction")
2055        } else {
2056            None
2057        };
2058
2059        let tracking_store = TrackingBackingStore::new(self.get_backing_store().as_ref());
2060
2061        let unsettled_object_funds =
2062            self.unsettled_object_withdrawals.as_ref() as &dyn UnsettledObjectFundsRead;
2063
2064        #[allow(unused_mut)]
2065        let (inner_temp_store, _, mut effects, timings, execution_error_opt) = self
2066            .execute_transaction_to_effects(
2067                &**epoch_store.executor(),
2068                &tracking_store,
2069                protocol_config,
2070                // TODO: would be nice to pass the whole NodeConfig here, but it creates a
2071                // cyclic dependency w/ sui-adapter
2072                self.config
2073                    .expensive_safety_check_config
2074                    .enable_deep_per_tx_sui_conservation_check(),
2075                execution_params,
2076                &epoch_store.epoch_start_config().epoch_data().epoch_id(),
2077                epoch_store
2078                    .epoch_start_config()
2079                    .epoch_data()
2080                    .epoch_start_timestamp(),
2081                input_objects,
2082                system_object_versions,
2083                unsettled_object_funds,
2084                gas_data,
2085                epoch_store.reference_gas_price(),
2086                kind,
2087                rewritten_inputs,
2088                signer,
2089                tx_digest,
2090            );
2091
2092        if !protocol_config.check_object_funds_withdraw_in_execution() {
2093            // TODO: Move the object funds checker to the executor so that it can eventually be
2094            // removed from the active code path.
2095            let object_funds_checker = self.object_funds_checker.load();
2096            if let Some(object_funds_checker) = object_funds_checker.as_ref()
2097                && !object_funds_checker.should_commit_object_funds_withdraws(
2098                    certificate,
2099                    &effects,
2100                    &inner_temp_store.accumulator_running_max_withdraws,
2101                    &execution_env,
2102                    self.get_account_funds_read(),
2103                    &self.execution_scheduler,
2104                    epoch_store,
2105                )
2106            {
2107                assert_reachable_gated!("retry object withdraw later", |pc| !pc
2108                    .check_object_funds_withdraw_in_execution());
2109                return ExecutionOutput::RetryLater;
2110            }
2111        } else {
2112            match effects.status() {
2113                ExecutionStatus::Success => {
2114                    if let Some(accumulator_version) =
2115                        execution_env.assigned_versions.accumulator_version()
2116                    {
2117                        self.unsettled_object_withdrawals
2118                            .record_object_funds_withdraws(
2119                                certificate.transaction_data(),
2120                                &effects,
2121                                &inner_temp_store.accumulator_running_max_withdraws,
2122                                accumulator_version,
2123                                self.chain_identifier,
2124                            );
2125                    }
2126                }
2127                ExecutionStatus::Failure(failure) => {
2128                    if sui_types::funds_accumulator::is_object_funds_insufficient_abort(
2129                        &failure.error,
2130                    ) {
2131                        assert_reachable_gated!("object funds insufficient in execution", |pc| pc
2132                            .check_object_funds_withdraw_in_execution());
2133                        self.object_funds_checker_metrics
2134                            .in_execution_check_result
2135                            .with_label_values(&["insufficient"])
2136                            .inc();
2137                    }
2138                }
2139            }
2140        }
2141
2142        // (test-only) Inject a fork before the effects-digest check below. Placed here so that a
2143        // forked validator executing a *certified* checkpoint (expected_effects_digest is set, i.e.
2144        // the checkpoint-executor path) trips the transaction-fork check. On the builder path
2145        // (expected_effects_digest is None) the check is skipped, so this still produces a checkpoint
2146        // fork as before.
2147        fail_point_arg!("simulate_fork_during_execution", |(
2148            forked_validators,
2149            full_halt,
2150            effects_overrides,
2151            fork_probability,
2152            executor_path_only,
2153        ): (
2154            std::sync::Arc<
2155                std::sync::Mutex<std::collections::HashSet<sui_types::base_types::AuthorityName>>,
2156            >,
2157            bool,
2158            std::sync::Arc<std::sync::Mutex<std::collections::BTreeMap<String, String>>>,
2159            f32,
2160            bool,
2161        )| {
2162            #[cfg(msim)]
2163            // When `executor_path_only` is set, fork only while executing a certified checkpoint
2164            // (expected_effects_digest is set) so the divergence trips the transaction-fork check
2165            // below; otherwise fork on any path (the builder path yields a checkpoint fork).
2166            if !executor_path_only || expected_effects_digest.is_some() {
2167                self.simulate_fork_during_execution(
2168                    certificate,
2169                    epoch_store,
2170                    &mut effects,
2171                    forked_validators,
2172                    full_halt,
2173                    effects_overrides,
2174                    fork_probability,
2175                );
2176            }
2177        });
2178
2179        if let Some(expected) = expected_effects_digest
2180            && effects.digest() != expected.digest()
2181        {
2182            let expected_effects_digest = expected.digest();
2183            // We dont want to mask the original error, so we log it and continue.
2184            match self.debug_dump_transaction_state(
2185                &tx_digest,
2186                &effects,
2187                expected_effects_digest,
2188                &inner_temp_store,
2189                certificate,
2190                &self.config.state_debug_dump_config,
2191            ) {
2192                Ok(out_path) => {
2193                    info!(
2194                        "Dumped node state for transaction {} to {}",
2195                        tx_digest,
2196                        out_path.as_path().display().to_string()
2197                    );
2198                }
2199                Err(e) => {
2200                    error!("Error dumping state for transaction {}: {e}", tx_digest);
2201                }
2202            }
2203            let expected_effects = self
2204                .get_transaction_cache_reader()
2205                .get_effects(&expected_effects_digest);
2206            error!(
2207                ?tx_digest,
2208                ?expected,
2209                actual_effects = ?effects,
2210                expected_effects = ?expected_effects,
2211                "fork detected!"
2212            );
2213            if let Err(e) = self.checkpoint_store.record_transaction_fork_detected(
2214                tx_digest,
2215                expected_effects_digest,
2216                effects.digest(),
2217                expected.checkpoint_seq(),
2218            ) {
2219                error!("Failed to record transaction fork: {e}");
2220            }
2221
2222            fail_point_if!("kill_transaction_fork_node", || {
2223                #[cfg(msim)]
2224                {
2225                    tracing::error!(
2226                        fatal = true,
2227                        "Fork recovery test: killing node due to transaction effects fork for digest: {}",
2228                        tx_digest
2229                    );
2230                    sui_simulator::task::shutdown_current_node();
2231                }
2232            });
2233
2234            fatal!(
2235                "Transaction {} is expected to have effects digest {}, but got {}!",
2236                tx_digest,
2237                expected_effects_digest,
2238                effects.digest()
2239            );
2240        }
2241
2242        let unchanged_loaded_runtime_objects =
2243            crate::transaction_outputs::unchanged_loaded_runtime_objects(
2244                certificate.transaction_data(),
2245                &effects,
2246                &tracking_store.into_read_objects(),
2247            );
2248
2249        self.update_metrics(certificate, &inner_temp_store, &effects);
2250
2251        let transaction_outputs = TransactionOutputs::build_transaction_outputs(
2252            certificate.clone().into_unsigned(),
2253            effects,
2254            inner_temp_store,
2255            unchanged_loaded_runtime_objects,
2256        );
2257
2258        let elapsed = prepare_certificate_start_time.elapsed().as_micros() as f64;
2259        if elapsed > 0.0 {
2260            self.metrics.prepare_cert_gas_latency_ratio.observe(
2261                transaction_outputs
2262                    .effects
2263                    .gas_cost_summary()
2264                    .computation_cost as f64
2265                    / elapsed,
2266            );
2267        }
2268
2269        ExecutionOutput::Success((transaction_outputs, timings, execution_error_opt.err()))
2270    }
2271
2272    pub fn prepare_certificate_for_benchmark(
2273        &self,
2274        certificate: &VerifiedExecutableTransaction,
2275        input_objects: InputObjects,
2276        epoch_store: &Arc<AuthorityPerEpochStore>,
2277    ) -> SuiResult<(TransactionOutputs, Option<ExecutionError>)> {
2278        let lock = RwLock::new(epoch_store.epoch());
2279        let execution_guard = lock.try_read().unwrap();
2280
2281        let (transaction_outputs, _timings, execution_error_opt) = self
2282            .execute_certificate(
2283                &execution_guard,
2284                certificate,
2285                input_objects,
2286                None,
2287                ExecutionEnv::default(),
2288                epoch_store,
2289            )
2290            .unwrap();
2291        Ok((transaction_outputs, execution_error_opt))
2292    }
2293
2294    pub fn simulate_transaction(
2295        &self,
2296        transaction: TransactionData,
2297        checks: TransactionChecks,
2298        allow_mock_gas_coin: bool,
2299    ) -> SuiResult<SimulateTransactionResult> {
2300        if transaction.kind().is_system_tx() {
2301            return Err(SuiErrorKind::UnsupportedFeatureError {
2302                error: "simulate does not support system transactions".to_string(),
2303            }
2304            .into());
2305        }
2306
2307        let epoch_store = self.load_epoch_store_one_call_per_task();
2308        if !self.is_fullnode(&epoch_store) {
2309            return Err(SuiErrorKind::UnsupportedFeatureError {
2310                error: "simulate is only supported on fullnodes".to_string(),
2311            }
2312            .into());
2313        }
2314
2315        if checks.disabled() && self.config.dev_inspect_disabled {
2316            return Err(SuiErrorKind::UnsupportedFeatureError {
2317                error: "simulate with checks disabled is not allowed on this node".to_string(),
2318            }
2319            .into());
2320        }
2321
2322        let transaction_deny_config = self
2323            .transaction_deny_config_manager
2324            .effective_config()
2325            .load();
2326        let epoch_data = epoch_store.epoch_start_config().epoch_data();
2327        let suggested_gas_price = self
2328            .congestion_tracker
2329            .get_suggested_gas_prices(&transaction);
2330
2331        crate::transaction_simulation::simulate_transaction(
2332            transaction,
2333            checks,
2334            allow_mock_gas_coin,
2335            suggested_gas_price,
2336            epoch_store.tx_validity_check_context(),
2337            epoch_data.epoch_id(),
2338            epoch_data.epoch_start_timestamp(),
2339            self.chain_identifier,
2340            transaction_deny_config.as_ref(),
2341            self.config.certificate_deny_config.certificate_deny_set(),
2342            &self.input_loader,
2343            self.get_backing_store().as_ref(),
2344            self.get_backing_package_store().as_ref(),
2345            epoch_store.simulate_executor().as_ref(),
2346            self.coin_reservation_resolver.as_ref(),
2347            self.get_account_funds_read().as_ref(),
2348            &self.config.verifier_signing_config,
2349            &self.metrics.bytecode_verifier_metrics,
2350            &self.metrics.execution_metrics,
2351        )
2352    }
2353
2354    // Only used for testing because of how epoch store is loaded.
2355    pub fn reference_gas_price_for_testing(&self) -> Result<u64, anyhow::Error> {
2356        let epoch_store = self.epoch_store_for_testing();
2357        Ok(epoch_store.reference_gas_price())
2358    }
2359
2360    pub fn is_tx_already_executed(&self, digest: &TransactionDigest) -> bool {
2361        self.get_transaction_cache_reader()
2362            .is_tx_already_executed(digest)
2363    }
2364
2365    #[cfg(msim)]
2366    fn simulate_fork_during_execution(
2367        &self,
2368        certificate: &VerifiedExecutableTransaction,
2369        epoch_store: &Arc<AuthorityPerEpochStore>,
2370        effects: &mut TransactionEffects,
2371        forked_validators: std::sync::Arc<
2372            std::sync::Mutex<std::collections::HashSet<sui_types::base_types::AuthorityName>>,
2373        >,
2374        full_halt: bool,
2375        effects_overrides: std::sync::Arc<
2376            std::sync::Mutex<std::collections::BTreeMap<String, String>>,
2377        >,
2378        fork_probability: f32,
2379    ) {
2380        static TOTAL_FAILING_STAKE: std::sync::Mutex<u64> = std::sync::Mutex::new(0);
2381        if !certificate.data().intent_message().value.is_system_tx() {
2382            let committee = epoch_store.committee();
2383            let cur_stake = (**committee).weight(&self.name);
2384            if cur_stake > 0 {
2385                {
2386                    let mut total_stake = TOTAL_FAILING_STAKE.lock().unwrap();
2387                    let total_stake = &mut *total_stake;
2388                    let already_forked = forked_validators
2389                        .lock()
2390                        .ok()
2391                        .map(|set| set.contains(&self.name))
2392                        .unwrap_or(false);
2393
2394                    if !already_forked {
2395                        let should_fork = if full_halt {
2396                            // For full halt, fork enough nodes to reach validity threshold
2397                            *total_stake <= committee.validity_threshold()
2398                        } else {
2399                            // For partial fork, stay strictly below validity threshold
2400                            *total_stake + cur_stake < committee.validity_threshold()
2401                        };
2402
2403                        if should_fork {
2404                            *total_stake += cur_stake;
2405
2406                            if let Ok(mut external_set) = forked_validators.lock() {
2407                                external_set.insert(self.name);
2408                                info!("forked_validators: {:?}", external_set);
2409                            }
2410                        }
2411                    }
2412
2413                    if let Ok(external_set) = forked_validators.lock() {
2414                        if external_set.contains(&self.name) {
2415                            // If effects_overrides is empty, deterministically select a tx_digest to fork with 1/100 probability.
2416                            // Fork this transaction and record the digest and the original effects to original_effects.
2417                            // If original_effects is nonempty and contains a key matching this transaction digest (i.e.
2418                            // the transaction was forked on a different validator), fork this txn as well.
2419
2420                            let tx_digest = certificate.digest().to_string();
2421                            if let Ok(mut overrides) = effects_overrides.lock() {
2422                                if overrides.contains_key(&tx_digest)
2423                                    || overrides.is_empty()
2424                                        && sui_simulator::random::deterministic_probability(
2425                                            &tx_digest,
2426                                            fork_probability,
2427                                        )
2428                                {
2429                                    let original_effects_digest = effects.digest().to_string();
2430                                    overrides
2431                                        .insert(tx_digest.clone(), original_effects_digest.clone());
2432                                    info!(
2433                                        ?tx_digest,
2434                                        ?original_effects_digest,
2435                                        "Captured forked effects digest for transaction"
2436                                    );
2437                                    effects.gas_cost_summary_mut_for_testing().computation_cost +=
2438                                        1;
2439                                }
2440                            }
2441                        }
2442                    }
2443                }
2444            }
2445        }
2446    }
2447
2448    pub fn unixtime_now_ms() -> u64 {
2449        let now = SystemTime::now()
2450            .duration_since(UNIX_EPOCH)
2451            .expect("Time went backwards")
2452            .as_millis();
2453        u64::try_from(now).expect("Travelling in time machine")
2454    }
2455
2456    // TODO(fastpath): update this handler for Mysticeti fastpath.
2457    // There will no longer be validator quorum signed transactions or effects.
2458    // The proof of finality needs to come from checkpoints.
2459    #[instrument(level = "trace", skip_all)]
2460    pub async fn handle_transaction_info_request(
2461        &self,
2462        request: TransactionInfoRequest,
2463    ) -> SuiResult<TransactionInfoResponse> {
2464        let epoch_store = self.load_epoch_store_one_call_per_task();
2465        let (transaction, status) = self
2466            .get_transaction_status(&request.transaction_digest, &epoch_store)?
2467            .ok_or(SuiErrorKind::TransactionNotFound {
2468                digest: request.transaction_digest,
2469            })?;
2470        Ok(TransactionInfoResponse {
2471            transaction,
2472            status,
2473        })
2474    }
2475
2476    #[instrument(level = "trace", skip_all)]
2477    pub async fn handle_object_info_request(
2478        &self,
2479        request: ObjectInfoRequest,
2480    ) -> SuiResult<ObjectInfoResponse> {
2481        let requested_object_seq = match request.request_kind {
2482            ObjectInfoRequestKind::LatestObjectInfo => {
2483                let (_, seq, _) =
2484                    self.get_object_or_tombstone(request.object_id)
2485                        .ok_or_else(|| {
2486                            SuiError::from(UserInputError::ObjectNotFound {
2487                                object_id: request.object_id,
2488                                version: None,
2489                            })
2490                        })?;
2491                seq
2492            }
2493            ObjectInfoRequestKind::PastObjectInfoDebug(seq) => seq,
2494        };
2495
2496        let object = self
2497            .get_object_store()
2498            .get_object_by_key(&request.object_id, requested_object_seq)
2499            .ok_or_else(|| {
2500                SuiError::from(UserInputError::ObjectNotFound {
2501                    object_id: request.object_id,
2502                    version: Some(requested_object_seq),
2503                })
2504            })?;
2505
2506        let layout = if let (LayoutGenerationOption::Generate, Some(move_obj)) =
2507            (request.generate_layout, object.data.try_as_move())
2508        {
2509            Some(into_struct_layout(
2510                SyncResolver::new(PackageStoreWithLruCache::new(
2511                    self.get_backing_package_store().as_ref(),
2512                ))
2513                .get_annotated_layout(&move_obj.type_().clone().into())?,
2514            )?)
2515        } else {
2516            None
2517        };
2518
2519        Ok(ObjectInfoResponse {
2520            object,
2521            layout,
2522            // Validators no longer store signed transactions, so the locking
2523            // transaction cannot be returned.
2524            lock_for_debugging: None,
2525        })
2526    }
2527
2528    #[instrument(level = "trace", skip_all)]
2529    pub fn handle_checkpoint_request(
2530        &self,
2531        request: &CheckpointRequest,
2532    ) -> SuiResult<CheckpointResponse> {
2533        let summary = match request.sequence_number {
2534            Some(seq) => self
2535                .checkpoint_store
2536                .get_checkpoint_by_sequence_number(seq)?,
2537            None => self.checkpoint_store.get_latest_certified_checkpoint()?,
2538        }
2539        .map(|v| v.into_inner());
2540        let contents = match &summary {
2541            Some(s) => self
2542                .checkpoint_store
2543                .get_checkpoint_contents(&s.content_digest)?,
2544            None => None,
2545        };
2546        Ok(CheckpointResponse {
2547            checkpoint: summary,
2548            contents,
2549        })
2550    }
2551
2552    #[instrument(level = "trace", skip_all)]
2553    pub fn handle_checkpoint_request_v2(
2554        &self,
2555        request: &CheckpointRequestV2,
2556    ) -> SuiResult<CheckpointResponseV2> {
2557        let summary = if request.certified {
2558            let summary = match request.sequence_number {
2559                Some(seq) => self
2560                    .checkpoint_store
2561                    .get_checkpoint_by_sequence_number(seq)?,
2562                None => self.checkpoint_store.get_latest_certified_checkpoint()?,
2563            }
2564            .map(|v| v.into_inner());
2565            summary.map(CheckpointSummaryResponse::Certified)
2566        } else {
2567            let summary = match request.sequence_number {
2568                Some(seq) => self.checkpoint_store.get_locally_computed_checkpoint(seq)?,
2569                None => self
2570                    .checkpoint_store
2571                    .get_latest_locally_computed_checkpoint()?,
2572            };
2573            summary.map(CheckpointSummaryResponse::Pending)
2574        };
2575        let contents = match &summary {
2576            Some(s) => self
2577                .checkpoint_store
2578                .get_checkpoint_contents(&s.content_digest())?,
2579            None => None,
2580        };
2581        Ok(CheckpointResponseV2 {
2582            checkpoint: summary,
2583            contents,
2584        })
2585    }
2586
2587    fn check_protocol_version(
2588        supported_protocol_versions: SupportedProtocolVersions,
2589        current_version: ProtocolVersion,
2590    ) {
2591        info!("current protocol version is now {:?}", current_version);
2592        info!("supported versions are: {:?}", supported_protocol_versions);
2593        if !supported_protocol_versions.is_version_supported(current_version) {
2594            let msg = format!(
2595                "Unsupported protocol version. The network is at {:?}, but this SuiNode only supports: {:?}. Shutting down.",
2596                current_version, supported_protocol_versions,
2597            );
2598
2599            error!("{}", msg);
2600            eprintln!("{}", msg);
2601
2602            #[cfg(not(msim))]
2603            std::process::exit(1);
2604
2605            #[cfg(msim)]
2606            sui_simulator::task::shutdown_current_node();
2607        }
2608    }
2609
2610    #[allow(clippy::disallowed_methods)] // allow unbounded_channel()
2611    #[allow(clippy::too_many_arguments)]
2612    pub async fn new(
2613        name: AuthorityName,
2614        secret: StableSyncAuthoritySigner,
2615        supported_protocol_versions: SupportedProtocolVersions,
2616        store: Arc<AuthorityStore>,
2617        execution_cache_trait_pointers: ExecutionCacheTraitPointers,
2618        epoch_store: Arc<AuthorityPerEpochStore>,
2619        committee_store: Arc<CommitteeStore>,
2620        rpc_store: Option<RpcStore>,
2621        checkpoint_store: Arc<CheckpointStore>,
2622        prometheus_registry: &Registry,
2623        db_checkpoint_config: &DBCheckpointConfig,
2624        config: NodeConfig,
2625        chain_identifier: ChainIdentifier,
2626        policy_config: Option<PolicyConfig>,
2627        firewall_config: Option<RemoteFirewallConfig>,
2628        pruner_watermarks: Arc<PrunerWatermarks>,
2629    ) -> Arc<Self> {
2630        Self::check_protocol_version(supported_protocol_versions, epoch_store.protocol_version());
2631
2632        let metrics = Arc::new(AuthorityMetrics::new(prometheus_registry));
2633        let (tx_ready_certificates, rx_ready_certificates) = unbounded_channel();
2634        let execution_scheduler = Arc::new(ExecutionScheduler::new(
2635            execution_cache_trait_pointers.object_cache_reader.clone(),
2636            execution_cache_trait_pointers.account_funds_read.clone(),
2637            execution_cache_trait_pointers
2638                .transaction_cache_reader
2639                .clone(),
2640            tx_ready_certificates,
2641            &epoch_store,
2642            config.funds_withdraw_scheduler_type,
2643            metrics.clone(),
2644            prometheus_registry,
2645        ));
2646        let (tx_execution_shutdown, rx_execution_shutdown) = oneshot::channel();
2647
2648        let _authority_per_epoch_pruner = AuthorityPerEpochStorePruner::new(
2649            epoch_store.get_parent_path(),
2650            &config.authority_store_pruning_config,
2651        );
2652        let _pruner = AuthorityStorePruner::new(
2653            store.perpetual_tables.clone(),
2654            checkpoint_store.clone(),
2655            rpc_store,
2656            config.authority_store_pruning_config.clone(),
2657            epoch_store.committee().authority_exists(&name),
2658            epoch_store.epoch_start_state().epoch_duration_ms(),
2659            prometheus_registry,
2660            pruner_watermarks,
2661        );
2662        let input_loader =
2663            TransactionInputLoader::new(execution_cache_trait_pointers.object_cache_reader.clone());
2664        let epoch = epoch_store.epoch();
2665        let traffic_controller_metrics =
2666            Arc::new(TrafficControllerMetrics::new(prometheus_registry));
2667        let traffic_controller = if let Some(policy_config) = policy_config {
2668            Some(Arc::new(
2669                TrafficController::init(
2670                    policy_config,
2671                    traffic_controller_metrics,
2672                    firewall_config.clone(),
2673                )
2674                .await,
2675            ))
2676        } else {
2677            None
2678        };
2679
2680        let fork_recovery_state = config.fork_recovery.as_ref().map(|fork_config| {
2681            ForkRecoveryState::new(Some(fork_config))
2682                .expect("Failed to initialize fork recovery state")
2683        });
2684
2685        let coin_reservation_resolver = Arc::new(CachingCoinReservationResolver::new(
2686            execution_cache_trait_pointers
2687                .runtime_object_resolver
2688                .clone(),
2689        ));
2690
2691        let object_funds_checker_metrics =
2692            Arc::new(ObjectFundsCheckerMetrics::new(prometheus_registry));
2693
2694        let transaction_deny_config_manager = TransactionDenyConfigManager::new(
2695            name,
2696            config.transaction_deny_config.clone(),
2697            config.peer_deny_sync_config.clone(),
2698            epoch_store.committee().clone(),
2699            store.perpetual_tables.clone(),
2700            prometheus_registry,
2701        )
2702        .expect("Failed to initialize TransactionDenyConfigManager");
2703        // Drop any cached entries from peers no longer in the active committee.
2704        if let Err(e) =
2705            transaction_deny_config_manager.update_for_committee(epoch_store.committee().clone())
2706        {
2707            warn!(
2708                "Initial update_for_committee failed during AuthorityState init: {:?}",
2709                e
2710            );
2711        }
2712
2713        let state = Arc::new(AuthorityState {
2714            name,
2715            secret,
2716            execution_lock: RwLock::new(epoch),
2717            epoch_store: ArcSwap::new(epoch_store.clone()),
2718            input_loader,
2719            execution_cache_trait_pointers,
2720            coin_reservation_resolver,
2721            checkpoint_store,
2722            committee_store,
2723            execution_scheduler,
2724            tx_execution_shutdown: Mutex::new(Some(tx_execution_shutdown)),
2725            metrics,
2726            _pruner,
2727            _authority_per_epoch_pruner,
2728            db_checkpoint_config: db_checkpoint_config.clone(),
2729            config,
2730            overload_info: AuthorityOverloadInfo::default(),
2731            chain_identifier,
2732            congestion_tracker: Arc::new(CongestionTracker::new()),
2733            consensus_gasless_counter: Arc::new(ConsensusGaslessCounter::default()),
2734            traffic_controller,
2735            fork_recovery_state,
2736            notify_epoch: tokio::sync::watch::channel(epoch).0,
2737            object_funds_checker: ArcSwapOption::empty(),
2738            // unsettled_object_withdrawals needs to be initialized unconditionally, even on fullnodes.
2739            // Once we enable object funds checking during execution, fullnodes will need it to track
2740            // unsettled object withdraws as well similar to validators.
2741            unsettled_object_withdrawals: Arc::new(UnsettledObjectWithdrawals::new(
2742                object_funds_checker_metrics.clone(),
2743            )),
2744            object_funds_checker_metrics,
2745            transaction_deny_config_manager,
2746        });
2747        state.init_object_funds_checker().await;
2748
2749        // Start a task to execute ready certificates.
2750        let authority_state = Arc::downgrade(&state);
2751        let causal_admission = state.execution_scheduler.causal_admission().clone();
2752        spawn_monitored_task!(execution_process(
2753            authority_state,
2754            rx_ready_certificates,
2755            rx_execution_shutdown,
2756            causal_admission,
2757        ));
2758        if epoch_store
2759            .protocol_config()
2760            .enable_multi_epoch_transaction_expiration()
2761            && epoch_store.epoch() > 0
2762        {
2763            use typed_store::Map;
2764            let previous_epoch = epoch_store.epoch() - 1;
2765            let start_key = (previous_epoch, TransactionDigest::ZERO);
2766            let end_key = (previous_epoch + 1, TransactionDigest::ZERO);
2767            let has_previous_epoch_data = store
2768                .perpetual_tables
2769                .executed_transaction_digests
2770                .safe_range_iter(start_key..end_key)
2771                .next()
2772                .is_some();
2773
2774            if !has_previous_epoch_data {
2775                panic!(
2776                    "enable_multi_epoch_transaction_expiration is enabled but no transaction data found for previous epoch {}. \
2777                    This indicates the node was restored using an old version of sui-tool that does not backfill the table. \
2778                    Please restore from a snapshot using the latest version of sui-tool.",
2779                    previous_epoch
2780                );
2781            }
2782        }
2783
2784        state
2785    }
2786
2787    async fn init_object_funds_checker(&self) {
2788        let epoch_store = self.epoch_store.load();
2789        // TODO: Once we enable object funds checking during execution, we will no longer need to initialize the object funds checker here.
2790        if self.node_role(&epoch_store).runs_consensus()
2791            && epoch_store.protocol_config().enable_object_funds_withdraw()
2792        {
2793            if self.object_funds_checker.load().is_none() {
2794                let inner = self.get_object(&SUI_ACCUMULATOR_ROOT_OBJECT_ID).map(|o| {
2795                    Arc::new(ObjectFundsCheckerDEPRECATED::new(
2796                        o.version(),
2797                        self.unsettled_object_withdrawals.clone(),
2798                        self.object_funds_checker_metrics.clone(),
2799                    ))
2800                });
2801                self.object_funds_checker.store(inner);
2802            }
2803        } else {
2804            self.object_funds_checker.store(None);
2805        }
2806    }
2807
2808    // TODO: Consolidate our traits to reduce the number of methods here.
2809    pub fn get_object_cache_reader(&self) -> &Arc<dyn ObjectCacheRead> {
2810        &self.execution_cache_trait_pointers.object_cache_reader
2811    }
2812
2813    pub fn get_transaction_cache_reader(&self) -> &Arc<dyn TransactionCacheRead> {
2814        &self.execution_cache_trait_pointers.transaction_cache_reader
2815    }
2816
2817    pub fn get_cache_writer(&self) -> &Arc<dyn ExecutionCacheWrite> {
2818        &self.execution_cache_trait_pointers.cache_writer
2819    }
2820
2821    pub fn get_backing_store(&self) -> &Arc<dyn BackingStore + Send + Sync> {
2822        &self.execution_cache_trait_pointers.backing_store
2823    }
2824
2825    pub fn get_runtime_object_resolver(&self) -> &Arc<dyn RuntimeObjectResolver + Send + Sync> {
2826        &self.execution_cache_trait_pointers.runtime_object_resolver
2827    }
2828
2829    pub(crate) fn get_account_funds_read(&self) -> &Arc<dyn AccountFundsRead> {
2830        &self.execution_cache_trait_pointers.account_funds_read
2831    }
2832
2833    pub fn get_backing_package_store(&self) -> &Arc<dyn BackingPackageStore + Send + Sync> {
2834        &self.execution_cache_trait_pointers.backing_package_store
2835    }
2836
2837    pub fn get_object_store(&self) -> &Arc<dyn ObjectStore + Send + Sync> {
2838        &self.execution_cache_trait_pointers.object_store
2839    }
2840
2841    pub fn get_reconfig_api(&self) -> &Arc<dyn ExecutionCacheReconfigAPI> {
2842        &self.execution_cache_trait_pointers.reconfig_api
2843    }
2844
2845    pub fn get_global_state_hash_store(&self) -> &Arc<dyn GlobalStateHashStore> {
2846        &self.execution_cache_trait_pointers.global_state_hash_store
2847    }
2848
2849    pub fn get_checkpoint_cache(&self) -> &Arc<dyn CheckpointCache> {
2850        &self.execution_cache_trait_pointers.checkpoint_cache
2851    }
2852
2853    pub fn get_state_sync_store(&self) -> &Arc<dyn StateSyncAPI> {
2854        &self.execution_cache_trait_pointers.state_sync_store
2855    }
2856
2857    pub fn get_cache_commit(&self) -> &Arc<dyn ExecutionCacheCommit> {
2858        &self.execution_cache_trait_pointers.cache_commit
2859    }
2860
2861    pub fn database_for_testing(&self) -> Arc<AuthorityStore> {
2862        self.execution_cache_trait_pointers
2863            .testing_api
2864            .database_for_testing()
2865    }
2866
2867    /// Access to the underlying authority store for diagnostic tooling (db-shell).
2868    ///
2869    /// Goes through `testing_api` deliberately: db-shell is read-only diagnostics
2870    /// that bypasses the writeback cache, and we want the execution path to have
2871    /// no other route to the raw `AuthorityStore`. Using the testing API here
2872    /// keeps that invariant visible — diagnostic code is the only non-test caller.
2873    pub fn authority_store(&self) -> Arc<AuthorityStore> {
2874        self.execution_cache_trait_pointers
2875            .testing_api
2876            .database_for_testing()
2877    }
2878
2879    pub fn cache_for_testing(&self) -> &WritebackCache {
2880        self.execution_cache_trait_pointers
2881            .testing_api
2882            .cache_for_testing()
2883    }
2884
2885    pub async fn prune_checkpoints_for_eligible_epochs_for_testing(
2886        &self,
2887        config: NodeConfig,
2888        metrics: Arc<AuthorityStorePruningMetrics>,
2889    ) -> anyhow::Result<()> {
2890        use crate::authority::authority_store_pruner::PrunerWatermarks;
2891        let watermarks = Arc::new(PrunerWatermarks::default());
2892        AuthorityStorePruner::prune_checkpoints_for_eligible_epochs(
2893            &self.database_for_testing().perpetual_tables,
2894            &self.checkpoint_store,
2895            None,
2896            config.authority_store_pruning_config,
2897            metrics,
2898            EPOCH_DURATION_MS_FOR_TESTING,
2899            &watermarks,
2900        )
2901        .await
2902    }
2903
2904    pub fn execution_scheduler(&self) -> &Arc<ExecutionScheduler> {
2905        &self.execution_scheduler
2906    }
2907
2908    /// Attempts to acquire execution lock for an executable transaction.
2909    /// Returns Some(lock) if the transaction is matching current executed epoch.
2910    /// Returns None if validator is halted at epoch end or epoch mismatch.
2911    pub fn execution_lock_for_executable_transaction(
2912        &self,
2913        transaction: &VerifiedExecutableTransaction,
2914    ) -> Option<ExecutionLockReadGuard<'_>> {
2915        let lock = self.execution_lock.try_read().ok()?;
2916        if *lock == transaction.auth_sig().epoch() {
2917            Some(lock)
2918        } else {
2919            // TODO: Can this still happen?
2920            None
2921        }
2922    }
2923
2924    /// Acquires the execution lock for the duration of transaction validation.
2925    /// This prevents reconfiguration from starting until we are finished validating the transaction.
2926    fn execution_lock_for_validation(&self) -> SuiResult<ExecutionLockReadGuard<'_>> {
2927        self.execution_lock
2928            .try_read()
2929            .map_err(|_| SuiErrorKind::ValidatorHaltedAtEpochEnd.into())
2930    }
2931
2932    pub async fn execution_lock_for_reconfiguration(&self) -> ExecutionLockWriteGuard<'_> {
2933        self.execution_lock.write().await
2934    }
2935
2936    #[instrument(level = "error", skip_all)]
2937    pub async fn reconfigure(
2938        &self,
2939        cur_epoch_store: &AuthorityPerEpochStore,
2940        supported_protocol_versions: SupportedProtocolVersions,
2941        new_committee: Committee,
2942        epoch_start_configuration: EpochStartConfiguration,
2943        state_hasher: Arc<GlobalStateHasher>,
2944        expensive_safety_check_config: &ExpensiveSafetyCheckConfig,
2945        epoch_last_checkpoint: CheckpointSequenceNumber,
2946    ) -> SuiResult<Arc<AuthorityPerEpochStore>> {
2947        Self::check_protocol_version(
2948            supported_protocol_versions,
2949            epoch_start_configuration
2950                .epoch_start_state()
2951                .protocol_version(),
2952        );
2953
2954        self.committee_store.insert_new_committee(&new_committee)?;
2955
2956        // Wait until no transactions are being executed.
2957        let mut execution_lock = self.execution_lock_for_reconfiguration().await;
2958
2959        // Terminate all epoch-specific tasks (those started with within_alive_epoch).
2960        cur_epoch_store.epoch_terminated().await;
2961
2962        // Record metrics in case the node has not observed epoch close in consensus.
2963        cur_epoch_store.record_epoch_close_time_once();
2964
2965        // Safe to begin reconfiguration now. No transactions are being executed,
2966        // and no epoch-specific tasks are running.
2967
2968        self.get_reconfig_api()
2969            .clear_state_end_of_epoch(&execution_lock);
2970        self.check_system_consistency(cur_epoch_store, state_hasher, expensive_safety_check_config);
2971        self.maybe_reaccumulate_state_hash(
2972            cur_epoch_store,
2973            epoch_start_configuration
2974                .epoch_start_state()
2975                .protocol_version(),
2976        );
2977        self.get_reconfig_api()
2978            .set_epoch_start_configuration(&epoch_start_configuration);
2979        if let Some(checkpoint_path) = &self.db_checkpoint_config.checkpoint_path
2980            && self
2981                .db_checkpoint_config
2982                .perform_db_checkpoints_at_epoch_end
2983        {
2984            let current_epoch = cur_epoch_store.epoch();
2985            let epoch_checkpoint_path = checkpoint_path.join(format!("epoch_{}", current_epoch));
2986            self.checkpoint_all_dbs(&epoch_checkpoint_path, cur_epoch_store)?;
2987        }
2988
2989        self.get_reconfig_api()
2990            .reconfigure_cache(&epoch_start_configuration)
2991            .await;
2992
2993        let new_epoch = new_committee.epoch;
2994        let new_epoch_store = self
2995            .reopen_epoch_db(
2996                cur_epoch_store,
2997                new_committee,
2998                epoch_start_configuration,
2999                expensive_safety_check_config,
3000                epoch_last_checkpoint,
3001            )
3002            .await?;
3003        assert_eq!(new_epoch_store.epoch(), new_epoch);
3004        self.execution_scheduler
3005            .reconfigure(&new_epoch_store, self.get_account_funds_read());
3006        self.init_object_funds_checker().await;
3007
3008        // Update the committee and drop entries for peers no longer in it before tx
3009        // processing resumes for the new epoch.
3010        if let Err(e) = self
3011            .transaction_deny_config_manager
3012            .update_for_committee(new_epoch_store.committee().clone())
3013        {
3014            warn!(
3015                "TransactionDenyConfigManager update_for_committee failed at reconfigure: {:?}",
3016                e
3017            );
3018        }
3019
3020        *execution_lock = new_epoch;
3021
3022        self.notify_epoch(new_epoch);
3023        // drop execution_lock after epoch store was updated
3024        // see also assert in AuthorityState::process_certificate
3025        // on the epoch store and execution lock epoch match
3026        Ok(new_epoch_store)
3027    }
3028
3029    fn notify_epoch(&self, new_epoch: EpochId) {
3030        self.notify_epoch.send_modify(|epoch| *epoch = new_epoch);
3031    }
3032
3033    pub async fn wait_for_epoch(&self, target_epoch: EpochId) -> Result<EpochId, RecvError> {
3034        let mut rx = self.notify_epoch.subscribe();
3035        loop {
3036            let epoch = *rx.borrow();
3037            if epoch >= target_epoch {
3038                return Ok(epoch);
3039            }
3040            rx.changed().await?;
3041        }
3042    }
3043
3044    /// The accumulator root version a transaction executed right now would read, or
3045    /// None when accumulators are not enabled. Test paths that execute directly attach
3046    /// this to their assigned versions: the test version-assignment helper assigns no
3047    /// root version, but execution reads the root implicitly for object funds withdraws.
3048    pub fn accumulator_version_for_testing(
3049        &self,
3050    ) -> Option<sui_types::base_types::ConsensusObjectVersion> {
3051        let initial_shared_version = self
3052            .epoch_store_for_testing()
3053            .epoch_start_config()
3054            .accumulator_root_obj_initial_shared_version()?;
3055        let version = self.get_object(&SUI_ACCUMULATOR_ROOT_OBJECT_ID)?.version();
3056        Some(sui_types::base_types::ConsensusObjectVersion {
3057            initial_shared_version,
3058            version,
3059        })
3060    }
3061
3062    /// Executes accumulator settlement for testing purposes.
3063    /// Returns a list of (transaction, execution_env) pairs that can be replayed on another
3064    /// AuthorityState (e.g., a fullnode) using `replay_settlement_for_testing`.
3065    pub async fn settle_accumulator_for_testing(
3066        &self,
3067        effects: &[TransactionEffects],
3068        checkpoint_seq: Option<u64>,
3069    ) -> Vec<(VerifiedExecutableTransaction, ExecutionEnv)> {
3070        let accumulator_version = self
3071            .get_object(&SUI_ACCUMULATOR_ROOT_OBJECT_ID)
3072            .unwrap()
3073            .version();
3074        // Use provided checkpoint sequence, or fall back to accumulator version.
3075        let ckpt_seq = checkpoint_seq.unwrap_or_else(|| accumulator_version.value());
3076        let builder = AccumulatorSettlementTxBuilder::new(
3077            Some(self.get_transaction_cache_reader().as_ref()),
3078            effects,
3079            ckpt_seq,
3080            0,
3081        );
3082        let balance_changes = builder.collect_funds_changes();
3083        let epoch_store = self.epoch_store_for_testing();
3084        let epoch = epoch_store.epoch();
3085        let accumulator_root_obj_initial_shared_version = epoch_store
3086            .epoch_start_config()
3087            .accumulator_root_obj_initial_shared_version()
3088            .unwrap();
3089        let settlements = builder.build_tx(
3090            epoch_store.protocol_config(),
3091            epoch,
3092            accumulator_root_obj_initial_shared_version,
3093            ckpt_seq,
3094            ckpt_seq,
3095        );
3096
3097        let settlements: Vec<_> = settlements
3098            .into_iter()
3099            .map(|tx| {
3100                VerifiedExecutableTransaction::new_system(
3101                    VerifiedTransaction::new_system_transaction(tx),
3102                    epoch,
3103                )
3104            })
3105            .collect();
3106
3107        // The test version-assignment helper assigns no accumulator root version, and
3108        // the barrier settles object funds at the version it writes.
3109        let root_version = sui_types::base_types::ConsensusObjectVersion {
3110            initial_shared_version: accumulator_root_obj_initial_shared_version,
3111            version: accumulator_version,
3112        };
3113        let with_root_version = |assigned: shared_object_version_manager::AssignedVersions| {
3114            assigned.with_accumulator_version_for_testing(root_version)
3115        };
3116
3117        let assigned_versions = epoch_store
3118            .assign_shared_object_versions_for_tests(
3119                self.get_object_cache_reader().as_ref(),
3120                &settlements,
3121            )
3122            .unwrap();
3123        let version_map = assigned_versions.into_map();
3124
3125        let mut replay_txns = Vec::new();
3126        let mut settlement_effects = Vec::with_capacity(settlements.len());
3127        for tx in settlements {
3128            let assigned = with_root_version(version_map.get(&tx.key()).unwrap().clone());
3129            let env = ExecutionEnv::new().with_assigned_versions(assigned);
3130            let (effects, _) = self
3131                .try_execute_immediately(&tx.clone(), env.clone(), &epoch_store)
3132                .unwrap();
3133            assert!(effects.status().is_ok());
3134            replay_txns.push((tx, env));
3135            settlement_effects.push(effects);
3136        }
3137
3138        let barrier = accumulators::build_accumulator_barrier_tx(
3139            epoch,
3140            accumulator_root_obj_initial_shared_version,
3141            ckpt_seq,
3142            &settlement_effects,
3143        );
3144        let barrier = VerifiedExecutableTransaction::new_system(
3145            VerifiedTransaction::new_system_transaction(barrier),
3146            epoch,
3147        );
3148
3149        let assigned_versions = epoch_store
3150            .assign_shared_object_versions_for_tests(
3151                self.get_object_cache_reader().as_ref(),
3152                std::slice::from_ref(&barrier),
3153            )
3154            .unwrap();
3155        let version_map = assigned_versions.into_map();
3156
3157        let barrier_assigned = with_root_version(version_map.get(&barrier.key()).unwrap().clone());
3158        let env = ExecutionEnv::new().with_assigned_versions(barrier_assigned);
3159        let (effects, _) = self
3160            .try_execute_immediately(&barrier.clone(), env.clone(), &epoch_store)
3161            .unwrap();
3162        assert!(effects.status().is_ok());
3163        replay_txns.push((barrier, env));
3164
3165        let next_accumulator_version = accumulator_version.next();
3166        self.execution_scheduler
3167            .settle_address_funds(FundsSettlement {
3168                funds_changes: balance_changes,
3169                next_accumulator_version,
3170            });
3171        // object funds are settled while executing the barrier transaction
3172
3173        replay_txns
3174    }
3175
3176    /// Replays settlement transactions on this AuthorityState.
3177    /// Used to sync a fullnode with settlement transactions executed on a validator.
3178    pub async fn replay_settlement_for_testing(
3179        &self,
3180        txns: &[(VerifiedExecutableTransaction, ExecutionEnv)],
3181    ) {
3182        let epoch_store = self.epoch_store_for_testing();
3183        for (tx, env) in txns {
3184            let (effects, _) = self
3185                .try_execute_immediately(tx, env.clone(), &epoch_store)
3186                .unwrap();
3187            assert!(effects.status().is_ok());
3188        }
3189    }
3190
3191    /// Advance the epoch store to the next epoch for testing only.
3192    /// This only manually sets all the places where we have the epoch number.
3193    /// It doesn't properly reconfigure the node, hence should be only used for testing.
3194    pub async fn reconfigure_for_testing(&self) {
3195        let mut execution_lock = self.execution_lock_for_reconfiguration().await;
3196        let epoch_store = self.epoch_store_for_testing().clone();
3197        let protocol_config = epoch_store.protocol_config().clone();
3198        // The current protocol config used in the epoch store may have been overridden and diverged from
3199        // the protocol config definitions. That override may have now been dropped when the initial guard was dropped.
3200        // We reapply the override before creating the new epoch store, to make sure that
3201        // the new epoch store has the same protocol config as the current one.
3202        // Since this is for testing only, we mostly like to keep the protocol config the same
3203        // across epochs.
3204        let _guard =
3205            ProtocolConfig::apply_overrides_for_testing(move |_, _| protocol_config.clone());
3206        let new_epoch_store = epoch_store.new_at_next_epoch_for_testing(
3207            self.get_backing_package_store().clone(),
3208            self.get_object_store().clone(),
3209            &self.config.expensive_safety_check_config,
3210            &self.config,
3211            self.checkpoint_store
3212                .get_epoch_last_checkpoint(epoch_store.epoch())
3213                .unwrap()
3214                .map(|c| *c.sequence_number())
3215                .unwrap_or_default(),
3216        );
3217        self.execution_scheduler
3218            .reconfigure(&new_epoch_store, self.get_account_funds_read());
3219        let new_epoch = new_epoch_store.epoch();
3220        self.epoch_store.store(new_epoch_store);
3221        epoch_store.epoch_terminated().await;
3222
3223        *execution_lock = new_epoch;
3224    }
3225
3226    /// This is a temporary method to be used when we enable simplified_unwrap_then_delete.
3227    /// It re-accumulates state hash for the new epoch if simplified_unwrap_then_delete is enabled.
3228    #[instrument(level = "error", skip_all)]
3229    fn maybe_reaccumulate_state_hash(
3230        &self,
3231        cur_epoch_store: &AuthorityPerEpochStore,
3232        new_protocol_version: ProtocolVersion,
3233    ) {
3234        self.get_reconfig_api()
3235            .maybe_reaccumulate_state_hash(cur_epoch_store, new_protocol_version);
3236    }
3237
3238    #[instrument(level = "error", skip_all)]
3239    fn check_system_consistency(
3240        &self,
3241        cur_epoch_store: &AuthorityPerEpochStore,
3242        state_hasher: Arc<GlobalStateHasher>,
3243        expensive_safety_check_config: &ExpensiveSafetyCheckConfig,
3244    ) {
3245        info!(
3246            "Performing sui conservation consistency check for epoch {}",
3247            cur_epoch_store.epoch()
3248        );
3249
3250        if let Err(err) = self
3251            .get_reconfig_api()
3252            .expensive_check_sui_conservation(cur_epoch_store)
3253        {
3254            if cfg!(debug_assertions) {
3255                panic!("{}", err);
3256            } else {
3257                // We cannot panic in production yet because it is known that there are some
3258                // inconsistencies in testnet. We will enable this once we make it balanced again in testnet.
3259                warn!("Sui conservation consistency check failed: {}", err);
3260            }
3261        } else {
3262            info!("Sui conservation consistency check passed");
3263        }
3264
3265        // check for root state hash consistency with live object set
3266        if expensive_safety_check_config.enable_state_consistency_check() {
3267            info!(
3268                "Performing state consistency check for epoch {}",
3269                cur_epoch_store.epoch()
3270            );
3271            self.expensive_check_is_consistent_state(state_hasher, cur_epoch_store);
3272        }
3273    }
3274
3275    fn expensive_check_is_consistent_state(
3276        &self,
3277        state_hasher: Arc<GlobalStateHasher>,
3278        cur_epoch_store: &AuthorityPerEpochStore,
3279    ) {
3280        let live_object_set_hash = state_hasher.digest_live_object_set(
3281            !cur_epoch_store
3282                .protocol_config()
3283                .simplified_unwrap_then_delete(),
3284        );
3285
3286        let root_state_hash: ECMHLiveObjectSetDigest = self
3287            .get_global_state_hash_store()
3288            .get_root_state_hash_for_epoch(cur_epoch_store.epoch())
3289            .expect("Retrieving root state hash cannot fail")
3290            .expect("Root state hash for epoch must exist")
3291            .1
3292            .digest()
3293            .into();
3294
3295        let is_inconsistent = root_state_hash != live_object_set_hash;
3296        if is_inconsistent {
3297            debug_fatal!(
3298                "Inconsistent state detected: root state hash: {:?}, live object set hash: {:?}",
3299                root_state_hash,
3300                live_object_set_hash
3301            );
3302        } else {
3303            info!("State consistency check passed");
3304        }
3305
3306        state_hasher.set_inconsistent_state(is_inconsistent);
3307    }
3308
3309    pub fn current_epoch_for_testing(&self) -> EpochId {
3310        self.epoch_store_for_testing().epoch()
3311    }
3312
3313    #[instrument(level = "error", skip_all)]
3314    pub fn checkpoint_all_dbs(
3315        &self,
3316        checkpoint_path: &Path,
3317        cur_epoch_store: &AuthorityPerEpochStore,
3318    ) -> SuiResult {
3319        let _metrics_guard = self.metrics.db_checkpoint_latency.start_timer();
3320        let current_epoch = cur_epoch_store.epoch();
3321
3322        if checkpoint_path.exists() {
3323            info!("Skipping db checkpoint as it already exists for epoch: {current_epoch}");
3324            return Ok(());
3325        }
3326
3327        let checkpoint_path_tmp = checkpoint_path.with_extension("tmp");
3328        let store_checkpoint_path_tmp = checkpoint_path_tmp.join("store");
3329
3330        if checkpoint_path_tmp.exists() {
3331            fs::remove_dir_all(&checkpoint_path_tmp)
3332                .map_err(|e| SuiErrorKind::FileIOError(e.to_string()))?;
3333        }
3334
3335        fs::create_dir_all(&checkpoint_path_tmp)
3336            .map_err(|e| SuiErrorKind::FileIOError(e.to_string()))?;
3337        fs::create_dir(&store_checkpoint_path_tmp)
3338            .map_err(|e| SuiErrorKind::FileIOError(e.to_string()))?;
3339
3340        // NOTE: Do not change the order of invoking these checkpoint calls
3341        // We want to snapshot checkpoint db first to not race with state sync
3342        self.checkpoint_store
3343            .checkpoint_db(&checkpoint_path_tmp.join("checkpoints"))?;
3344
3345        self.get_reconfig_api()
3346            .checkpoint_db(&store_checkpoint_path_tmp.join("perpetual"))?;
3347
3348        self.committee_store
3349            .checkpoint_db(&checkpoint_path_tmp.join("epochs"))?;
3350
3351        fs::rename(checkpoint_path_tmp, checkpoint_path)
3352            .map_err(|e| SuiErrorKind::FileIOError(e.to_string()))?;
3353        Ok(())
3354    }
3355
3356    /// Load the current epoch store. This can change during reconfiguration. To ensure that
3357    /// we never end up accessing different epoch stores in a single task, we need to make sure
3358    /// that this is called once per task. Each call needs to be carefully audited to ensure it is
3359    /// the case. This also means we should minimize the number of call-sites. Only call it when
3360    /// there is no way to obtain it from somewhere else.
3361    pub fn load_epoch_store_one_call_per_task(&self) -> Guard<Arc<AuthorityPerEpochStore>> {
3362        self.epoch_store.load()
3363    }
3364
3365    // Load the epoch store, should be used in tests only.
3366    pub fn epoch_store_for_testing(&self) -> Guard<Arc<AuthorityPerEpochStore>> {
3367        self.load_epoch_store_one_call_per_task()
3368    }
3369
3370    pub fn transaction_deny_config_manager(&self) -> &Arc<TransactionDenyConfigManager> {
3371        &self.transaction_deny_config_manager
3372    }
3373
3374    /// The operator-configured local `TransactionDenyConfig` (before any peer
3375    /// recommendations are merged).
3376    pub fn local_transaction_deny_config(&self) -> &Arc<TransactionDenyConfig> {
3377        self.transaction_deny_config_manager.local()
3378    }
3379
3380    pub fn clone_committee_for_testing(&self) -> Committee {
3381        Committee::clone(self.epoch_store_for_testing().committee())
3382    }
3383
3384    #[instrument(level = "trace", skip_all)]
3385    pub fn get_object(&self, object_id: &ObjectID) -> Option<Object> {
3386        self.get_object_store().get_object(object_id)
3387    }
3388
3389    pub fn get_sui_system_package_object_ref(&self) -> SuiResult<ObjectRef> {
3390        Ok(self
3391            .get_object(&SUI_SYSTEM_ADDRESS.into())
3392            .expect("framework object should always exist")
3393            .compute_object_reference())
3394    }
3395
3396    // This function is only used for testing.
3397    pub fn get_sui_system_state_object_for_testing(&self) -> SuiResult<SuiSystemState> {
3398        self.get_object_cache_reader()
3399            .get_sui_system_state_object_unsafe()
3400    }
3401
3402    #[instrument(level = "trace", skip_all)]
3403    fn get_transaction_checkpoint_sequence(
3404        &self,
3405        digest: &TransactionDigest,
3406        epoch_store: &AuthorityPerEpochStore,
3407    ) -> SuiResult<Option<CheckpointSequenceNumber>> {
3408        epoch_store.get_transaction_checkpoint(digest)
3409    }
3410
3411    #[instrument(level = "trace", skip_all)]
3412    pub fn get_checkpoint_by_sequence_number(
3413        &self,
3414        sequence_number: CheckpointSequenceNumber,
3415    ) -> SuiResult<Option<VerifiedCheckpoint>> {
3416        Ok(self
3417            .checkpoint_store
3418            .get_checkpoint_by_sequence_number(sequence_number)?)
3419    }
3420
3421    #[instrument(level = "trace", skip_all)]
3422    pub fn get_transaction_checkpoint_for_tests(
3423        &self,
3424        digest: &TransactionDigest,
3425        epoch_store: &AuthorityPerEpochStore,
3426    ) -> SuiResult<Option<VerifiedCheckpoint>> {
3427        let checkpoint = self.get_transaction_checkpoint_sequence(digest, epoch_store)?;
3428        let Some(checkpoint) = checkpoint else {
3429            return Ok(None);
3430        };
3431        let checkpoint = self
3432            .checkpoint_store
3433            .get_checkpoint_by_sequence_number(checkpoint)?;
3434        Ok(checkpoint)
3435    }
3436
3437    #[instrument(level = "trace", skip_all)]
3438    pub fn get_object_read(&self, object_id: &ObjectID) -> SuiResult<ObjectRead> {
3439        Ok(
3440            match self
3441                .get_object_cache_reader()
3442                .get_latest_object_or_tombstone(*object_id)
3443            {
3444                Some((_, ObjectOrTombstone::Object(object))) => {
3445                    let layout = self.get_object_layout(&object)?;
3446                    ObjectRead::Exists(object.compute_object_reference(), object, layout)
3447                }
3448                Some((_, ObjectOrTombstone::Tombstone(objref))) => ObjectRead::Deleted(objref),
3449                None => ObjectRead::NotExists(*object_id),
3450            },
3451        )
3452    }
3453
3454    /// Chain Identifier is the digest of the genesis checkpoint.
3455    pub fn get_chain_identifier(&self) -> ChainIdentifier {
3456        self.chain_identifier
3457    }
3458
3459    /// This function aims to serve rpc reads on past objects and
3460    /// we don't expect it to be called for other purposes.
3461    /// Depending on the object pruning policies that will be enforced in the
3462    /// future there is no software-level guarantee/SLA to retrieve an object
3463    /// with an old version even if it exists/existed.
3464    #[instrument(level = "trace", skip_all)]
3465    pub fn get_past_object_read(
3466        &self,
3467        object_id: &ObjectID,
3468        version: SequenceNumber,
3469    ) -> SuiResult<PastObjectRead> {
3470        // Firstly we see if the object ever existed by getting its latest data
3471        let Some(obj_ref) = self
3472            .get_object_cache_reader()
3473            .get_latest_object_ref_or_tombstone(*object_id)
3474        else {
3475            return Ok(PastObjectRead::ObjectNotExists(*object_id));
3476        };
3477
3478        if version > obj_ref.1 {
3479            return Ok(PastObjectRead::VersionTooHigh {
3480                object_id: *object_id,
3481                asked_version: version,
3482                latest_version: obj_ref.1,
3483            });
3484        }
3485
3486        if version < obj_ref.1 {
3487            // Read past objects
3488            return Ok(match self.read_object_at_version(object_id, version)? {
3489                Some((object, layout)) => {
3490                    let obj_ref = object.compute_object_reference();
3491                    PastObjectRead::VersionFound(obj_ref, object, layout)
3492                }
3493
3494                None => PastObjectRead::VersionNotFound(*object_id, version),
3495            });
3496        }
3497
3498        if !obj_ref.2.is_alive() {
3499            return Ok(PastObjectRead::ObjectDeleted(obj_ref));
3500        }
3501
3502        match self.read_object_at_version(object_id, obj_ref.1)? {
3503            Some((object, layout)) => Ok(PastObjectRead::VersionFound(obj_ref, object, layout)),
3504            None => {
3505                debug_fatal!(
3506                    "Object with in parent_entry is missing from object store, datastore is \
3507                     inconsistent"
3508                );
3509                Err(UserInputError::ObjectNotFound {
3510                    object_id: *object_id,
3511                    version: Some(obj_ref.1),
3512                }
3513                .into())
3514            }
3515        }
3516    }
3517
3518    #[instrument(level = "trace", skip_all)]
3519    fn read_object_at_version(
3520        &self,
3521        object_id: &ObjectID,
3522        version: SequenceNumber,
3523    ) -> SuiResult<Option<(Object, Option<MoveStructLayout>)>> {
3524        let Some(object) = self
3525            .get_object_cache_reader()
3526            .get_object_by_key(object_id, version)
3527        else {
3528            return Ok(None);
3529        };
3530
3531        let layout = self.get_object_layout(&object)?;
3532        Ok(Some((object, layout)))
3533    }
3534
3535    pub fn get_object_layout(&self, object: &Object) -> SuiResult<Option<MoveStructLayout>> {
3536        let layout = object
3537            .data
3538            .try_as_move()
3539            .map(|object| {
3540                into_struct_layout(
3541                    SyncResolver::new(PackageStoreWithLruCache::new(
3542                        self.get_backing_package_store().as_ref(),
3543                    ))
3544                    .get_annotated_layout(&object.type_().clone().into())?,
3545                )
3546            })
3547            .transpose()?;
3548        Ok(layout)
3549    }
3550
3551    #[instrument(level = "trace", skip_all)]
3552    pub fn get_executed_transaction_and_effects(
3553        &self,
3554        digest: TransactionDigest,
3555    ) -> SuiResult<(Transaction, TransactionEffects)> {
3556        let transaction = self
3557            .get_transaction_cache_reader()
3558            .get_transaction_block(&digest)
3559            .ok_or(SuiErrorKind::TransactionNotFound { digest })?;
3560        let effects = self
3561            .get_transaction_cache_reader()
3562            .get_executed_effects(&digest)
3563            .ok_or(SuiErrorKind::TransactionNotFound { digest })?;
3564        Ok(((*transaction).clone().into_inner(), effects))
3565    }
3566
3567    #[instrument(level = "trace", skip_all)]
3568    pub fn multi_get_checkpoint_by_sequence_number(
3569        &self,
3570        sequence_numbers: &[CheckpointSequenceNumber],
3571    ) -> SuiResult<Vec<Option<VerifiedCheckpoint>>> {
3572        Ok(self
3573            .checkpoint_store
3574            .multi_get_checkpoint_by_sequence_number(sequence_numbers)?)
3575    }
3576
3577    #[instrument(level = "trace", skip_all)]
3578    pub fn get_transaction_events(
3579        &self,
3580        digest: &TransactionDigest,
3581    ) -> SuiResult<TransactionEvents> {
3582        self.get_transaction_cache_reader()
3583            .get_events(digest)
3584            .ok_or(SuiErrorKind::TransactionEventsNotFound { digest: *digest }.into())
3585    }
3586
3587    pub fn get_transaction_input_objects(
3588        &self,
3589        effects: &TransactionEffects,
3590    ) -> SuiResult<Vec<Object>> {
3591        sui_types::storage::get_transaction_input_objects(self.get_object_store(), effects)
3592            .map_err(Into::into)
3593    }
3594
3595    pub fn get_transaction_output_objects(
3596        &self,
3597        effects: &TransactionEffects,
3598    ) -> SuiResult<Vec<Object>> {
3599        sui_types::storage::get_transaction_output_objects(self.get_object_store(), effects)
3600            .map_err(Into::into)
3601    }
3602
3603    pub fn get_checkpoint_store(&self) -> &Arc<CheckpointStore> {
3604        &self.checkpoint_store
3605    }
3606
3607    pub fn get_latest_checkpoint_sequence_number(&self) -> SuiResult<CheckpointSequenceNumber> {
3608        self.get_checkpoint_store()
3609            .get_highest_executed_checkpoint_seq_number()?
3610            .ok_or(
3611                SuiErrorKind::UserInputError {
3612                    error: UserInputError::LatestCheckpointSequenceNumberNotFound,
3613                }
3614                .into(),
3615            )
3616    }
3617
3618    #[cfg(msim)]
3619    pub fn get_highest_pruned_checkpoint_for_testing(&self) -> SuiResult<CheckpointSequenceNumber> {
3620        self.database_for_testing()
3621            .perpetual_tables
3622            .get_highest_pruned_checkpoint()
3623            .map(|c| c.unwrap_or(0))
3624            .map_err(Into::into)
3625    }
3626
3627    #[instrument(level = "trace", skip_all)]
3628    pub fn get_checkpoint_summary_by_sequence_number(
3629        &self,
3630        sequence_number: CheckpointSequenceNumber,
3631    ) -> SuiResult<CheckpointSummary> {
3632        let verified_checkpoint = self
3633            .get_checkpoint_store()
3634            .get_checkpoint_by_sequence_number(sequence_number)?;
3635        match verified_checkpoint {
3636            Some(verified_checkpoint) => Ok(verified_checkpoint.into_inner().into_data()),
3637            None => Err(SuiErrorKind::UserInputError {
3638                error: UserInputError::VerifiedCheckpointNotFound(sequence_number),
3639            }
3640            .into()),
3641        }
3642    }
3643
3644    #[instrument(level = "trace", skip_all)]
3645    pub fn get_checkpoint_summary_by_digest(
3646        &self,
3647        digest: CheckpointDigest,
3648    ) -> SuiResult<CheckpointSummary> {
3649        let verified_checkpoint = self
3650            .get_checkpoint_store()
3651            .get_checkpoint_by_digest(&digest)?;
3652        match verified_checkpoint {
3653            Some(verified_checkpoint) => Ok(verified_checkpoint.into_inner().into_data()),
3654            None => Err(SuiErrorKind::UserInputError {
3655                error: UserInputError::VerifiedCheckpointDigestNotFound(Base58::encode(digest)),
3656            }
3657            .into()),
3658        }
3659    }
3660
3661    #[instrument(level = "trace", skip_all)]
3662    pub fn find_publish_txn_digest(&self, package_id: ObjectID) -> SuiResult<TransactionDigest> {
3663        if is_system_package(package_id) {
3664            return self.find_genesis_txn_digest();
3665        }
3666        Ok(self
3667            .get_object_read(&package_id)?
3668            .into_object()?
3669            .previous_transaction)
3670    }
3671
3672    #[instrument(level = "trace", skip_all)]
3673    pub fn find_genesis_txn_digest(&self) -> SuiResult<TransactionDigest> {
3674        let summary = self
3675            .get_verified_checkpoint_by_sequence_number(0)?
3676            .into_message();
3677        let content = self.get_checkpoint_contents(summary.content_digest)?;
3678        let genesis_transaction = content.enumerate_transactions(&summary).next();
3679        Ok(genesis_transaction
3680            .ok_or(SuiErrorKind::UserInputError {
3681                error: UserInputError::GenesisTransactionNotFound,
3682            })?
3683            .1
3684            .transaction)
3685    }
3686
3687    #[instrument(level = "trace", skip_all)]
3688    pub fn get_verified_checkpoint_by_sequence_number(
3689        &self,
3690        sequence_number: CheckpointSequenceNumber,
3691    ) -> SuiResult<VerifiedCheckpoint> {
3692        let verified_checkpoint = self
3693            .get_checkpoint_store()
3694            .get_checkpoint_by_sequence_number(sequence_number)?;
3695        match verified_checkpoint {
3696            Some(verified_checkpoint) => Ok(verified_checkpoint),
3697            None => Err(SuiErrorKind::UserInputError {
3698                error: UserInputError::VerifiedCheckpointNotFound(sequence_number),
3699            }
3700            .into()),
3701        }
3702    }
3703
3704    #[instrument(level = "trace", skip_all)]
3705    pub fn get_verified_checkpoint_summary_by_digest(
3706        &self,
3707        digest: CheckpointDigest,
3708    ) -> SuiResult<VerifiedCheckpoint> {
3709        let verified_checkpoint = self
3710            .get_checkpoint_store()
3711            .get_checkpoint_by_digest(&digest)?;
3712        match verified_checkpoint {
3713            Some(verified_checkpoint) => Ok(verified_checkpoint),
3714            None => Err(SuiErrorKind::UserInputError {
3715                error: UserInputError::VerifiedCheckpointDigestNotFound(Base58::encode(digest)),
3716            }
3717            .into()),
3718        }
3719    }
3720
3721    #[instrument(level = "trace", skip_all)]
3722    pub fn get_checkpoint_contents(
3723        &self,
3724        digest: CheckpointContentsDigest,
3725    ) -> SuiResult<CheckpointContents> {
3726        self.get_checkpoint_store()
3727            .get_checkpoint_contents(&digest)?
3728            .ok_or(
3729                SuiErrorKind::UserInputError {
3730                    error: UserInputError::CheckpointContentsNotFound(digest),
3731                }
3732                .into(),
3733            )
3734    }
3735
3736    #[instrument(level = "trace", skip_all)]
3737    pub fn get_checkpoint_contents_by_sequence_number(
3738        &self,
3739        sequence_number: CheckpointSequenceNumber,
3740    ) -> SuiResult<CheckpointContents> {
3741        let verified_checkpoint = self
3742            .get_checkpoint_store()
3743            .get_checkpoint_by_sequence_number(sequence_number)?;
3744        match verified_checkpoint {
3745            Some(verified_checkpoint) => {
3746                let content_digest = verified_checkpoint.into_inner().content_digest;
3747                self.get_checkpoint_contents(content_digest)
3748            }
3749            None => Err(SuiErrorKind::UserInputError {
3750                error: UserInputError::VerifiedCheckpointNotFound(sequence_number),
3751            }
3752            .into()),
3753        }
3754    }
3755
3756    pub fn insert_genesis_object(&self, object: Object) {
3757        self.get_reconfig_api().insert_genesis_object(object);
3758    }
3759
3760    pub fn insert_genesis_objects(&self, objects: &[Object]) {
3761        for o in objects {
3762            self.insert_genesis_object(o.clone());
3763        }
3764    }
3765
3766    /// Make a status response for a transaction
3767    #[instrument(level = "trace", skip_all)]
3768    pub fn get_transaction_status(
3769        &self,
3770        transaction_digest: &TransactionDigest,
3771        epoch_store: &Arc<AuthorityPerEpochStore>,
3772    ) -> SuiResult<Option<(SenderSignedData, TransactionStatus)>> {
3773        // TODO: In the case of read path, we should not have to re-sign the effects.
3774        if let Some(effects) =
3775            self.get_signed_effects_and_maybe_resign(transaction_digest, epoch_store)?
3776        {
3777            if let Some(transaction) = self
3778                .get_transaction_cache_reader()
3779                .get_transaction_block(transaction_digest)
3780            {
3781                let events = if effects.events_digest().is_some() {
3782                    self.get_transaction_events(effects.transaction_digest())?
3783                } else {
3784                    TransactionEvents::default()
3785                };
3786                // The cert_sig slot is permanently None: validators no longer aggregate or
3787                // persist per-transaction quorum signatures.
3788                return Ok(Some((
3789                    (*transaction).clone().into_message(),
3790                    TransactionStatus::Executed(None, effects.into_inner(), events),
3791                )));
3792            } else {
3793                // The read of effects and read of transaction are not atomic. It's possible that we reverted
3794                // the transaction (during epoch change) in between the above two reads, and we end up
3795                // having effects but not transaction. In this case, we just fall through.
3796                debug!(tx_digest=?transaction_digest, "Signed effects exist but no transaction found");
3797            }
3798        }
3799        // Validators no longer sign transactions before execution, so there is no
3800        // TransactionStatus::Signed state to report.
3801        Ok(None)
3802    }
3803
3804    /// Get the signed effects of the given transaction. If the effects was signed in a previous
3805    /// epoch, re-sign it so that the caller is able to form a cert of the effects in the current
3806    /// epoch.
3807    #[instrument(level = "trace", skip_all)]
3808    pub fn get_signed_effects_and_maybe_resign(
3809        &self,
3810        transaction_digest: &TransactionDigest,
3811        epoch_store: &Arc<AuthorityPerEpochStore>,
3812    ) -> SuiResult<Option<VerifiedSignedTransactionEffects>> {
3813        let effects = self
3814            .get_transaction_cache_reader()
3815            .get_executed_effects(transaction_digest);
3816        match effects {
3817            Some(effects) => {
3818                // If the transaction was executed in previous epochs, the validator will
3819                // re-sign the effects with new current epoch so that a client is always able to
3820                // obtain an effects certificate at the current epoch.
3821                //
3822                // Why is this necessary? Consider the following case:
3823                // - assume there are 4 validators
3824                // - Quorum driver gets 2 signed effects before reconfig halt
3825                // - The tx makes it into final checkpoint.
3826                // - 2 validators go away and are replaced in the new epoch.
3827                // - The new epoch begins.
3828                // - The quorum driver cannot complete the partial effects cert from the previous epoch,
3829                //   because it may not be able to reach either of the 2 former validators.
3830                // - But, if the 2 validators that stayed are willing to re-sign the effects in the new
3831                //   epoch, the QD can make a new effects cert and return it to the client.
3832                //
3833                // This is a considered a short-term workaround. Eventually, Quorum Driver should be able
3834                // to return either an effects certificate, -or- a proof of inclusion in a checkpoint. In
3835                // the case above, the Quorum Driver would return a proof of inclusion in the final
3836                // checkpoint, and this code would no longer be necessary.
3837                if effects.executed_epoch() != epoch_store.epoch() {
3838                    debug!(
3839                        tx_digest=?transaction_digest,
3840                        effects_epoch=?effects.executed_epoch(),
3841                        epoch=?epoch_store.epoch(),
3842                        "Re-signing the effects with the current epoch"
3843                    );
3844                }
3845                Ok(Some(self.sign_effects(effects, epoch_store)?))
3846            }
3847            None => Ok(None),
3848        }
3849    }
3850
3851    /// A client aggregating effects signatures towards a quorum assumes finality once it
3852    /// collects 2f+1 of them, so within an epoch this validator must never assert two
3853    /// different effects for the same transaction on any RPC surface, signed or unsigned.
3854    /// Executed effects can change across a restart if an uncommitted transaction is
3855    /// re-executed with divergent results (e.g. by a new binary), so every effects-reporting
3856    /// path calls this before returning effects, and refuses to contradict a signature that
3857    /// may already be in a client's hands.
3858    pub fn check_effects_against_previously_signed(
3859        &self,
3860        epoch_store: &AuthorityPerEpochStore,
3861        tx_digest: &TransactionDigest,
3862        effects_digest: &TransactionEffectsDigest,
3863        surface: &'static str,
3864    ) -> SuiResult<()> {
3865        if let Some(previously_signed_digest) = epoch_store.get_signed_effects_digest(tx_digest)?
3866            && previously_signed_digest != *effects_digest
3867        {
3868            self.metrics
3869                .signed_effects_equivocation_prevented
3870                .with_label_values(&[surface])
3871                .inc();
3872            error!(
3873                ?tx_digest,
3874                ?previously_signed_digest,
3875                executed_digest = ?effects_digest,
3876                surface,
3877                "refusing to report effects that differ from previously signed effects"
3878            );
3879            return Err(SuiErrorKind::GenericAuthorityError {
3880                error: format!(
3881                    "Refusing to report effects for transaction {tx_digest}: effects digest \
3882                     {effects_digest} differs from previously signed effects digest \
3883                     {previously_signed_digest}"
3884                ),
3885            }
3886            .into());
3887        }
3888        Ok(())
3889    }
3890
3891    #[instrument(level = "trace", skip_all)]
3892    pub(crate) fn sign_effects(
3893        &self,
3894        effects: TransactionEffects,
3895        epoch_store: &Arc<AuthorityPerEpochStore>,
3896    ) -> SuiResult<VerifiedSignedTransactionEffects> {
3897        let tx_digest = *effects.transaction_digest();
3898
3899        self.check_effects_against_previously_signed(
3900            epoch_store,
3901            &tx_digest,
3902            &effects.digest(),
3903            "sign_effects",
3904        )?;
3905
3906        let signed_effects = match epoch_store.get_effects_signature(&tx_digest)? {
3907            Some(sig) => {
3908                debug_assert!(sig.epoch == epoch_store.epoch());
3909                SignedTransactionEffects::new_from_data_and_sig(effects, sig)
3910            }
3911            _ => {
3912                let sig = AuthoritySignInfo::new(
3913                    epoch_store.epoch(),
3914                    &effects,
3915                    Intent::sui_app(IntentScope::TransactionEffects),
3916                    self.name,
3917                    &*self.secret,
3918                );
3919
3920                let effects = SignedTransactionEffects::new_from_data_and_sig(effects, sig.clone());
3921
3922                epoch_store.insert_effects_digest_and_signature(
3923                    &tx_digest,
3924                    effects.digest(),
3925                    &sig,
3926                )?;
3927
3928                effects
3929            }
3930        };
3931
3932        Ok(VerifiedSignedTransactionEffects::new_unchecked(
3933            signed_effects,
3934        ))
3935    }
3936
3937    pub fn get_objects(&self, objects: &[ObjectID]) -> Vec<Option<Object>> {
3938        self.get_object_cache_reader().get_objects(objects)
3939    }
3940
3941    pub fn get_object_or_tombstone(&self, object_id: ObjectID) -> Option<ObjectRef> {
3942        self.get_object_cache_reader()
3943            .get_latest_object_ref_or_tombstone(object_id)
3944    }
3945
3946    /// Ordinarily, protocol upgrades occur when 2f + 1 + (f *
3947    /// ProtocolConfig::buffer_stake_for_protocol_upgrade_bps) vote for the upgrade.
3948    ///
3949    /// This method can be used to dynamic adjust the amount of buffer. If set to 0, the upgrade
3950    /// will go through with only 2f+1 votes.
3951    ///
3952    /// IMPORTANT: If this is used, it must be used on >=2f+1 validators (all should have the same
3953    /// value), or you risk halting the chain.
3954    pub fn set_override_protocol_upgrade_buffer_stake(
3955        &self,
3956        expected_epoch: EpochId,
3957        buffer_stake_bps: u64,
3958    ) -> SuiResult {
3959        let epoch_store = self.load_epoch_store_one_call_per_task();
3960        let actual_epoch = epoch_store.epoch();
3961        if actual_epoch != expected_epoch {
3962            return Err(SuiErrorKind::WrongEpoch {
3963                expected_epoch,
3964                actual_epoch,
3965            }
3966            .into());
3967        }
3968
3969        epoch_store.set_override_protocol_upgrade_buffer_stake(buffer_stake_bps)
3970    }
3971
3972    pub fn clear_override_protocol_upgrade_buffer_stake(
3973        &self,
3974        expected_epoch: EpochId,
3975    ) -> SuiResult {
3976        let epoch_store = self.load_epoch_store_one_call_per_task();
3977        let actual_epoch = epoch_store.epoch();
3978        if actual_epoch != expected_epoch {
3979            return Err(SuiErrorKind::WrongEpoch {
3980                expected_epoch,
3981                actual_epoch,
3982            }
3983            .into());
3984        }
3985
3986        epoch_store.clear_override_protocol_upgrade_buffer_stake()
3987    }
3988
3989    /// Get the set of system packages that are compiled in to this build, if those packages are
3990    /// compatible with the current versions of those packages on-chain.
3991    pub async fn get_available_system_packages(
3992        &self,
3993        binary_config: &BinaryConfig,
3994    ) -> Vec<ObjectRef> {
3995        let mut results = vec![];
3996
3997        let system_packages = BuiltInFramework::iter_system_packages();
3998
3999        // Add extra framework packages during simtest
4000        #[cfg(msim)]
4001        let extra_packages = framework_injection::get_extra_packages(self.name);
4002        #[cfg(msim)]
4003        let system_packages = system_packages.map(|p| p).chain(extra_packages.iter());
4004
4005        for system_package in system_packages {
4006            let modules = system_package.modules().to_vec();
4007            // In simtests, we could override the current built-in framework packages.
4008            #[cfg(msim)]
4009            let modules =
4010                match framework_injection::get_override_modules(&system_package.id, self.name) {
4011                    Some(overrides) if overrides.is_empty() => continue,
4012                    Some(overrides) => overrides,
4013                    None => modules,
4014                };
4015
4016            let Some(obj_ref) = sui_framework::compare_system_package(
4017                &self.get_object_store(),
4018                &system_package.id,
4019                &modules,
4020                system_package.dependencies.to_vec(),
4021                binary_config,
4022            )
4023            .await
4024            else {
4025                return vec![];
4026            };
4027            results.push(obj_ref);
4028        }
4029
4030        results
4031    }
4032
4033    /// Return the new versions, module bytes, and dependencies for the packages that have been
4034    /// committed to for a framework upgrade, in `system_packages`.  Loads the module contents from
4035    /// the binary, and performs the following checks:
4036    ///
4037    /// - Whether its contents matches what is on-chain already, in which case no upgrade is
4038    ///   required, and its contents are omitted from the output.
4039    /// - Whether the contents in the binary can form a package whose digest matches the input,
4040    ///   meaning the framework will be upgraded, and this authority can satisfy that upgrade, in
4041    ///   which case the contents are included in the output.
4042    ///
4043    /// If a needed version of the framework can't be loaded, the binary does not contain the
4044    /// bytes for that framework ID, or the resulting package fails the digest check, `None` is
4045    /// returned indicating that this authority cannot run the upgrade that the network voted on.
4046    ///
4047    /// All object lookups are pinned to the versions in `system_packages` instead of using the
4048    /// latest versions, so that the result is deterministic even if the change epoch transaction
4049    /// that performs the upgrade has already been executed locally (e.g. via state sync). In that
4050    /// case the reconstructed change epoch transaction is byte-identical to the executed one, and
4051    /// the caller detects it as already executed.
4052    async fn get_system_package_bytes(
4053        &self,
4054        system_packages: Vec<ObjectRef>,
4055        binary_config: &BinaryConfig,
4056    ) -> Option<Vec<(SequenceNumber, Vec<Vec<u8>>, Vec<ObjectID>)>> {
4057        let object_store = self.get_object_cache_reader();
4058
4059        let mut res = Vec::with_capacity(system_packages.len());
4060        for system_package_ref in system_packages {
4061            if let Some(object) =
4062                object_store.get_object_by_key(&system_package_ref.0, system_package_ref.1)
4063                && object.compute_object_reference() == system_package_ref
4064            {
4065                // Skip this one because it doesn't need to be upgraded.
4066                info!("Framework {} does not need updating", system_package_ref.0);
4067                continue;
4068            }
4069
4070            // The digest in `system_package_ref` commits to a package built on top of the
4071            // predecessor version's `previous_transaction` (see `compare_system_package`), so it
4072            // must be re-derived from that version. A ref at `OBJECT_START_VERSION` is a freshly
4073            // created package with no predecessor.
4074            let prev_transaction = if system_package_ref.1 == OBJECT_START_VERSION {
4075                TransactionDigest::genesis_marker()
4076            } else {
4077                let prev_version = system_package_ref
4078                    .1
4079                    .one_before()
4080                    .expect("version is greater than OBJECT_START_VERSION");
4081                let Some(prev_object) =
4082                    object_store.get_object_by_key(&system_package_ref.0, prev_version)
4083                else {
4084                    error!(
4085                        "Framework {} not available locally at version {:?}, cannot derive \
4086                        upgrade to {system_package_ref:?}",
4087                        system_package_ref.0, prev_version
4088                    );
4089                    return None;
4090                };
4091                prev_object.previous_transaction
4092            };
4093
4094            #[cfg(msim)]
4095            let SystemPackage {
4096                id: _,
4097                bytes,
4098                dependencies,
4099            } = framework_injection::get_override_system_package(&system_package_ref.0, self.name)
4100                .unwrap_or_else(|| {
4101                    BuiltInFramework::get_package_by_id(&system_package_ref.0).clone()
4102                });
4103
4104            #[cfg(not(msim))]
4105            let SystemPackage {
4106                id: _,
4107                bytes,
4108                dependencies,
4109            } = BuiltInFramework::get_package_by_id(&system_package_ref.0).clone();
4110
4111            let modules: Vec<_> = bytes
4112                .iter()
4113                .map(|m| CompiledModule::deserialize_with_config(m, binary_config).unwrap())
4114                .collect();
4115
4116            let new_object = Object::new_system_package(
4117                &modules,
4118                system_package_ref.1,
4119                dependencies.clone(),
4120                prev_transaction,
4121            );
4122
4123            let new_ref = new_object.compute_object_reference();
4124            if new_ref != system_package_ref {
4125                if cfg!(msim) {
4126                    // debug_fatal required here for test_framework_upgrade_conflicting_versions to pass
4127                    debug_fatal!(
4128                        "Framework mismatch -- binary: {new_ref:?}\n  upgrade: {system_package_ref:?}"
4129                    );
4130                } else {
4131                    error!(
4132                        "Framework mismatch -- binary: {new_ref:?}\n  upgrade: {system_package_ref:?}"
4133                    );
4134                }
4135                return None;
4136            }
4137
4138            res.push((system_package_ref.1, bytes, dependencies));
4139        }
4140
4141        Some(res)
4142    }
4143
4144    fn is_protocol_version_supported_v2(
4145        current_protocol_version: ProtocolVersion,
4146        proposed_protocol_version: ProtocolVersion,
4147        protocol_config: &ProtocolConfig,
4148        committee: &Committee,
4149        capabilities: Vec<AuthorityCapabilitiesV2>,
4150        mut buffer_stake_bps: u64,
4151    ) -> Option<(ProtocolVersion, Vec<ObjectRef>)> {
4152        if proposed_protocol_version > current_protocol_version + 1
4153            && !protocol_config.advance_to_highest_supported_protocol_version()
4154        {
4155            return None;
4156        }
4157
4158        if buffer_stake_bps > 10000 {
4159            warn!("clamping buffer_stake_bps to 10000");
4160            buffer_stake_bps = 10000;
4161        }
4162
4163        // For each validator, gather the protocol version and system packages that it would like
4164        // to upgrade to in the next epoch.
4165        let mut desired_upgrades: Vec<_> = capabilities
4166            .into_iter()
4167            .filter_map(|mut cap| {
4168                // A validator that lists no packages is voting against any change at all.
4169                if cap.available_system_packages.is_empty() {
4170                    return None;
4171                }
4172
4173                cap.available_system_packages.sort();
4174
4175                info!(
4176                    "validator {:?} supports {:?} with system packages: {:?}",
4177                    cap.authority.concise(),
4178                    cap.supported_protocol_versions,
4179                    cap.available_system_packages,
4180                );
4181
4182                // A validator that only supports the current protocol version is also voting
4183                // against any change, because framework upgrades always require a protocol version
4184                // bump.
4185                cap.supported_protocol_versions
4186                    .get_version_digest(proposed_protocol_version)
4187                    .map(|digest| (digest, cap.available_system_packages, cap.authority))
4188            })
4189            .collect();
4190
4191        // There can only be one set of votes that have a majority, find one if it exists.
4192        desired_upgrades.sort();
4193        desired_upgrades
4194            .into_iter()
4195            .chunk_by(|(digest, packages, _authority)| (*digest, packages.clone()))
4196            .into_iter()
4197            .find_map(|((digest, packages), group)| {
4198                // should have been filtered out earlier.
4199                assert!(!packages.is_empty());
4200
4201                let mut stake_aggregator: StakeAggregator<(), true> =
4202                    StakeAggregator::new(Arc::new(committee.clone()));
4203
4204                for (_, _, authority) in group {
4205                    stake_aggregator.insert_generic(authority, ());
4206                }
4207
4208                let total_votes = stake_aggregator.total_votes();
4209                let quorum_threshold = committee.quorum_threshold();
4210                let f = committee.total_votes() - committee.quorum_threshold();
4211
4212                // multiple by buffer_stake_bps / 10000, rounded up.
4213                let buffer_stake = (f * buffer_stake_bps).div_ceil(10000);
4214                let effective_threshold = quorum_threshold + buffer_stake;
4215
4216                info!(
4217                    protocol_config_digest = ?digest,
4218                    ?total_votes,
4219                    ?quorum_threshold,
4220                    ?buffer_stake_bps,
4221                    ?effective_threshold,
4222                    ?proposed_protocol_version,
4223                    ?packages,
4224                    "support for upgrade"
4225                );
4226
4227                let has_support = total_votes >= effective_threshold;
4228                has_support.then_some((proposed_protocol_version, packages))
4229            })
4230    }
4231
4232    fn choose_protocol_version_and_system_packages_v2(
4233        current_protocol_version: ProtocolVersion,
4234        protocol_config: &ProtocolConfig,
4235        committee: &Committee,
4236        capabilities: Vec<AuthorityCapabilitiesV2>,
4237        buffer_stake_bps: u64,
4238    ) -> (ProtocolVersion, Vec<ObjectRef>) {
4239        assert!(protocol_config.authority_capabilities_v2());
4240        let mut next_protocol_version = current_protocol_version;
4241        let mut system_packages = vec![];
4242
4243        while let Some((version, packages)) = Self::is_protocol_version_supported_v2(
4244            current_protocol_version,
4245            next_protocol_version + 1,
4246            protocol_config,
4247            committee,
4248            capabilities.clone(),
4249            buffer_stake_bps,
4250        ) {
4251            next_protocol_version = version;
4252            system_packages = packages;
4253        }
4254
4255        (next_protocol_version, system_packages)
4256    }
4257
4258    #[instrument(level = "debug", skip_all)]
4259    fn create_authenticator_state_tx(
4260        &self,
4261        epoch_store: &Arc<AuthorityPerEpochStore>,
4262    ) -> Option<EndOfEpochTransactionKind> {
4263        if !epoch_store.protocol_config().enable_jwk_consensus_updates() {
4264            info!("authenticator state transactions not enabled");
4265            return None;
4266        }
4267
4268        let authenticator_state_exists = epoch_store.authenticator_state_exists();
4269        let tx = if authenticator_state_exists {
4270            let next_epoch = epoch_store.epoch().checked_add(1).expect("epoch overflow");
4271            let min_epoch =
4272                next_epoch.saturating_sub(epoch_store.protocol_config().max_age_of_jwk_in_epochs());
4273            let authenticator_obj_initial_shared_version = epoch_store
4274                .epoch_start_config()
4275                .authenticator_obj_initial_shared_version()
4276                .expect("initial version must exist");
4277
4278            let tx = EndOfEpochTransactionKind::new_authenticator_state_expire(
4279                min_epoch,
4280                authenticator_obj_initial_shared_version,
4281            );
4282
4283            info!(?min_epoch, "Creating AuthenticatorStateExpire tx",);
4284
4285            tx
4286        } else {
4287            let tx = EndOfEpochTransactionKind::new_authenticator_state_create();
4288            info!("Creating AuthenticatorStateCreate tx");
4289            tx
4290        };
4291        Some(tx)
4292    }
4293
4294    #[instrument(level = "debug", skip_all)]
4295    fn create_randomness_state_tx(
4296        &self,
4297        epoch_store: &Arc<AuthorityPerEpochStore>,
4298    ) -> Option<EndOfEpochTransactionKind> {
4299        if !epoch_store.protocol_config().random_beacon() {
4300            info!("randomness state transactions not enabled");
4301            return None;
4302        }
4303
4304        if epoch_store.randomness_state_exists() {
4305            return None;
4306        }
4307
4308        let tx = EndOfEpochTransactionKind::new_randomness_state_create();
4309        info!("Creating RandomnessStateCreate tx");
4310        Some(tx)
4311    }
4312
4313    #[instrument(level = "debug", skip_all)]
4314    fn create_accumulator_root_tx(
4315        &self,
4316        epoch_store: &Arc<AuthorityPerEpochStore>,
4317    ) -> Option<EndOfEpochTransactionKind> {
4318        if !epoch_store
4319            .protocol_config()
4320            .create_root_accumulator_object()
4321        {
4322            info!("accumulator root creation not enabled");
4323            return None;
4324        }
4325
4326        if epoch_store.accumulator_root_exists() {
4327            return None;
4328        }
4329
4330        let tx = EndOfEpochTransactionKind::new_accumulator_root_create();
4331        info!("Creating AccumulatorRootCreate tx");
4332        Some(tx)
4333    }
4334
4335    #[instrument(level = "debug", skip_all)]
4336    fn create_write_accumulator_storage_cost_tx(
4337        &self,
4338        epoch_store: &Arc<AuthorityPerEpochStore>,
4339    ) -> Option<EndOfEpochTransactionKind> {
4340        if !epoch_store.accumulator_root_exists() {
4341            info!("accumulator root does not exist yet");
4342            return None;
4343        }
4344        if !epoch_store.protocol_config().enable_accumulators() {
4345            info!("accumulators not enabled");
4346            return None;
4347        }
4348
4349        let object_store = self.get_object_store();
4350        let object_count =
4351            match accumulator_metadata::get_accumulator_object_count(object_store.as_ref()) {
4352                Ok(Some(count)) => count,
4353                Ok(None) => return None,
4354                Err(e) => {
4355                    fatal!("failed to read accumulator object count: {e}");
4356                }
4357            };
4358
4359        let storage_cost = object_count.saturating_mul(
4360            epoch_store
4361                .protocol_config()
4362                .accumulator_object_storage_cost(),
4363        );
4364
4365        let tx = EndOfEpochTransactionKind::new_write_accumulator_storage_cost(storage_cost);
4366        info!(
4367            object_count,
4368            storage_cost, "Creating WriteAccumulatorStorageCost tx"
4369        );
4370        Some(tx)
4371    }
4372
4373    #[instrument(level = "debug", skip_all)]
4374    fn create_coin_registry_tx(
4375        &self,
4376        epoch_store: &Arc<AuthorityPerEpochStore>,
4377    ) -> Option<EndOfEpochTransactionKind> {
4378        if !epoch_store.protocol_config().enable_coin_registry() {
4379            info!("coin registry not enabled");
4380            return None;
4381        }
4382
4383        if epoch_store.coin_registry_exists() {
4384            return None;
4385        }
4386
4387        let tx = EndOfEpochTransactionKind::new_coin_registry_create();
4388        info!("Creating CoinRegistryCreate tx");
4389        Some(tx)
4390    }
4391
4392    #[instrument(level = "debug", skip_all)]
4393    fn create_display_registry_tx(
4394        &self,
4395        epoch_store: &Arc<AuthorityPerEpochStore>,
4396    ) -> Option<EndOfEpochTransactionKind> {
4397        if !epoch_store.protocol_config().enable_display_registry() {
4398            info!("display registry not enabled");
4399            return None;
4400        }
4401
4402        if epoch_store.display_registry_exists() {
4403            return None;
4404        }
4405
4406        let tx = EndOfEpochTransactionKind::new_display_registry_create();
4407        info!("Creating DisplayRegistryCreate tx");
4408        Some(tx)
4409    }
4410
4411    #[instrument(level = "debug", skip_all)]
4412    fn create_bridge_tx(
4413        &self,
4414        epoch_store: &Arc<AuthorityPerEpochStore>,
4415    ) -> Option<EndOfEpochTransactionKind> {
4416        if !epoch_store.protocol_config().bridge() {
4417            info!("bridge not enabled");
4418            return None;
4419        }
4420        if epoch_store.bridge_exists() {
4421            return None;
4422        }
4423        let tx = EndOfEpochTransactionKind::new_bridge_create(epoch_store.get_chain_identifier());
4424        info!("Creating Bridge Create tx");
4425        Some(tx)
4426    }
4427
4428    #[instrument(level = "debug", skip_all)]
4429    fn init_bridge_committee_tx(
4430        &self,
4431        epoch_store: &Arc<AuthorityPerEpochStore>,
4432    ) -> Option<EndOfEpochTransactionKind> {
4433        if !epoch_store.protocol_config().bridge() {
4434            info!("bridge not enabled");
4435            return None;
4436        }
4437        if !epoch_store
4438            .protocol_config()
4439            .should_try_to_finalize_bridge_committee()
4440        {
4441            info!("should not try to finalize bridge committee yet");
4442            return None;
4443        }
4444        // Only create this transaction if bridge exists
4445        if !epoch_store.bridge_exists() {
4446            return None;
4447        }
4448
4449        if epoch_store.bridge_committee_initiated() {
4450            return None;
4451        }
4452
4453        let bridge_initial_shared_version = epoch_store
4454            .epoch_start_config()
4455            .bridge_obj_initial_shared_version()
4456            .expect("initial version must exist");
4457        let tx = EndOfEpochTransactionKind::init_bridge_committee(bridge_initial_shared_version);
4458        info!("Init Bridge committee tx");
4459        Some(tx)
4460    }
4461
4462    #[instrument(level = "debug", skip_all)]
4463    fn create_deny_list_state_tx(
4464        &self,
4465        epoch_store: &Arc<AuthorityPerEpochStore>,
4466    ) -> Option<EndOfEpochTransactionKind> {
4467        if !epoch_store.protocol_config().enable_coin_deny_list() {
4468            return None;
4469        }
4470
4471        if epoch_store.coin_deny_list_state_exists() {
4472            return None;
4473        }
4474
4475        let tx = EndOfEpochTransactionKind::new_deny_list_state_create();
4476        info!("Creating DenyListStateCreate tx");
4477        Some(tx)
4478    }
4479
4480    #[instrument(level = "debug", skip_all)]
4481    fn create_address_alias_state_tx(
4482        &self,
4483        epoch_store: &Arc<AuthorityPerEpochStore>,
4484    ) -> Option<EndOfEpochTransactionKind> {
4485        if !epoch_store.protocol_config().address_aliases() {
4486            info!("address aliases not enabled");
4487            return None;
4488        }
4489
4490        if epoch_store.address_alias_state_exists() {
4491            return None;
4492        }
4493
4494        let tx = EndOfEpochTransactionKind::new_address_alias_state_create();
4495        info!("Creating AddressAliasStateCreate tx");
4496        Some(tx)
4497    }
4498
4499    #[instrument(level = "debug", skip_all)]
4500    fn create_forwarding_address_registry_tx(
4501        &self,
4502        epoch_store: &Arc<AuthorityPerEpochStore>,
4503    ) -> Option<EndOfEpochTransactionKind> {
4504        if !epoch_store
4505            .protocol_config()
4506            .create_forwarding_address_registry()
4507        {
4508            info!("forwarding address registry creation not enabled");
4509            return None;
4510        }
4511
4512        if epoch_store.forwarding_address_registry_exists() {
4513            return None;
4514        }
4515
4516        let tx = EndOfEpochTransactionKind::new_forwarding_address_registry_create();
4517        info!("Creating ForwardingAddressRegistryCreate tx");
4518        Some(tx)
4519    }
4520
4521    #[instrument(level = "debug", skip_all)]
4522    fn create_execution_time_observations_tx(
4523        &self,
4524        epoch_store: &Arc<AuthorityPerEpochStore>,
4525        end_of_epoch_observation_keys: Vec<ExecutionTimeObservationKey>,
4526        last_checkpoint_before_end_of_epoch: CheckpointSequenceNumber,
4527    ) -> Option<EndOfEpochTransactionKind> {
4528        let PerObjectCongestionControlMode::ExecutionTimeEstimate(params) = epoch_store
4529            .protocol_config()
4530            .per_object_congestion_control_mode()
4531        else {
4532            return None;
4533        };
4534
4535        // Load tx in the last N checkpoints before end-of-epoch, and save only the
4536        // execution time observations for commands in these checkpoints.
4537        let start_checkpoint = std::cmp::max(
4538            last_checkpoint_before_end_of_epoch
4539                .saturating_sub(params.stored_observations_num_included_checkpoints - 1),
4540            // If we have <N checkpoints in the epoch, use all of them.
4541            epoch_store
4542                .epoch()
4543                .checked_sub(1)
4544                .map(|prev_epoch| {
4545                    self.checkpoint_store
4546                        .get_epoch_last_checkpoint_seq_number(prev_epoch)
4547                        .expect("typed store must not fail")
4548                        .expect(
4549                            "sequence number of last checkpoint of preceding epoch must be saved",
4550                        )
4551                        + 1
4552                })
4553                .unwrap_or(1),
4554        );
4555        info!(
4556            "reading checkpoint range {:?}..={:?}",
4557            start_checkpoint, last_checkpoint_before_end_of_epoch
4558        );
4559        let sequence_numbers =
4560            (start_checkpoint..=last_checkpoint_before_end_of_epoch).collect::<Vec<_>>();
4561        let contents_digests: Vec<_> = self
4562            .checkpoint_store
4563            .multi_get_locally_computed_checkpoints(&sequence_numbers)
4564            .expect("typed store must not fail")
4565            .into_iter()
4566            .zip_debug_eq(sequence_numbers)
4567            .map(|(maybe_checkpoint, sequence_number)| {
4568                if let Some(checkpoint) = maybe_checkpoint {
4569                    checkpoint.content_digest
4570                } else {
4571                    // If locally computed checkpoint summary was already pruned, load the
4572                    // certified checkpoint.
4573                    self.checkpoint_store
4574                        .get_checkpoint_by_sequence_number(sequence_number)
4575                        .expect("typed store must not fail")
4576                        .unwrap_or_else(|| {
4577                            fatal!("preceding checkpoints must exist by end of epoch")
4578                        })
4579                        .data()
4580                        .content_digest
4581                }
4582            })
4583            .collect();
4584        let tx_digests: Vec<_> = self
4585            .checkpoint_store
4586            .multi_get_checkpoint_content(&contents_digests)
4587            .expect("typed store must not fail")
4588            .into_iter()
4589            .flat_map(|maybe_contents| {
4590                maybe_contents
4591                    .expect("preceding checkpoint contents must exist by end of epoch")
4592                    .into_inner()
4593                    .into_iter()
4594                    .map(|digests| digests.transaction)
4595            })
4596            .collect();
4597        let included_execution_time_observations: HashSet<_> = self
4598            .get_transaction_cache_reader()
4599            .multi_get_transaction_blocks(&tx_digests)
4600            .into_iter()
4601            .flat_map(|maybe_tx| {
4602                if let TransactionKind::ProgrammableTransaction(ptb) = maybe_tx
4603                    .expect("preceding transaction must exist by end of epoch")
4604                    .transaction_data()
4605                    .kind()
4606                {
4607                    #[allow(clippy::unnecessary_to_owned)]
4608                    itertools::Either::Left(
4609                        ptb.commands
4610                            .to_owned()
4611                            .into_iter()
4612                            .map(|cmd| ExecutionTimeObservationKey::from_command(&cmd)),
4613                    )
4614                } else {
4615                    itertools::Either::Right(std::iter::empty())
4616                }
4617            })
4618            .chain(end_of_epoch_observation_keys.into_iter())
4619            .collect();
4620
4621        let tx = EndOfEpochTransactionKind::new_store_execution_time_observations(
4622            epoch_store
4623                .get_end_of_epoch_execution_time_observations()
4624                .filter_and_sort_v1(
4625                    |(key, _)| included_execution_time_observations.contains(key),
4626                    params.stored_observations_limit.try_into().unwrap(),
4627                ),
4628        );
4629        info!("Creating StoreExecutionTimeObservations tx");
4630        Some(tx)
4631    }
4632
4633    /// Creates and execute the advance epoch transaction to effects without committing it to the database.
4634    /// The effects of the change epoch tx are only written to the database after a certified checkpoint has been
4635    /// formed and executed by CheckpointExecutor.
4636    ///
4637    /// When a framework upgraded has been decided on, but the validator does not have the new
4638    /// versions of the packages locally, the validator cannot form the ChangeEpochTx. In this case
4639    /// it returns Err, indicating that the checkpoint builder should give up trying to make the
4640    /// final checkpoint. As long as the network is able to create a certified checkpoint (which
4641    /// should be ensured by the capabilities vote), it will arrive via state sync and be executed
4642    /// by CheckpointExecutor.
4643    #[instrument(level = "error", skip_all)]
4644    pub async fn create_and_execute_advance_epoch_tx(
4645        &self,
4646        epoch_store: &Arc<AuthorityPerEpochStore>,
4647        gas_cost_summary: &GasCostSummary,
4648        checkpoint: CheckpointSequenceNumber,
4649        epoch_start_timestamp_ms: CheckpointTimestamp,
4650        end_of_epoch_observation_keys: Vec<ExecutionTimeObservationKey>,
4651        // This may be less than `checkpoint - 1` if the end-of-epoch PendingCheckpoint produced
4652        // >1 checkpoint.
4653        last_checkpoint: CheckpointSequenceNumber,
4654    ) -> CheckpointBuilderResult<(SuiSystemState, TransactionEffects)> {
4655        let mut txns = Vec::new();
4656
4657        if let Some(tx) = self.create_authenticator_state_tx(epoch_store) {
4658            txns.push(tx);
4659        }
4660        if let Some(tx) = self.create_randomness_state_tx(epoch_store) {
4661            txns.push(tx);
4662        }
4663        if let Some(tx) = self.create_bridge_tx(epoch_store) {
4664            txns.push(tx);
4665        }
4666        if let Some(tx) = self.init_bridge_committee_tx(epoch_store) {
4667            txns.push(tx);
4668        }
4669        if let Some(tx) = self.create_deny_list_state_tx(epoch_store) {
4670            txns.push(tx);
4671        }
4672        if let Some(tx) = self.create_execution_time_observations_tx(
4673            epoch_store,
4674            end_of_epoch_observation_keys,
4675            last_checkpoint,
4676        ) {
4677            txns.push(tx);
4678        }
4679        if let Some(tx) = self.create_accumulator_root_tx(epoch_store) {
4680            txns.push(tx);
4681        }
4682
4683        if let Some(tx) = self.create_coin_registry_tx(epoch_store) {
4684            txns.push(tx);
4685        }
4686        if let Some(tx) = self.create_display_registry_tx(epoch_store) {
4687            txns.push(tx);
4688        }
4689        if let Some(tx) = self.create_address_alias_state_tx(epoch_store) {
4690            txns.push(tx);
4691        }
4692        if let Some(tx) = self.create_forwarding_address_registry_tx(epoch_store) {
4693            txns.push(tx);
4694        }
4695        if let Some(tx) = self.create_write_accumulator_storage_cost_tx(epoch_store) {
4696            txns.push(tx);
4697        }
4698
4699        let next_epoch = epoch_store.epoch() + 1;
4700
4701        let buffer_stake_bps = epoch_store.get_effective_buffer_stake_bps();
4702
4703        let (next_epoch_protocol_version, next_epoch_system_packages) =
4704            Self::choose_protocol_version_and_system_packages_v2(
4705                epoch_store.protocol_version(),
4706                epoch_store.protocol_config(),
4707                epoch_store.committee(),
4708                epoch_store
4709                    .get_capabilities_v2()
4710                    .expect("read capabilities from db cannot fail"),
4711                buffer_stake_bps,
4712            );
4713
4714        // since system packages are created during the current epoch, they should abide by the
4715        // rules of the current epoch, including the current epoch's max Move binary format version
4716        let config = epoch_store.protocol_config();
4717        let binary_config = config.binary_config(None);
4718        let Some(next_epoch_system_package_bytes) = self
4719            .get_system_package_bytes(next_epoch_system_packages.clone(), &binary_config)
4720            .await
4721        else {
4722            if next_epoch_protocol_version <= ProtocolVersion::MAX {
4723                // This case should only be hit if the validator supports the new protocol version,
4724                // but carries a different framework. The validator should still be able to
4725                // reconfigure, as the correct framework will be installed by the change epoch txn.
4726                debug_fatal!(
4727                    "upgraded system packages {:?} are not locally available, cannot create \
4728                    ChangeEpochTx. validator binary must be upgraded to the correct version!",
4729                    next_epoch_system_packages
4730                );
4731            } else {
4732                error!(
4733                    "validator does not support next_epoch_protocol_version {:?} - will shut down after reconfig unless upgraded",
4734                    next_epoch_protocol_version
4735                );
4736            }
4737            // the checkpoint builder will keep retrying forever when it hits this error.
4738            // Eventually, one of two things will happen:
4739            // - The operator will upgrade this binary to one that has the new packages locally,
4740            //   and this function will succeed.
4741            // - The final checkpoint will be certified by other validators, we will receive it via
4742            //   state sync, and execute it. This will upgrade the framework packages, reconfigure,
4743            //   and most likely shut down in the new epoch (this validator likely doesn't support
4744            //   the new protocol version, or else it should have had the packages.)
4745            return Err(CheckpointBuilderError::SystemPackagesMissing);
4746        };
4747
4748        let tx = if epoch_store
4749            .protocol_config()
4750            .end_of_epoch_transaction_supported()
4751        {
4752            txns.push(EndOfEpochTransactionKind::new_change_epoch(
4753                next_epoch,
4754                next_epoch_protocol_version,
4755                gas_cost_summary.storage_cost,
4756                gas_cost_summary.computation_cost,
4757                gas_cost_summary.storage_rebate,
4758                gas_cost_summary.non_refundable_storage_fee,
4759                epoch_start_timestamp_ms,
4760                next_epoch_system_package_bytes,
4761            ));
4762
4763            VerifiedTransaction::new_end_of_epoch_transaction(txns)
4764        } else {
4765            VerifiedTransaction::new_change_epoch(
4766                next_epoch,
4767                next_epoch_protocol_version,
4768                gas_cost_summary.storage_cost,
4769                gas_cost_summary.computation_cost,
4770                gas_cost_summary.storage_rebate,
4771                gas_cost_summary.non_refundable_storage_fee,
4772                epoch_start_timestamp_ms,
4773                next_epoch_system_package_bytes,
4774            )
4775        };
4776
4777        let executable_tx = VerifiedExecutableTransaction::new_from_checkpoint(
4778            tx.clone(),
4779            epoch_store.epoch(),
4780            checkpoint,
4781        );
4782
4783        let tx_digest = executable_tx.digest();
4784
4785        info!(
4786            ?next_epoch,
4787            ?next_epoch_protocol_version,
4788            ?next_epoch_system_packages,
4789            computation_cost=?gas_cost_summary.computation_cost,
4790            storage_cost=?gas_cost_summary.storage_cost,
4791            storage_rebate=?gas_cost_summary.storage_rebate,
4792            non_refundable_storage_fee=?gas_cost_summary.non_refundable_storage_fee,
4793            ?tx_digest,
4794            "Creating advance epoch transaction"
4795        );
4796
4797        fail_point_async!("change_epoch_tx_delay");
4798        let tx_lock = epoch_store.acquire_tx_lock(tx_digest);
4799
4800        // The tx could have been executed by state sync already - if so simply return an error.
4801        // The checkpoint builder will shortly be terminated by reconfiguration anyway.
4802        if self
4803            .get_transaction_cache_reader()
4804            .is_tx_already_executed(tx_digest)
4805        {
4806            warn!("change epoch tx has already been executed via state sync");
4807            return Err(CheckpointBuilderError::ChangeEpochTxAlreadyExecuted);
4808        }
4809
4810        let Some(execution_guard) = self.execution_lock_for_executable_transaction(&executable_tx)
4811        else {
4812            return Err(CheckpointBuilderError::ChangeEpochTxAlreadyExecuted);
4813        };
4814
4815        // We must manually assign the shared object versions to the transaction before executing it.
4816        // This is because we do not sequence end-of-epoch transactions through consensus.
4817        let assigned_versions = epoch_store.assign_shared_object_versions_idempotent(
4818            self.get_object_cache_reader().as_ref(),
4819            std::iter::once(&Schedulable::Transaction(&executable_tx)),
4820        )?;
4821
4822        assert_eq!(assigned_versions.0.len(), 1);
4823        let assigned_versions = assigned_versions.0.into_iter().next().unwrap().1;
4824
4825        let input_objects = self.read_objects_for_execution(
4826            &tx_lock,
4827            &executable_tx,
4828            &assigned_versions,
4829            epoch_store,
4830        )?;
4831
4832        let (transaction_outputs, _timings, _execution_error_opt) = self
4833            .execute_certificate(
4834                &execution_guard,
4835                &executable_tx,
4836                input_objects,
4837                None,
4838                ExecutionEnv::default(),
4839                epoch_store,
4840            )
4841            .unwrap();
4842        let system_obj = get_sui_system_state(&transaction_outputs.written)
4843            .expect("change epoch tx must write to system object");
4844
4845        let effects = transaction_outputs.effects;
4846        // We must write tx and effects to the state sync tables so that state sync is able to
4847        // deliver to the transaction to CheckpointExecutor after it is included in a certified
4848        // checkpoint.
4849        self.get_state_sync_store()
4850            .insert_transaction_and_effects(&tx, &effects);
4851
4852        info!(
4853            "Effects summary of the change epoch transaction: {:?}",
4854            effects.summary_for_debug()
4855        );
4856        epoch_store.record_checkpoint_builder_is_safe_mode_metric(system_obj.safe_mode());
4857        // The change epoch transaction cannot fail to execute.
4858        assert!(effects.status().is_ok());
4859        Ok((system_obj, effects))
4860    }
4861
4862    #[instrument(level = "error", skip_all)]
4863    async fn reopen_epoch_db(
4864        &self,
4865        cur_epoch_store: &AuthorityPerEpochStore,
4866        new_committee: Committee,
4867        epoch_start_configuration: EpochStartConfiguration,
4868        expensive_safety_check_config: &ExpensiveSafetyCheckConfig,
4869        epoch_last_checkpoint: CheckpointSequenceNumber,
4870    ) -> SuiResult<Arc<AuthorityPerEpochStore>> {
4871        let new_epoch = new_committee.epoch;
4872        info!(new_epoch = ?new_epoch, "re-opening AuthorityEpochTables for new epoch");
4873        assert_eq!(
4874            epoch_start_configuration.epoch_start_state().epoch(),
4875            new_committee.epoch
4876        );
4877        fail_point!("before-open-new-epoch-store");
4878        let new_epoch_store = cur_epoch_store.new_at_next_epoch(
4879            self.name,
4880            new_committee,
4881            epoch_start_configuration,
4882            self.get_backing_package_store().clone(),
4883            self.get_object_store().clone(),
4884            expensive_safety_check_config,
4885            &self.config,
4886            epoch_last_checkpoint,
4887            self.config.fullnode_sync_mode,
4888        )?;
4889        self.epoch_store.store(new_epoch_store.clone());
4890        Ok(new_epoch_store)
4891    }
4892
4893    #[cfg(test)]
4894    pub(crate) fn iter_live_object_set_for_testing(
4895        &self,
4896    ) -> impl Iterator<Item = authority_store_tables::LiveObject> + '_ {
4897        let include_wrapped_object = !self
4898            .epoch_store_for_testing()
4899            .protocol_config()
4900            .simplified_unwrap_then_delete();
4901        self.get_global_state_hash_store()
4902            .iter_cached_live_object_set_for_testing(include_wrapped_object)
4903    }
4904
4905    #[cfg(test)]
4906    pub(crate) fn shutdown_execution_for_test(&self) {
4907        self.tx_execution_shutdown
4908            .lock()
4909            .take()
4910            .unwrap()
4911            .send(())
4912            .unwrap();
4913    }
4914
4915    /// NOTE: this function is only to be used for fuzzing and testing. Never use in prod
4916    pub async fn insert_objects_unsafe_for_testing_only(&self, objects: &[Object]) -> SuiResult {
4917        self.get_reconfig_api().bulk_insert_genesis_objects(objects);
4918        self.get_object_cache_reader()
4919            .force_reload_system_packages(&BuiltInFramework::all_package_ids());
4920        self.get_reconfig_api()
4921            .clear_state_end_of_epoch(&self.execution_lock_for_reconfiguration().await);
4922        Ok(())
4923    }
4924}
4925
4926#[cfg(msim)]
4927pub mod framework_injection {
4928    use move_binary_format::CompiledModule;
4929    use std::collections::BTreeMap;
4930    use std::collections::BTreeSet;
4931    use std::sync::Mutex;
4932    use sui_framework::{BuiltInFramework, SystemPackage};
4933    use sui_types::base_types::{AuthorityName, ObjectID};
4934    use sui_types::is_system_package;
4935
4936    type FrameworkOverrideConfig = BTreeMap<ObjectID, PackageOverrideConfig>;
4937
4938    static OVERRIDE: Mutex<FrameworkOverrideConfig> = Mutex::new(BTreeMap::new());
4939
4940    type Framework = Vec<CompiledModule>;
4941
4942    pub type PackageUpgradeCallback =
4943        Box<dyn Fn(AuthorityName) -> Option<Framework> + Send + Sync + 'static>;
4944
4945    enum PackageOverrideConfig {
4946        Global(Framework),
4947        PerValidator(PackageUpgradeCallback),
4948    }
4949
4950    fn compiled_modules_to_bytes(modules: &[CompiledModule]) -> Vec<Vec<u8>> {
4951        modules
4952            .iter()
4953            .map(|m| {
4954                let mut buf = Vec::new();
4955                m.serialize_with_version(m.version, &mut buf).unwrap();
4956                buf
4957            })
4958            .collect()
4959    }
4960
4961    pub fn set_override(package_id: ObjectID, modules: Vec<CompiledModule>) {
4962        OVERRIDE
4963            .lock()
4964            .unwrap()
4965            .insert(package_id, PackageOverrideConfig::Global(modules));
4966    }
4967
4968    pub fn set_override_cb(package_id: ObjectID, func: PackageUpgradeCallback) {
4969        OVERRIDE
4970            .lock()
4971            .unwrap()
4972            .insert(package_id, PackageOverrideConfig::PerValidator(func));
4973    }
4974
4975    pub fn set_system_packages(packages: Vec<SystemPackage>) {
4976        let mut cfg = OVERRIDE.lock().unwrap();
4977        let mut new_packages_not_to_include: BTreeSet<_> =
4978            BuiltInFramework::all_package_ids().into_iter().collect();
4979        for pkg in &packages {
4980            new_packages_not_to_include.remove(&pkg.id);
4981        }
4982        for pkg in packages {
4983            cfg.insert(pkg.id, PackageOverrideConfig::Global(pkg.modules()));
4984        }
4985        for empty_pkg in new_packages_not_to_include {
4986            cfg.insert(empty_pkg, PackageOverrideConfig::Global(vec![]));
4987        }
4988    }
4989
4990    pub fn get_override_bytes(package_id: &ObjectID, name: AuthorityName) -> Option<Vec<Vec<u8>>> {
4991        OVERRIDE
4992            .lock()
4993            .unwrap()
4994            .get(package_id)
4995            .and_then(|entry| match entry {
4996                PackageOverrideConfig::Global(framework) => {
4997                    Some(compiled_modules_to_bytes(framework))
4998                }
4999                PackageOverrideConfig::PerValidator(func) => {
5000                    func(name).map(|fw| compiled_modules_to_bytes(&fw))
5001                }
5002            })
5003    }
5004
5005    pub fn get_override_modules(
5006        package_id: &ObjectID,
5007        name: AuthorityName,
5008    ) -> Option<Vec<CompiledModule>> {
5009        OVERRIDE
5010            .lock()
5011            .unwrap()
5012            .get(package_id)
5013            .and_then(|entry| match entry {
5014                PackageOverrideConfig::Global(framework) => Some(framework.clone()),
5015                PackageOverrideConfig::PerValidator(func) => func(name),
5016            })
5017    }
5018
5019    pub fn get_override_system_package(
5020        package_id: &ObjectID,
5021        name: AuthorityName,
5022    ) -> Option<SystemPackage> {
5023        let bytes = get_override_bytes(package_id, name)?;
5024        let dependencies = if is_system_package(*package_id) {
5025            BuiltInFramework::get_package_by_id(package_id)
5026                .dependencies
5027                .to_vec()
5028        } else {
5029            // Assume that entirely new injected packages depend on all existing system packages.
5030            BuiltInFramework::all_package_ids()
5031        };
5032        Some(SystemPackage {
5033            id: *package_id,
5034            bytes,
5035            dependencies,
5036        })
5037    }
5038
5039    pub fn get_extra_packages(name: AuthorityName) -> Vec<SystemPackage> {
5040        let built_in = BTreeSet::from_iter(BuiltInFramework::all_package_ids().into_iter());
5041        let extra: Vec<ObjectID> = OVERRIDE
5042            .lock()
5043            .unwrap()
5044            .keys()
5045            .filter_map(|package| (!built_in.contains(package)).then_some(*package))
5046            .collect();
5047
5048        extra
5049            .into_iter()
5050            .map(|package| SystemPackage {
5051                id: package,
5052                bytes: get_override_bytes(&package, name).unwrap(),
5053                dependencies: BuiltInFramework::all_package_ids(),
5054            })
5055            .collect()
5056    }
5057}
5058
5059#[derive(Debug, Serialize, Deserialize, Clone)]
5060pub struct ObjDumpFormat {
5061    pub id: ObjectID,
5062    pub version: VersionNumber,
5063    pub digest: ObjectDigest,
5064    pub object: Object,
5065}
5066
5067impl ObjDumpFormat {
5068    fn new(object: Object) -> Self {
5069        let oref = object.compute_object_reference();
5070        Self {
5071            id: oref.0,
5072            version: oref.1,
5073            digest: oref.2,
5074            object,
5075        }
5076    }
5077}
5078
5079#[derive(Debug, Serialize, Deserialize, Clone)]
5080pub struct NodeStateDump {
5081    pub tx_digest: TransactionDigest,
5082    pub sender_signed_data: SenderSignedData,
5083    pub executed_epoch: u64,
5084    pub reference_gas_price: u64,
5085    pub protocol_version: u64,
5086    pub epoch_start_timestamp_ms: u64,
5087    pub computed_effects: TransactionEffects,
5088    pub expected_effects_digest: TransactionEffectsDigest,
5089    pub relevant_system_packages: Vec<ObjDumpFormat>,
5090    pub shared_objects: Vec<ObjDumpFormat>,
5091    pub loaded_child_objects: Vec<ObjDumpFormat>,
5092    pub modified_at_versions: Vec<ObjDumpFormat>,
5093    pub runtime_reads: Vec<ObjDumpFormat>,
5094    pub input_objects: Vec<ObjDumpFormat>,
5095}
5096
5097impl NodeStateDump {
5098    pub fn new(
5099        tx_digest: &TransactionDigest,
5100        effects: &TransactionEffects,
5101        expected_effects_digest: TransactionEffectsDigest,
5102        object_store: &dyn ObjectStore,
5103        epoch_store: &Arc<AuthorityPerEpochStore>,
5104        inner_temporary_store: &InnerTemporaryStore,
5105        certificate: &VerifiedExecutableTransaction,
5106    ) -> SuiResult<Self> {
5107        // Epoch info
5108        let executed_epoch = epoch_store.epoch();
5109        let reference_gas_price = epoch_store.reference_gas_price();
5110        let epoch_start_config = epoch_store.epoch_start_config();
5111        let protocol_version = epoch_store.protocol_version().as_u64();
5112        let epoch_start_timestamp_ms = epoch_start_config.epoch_data().epoch_start_timestamp();
5113
5114        // Record all system packages at this version
5115        let mut relevant_system_packages = Vec::new();
5116        for sys_package_id in BuiltInFramework::all_package_ids() {
5117            if let Some(w) = object_store.get_object(&sys_package_id) {
5118                relevant_system_packages.push(ObjDumpFormat::new(w))
5119            }
5120        }
5121
5122        // Record all the shared objects
5123        let mut shared_objects = Vec::new();
5124        for kind in effects.accessed_consensus_objects() {
5125            match kind {
5126                InputConsensusObject::Mutate(obj_ref) | InputConsensusObject::ReadOnly(obj_ref) => {
5127                    if let Some(w) = object_store.get_object_by_key(&obj_ref.0, obj_ref.1) {
5128                        shared_objects.push(ObjDumpFormat::new(w))
5129                    }
5130                }
5131                InputConsensusObject::ReadConsensusStreamEnded(..)
5132                | InputConsensusObject::MutateConsensusStreamEnded(..)
5133                | InputConsensusObject::Cancelled(..) => (), // TODO: consider record congested objects.
5134            }
5135        }
5136
5137        // Record all loaded child objects
5138        // Child objects which are read but not mutated are not tracked anywhere else
5139        let mut loaded_child_objects = Vec::new();
5140        for (id, meta) in &inner_temporary_store.loaded_runtime_objects {
5141            if let Some(w) = object_store.get_object_by_key(id, meta.version) {
5142                loaded_child_objects.push(ObjDumpFormat::new(w))
5143            }
5144        }
5145
5146        // Record all modified objects
5147        let mut modified_at_versions = Vec::new();
5148        for (id, ver) in effects.modified_at_versions() {
5149            if let Some(w) = object_store.get_object_by_key(&id, ver) {
5150                modified_at_versions.push(ObjDumpFormat::new(w))
5151            }
5152        }
5153
5154        // Packages read at runtime, which were not previously loaded into the temoorary store
5155        // Some packages may be fetched at runtime and wont show up in input objects
5156        let mut runtime_reads = Vec::new();
5157        for obj in inner_temporary_store
5158            .runtime_packages_loaded_from_db
5159            .values()
5160        {
5161            runtime_reads.push(ObjDumpFormat::new(obj.object().clone()));
5162        }
5163
5164        // All other input objects should already be in `inner_temporary_store.objects`
5165
5166        Ok(Self {
5167            tx_digest: *tx_digest,
5168            executed_epoch,
5169            reference_gas_price,
5170            epoch_start_timestamp_ms,
5171            protocol_version,
5172            relevant_system_packages,
5173            shared_objects,
5174            loaded_child_objects,
5175            modified_at_versions,
5176            runtime_reads,
5177            sender_signed_data: certificate.clone().into_message(),
5178            input_objects: inner_temporary_store
5179                .input_objects
5180                .values()
5181                .map(|o| ObjDumpFormat::new(o.clone()))
5182                .collect(),
5183            computed_effects: effects.clone(),
5184            expected_effects_digest,
5185        })
5186    }
5187
5188    pub fn all_objects(&self) -> Vec<ObjDumpFormat> {
5189        let mut objects = Vec::new();
5190        objects.extend(self.relevant_system_packages.clone());
5191        objects.extend(self.shared_objects.clone());
5192        objects.extend(self.loaded_child_objects.clone());
5193        objects.extend(self.modified_at_versions.clone());
5194        objects.extend(self.runtime_reads.clone());
5195        objects.extend(self.input_objects.clone());
5196        objects
5197    }
5198
5199    pub fn write_to_file(&self, path: &Path) -> Result<PathBuf, anyhow::Error> {
5200        let file_name = format!(
5201            "{}_{}_NODE_DUMP.json",
5202            self.tx_digest,
5203            AuthorityState::unixtime_now_ms()
5204        );
5205        let mut path = path.to_path_buf();
5206        path.push(&file_name);
5207        let mut file = File::create(path.clone())?;
5208        file.write_all(serde_json::to_string_pretty(self)?.as_bytes())?;
5209        Ok(path)
5210    }
5211
5212    pub fn read_from_file(path: &PathBuf) -> Result<Self, anyhow::Error> {
5213        let file = File::open(path)?;
5214        serde_json::from_reader(file).map_err(|e| anyhow::anyhow!(e))
5215    }
5216}
5217
5218/// Run deny list checks and process funds withdrawals before loading input objects.
5219pub(crate) fn pre_object_load_checks(
5220    tx_data: &TransactionData,
5221    tx_signatures: &[GenericSignature],
5222    input_object_kinds: &[InputObjectKind],
5223    receiving_objects_refs: &[ObjectRef],
5224    protocol_config: &ProtocolConfig,
5225    transaction_deny_config: &TransactionDenyConfig,
5226    backing_package_store: &dyn BackingPackageStore,
5227    chain_identifier: ChainIdentifier,
5228    coin_reservation_resolver: &dyn CoinReservationResolverTrait,
5229    account_funds_read: &dyn AccountFundsRead,
5230) -> SuiResult<BTreeMap<AccumulatorObjId, (u64, TypeTag, SuiAddress)>> {
5231    // Note: the deny checks may do redundant package loads but:
5232    // - they only load packages when there is an active package deny map
5233    // - the loads are cached anyway
5234    sui_transaction_checks::deny::check_transaction_for_signing(
5235        tx_data,
5236        tx_signatures,
5237        input_object_kinds,
5238        receiving_objects_refs,
5239        transaction_deny_config,
5240        backing_package_store,
5241    )?;
5242
5243    let declared_withdrawals = tx_data
5244        .process_funds_withdrawals_for_signing(chain_identifier, coin_reservation_resolver)?;
5245
5246    account_funds_read.check_amounts_available(&declared_withdrawals)?;
5247
5248    if protocol_config.gasless_verify_remaining_balance() && tx_data.is_gasless_transaction() {
5249        let min_amounts = sui_types::transaction::get_gasless_allowed_token_types(protocol_config);
5250        account_funds_read
5251            .check_remaining_amounts_after_withdrawal(&declared_withdrawals, &min_amounts)?;
5252    }
5253
5254    Ok(declared_withdrawals)
5255}