1use crate::accumulators::coin_reservations::CachingCoinReservationResolver;
6use crate::accumulators::funds_read::AccountFundsRead;
7use crate::accumulators::object_funds_checker::ObjectFundsChecker;
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::jsonrpc_index::CoinIndexKey2;
22use crate::traffic_controller::TrafficController;
23use crate::traffic_controller::metrics::TrafficControllerMetrics;
24use crate::transaction_deny_config_manager::TransactionDenyConfigManager;
25use crate::transaction_outputs::TransactionOutputs;
26use arc_swap::{ArcSwap, ArcSwapOption, Guard};
27use async_trait::async_trait;
28use authority_per_epoch_store::CertLockGuard;
29use dashmap::DashMap;
30use fastcrypto::encoding::Base58;
31use fastcrypto::encoding::Encoding;
32use fastcrypto::hash::MultisetHash;
33use itertools::Itertools;
34use move_binary_format::CompiledModule;
35use move_binary_format::binary_config::BinaryConfig;
36use move_core_types::annotated_value::MoveStructLayout;
37use move_core_types::language_storage::ModuleId;
38use mysten_common::ZipDebugEqIteratorExt;
39use mysten_common::{assert_reachable, fatal};
40use parking_lot::Mutex;
41use prometheus::{
42 Histogram, HistogramVec, IntCounter, IntCounterVec, IntGauge, IntGaugeVec, Registry,
43 register_histogram_vec_with_registry, register_histogram_with_registry,
44 register_int_counter_vec_with_registry, register_int_counter_with_registry,
45 register_int_gauge_vec_with_registry, register_int_gauge_with_registry,
46};
47use serde::de::DeserializeOwned;
48use serde::{Deserialize, Serialize};
49use shared_object_version_manager::AssignedVersions;
50use shared_object_version_manager::Schedulable;
51use std::collections::BTreeMap;
52use std::collections::BTreeSet;
53use std::fs::File;
54use std::io::Write;
55use std::path::{Path, PathBuf};
56use std::sync::atomic::Ordering;
57use std::time::Duration;
58use std::time::Instant;
59use std::time::SystemTime;
60use std::time::UNIX_EPOCH;
61use std::{
62 collections::{HashMap, HashSet},
63 fs,
64 pin::Pin,
65 str::FromStr,
66 sync::Arc,
67 vec,
68};
69use sui_config::NodeConfig;
70use sui_config::node::{AuthorityOverloadConfig, StateDebugDumpConfig};
71use sui_config::transaction_deny_config::TransactionDenyConfig;
72use sui_execution::Executor;
73use sui_protocol_config::PerObjectCongestionControlMode;
74use sui_types::accumulator_root::AccumulatorObjId;
75use sui_types::base_types::SystemObjectVersions;
76use sui_types::dynamic_field::visitor as DFV;
77use sui_types::execution::ExecutionOutput;
78use sui_types::execution::ExecutionTimeObservationKey;
79use sui_types::execution::ExecutionTiming;
80use sui_types::execution_params::ExecutionOrEarlyError;
81use sui_types::execution_params::FundsWithdrawStatus;
82use sui_types::execution_params::get_early_execution_error;
83use sui_types::inner_temporary_store::PackageStoreWithFallback;
84use sui_types::layout_resolver::LayoutResolver;
85use sui_types::layout_resolver::into_struct_layout;
86use sui_types::messages_consensus::AuthorityCapabilitiesV2;
87use sui_types::node_role::NodeRole;
88use sui_types::object::bounded_visitor::BoundedVisitor;
89use sui_types::storage::InputKey;
90use sui_types::storage::OverlayBackingPackageStore;
91use sui_types::storage::RuntimeObjectResolver;
92use sui_types::storage::TrackingBackingStore;
93use sui_types::traffic_control::{
94 PolicyConfig, RemoteFirewallConfig, TrafficControlReconfigParams,
95};
96use sui_types::transaction_executor::SimulateTransactionResult;
97use sui_types::transaction_executor::TransactionChecks;
98use sui_types::{SUI_ACCUMULATOR_ROOT_OBJECT_ID, accumulator_metadata};
99use tap::TapFallible;
100use tokio::sync::RwLock;
101use tokio::sync::mpsc::unbounded_channel;
102use tokio::sync::oneshot;
103use tokio::sync::watch::error::RecvError;
104use tokio::time::timeout;
105use tracing::{debug, error, info, instrument, warn};
106
107use self::authority_store::ExecutionLockWriteGuard;
108use self::authority_store_pruner::{AuthorityStorePruningMetrics, PrunerWatermarks};
109pub use authority_store::{AuthorityStore, ResolverWrapper};
110use mysten_metrics::{monitored_scope, spawn_monitored_task};
111
112use crate::jsonrpc_index::IndexStore;
113use crate::jsonrpc_index::{
114 CoinInfo, IndexStoreCacheUpdates, IndexStoreCacheUpdatesWithLocks, ObjectIndexChanges,
115};
116use mysten_common::debug_fatal;
117use shared_crypto::intent::{Intent, IntentScope};
118use sui_config::genesis::Genesis;
119use sui_config::node::{DBCheckpointConfig, ExpensiveSafetyCheckConfig};
120use sui_framework::{BuiltInFramework, SystemPackage};
121use sui_json_rpc_types::{
122 DevInspectResults, DryRunTransactionBlockResponse, EventFilter, SuiEvent, SuiMoveValue,
123 SuiObjectDataFilter, SuiTransactionBlockData, SuiTransactionBlockEffects,
124 SuiTransactionBlockEvents, TransactionFilter,
125};
126use sui_macros::{fail_point, fail_point_arg, fail_point_async, fail_point_if};
127use sui_rpc_store::Store as RpcStore;
128use sui_storage::key_value_store::{TransactionKeyValueStore, TransactionKeyValueStoreTrait};
129use sui_storage::key_value_store_metrics::KeyValueStoreMetrics;
130use sui_types::accumulator_root::AccumulatorValue;
131use sui_types::authenticator_state::get_authenticator_state;
132use sui_types::balance::Balance;
133use sui_types::coin_reservation::{self, CoinReservationResolverTrait};
134use sui_types::committee::{EpochId, ProtocolVersion};
135use sui_types::crypto::{AuthoritySignInfo, Signer};
136use sui_types::deny_list_v1::check_coin_deny_list_v1;
137use sui_types::digests::ChainIdentifier;
138use sui_types::dynamic_field::{DynamicFieldInfo, DynamicFieldName};
139use sui_types::effects::{
140 InputConsensusObject, SignedTransactionEffects, TransactionEffects, TransactionEffectsAPI,
141 TransactionEvents, VerifiedSignedTransactionEffects,
142};
143use sui_types::error::{ExecutionError, SuiErrorKind, UserInputError};
144use sui_types::event::EventID;
145use sui_types::executable_transaction::VerifiedExecutableTransaction;
146use sui_types::gas::{GasCostSummary, SuiGasStatus};
147use sui_types::inner_temporary_store::{InnerTemporaryStore, ObjectMap, TxCoins, WrittenObjects};
148use sui_types::message_envelope::Message;
149use sui_types::messages_checkpoint::{
150 CertifiedCheckpointSummary, CheckpointCommitment, CheckpointContents, CheckpointContentsDigest,
151 CheckpointDigest, CheckpointRequest, CheckpointRequestV2, CheckpointResponse,
152 CheckpointResponseV2, CheckpointSequenceNumber, CheckpointSummary, CheckpointSummaryResponse,
153 CheckpointTimestamp, ECMHLiveObjectSetDigest, VerifiedCheckpoint,
154};
155use sui_types::messages_grpc::{
156 LayoutGenerationOption, ObjectInfoRequest, ObjectInfoRequestKind, ObjectInfoResponse,
157 TransactionInfoRequest, TransactionInfoResponse, TransactionStatus,
158};
159use sui_types::metrics::{BytecodeVerifierMetrics, ExecutionMetrics};
160#[cfg(test)]
161use sui_types::object::MoveObject;
162use sui_types::object::{OBJECT_START_VERSION, Owner, PastObjectRead};
163use sui_types::signature::GenericSignature;
164use sui_types::storage::{
165 BackingPackageStore, BackingStore, ObjectKey, ObjectOrTombstone, ObjectStore, WriteKind,
166};
167use sui_types::sui_system_state::SuiSystemStateTrait;
168use sui_types::sui_system_state::epoch_start_sui_system_state::EpochStartSystemStateTrait;
169use sui_types::sui_system_state::{SuiSystemState, get_sui_system_state};
170use sui_types::supported_protocol_versions::{ProtocolConfig, SupportedProtocolVersions};
171use sui_types::{
172 SUI_SYSTEM_ADDRESS,
173 base_types::*,
174 committee::Committee,
175 crypto::AuthoritySignature,
176 error::{SuiError, SuiResult},
177 object::{Object, ObjectRead},
178 transaction::*,
179};
180use sui_types::{TypeTag, is_system_package};
181use typed_store::TypedStoreError;
182use typed_store::rocks::StagedBatch;
183
184use crate::authority::authority_per_epoch_store::{AuthorityPerEpochStore, CertTxGuard};
185use crate::authority::authority_per_epoch_store_pruner::AuthorityPerEpochStorePruner;
186use crate::authority::authority_store::ExecutionLockReadGuard;
187use crate::authority::authority_store_pruner::{
188 AuthorityStorePruner, EPOCH_DURATION_MS_FOR_TESTING,
189};
190use crate::authority::epoch_start_configuration::EpochStartConfigTrait;
191use crate::authority::epoch_start_configuration::EpochStartConfiguration;
192use crate::checkpoints::CheckpointStore;
193use crate::epoch::committee_store::CommitteeStore;
194use crate::execution_cache::{
195 CheckpointCache, ExecutionCacheCommit, ExecutionCacheReconfigAPI, ExecutionCacheWrite,
196 ObjectCacheRead, StateSyncAPI,
197};
198use crate::execution_driver::execution_process;
199use crate::global_state_hasher::{GlobalStateHashStore, GlobalStateHasher, WrappedObject};
200use crate::metrics::LatencyObserver;
201use crate::metrics::RateTracker;
202use crate::module_cache_metrics::ResolverMetrics;
203use crate::overload_monitor::{AuthorityOverloadInfo, overload_monitor_accept_tx};
204use crate::stake_aggregator::StakeAggregator;
205use crate::subscription_handler::SubscriptionHandler;
206use crate::transaction_input_loader::TransactionInputLoader;
207
208#[cfg(msim)]
209pub use crate::checkpoints::checkpoint_executor::utils::{
210 CheckpointTimeoutConfig, init_checkpoint_timeout_config,
211};
212
213#[cfg(msim)]
214use sui_types::committee::CommitteeTrait;
215use sui_types::deny_list_v2::check_coin_deny_list_v2_during_signing;
216
217#[cfg(test)]
218#[path = "unit_tests/authority_tests.rs"]
219pub mod authority_tests;
220
221#[cfg(test)]
222#[path = "unit_tests/transaction_tests.rs"]
223pub mod transaction_tests;
224
225#[cfg(test)]
226#[path = "unit_tests/batch_transaction_tests.rs"]
227mod batch_transaction_tests;
228
229#[cfg(test)]
230#[path = "unit_tests/move_integration_tests.rs"]
231pub mod move_integration_tests;
232
233#[cfg(test)]
234#[path = "unit_tests/gas_tests.rs"]
235mod gas_tests;
236
237#[cfg(test)]
238#[path = "unit_tests/gas_data_tests.rs"]
239mod gas_data_tests;
240
241#[cfg(test)]
242#[path = "unit_tests/batch_verification_tests.rs"]
243mod batch_verification_tests;
244
245#[cfg(test)]
246#[path = "unit_tests/coin_deny_list_tests.rs"]
247mod coin_deny_list_tests;
248
249#[cfg(test)]
250#[path = "unit_tests/auth_unit_test_utils.rs"]
251pub mod auth_unit_test_utils;
252
253pub mod authority_test_utils;
254
255pub mod authority_per_epoch_store;
256pub mod authority_per_epoch_store_pruner;
257
258pub mod authority_store_pruner;
259pub mod authority_store_tables;
260pub mod authority_store_types;
261pub mod congestion_log;
262pub mod consensus_tx_status_cache;
263pub(crate) mod epoch_marker_key;
264pub mod epoch_start_configuration;
265pub mod execution_time_estimator;
266pub mod finalized_transactions_cache;
267pub mod shared_object_congestion_tracker;
268pub mod shared_object_version_manager;
269pub mod submitted_transaction_cache;
270pub mod test_authority_builder;
271pub mod transaction_deferral;
272pub mod transaction_reject_reason_cache;
273mod weighted_moving_average;
274
275pub(crate) mod authority_store;
276pub mod backpressure;
277
278pub struct AuthorityMetrics {
280 tx_orders: IntCounter,
281 total_certs: IntCounter,
282 total_effects: IntCounter,
283 pub shared_obj_tx: IntCounter,
285 sponsored_tx: IntCounter,
286 num_input_objs: Histogram,
287 num_shared_objects: Histogram,
289 batch_size: Histogram,
290
291 authority_state_handle_vote_transaction_latency: Histogram,
292
293 internal_execution_latency: Histogram,
294 signed_effects_equivocation_prevented: IntCounterVec,
297 execution_load_input_objects_latency: Histogram,
298 prepare_certificate_latency: Histogram,
299 commit_certificate_latency: Histogram,
300 db_checkpoint_latency: Histogram,
301
302 pub(crate) transaction_manager_num_enqueued_certificates: IntCounterVec,
304 pub(crate) transaction_manager_num_pending_certificates: IntGauge,
305 pub(crate) transaction_manager_num_executing_certificates: IntGauge,
306 pub(crate) transaction_manager_transaction_queue_age_s: Histogram,
307
308 pub(crate) execution_driver_executed_transactions: IntCounter,
309 pub(crate) execution_driver_paused_transactions: IntCounter,
310 pub(crate) execution_driver_dispatch_queue: IntGauge,
311 pub(crate) execution_queueing_delay_s: Histogram,
312 pub(crate) prepare_cert_gas_latency_ratio: Histogram,
313 pub(crate) execution_gas_latency_ratio: Histogram,
314
315 pub(crate) skipped_consensus_txns: IntCounter,
316 pub(crate) skipped_consensus_txns_cache_hit: IntCounter,
317 pub(crate) consensus_handler_duplicate_tx_count: Histogram,
318
319 pub(crate) authority_overload_status: IntGauge,
320 pub(crate) authority_load_shedding_percentage: IntGauge,
321
322 pub(crate) transaction_overload_sources: IntCounterVec,
323
324 post_processing_total_events_emitted: IntCounter,
326 post_processing_total_tx_indexed: IntCounter,
327 post_processing_total_tx_had_event_processed: IntCounter,
328 post_processing_total_failures: IntCounter,
329
330 pub consensus_handler_processed: IntCounterVec,
332 pub consensus_handler_processed_user_transactions: IntCounterVec,
333 pub consensus_handler_transaction_sizes: HistogramVec,
334 pub consensus_handler_max_transaction_size: IntGaugeVec,
335 pub consensus_handler_deferred_transactions: IntCounter,
336 pub consensus_handler_congested_transactions: IntCounter,
337 pub consensus_handler_unpaid_amplification_deferrals: IntCounter,
338 pub consensus_handler_double_spend_deferrals: IntCounter,
339 pub consensus_handler_double_spend_conflict_count: HistogramVec,
340 pub consensus_handler_double_spend_conflicting_authority: IntCounterVec,
341 pub consensus_handler_cancelled_transactions: IntCounter,
342 pub consensus_handler_dropped_transactions: IntCounterVec,
343 pub consensus_handler_max_object_costs: IntGaugeVec,
344 pub consensus_committed_subdags: IntCounterVec,
345 pub accumulator_deposits: IntCounter,
346 pub accumulator_withdrawals: IntCounter,
347 pub consensus_committed_messages: IntGaugeVec,
348 pub consensus_committed_user_transactions: IntGaugeVec,
349 pub consensus_finalized_user_transactions: IntGaugeVec,
350 pub consensus_rejected_user_transactions: IntGaugeVec,
351 pub consensus_dropped_user_transactions: IntGaugeVec,
352 pub consensus_calculated_throughput: IntGauge,
353 pub consensus_calculated_throughput_profile: IntGauge,
354 pub consensus_block_handler_block_processed: IntCounter,
355 pub consensus_block_handler_txn_processed: IntCounterVec,
356 pub consensus_block_handler_fastpath_executions: IntCounter,
357 pub consensus_timestamp_bias: Histogram,
358
359 pub execution_metrics: Arc<ExecutionMetrics>,
360
361 pub bytecode_verifier_metrics: Arc<BytecodeVerifierMetrics>,
363
364 pub zklogin_sig_count: IntCounter,
366 pub multisig_sig_count: IntCounter,
368
369 pub execution_queueing_latency: LatencyObserver,
372
373 pub txn_ready_rate_tracker: Arc<Mutex<RateTracker>>,
380
381 pub execution_rate_tracker: Arc<Mutex<RateTracker>>,
384}
385
386const POSITIVE_INT_BUCKETS: &[f64] = &[
388 1., 2., 5., 7., 10., 20., 50., 70., 100., 200., 500., 700., 1000., 2000., 5000., 7000., 10000.,
389 20000., 50000., 70000., 100000., 200000., 500000., 700000., 1000000., 2000000., 5000000.,
390 7000000., 10000000.,
391];
392
393const CONSENSUS_TRANSACTION_SIZE_BUCKETS: &[f64] = &[
394 1., 2., 5., 7., 10., 20., 50., 70., 100., 200., 500., 700., 1000., 2000., 5000., 7000., 10000.,
395 20000., 50000., 70000., 100000., 150000., 200000., 250000., 300000., 500000., 700000.,
396 1000000., 2000000., 5000000., 7000000., 10000000.,
397];
398
399const LATENCY_SEC_BUCKETS: &[f64] = &[
400 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.,
401 10., 20., 30., 60., 90.,
402];
403
404const LOW_LATENCY_SEC_BUCKETS: &[f64] = &[
406 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,
407 0.2, 0.5, 1., 2., 5., 10., 20., 50., 100.,
408];
409
410const TIMESTAMP_BIAS_SEC_BUCKETS: &[f64] = &[
413 -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,
414 2.0, 10.0, 30.0,
415];
416
417const GAS_LATENCY_RATIO_BUCKETS: &[f64] = &[
418 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,
419 3000.0, 4000.0, 5000.0, 6000.0, 7000.0, 8000.0, 9000.0, 10000.0, 50000.0, 100000.0, 1000000.0,
420];
421
422pub const DEV_INSPECT_GAS_COIN_VALUE: u64 = 1_000_000_000_000_000_000;
423
424pub const WAIT_FOR_FASTPATH_INPUT_TIMEOUT: Duration = Duration::from_secs(2);
428
429impl AuthorityMetrics {
430 pub fn new(registry: &prometheus::Registry) -> AuthorityMetrics {
431 Self {
432 tx_orders: register_int_counter_with_registry!(
433 "total_transaction_orders",
434 "Total number of transaction orders",
435 registry,
436 )
437 .unwrap(),
438 total_certs: register_int_counter_with_registry!(
439 "total_transaction_certificates",
440 "Total number of transaction certificates handled",
441 registry,
442 )
443 .unwrap(),
444 total_effects: register_int_counter_with_registry!(
446 "total_transaction_effects",
447 "Total number of transaction effects produced",
448 registry,
449 )
450 .unwrap(),
451
452 shared_obj_tx: register_int_counter_with_registry!(
453 "num_shared_obj_tx",
454 "Number of transactions involving shared objects",
455 registry,
456 )
457 .unwrap(),
458
459 sponsored_tx: register_int_counter_with_registry!(
460 "num_sponsored_tx",
461 "Number of sponsored transactions",
462 registry,
463 )
464 .unwrap(),
465
466 num_input_objs: register_histogram_with_registry!(
467 "num_input_objects",
468 "Distribution of number of input TX objects per TX",
469 POSITIVE_INT_BUCKETS.to_vec(),
470 registry,
471 )
472 .unwrap(),
473 num_shared_objects: register_histogram_with_registry!(
474 "num_shared_objects",
475 "Number of shared input objects per TX",
476 POSITIVE_INT_BUCKETS.to_vec(),
477 registry,
478 )
479 .unwrap(),
480 batch_size: register_histogram_with_registry!(
481 "batch_size",
482 "Distribution of size of transaction batch",
483 POSITIVE_INT_BUCKETS.to_vec(),
484 registry,
485 )
486 .unwrap(),
487 authority_state_handle_vote_transaction_latency: register_histogram_with_registry!(
488 "authority_state_handle_vote_transaction_latency",
489 "Latency of voting on transactions without signing",
490 LATENCY_SEC_BUCKETS.to_vec(),
491 registry,
492 )
493 .unwrap(),
494 internal_execution_latency: register_histogram_with_registry!(
495 "authority_state_internal_execution_latency",
496 "Latency of actual certificate executions",
497 LATENCY_SEC_BUCKETS.to_vec(),
498 registry,
499 )
500 .unwrap(),
501 signed_effects_equivocation_prevented: register_int_counter_vec_with_registry!(
502 "authority_state_signed_effects_equivocation_prevented",
503 "Number of times the validator refused to report effects that differ from previously signed effects for the same transaction, by RPC surface",
504 &["surface"],
505 registry,
506 )
507 .unwrap(),
508 execution_load_input_objects_latency: register_histogram_with_registry!(
509 "authority_state_execution_load_input_objects_latency",
510 "Latency of loading input objects for execution",
511 LOW_LATENCY_SEC_BUCKETS.to_vec(),
512 registry,
513 )
514 .unwrap(),
515 prepare_certificate_latency: register_histogram_with_registry!(
516 "authority_state_prepare_certificate_latency",
517 "Latency of executing certificates, before committing the results",
518 LATENCY_SEC_BUCKETS.to_vec(),
519 registry,
520 )
521 .unwrap(),
522 commit_certificate_latency: register_histogram_with_registry!(
523 "authority_state_commit_certificate_latency",
524 "Latency of committing certificate execution results",
525 LATENCY_SEC_BUCKETS.to_vec(),
526 registry,
527 )
528 .unwrap(),
529 db_checkpoint_latency: register_histogram_with_registry!(
530 "db_checkpoint_latency",
531 "Latency of checkpointing dbs",
532 LATENCY_SEC_BUCKETS.to_vec(),
533 registry,
534 ).unwrap(),
535 transaction_manager_num_enqueued_certificates: register_int_counter_vec_with_registry!(
536 "transaction_manager_num_enqueued_certificates",
537 "Current number of certificates enqueued to ExecutionScheduler",
538 &["result"],
539 registry,
540 )
541 .unwrap(),
542 transaction_manager_num_pending_certificates: register_int_gauge_with_registry!(
543 "transaction_manager_num_pending_certificates",
544 "Number of certificates pending in ExecutionScheduler, with at least 1 missing input object",
545 registry,
546 )
547 .unwrap(),
548 transaction_manager_num_executing_certificates: register_int_gauge_with_registry!(
549 "transaction_manager_num_executing_certificates",
550 "Number of executing certificates, including queued and actually running certificates",
551 registry,
552 )
553 .unwrap(),
554 authority_overload_status: register_int_gauge_with_registry!(
555 "authority_overload_status",
556 "Whether authority is current experiencing overload and enters load shedding mode.",
557 registry)
558 .unwrap(),
559 authority_load_shedding_percentage: register_int_gauge_with_registry!(
560 "authority_load_shedding_percentage",
561 "The percentage of transactions is shed when the authority is in load shedding mode.",
562 registry)
563 .unwrap(),
564 transaction_manager_transaction_queue_age_s: register_histogram_with_registry!(
565 "transaction_manager_transaction_queue_age_s",
566 "Time spent in waiting for transaction in the queue",
567 LATENCY_SEC_BUCKETS.to_vec(),
568 registry,
569 )
570 .unwrap(),
571 transaction_overload_sources: register_int_counter_vec_with_registry!(
572 "transaction_overload_sources",
573 "Number of times each source indicates transaction overload.",
574 &["source"],
575 registry)
576 .unwrap(),
577 execution_driver_executed_transactions: register_int_counter_with_registry!(
578 "execution_driver_executed_transactions",
579 "Cumulative number of transaction executed by execution driver",
580 registry,
581 )
582 .unwrap(),
583 execution_driver_paused_transactions: register_int_counter_with_registry!(
584 "execution_driver_paused_transactions",
585 "Cumulative number of transactions paused by execution driver",
586 registry,
587 )
588 .unwrap(),
589 execution_driver_dispatch_queue: register_int_gauge_with_registry!(
590 "execution_driver_dispatch_queue",
591 "Number of transaction pending in execution driver dispatch queue",
592 registry,
593 )
594 .unwrap(),
595 execution_queueing_delay_s: register_histogram_with_registry!(
596 "execution_queueing_delay_s",
597 "Queueing delay between a transaction is ready for execution until it starts executing.",
598 LATENCY_SEC_BUCKETS.to_vec(),
599 registry
600 )
601 .unwrap(),
602 prepare_cert_gas_latency_ratio: register_histogram_with_registry!(
603 "prepare_cert_gas_latency_ratio",
604 "The ratio of computation gas divided by VM execution latency.",
605 GAS_LATENCY_RATIO_BUCKETS.to_vec(),
606 registry
607 )
608 .unwrap(),
609 execution_gas_latency_ratio: register_histogram_with_registry!(
610 "execution_gas_latency_ratio",
611 "The ratio of computation gas divided by certificate execution latency, include committing certificate.",
612 GAS_LATENCY_RATIO_BUCKETS.to_vec(),
613 registry
614 )
615 .unwrap(),
616 skipped_consensus_txns: register_int_counter_with_registry!(
617 "skipped_consensus_txns",
618 "Total number of consensus transactions skipped",
619 registry,
620 )
621 .unwrap(),
622 skipped_consensus_txns_cache_hit: register_int_counter_with_registry!(
623 "skipped_consensus_txns_cache_hit",
624 "Total number of consensus transactions skipped because of local cache hit",
625 registry,
626 )
627 .unwrap(),
628 consensus_handler_duplicate_tx_count: register_histogram_with_registry!(
629 "consensus_handler_duplicate_tx_count",
630 "Number of times each transaction appears in its first consensus commit",
631 POSITIVE_INT_BUCKETS.to_vec(),
632 registry,
633 )
634 .unwrap(),
635 post_processing_total_events_emitted: register_int_counter_with_registry!(
636 "post_processing_total_events_emitted",
637 "Total number of events emitted in post processing",
638 registry,
639 )
640 .unwrap(),
641 post_processing_total_tx_indexed: register_int_counter_with_registry!(
642 "post_processing_total_tx_indexed",
643 "Total number of txes indexed in post processing",
644 registry,
645 )
646 .unwrap(),
647 post_processing_total_tx_had_event_processed: register_int_counter_with_registry!(
648 "post_processing_total_tx_had_event_processed",
649 "Total number of txes finished event processing in post processing",
650 registry,
651 )
652 .unwrap(),
653 post_processing_total_failures: register_int_counter_with_registry!(
654 "post_processing_total_failures",
655 "Total number of failure in post processing",
656 registry,
657 )
658 .unwrap(),
659 consensus_handler_processed: register_int_counter_vec_with_registry!(
660 "consensus_handler_processed",
661 "Number of transactions processed by consensus handler, sliced by class and commit outcome (accepted/rejected)",
662 &["class", "outcome"],
663 registry
664 ).unwrap(),
665 consensus_handler_processed_user_transactions: register_int_counter_vec_with_registry!(
666 "consensus_handler_processed_user_transactions",
667 "Number of user transactions processed by consensus handler, sliced by commit outcome (accepted/rejected) and block author",
668 &["outcome", "authority"],
669 registry
670 ).unwrap(),
671 consensus_handler_transaction_sizes: register_histogram_vec_with_registry!(
672 "consensus_handler_transaction_sizes",
673 "Sizes of each type of transactions processed by consensus handler, sliced by class and commit outcome (accepted/rejected)",
674 &["class", "outcome"],
675 CONSENSUS_TRANSACTION_SIZE_BUCKETS.to_vec(),
676 registry
677 ).unwrap(),
678 consensus_handler_max_transaction_size: register_int_gauge_vec_with_registry!(
679 "consensus_handler_max_transaction_size",
680 "Maximum transaction size in bytes received by the consensus handler for each class",
681 &["class"],
682 registry,
683 ).unwrap(),
684 consensus_handler_deferred_transactions: register_int_counter_with_registry!(
685 "consensus_handler_deferred_transactions",
686 "Number of transactions deferred by consensus handler",
687 registry,
688 ).unwrap(),
689 consensus_handler_congested_transactions: register_int_counter_with_registry!(
690 "consensus_handler_congested_transactions",
691 "Number of transactions deferred by consensus handler due to congestion",
692 registry,
693 ).unwrap(),
694 consensus_handler_unpaid_amplification_deferrals: register_int_counter_with_registry!(
695 "consensus_handler_unpaid_amplification_deferrals",
696 "Number of transactions deferred due to unpaid consensus amplification",
697 registry,
698 ).unwrap(),
699 consensus_handler_double_spend_deferrals: register_int_counter_with_registry!(
700 "consensus_handler_double_spend_deferrals",
701 "Number of transactions deferred due to owned object double-spend contention",
702 registry,
703 ).unwrap(),
704 consensus_handler_double_spend_conflict_count: register_histogram_vec_with_registry!(
705 "consensus_handler_double_spend_conflict_count",
706 "Number of conflicting transactions per double-spend winner, by object type",
707 &["object_type"],
708 POSITIVE_INT_BUCKETS.to_vec(),
709 registry,
710 ).unwrap(),
711 consensus_handler_double_spend_conflicting_authority: register_int_counter_vec_with_registry!(
712 "consensus_handler_double_spend_conflicting_authority",
713 "Number of transactions involved in owned object double-spend contention, by the \
714 block authority that sequenced the transaction and its role in the conflict \
715 (winner = won the lock, loser = dropped)",
716 &["authority", "role"],
717 registry,
718 ).unwrap(),
719 consensus_handler_cancelled_transactions: register_int_counter_with_registry!(
720 "consensus_handler_cancelled_transactions",
721 "Number of transactions cancelled by consensus handler",
722 registry,
723 ).unwrap(),
724 consensus_handler_dropped_transactions: register_int_counter_vec_with_registry!(
725 "consensus_handler_dropped_transactions",
726 "Number of transactions dropped by consensus handler, by drop reason",
727 &["reason"],
728 registry,
729 ).unwrap(),
730 consensus_handler_max_object_costs: register_int_gauge_vec_with_registry!(
731 "consensus_handler_max_congestion_control_object_costs",
732 "Max object costs for congestion control in the current consensus commit",
733 &["commit_type"],
734 registry,
735 ).unwrap(),
736 consensus_committed_subdags: register_int_counter_vec_with_registry!(
737 "consensus_committed_subdags",
738 "Number of committed subdags, sliced by author",
739 &["authority"],
740 registry,
741 ).unwrap(),
742 accumulator_deposits: register_int_counter_with_registry!(
743 "accumulator_deposits",
744 "Total accumulator deposit (merge) events processed in settlement",
745 registry,
746 ).unwrap(),
747 accumulator_withdrawals: register_int_counter_with_registry!(
748 "accumulator_withdrawals",
749 "Total accumulator withdrawal (split) events processed in settlement",
750 registry,
751 ).unwrap(),
752 consensus_committed_messages: register_int_gauge_vec_with_registry!(
753 "consensus_committed_messages",
754 "Total number of committed consensus messages, sliced by author",
755 &["authority"],
756 registry,
757 ).unwrap(),
758 consensus_committed_user_transactions: register_int_gauge_vec_with_registry!(
759 "consensus_committed_user_transactions",
760 "Number of certified & user transactions committed, sliced by submitter and persisted across restarts within each epoch",
761 &["authority"],
762 registry,
763 ).unwrap(),
764 consensus_finalized_user_transactions: register_int_gauge_vec_with_registry!(
765 "consensus_finalized_user_transactions",
766 "Number of user transactions finalized, sliced by submitter",
767 &["authority"],
768 registry,
769 ).unwrap(),
770 consensus_rejected_user_transactions: register_int_gauge_vec_with_registry!(
771 "consensus_rejected_user_transactions",
772 "Number of user transactions rejected, sliced by submitter",
773 &["authority"],
774 registry,
775 ).unwrap(),
776 consensus_dropped_user_transactions: register_int_gauge_vec_with_registry!(
777 "consensus_dropped_user_transactions",
778 "Number of user transactions dropped post-consensus, sliced by submitter",
779 &["authority"],
780 registry,
781 ).unwrap(),
782 execution_metrics: Arc::new(ExecutionMetrics::new(registry)),
783 bytecode_verifier_metrics: Arc::new(BytecodeVerifierMetrics::new(registry)),
784 zklogin_sig_count: register_int_counter_with_registry!(
785 "zklogin_sig_count",
786 "Count of zkLogin signatures",
787 registry,
788 )
789 .unwrap(),
790 multisig_sig_count: register_int_counter_with_registry!(
791 "multisig_sig_count",
792 "Count of zkLogin signatures",
793 registry,
794 )
795 .unwrap(),
796 consensus_calculated_throughput: register_int_gauge_with_registry!(
797 "consensus_calculated_throughput",
798 "The calculated throughput from consensus output. Result is calculated based on unique transactions.",
799 registry,
800 ).unwrap(),
801 consensus_calculated_throughput_profile: register_int_gauge_with_registry!(
802 "consensus_calculated_throughput_profile",
803 "The current active calculated throughput profile",
804 registry
805 ).unwrap(),
806 consensus_block_handler_block_processed: register_int_counter_with_registry!(
807 "consensus_block_handler_block_processed",
808 "Number of blocks processed by consensus block handler.",
809 registry
810 ).unwrap(),
811 consensus_block_handler_txn_processed: register_int_counter_vec_with_registry!(
812 "consensus_block_handler_txn_processed",
813 "Number of transactions processed by consensus block handler, by whether they are certified or rejected.",
814 &["outcome"],
815 registry
816 ).unwrap(),
817 consensus_block_handler_fastpath_executions: register_int_counter_with_registry!(
818 "consensus_block_handler_fastpath_executions",
819 "Number of fastpath transactions sent for execution by consensus transaction handler",
820 registry,
821 ).unwrap(),
822 consensus_timestamp_bias: register_histogram_with_registry!(
823 "consensus_timestamp_bias",
824 "Bias/delay from consensus timestamp to system time",
825 TIMESTAMP_BIAS_SEC_BUCKETS.to_vec(),
826 registry
827 ).unwrap(),
828 execution_queueing_latency: LatencyObserver::new(),
829 txn_ready_rate_tracker: Arc::new(Mutex::new(RateTracker::new(Duration::from_secs(10)))),
830 execution_rate_tracker: Arc::new(Mutex::new(RateTracker::new(Duration::from_secs(10)))),
831 }
832 }
833
834 pub(crate) fn observe_consensus_handler_transaction_size(
835 &self,
836 class: &str,
837 outcome: &str,
838 size: usize,
839 ) {
840 self.consensus_handler_transaction_sizes
841 .with_label_values(&[class, outcome])
842 .observe(size as f64);
843
844 let max_transaction_size = self
845 .consensus_handler_max_transaction_size
846 .with_label_values(&[class]);
847 max_transaction_size.set(max_transaction_size.get().max(size as i64));
848 }
849}
850
851pub type StableSyncAuthoritySigner = Pin<Arc<dyn Signer<AuthoritySignature> + Send + Sync>>;
858
859#[derive(Debug, Clone, Copy, PartialEq, Eq)]
862pub enum ExpectedEffectsDigest {
863 Certified {
865 digest: TransactionEffectsDigest,
866 checkpoint_seq: CheckpointSequenceNumber,
867 },
868 Uncertified(TransactionEffectsDigest),
871}
872
873impl ExpectedEffectsDigest {
874 pub fn digest(&self) -> TransactionEffectsDigest {
875 match self {
876 Self::Certified { digest, .. } => *digest,
877 Self::Uncertified(digest) => *digest,
878 }
879 }
880
881 pub fn checkpoint_seq(&self) -> Option<CheckpointSequenceNumber> {
882 match self {
883 Self::Certified { checkpoint_seq, .. } => Some(*checkpoint_seq),
884 Self::Uncertified(_) => None,
885 }
886 }
887}
888
889#[derive(Debug, Clone)]
892pub struct ExecutionEnv {
893 pub assigned_versions: AssignedVersions,
895 pub expected_effects_digest: Option<ExpectedEffectsDigest>,
898 pub funds_withdraw_status: FundsWithdrawStatus,
901 pub barrier_dependencies: Vec<TransactionDigest>,
904}
905
906impl Default for ExecutionEnv {
907 fn default() -> Self {
908 Self {
909 assigned_versions: AssignedVersions::empty(),
910 expected_effects_digest: None,
911 funds_withdraw_status: FundsWithdrawStatus::MaybeSufficient,
912 barrier_dependencies: Default::default(),
913 }
914 }
915}
916
917impl ExecutionEnv {
918 pub fn new() -> Self {
919 Default::default()
920 }
921
922 pub fn with_expected_effects(mut self, expected: ExpectedEffectsDigest) -> Self {
923 self.expected_effects_digest = Some(expected);
924 self
925 }
926
927 pub fn with_assigned_versions(mut self, assigned_versions: AssignedVersions) -> Self {
928 self.assigned_versions = assigned_versions;
929 self
930 }
931
932 pub fn with_insufficient_funds(mut self) -> Self {
933 self.funds_withdraw_status = FundsWithdrawStatus::Insufficient;
934 self
935 }
936
937 pub fn with_barrier_dependencies(
938 mut self,
939 barrier_dependencies: BTreeSet<TransactionDigest>,
940 ) -> Self {
941 self.barrier_dependencies = barrier_dependencies.into_iter().collect();
942 self
943 }
944}
945
946#[derive(Debug)]
947pub struct ForkRecoveryState {
948 transaction_overrides:
950 parking_lot::RwLock<HashMap<TransactionDigest, TransactionEffectsDigest>>,
951}
952
953impl Default for ForkRecoveryState {
954 fn default() -> Self {
955 Self {
956 transaction_overrides: parking_lot::RwLock::new(HashMap::new()),
957 }
958 }
959}
960
961impl ForkRecoveryState {
962 pub fn new(config: Option<&sui_config::node::ForkRecoveryConfig>) -> Result<Self, SuiError> {
963 let Some(config) = config else {
964 return Ok(Self::default());
965 };
966
967 let mut transaction_overrides = HashMap::new();
968 for (tx_digest_str, effects_digest_str) in &config.transaction_overrides {
969 let tx_digest = TransactionDigest::from_str(tx_digest_str).map_err(|_| {
970 SuiErrorKind::Unknown(format!("Invalid transaction digest: {}", tx_digest_str))
971 })?;
972 let effects_digest =
973 TransactionEffectsDigest::from_str(effects_digest_str).map_err(|_| {
974 SuiErrorKind::Unknown(format!("Invalid effects digest: {}", effects_digest_str))
975 })?;
976 transaction_overrides.insert(tx_digest, effects_digest);
977 }
978
979 Ok(Self {
980 transaction_overrides: parking_lot::RwLock::new(transaction_overrides),
981 })
982 }
983
984 pub fn get_transaction_override(
985 &self,
986 tx_digest: &TransactionDigest,
987 ) -> Option<TransactionEffectsDigest> {
988 self.transaction_overrides.read().get(tx_digest).copied()
989 }
990}
991
992pub type PostProcessingOutput = (StagedBatch, IndexStoreCacheUpdates);
993
994pub struct AuthorityState {
995 pub name: AuthorityName,
998 pub secret: StableSyncAuthoritySigner,
1000
1001 input_loader: TransactionInputLoader,
1003 execution_cache_trait_pointers: ExecutionCacheTraitPointers,
1004 coin_reservation_resolver: Arc<CachingCoinReservationResolver>,
1005
1006 epoch_store: ArcSwap<AuthorityPerEpochStore>,
1007
1008 execution_lock: RwLock<EpochId>,
1013
1014 pub indexes: Option<Arc<IndexStore>>,
1015
1016 pub subscription_handler: Arc<SubscriptionHandler>,
1017 pub checkpoint_store: Arc<CheckpointStore>,
1018
1019 committee_store: Arc<CommitteeStore>,
1020
1021 execution_scheduler: Arc<ExecutionScheduler>,
1023
1024 #[allow(unused)]
1026 tx_execution_shutdown: Mutex<Option<oneshot::Sender<()>>>,
1027
1028 pub metrics: Arc<AuthorityMetrics>,
1029 _pruner: AuthorityStorePruner,
1030 _authority_per_epoch_pruner: AuthorityPerEpochStorePruner,
1031
1032 db_checkpoint_config: DBCheckpointConfig,
1034
1035 pub config: NodeConfig,
1036
1037 pub overload_info: AuthorityOverloadInfo,
1039
1040 chain_identifier: ChainIdentifier,
1042
1043 pub(crate) congestion_tracker: Arc<CongestionTracker>,
1044
1045 pub(crate) consensus_gasless_counter: Arc<ConsensusGaslessCounter>,
1047
1048 pub traffic_controller: Option<Arc<TrafficController>>,
1050
1051 fork_recovery_state: Option<ForkRecoveryState>,
1053
1054 notify_epoch: tokio::sync::watch::Sender<EpochId>,
1056
1057 pub(crate) object_funds_checker: ArcSwapOption<ObjectFundsChecker>,
1058 object_funds_checker_metrics: Arc<ObjectFundsCheckerMetrics>,
1059 pub(crate) unsettled_object_withdrawals: Arc<UnsettledObjectWithdrawals>,
1060
1061 pending_post_processing:
1065 Arc<DashMap<TransactionDigest, oneshot::Receiver<PostProcessingOutput>>>,
1066
1067 post_processing_semaphore: Arc<tokio::sync::Semaphore>,
1070
1071 transaction_deny_config_manager: Arc<TransactionDenyConfigManager>,
1074}
1075
1076impl AuthorityState {
1083 pub fn node_role(&self, epoch_store: &AuthorityPerEpochStore) -> NodeRole {
1084 epoch_store.node_role()
1085 }
1086
1087 pub fn is_validator(&self, epoch_store: &AuthorityPerEpochStore) -> bool {
1088 epoch_store.node_role().is_validator()
1089 }
1090
1091 pub fn is_fullnode(&self, epoch_store: &AuthorityPerEpochStore) -> bool {
1092 epoch_store.node_role().is_fullnode()
1093 }
1094
1095 pub fn committee_store(&self) -> &Arc<CommitteeStore> {
1096 &self.committee_store
1097 }
1098
1099 pub fn clone_committee_store(&self) -> Arc<CommitteeStore> {
1100 self.committee_store.clone()
1101 }
1102
1103 pub fn overload_config(&self) -> &AuthorityOverloadConfig {
1104 &self.config.authority_overload_config
1105 }
1106
1107 pub fn get_epoch_state_commitments(
1108 &self,
1109 epoch: EpochId,
1110 ) -> SuiResult<Option<Vec<CheckpointCommitment>>> {
1111 self.checkpoint_store.get_epoch_state_commitments(epoch)
1112 }
1113
1114 fn handle_transaction_deny_checks(
1115 &self,
1116 transaction: &VerifiedTransaction,
1117 epoch_store: &Arc<AuthorityPerEpochStore>,
1118 ) -> SuiResult<CheckedInputObjects> {
1119 let tx_digest = transaction.digest();
1120 let tx_data = transaction.data().transaction_data();
1121
1122 let input_object_kinds = tx_data.input_objects()?;
1123 let receiving_objects_refs = tx_data.receiving_objects();
1124
1125 let transaction_deny_config = self
1126 .transaction_deny_config_manager
1127 .effective_config()
1128 .load();
1129 pre_object_load_checks(
1130 tx_data,
1131 transaction.tx_signatures(),
1132 &input_object_kinds,
1133 &receiving_objects_refs,
1134 epoch_store.protocol_config(),
1135 transaction_deny_config.as_ref(),
1136 self.get_backing_package_store().as_ref(),
1137 self.chain_identifier,
1138 self.coin_reservation_resolver.as_ref(),
1139 self.get_account_funds_read().as_ref(),
1140 )?;
1141
1142 let (input_objects, receiving_objects) = self.input_loader.read_objects_for_signing(
1143 Some(tx_digest),
1144 &input_object_kinds,
1145 &receiving_objects_refs,
1146 epoch_store.epoch(),
1147 )?;
1148
1149 let (_gas_status, checked_input_objects) = sui_transaction_checks::check_transaction_input(
1150 epoch_store.protocol_config(),
1151 epoch_store.reference_gas_price(),
1152 tx_data,
1153 input_objects,
1154 &receiving_objects,
1155 &self.metrics.bytecode_verifier_metrics,
1156 &self.config.verifier_signing_config,
1157 )?;
1158
1159 self.handle_coin_deny_list_checks(
1160 tx_data,
1161 &checked_input_objects,
1162 &receiving_objects,
1163 epoch_store,
1164 )?;
1165
1166 Ok(checked_input_objects)
1167 }
1168
1169 fn handle_coin_deny_list_checks(
1170 &self,
1171 tx_data: &TransactionData,
1172 checked_input_objects: &CheckedInputObjects,
1173 receiving_objects: &ReceivingObjects,
1174 epoch_store: &Arc<AuthorityPerEpochStore>,
1175 ) -> SuiResult<()> {
1176 use sui_types::balance::Balance;
1177
1178 let declared_withdrawals = tx_data.process_funds_withdrawals_for_signing(
1179 self.chain_identifier,
1180 self.coin_reservation_resolver.as_ref(),
1181 )?;
1182
1183 let funds_withdraw_types = declared_withdrawals
1184 .values()
1185 .filter_map(|(_, type_tag, _)| {
1186 Balance::maybe_get_balance_type_param(type_tag)
1187 .map(|ty| ty.to_canonical_string(false))
1188 })
1189 .collect::<BTreeSet<_>>();
1190
1191 if epoch_store.coin_deny_list_v1_enabled() {
1192 check_coin_deny_list_v1(
1193 tx_data.sender(),
1194 checked_input_objects,
1195 receiving_objects,
1196 funds_withdraw_types.clone(),
1197 &self.get_object_store(),
1198 )?;
1199 }
1200
1201 if epoch_store.protocol_config().enable_coin_deny_list_v2() {
1202 check_coin_deny_list_v2_during_signing(
1203 tx_data.sender(),
1204 checked_input_objects,
1205 receiving_objects,
1206 funds_withdraw_types.clone(),
1207 &self.get_object_store(),
1208 )?;
1209 }
1210
1211 Ok(())
1212 }
1213
1214 #[instrument(level = "trace", skip_all, fields(tx_digest = ?transaction.digest()))]
1224 pub fn handle_vote_transaction(
1225 &self,
1226 epoch_store: &Arc<AuthorityPerEpochStore>,
1227 transaction: VerifiedTransaction,
1228 ) -> SuiResult<()> {
1229 debug!("handle_vote_transaction");
1230
1231 let _metrics_guard = self
1232 .metrics
1233 .authority_state_handle_vote_transaction_latency
1234 .start_timer();
1235 self.metrics.tx_orders.inc();
1236
1237 if !epoch_store
1241 .get_reconfig_state_read_lock_guard()
1242 .should_accept_user_certs()
1243 {
1244 return Err(SuiErrorKind::ValidatorHaltedAtEpochEnd.into());
1245 }
1246
1247 let tx_digest = *transaction.digest();
1252 if epoch_store.is_recently_finalized(&tx_digest)
1253 || epoch_store.transactions_executed_in_cur_epoch(&[tx_digest])?[0]
1254 {
1255 assert_reachable!("transaction recently executed");
1256 return Ok(());
1257 }
1258
1259 if self
1260 .get_transaction_cache_reader()
1261 .transaction_executed_in_last_epoch(transaction.digest(), epoch_store.epoch())
1262 {
1263 return Err(SuiErrorKind::TransactionAlreadyExecuted {
1264 digest: (*transaction.digest()),
1265 }
1266 .into());
1267 }
1268
1269 let _execution_lock = self.execution_lock_for_validation()?;
1271
1272 let checked_input_objects =
1273 self.handle_transaction_deny_checks(&transaction, epoch_store)?;
1274
1275 let owned_objects = checked_input_objects.inner().filter_owned_objects();
1276
1277 self.get_cache_writer()
1281 .validate_owned_object_versions(&owned_objects)
1282 }
1283
1284 pub fn check_transaction_validity(
1293 &self,
1294 epoch_store: &Arc<AuthorityPerEpochStore>,
1295 transaction: &VerifiedTransaction,
1296 enforce_live_input_objects: bool,
1297 ) -> SuiResult<()> {
1298 if !epoch_store
1299 .get_reconfig_state_read_lock_guard()
1300 .should_accept_user_certs()
1301 {
1302 return Err(SuiErrorKind::ValidatorHaltedAtEpochEnd.into());
1303 }
1304
1305 transaction.validity_check(&epoch_store.tx_validity_check_context())?;
1306
1307 let checked_input_objects =
1308 self.handle_transaction_deny_checks(transaction, epoch_store)?;
1309
1310 let owned_objects = checked_input_objects.inner().filter_owned_objects();
1312 let cache_reader = self.get_object_cache_reader();
1313
1314 for obj_ref in &owned_objects {
1315 if let Some(live_object) = cache_reader.get_object(&obj_ref.0) {
1316 if obj_ref.1 < live_object.version() {
1319 return Err(SuiErrorKind::UserInputError {
1320 error: UserInputError::ObjectVersionUnavailableForConsumption {
1321 provided_obj_ref: *obj_ref,
1322 current_version: live_object.version(),
1323 },
1324 }
1325 .into());
1326 }
1327
1328 if enforce_live_input_objects && live_object.version() < obj_ref.1 {
1329 return Err(SuiErrorKind::UserInputError {
1331 error: UserInputError::ObjectVersionUnavailableForConsumption {
1332 provided_obj_ref: *obj_ref,
1333 current_version: live_object.version(),
1334 },
1335 }
1336 .into());
1337 }
1338
1339 if obj_ref.1 == live_object.version() && obj_ref.2 != live_object.digest() {
1341 return Err(SuiErrorKind::UserInputError {
1342 error: UserInputError::InvalidObjectDigest {
1343 object_id: obj_ref.0,
1344 expected_digest: live_object.digest(),
1345 },
1346 }
1347 .into());
1348 }
1349 }
1350 }
1351
1352 Ok(())
1353 }
1354
1355 pub fn check_system_overload_at_signing(&self) -> bool {
1356 self.config
1357 .authority_overload_config
1358 .check_system_overload_at_signing
1359 }
1360
1361 pub(crate) fn check_system_overload(
1362 &self,
1363 tx_data: &SenderSignedData,
1364 do_authority_overload_check: bool,
1365 ) -> SuiResult {
1366 if do_authority_overload_check {
1367 self.check_authority_overload(tx_data).tap_err(|_| {
1368 self.update_overload_metrics("execution_queue");
1369 })?;
1370 }
1371 self.execution_scheduler
1372 .check_execution_overload(self.overload_config(), tx_data)
1373 .tap_err(|_| {
1374 self.update_overload_metrics("execution_pending");
1375 })?;
1376 let pending_tx_count = self
1379 .get_cache_commit()
1380 .approximate_pending_transaction_count();
1381 if pending_tx_count > self.config.execution_cache.backpressure_threshold_for_rpc() {
1382 return Err(SuiErrorKind::ValidatorOverloadedRetryAfter {
1383 retry_after_secs: 10,
1384 }
1385 .into());
1386 }
1387
1388 Ok(())
1389 }
1390
1391 fn check_authority_overload(&self, tx_data: &SenderSignedData) -> SuiResult {
1392 if !self.overload_info.is_overload.load(Ordering::Relaxed) {
1393 return Ok(());
1394 }
1395
1396 let load_shedding_percentage = self
1397 .overload_info
1398 .load_shedding_percentage
1399 .load(Ordering::Relaxed);
1400 overload_monitor_accept_tx(load_shedding_percentage, tx_data.digest())
1401 }
1402
1403 pub(crate) fn update_overload_metrics(&self, source: &str) {
1404 self.metrics
1405 .transaction_overload_sources
1406 .with_label_values(&[source])
1407 .inc();
1408 }
1409
1410 pub(crate) async fn wait_for_fastpath_dependency_objects(
1414 &self,
1415 transaction: &VerifiedTransaction,
1416 epoch: EpochId,
1417 ) -> SuiResult<bool> {
1418 let txn_data = transaction.data().transaction_data();
1419 let (move_objects, packages, receiving_objects) = txn_data.fastpath_dependency_objects()?;
1420
1421 let fastpath_dependency_objects: Vec<_> = move_objects
1423 .into_iter()
1424 .filter_map(|obj_ref| self.should_wait_for_dependency_object(obj_ref))
1425 .chain(
1426 packages
1427 .into_iter()
1428 .map(|package_id| InputKey::Package { id: package_id }),
1429 )
1430 .collect();
1431 let receiving_keys: HashSet<_> = receiving_objects
1432 .into_iter()
1433 .filter_map(|receiving_obj_ref| {
1434 self.should_wait_for_dependency_object(receiving_obj_ref)
1435 })
1436 .collect();
1437 if fastpath_dependency_objects.is_empty() && receiving_keys.is_empty() {
1438 return Ok(true);
1439 }
1440
1441 let max_wait = if cfg!(msim) {
1444 Duration::from_millis(200)
1445 } else {
1446 WAIT_FOR_FASTPATH_INPUT_TIMEOUT
1447 };
1448
1449 match timeout(
1450 max_wait,
1451 self.get_object_cache_reader().notify_read_input_objects(
1452 &fastpath_dependency_objects,
1453 &receiving_keys,
1454 epoch,
1455 ),
1456 )
1457 .await
1458 {
1459 Ok(()) => Ok(true),
1460 Err(_) => Ok(false),
1463 }
1464 }
1465
1466 fn should_wait_for_dependency_object(&self, obj_ref: ObjectRef) -> Option<InputKey> {
1473 let (obj_id, cur_version, _digest) = obj_ref;
1474 let Some(latest_obj_ref) = self
1475 .get_object_cache_reader()
1476 .get_latest_object_ref_or_tombstone(obj_id)
1477 else {
1478 return Some(InputKey::VersionedObject {
1480 id: FullObjectID::new(obj_id, None),
1481 version: cur_version,
1482 });
1483 };
1484 let latest_digest = latest_obj_ref.2;
1485 if latest_digest == ObjectDigest::OBJECT_DIGEST_DELETED {
1486 return None;
1488 }
1489 let latest_version = latest_obj_ref.1;
1490 if cur_version <= latest_version {
1491 return None;
1494 }
1495 Some(InputKey::VersionedObject {
1497 id: FullObjectID::new(obj_id, None),
1498 version: cur_version,
1499 })
1500 }
1501
1502 #[instrument(level = "trace", skip_all)]
1507 pub async fn wait_for_transaction_execution_for_testing(
1508 &self,
1509 transaction: &VerifiedExecutableTransaction,
1510 ) -> TransactionEffects {
1511 self.notify_read_effects_for_testing(
1512 "AuthorityState::wait_for_transaction_execution_for_testing",
1513 *transaction.digest(),
1514 )
1515 .await
1516 }
1517
1518 #[instrument(level = "trace", skip_all)]
1530 pub fn try_execute_immediately(
1531 &self,
1532 certificate: &VerifiedExecutableTransaction,
1533 mut execution_env: ExecutionEnv,
1534 epoch_store: &Arc<AuthorityPerEpochStore>,
1535 ) -> ExecutionOutput<(TransactionEffects, Option<ExecutionError>)> {
1536 let _scope = monitored_scope("Execution::try_execute_immediately");
1537 let _metrics_guard = self.metrics.internal_execution_latency.start_timer();
1538
1539 let tx_digest = certificate.digest();
1540
1541 if let Some(fork_recovery) = &self.fork_recovery_state
1542 && let Some(override_digest) = fork_recovery.get_transaction_override(tx_digest)
1543 {
1544 warn!(
1545 ?tx_digest,
1546 original_digest = ?execution_env.expected_effects_digest,
1547 override_digest = ?override_digest,
1548 "Applying fork recovery override for transaction effects digest"
1549 );
1550 execution_env.expected_effects_digest =
1551 Some(ExpectedEffectsDigest::Uncertified(override_digest));
1552 }
1553
1554 let tx_guard = epoch_store.acquire_tx_guard(certificate);
1556
1557 let tx_cache_reader = self.get_transaction_cache_reader();
1558 if let Some(effects) = tx_cache_reader.get_executed_effects(tx_digest) {
1559 if let Some(expected_effects_digest) = execution_env.expected_effects_digest {
1560 assert_eq!(
1561 effects.digest(),
1562 expected_effects_digest.digest(),
1563 "Unexpected effects digest for transaction {:?}",
1564 tx_digest
1565 );
1566 }
1567 tx_guard.release();
1568 return ExecutionOutput::Success((effects, None));
1569 }
1570
1571 let execution_start_time = Instant::now();
1572
1573 let Some(execution_guard) = self.execution_lock_for_executable_transaction(certificate)
1578 else {
1579 tx_guard.release();
1580 return ExecutionOutput::EpochEnded;
1581 };
1582 if *execution_guard != epoch_store.epoch() {
1587 tx_guard.release();
1588 info!("The epoch of the execution_guard doesn't match the epoch store");
1589 return ExecutionOutput::EpochEnded;
1590 }
1591
1592 let accumulator_version = execution_env.assigned_versions.accumulator_version();
1593
1594 let (transaction_outputs, timings, execution_error_opt) = match self.process_certificate(
1595 &tx_guard,
1596 &execution_guard,
1597 certificate,
1598 execution_env,
1599 epoch_store,
1600 ) {
1601 ExecutionOutput::Success(result) => result,
1602 output => return output.unwrap_err(),
1603 };
1604 let transaction_outputs = Arc::new(transaction_outputs);
1605
1606 fail_point!("crash");
1607
1608 let effects = transaction_outputs.effects.clone();
1609 debug!(
1610 ?tx_digest,
1611 fx_digest=?effects.digest(),
1612 "process_certificate succeeded in {:.3}ms",
1613 (execution_start_time.elapsed().as_micros() as f64) / 1000.0
1614 );
1615
1616 let commit_result = self.commit_certificate(certificate, transaction_outputs, epoch_store);
1617 if let Err(err) = commit_result {
1618 error!(?tx_digest, "Error committing transaction: {err}");
1619 tx_guard.release();
1620 return ExecutionOutput::Fatal(err);
1621 }
1622
1623 if let TransactionKind::AuthenticatorStateUpdate(auth_state) =
1624 certificate.data().transaction_data().kind()
1625 {
1626 if let Some(err) = &execution_error_opt {
1627 debug_fatal!("Authenticator state update failed: {:?}", err);
1628 }
1629 epoch_store.update_authenticator_state(auth_state);
1630
1631 if cfg!(debug_assertions) {
1633 let authenticator_state = get_authenticator_state(self.get_object_store())
1634 .expect("Read cannot fail")
1635 .expect("Authenticator state must exist");
1636
1637 let mut sys_jwks: Vec<_> = authenticator_state
1638 .active_jwks
1639 .into_iter()
1640 .map(|jwk| (jwk.jwk_id, jwk.jwk))
1641 .collect();
1642 let mut active_jwks: Vec<_> = epoch_store
1643 .signature_verifier
1644 .get_jwks()
1645 .into_iter()
1646 .collect();
1647 sys_jwks.sort();
1648 active_jwks.sort();
1649
1650 assert_eq!(sys_jwks, active_jwks);
1651 }
1652 }
1653
1654 if certificate
1655 .transaction_data()
1656 .kind()
1657 .is_accumulator_barrier_settle_tx()
1658 {
1659 let object_funds_checker = self.object_funds_checker.load();
1660 if let Some(object_funds_checker) = object_funds_checker.as_ref() {
1661 let next_accumulator_version = accumulator_version.unwrap().next();
1664 object_funds_checker.settle_accumulator_version(next_accumulator_version);
1665 }
1666 }
1667
1668 tx_guard.commit_tx();
1669
1670 let elapsed = execution_start_time.elapsed();
1671 epoch_store.record_local_execution_time(
1672 certificate.data().transaction_data(),
1673 &effects,
1674 timings,
1675 elapsed,
1676 );
1677
1678 let elapsed_us = elapsed.as_micros() as f64;
1679 if elapsed_us > 0.0 {
1680 self.metrics
1681 .execution_gas_latency_ratio
1682 .observe(effects.gas_cost_summary().computation_cost as f64 / elapsed_us);
1683 };
1684 ExecutionOutput::Success((effects, execution_error_opt))
1685 }
1686
1687 pub fn read_objects_for_execution(
1688 &self,
1689 tx_lock: &CertLockGuard,
1690 certificate: &VerifiedExecutableTransaction,
1691 assigned_shared_object_versions: &AssignedVersions,
1692 epoch_store: &Arc<AuthorityPerEpochStore>,
1693 ) -> SuiResult<InputObjects> {
1694 let _scope = monitored_scope("Execution::load_input_objects");
1695 let _metrics_guard = self
1696 .metrics
1697 .execution_load_input_objects_latency
1698 .start_timer();
1699 let input_objects = &certificate.data().transaction_data().input_objects()?;
1700 self.input_loader.read_objects_for_execution(
1701 &certificate.key(),
1702 tx_lock,
1703 input_objects,
1704 assigned_shared_object_versions,
1705 epoch_store.epoch(),
1706 )
1707 }
1708
1709 pub async fn try_execute_executable_for_test(
1710 &self,
1711 executable: &VerifiedExecutableTransaction,
1712 execution_env: ExecutionEnv,
1713 ) -> (VerifiedSignedTransactionEffects, Option<ExecutionError>) {
1714 let epoch_store = self.epoch_store_for_testing();
1715 let (effects, execution_error_opt) = self
1716 .try_execute_immediately(executable, execution_env, &epoch_store)
1717 .unwrap();
1718 self.flush_post_processing(executable.digest()).await;
1719 let signed_effects = self.sign_effects(effects, &epoch_store).unwrap();
1720 (signed_effects, execution_error_opt)
1721 }
1722
1723 pub async fn notify_read_effects_for_testing(
1728 &self,
1729 task_name: &'static str,
1730 digest: TransactionDigest,
1731 ) -> TransactionEffects {
1732 self.get_transaction_cache_reader()
1733 .notify_read_executed_effects(task_name, &[digest])
1734 .await
1735 .pop()
1736 .expect("must return correct number of effects")
1737 }
1738
1739 pub(crate) fn debug_dump_transaction_state(
1744 &self,
1745 tx_digest: &TransactionDigest,
1746 effects: &TransactionEffects,
1747 expected_effects_digest: TransactionEffectsDigest,
1748 inner_temporary_store: &InnerTemporaryStore,
1749 certificate: &VerifiedExecutableTransaction,
1750 debug_dump_config: &StateDebugDumpConfig,
1751 ) -> SuiResult<PathBuf> {
1752 let dump_dir = debug_dump_config
1753 .dump_file_directory
1754 .as_ref()
1755 .cloned()
1756 .unwrap_or(std::env::temp_dir());
1757 let epoch_store = self.load_epoch_store_one_call_per_task();
1758
1759 NodeStateDump::new(
1760 tx_digest,
1761 effects,
1762 expected_effects_digest,
1763 self.get_object_store().as_ref(),
1764 &epoch_store,
1765 inner_temporary_store,
1766 certificate,
1767 )?
1768 .write_to_file(&dump_dir)
1769 .map_err(|e| SuiErrorKind::FileIOError(e.to_string()).into())
1770 }
1771
1772 #[instrument(level = "trace", skip_all)]
1773 pub(crate) fn process_certificate(
1774 &self,
1775 tx_guard: &CertTxGuard,
1776 execution_guard: &ExecutionLockReadGuard<'_>,
1777 certificate: &VerifiedExecutableTransaction,
1778 execution_env: ExecutionEnv,
1779 epoch_store: &Arc<AuthorityPerEpochStore>,
1780 ) -> ExecutionOutput<(
1781 TransactionOutputs,
1782 Vec<ExecutionTiming>,
1783 Option<ExecutionError>,
1784 )> {
1785 let _scope = monitored_scope("Execution::process_certificate");
1786
1787 let input_objects = match self.read_objects_for_execution(
1788 tx_guard.as_lock_guard(),
1789 certificate,
1790 &execution_env.assigned_versions,
1791 epoch_store,
1792 ) {
1793 Ok(objects) => objects,
1794 Err(e) => return ExecutionOutput::Fatal(e),
1795 };
1796
1797 let expected_effects_digest = execution_env.expected_effects_digest;
1798
1799 fail_point_if!("correlated-crash-process-certificate", || {
1800 if sui_simulator::random::deterministic_probability_once(certificate.digest(), 0.01) {
1801 sui_simulator::task::kill_current_node(None);
1802 }
1803 });
1804
1805 self.execute_certificate(
1810 execution_guard,
1811 certificate,
1812 input_objects,
1813 expected_effects_digest,
1814 execution_env,
1815 epoch_store,
1816 )
1817 }
1818
1819 pub async fn reconfigure_traffic_control(
1820 &self,
1821 params: TrafficControlReconfigParams,
1822 ) -> Result<TrafficControlReconfigParams, SuiError> {
1823 if let Some(traffic_controller) = self.traffic_controller.as_ref() {
1824 traffic_controller.admin_reconfigure(params).await
1825 } else {
1826 Err(SuiErrorKind::InvalidAdminRequest(
1827 "Traffic controller is not configured on this node".to_string(),
1828 )
1829 .into())
1830 }
1831 }
1832
1833 #[instrument(level = "trace", skip_all)]
1834 fn commit_certificate(
1835 &self,
1836 certificate: &VerifiedExecutableTransaction,
1837 transaction_outputs: Arc<TransactionOutputs>,
1838 epoch_store: &Arc<AuthorityPerEpochStore>,
1839 ) -> SuiResult {
1840 let _scope: Option<mysten_metrics::MonitoredScopeGuard> =
1841 monitored_scope("Execution::commit_certificate");
1842 let _metrics_guard = self.metrics.commit_certificate_latency.start_timer();
1843
1844 let tx_digest = certificate.digest();
1845
1846 epoch_store.insert_executed_in_epoch(tx_digest);
1849 let key = certificate.key();
1850 if !matches!(key, TransactionKey::Digest(_)) {
1851 epoch_store.insert_tx_key(key, *tx_digest)?;
1852 }
1853
1854 fail_point!("crash");
1856
1857 self.get_cache_writer()
1858 .write_transaction_outputs(epoch_store.epoch(), transaction_outputs);
1859
1860 if let Some(settlement_key) = certificate
1865 .transaction_data()
1866 .kind()
1867 .accumulator_barrier_settlement_key()
1868 {
1869 epoch_store.notify_barrier_executed(settlement_key, *tx_digest);
1870 }
1871
1872 if certificate.transaction_data().is_end_of_epoch_tx() {
1873 self.get_object_cache_reader()
1876 .force_reload_system_packages(&BuiltInFramework::all_package_ids());
1877 }
1878
1879 Ok(())
1880 }
1881
1882 fn update_metrics(
1883 &self,
1884 certificate: &VerifiedExecutableTransaction,
1885 inner_temporary_store: &InnerTemporaryStore,
1886 effects: &TransactionEffects,
1887 ) {
1888 if certificate.has_zklogin_sig() {
1890 self.metrics.zklogin_sig_count.inc();
1891 } else if certificate.has_upgraded_multisig() {
1892 self.metrics.multisig_sig_count.inc();
1893 }
1894
1895 self.metrics.total_effects.inc();
1896 self.metrics.total_certs.inc();
1897
1898 let consensus_object_count = effects.accessed_consensus_objects().len();
1899 if consensus_object_count > 0 {
1900 self.metrics.shared_obj_tx.inc();
1901 }
1902
1903 if certificate.is_sponsored_tx() {
1904 self.metrics.sponsored_tx.inc();
1905 }
1906
1907 let input_object_count = inner_temporary_store.input_objects.len();
1908 self.metrics
1909 .num_input_objs
1910 .observe(input_object_count as f64);
1911 self.metrics
1912 .num_shared_objects
1913 .observe(consensus_object_count as f64);
1914 self.metrics.batch_size.observe(
1915 certificate
1916 .data()
1917 .intent_message()
1918 .value
1919 .kind()
1920 .num_commands() as f64,
1921 );
1922 }
1923
1924 fn execute_transaction_to_effects(
1927 &self,
1928 executor: &dyn Executor,
1929 store: &dyn BackingStore,
1930 protocol_config: &ProtocolConfig,
1931 enable_expensive_checks: bool,
1932 execution_params: ExecutionOrEarlyError,
1933 epoch_id: &EpochId,
1934 epoch_timestamp_ms: u64,
1935 input_objects: CheckedInputObjects,
1936 system_object_versions: SystemObjectVersions,
1937 gas_data: GasData,
1938 gas_status: SuiGasStatus,
1939 kind: TransactionKind,
1940 rewritten_inputs: Option<Vec<bool>>,
1941 signer: SuiAddress,
1942 tx_digest: TransactionDigest,
1943 ) -> (
1944 InnerTemporaryStore,
1945 SuiGasStatus,
1946 TransactionEffects,
1947 Vec<ExecutionTiming>,
1948 Result<(), ExecutionError>,
1949 ) {
1950 let (inner_temp_store, gas_status, effects, timings, execution_error) = executor
1951 .execute_transaction_to_effects_and_execution_error(
1953 store,
1954 protocol_config,
1955 self.metrics.execution_metrics.clone(),
1956 enable_expensive_checks,
1957 execution_params,
1958 epoch_id,
1959 epoch_timestamp_ms,
1960 input_objects,
1961 system_object_versions,
1962 gas_data,
1963 gas_status,
1964 kind,
1965 rewritten_inputs,
1966 signer,
1967 tx_digest,
1968 &mut None,
1969 );
1970
1971 (
1972 inner_temp_store,
1973 gas_status,
1974 effects,
1975 timings,
1976 execution_error,
1977 )
1978 }
1979
1980 #[instrument(level = "trace", skip_all)]
1989 fn execute_certificate(
1990 &self,
1991 _execution_guard: &ExecutionLockReadGuard<'_>,
1992 certificate: &VerifiedExecutableTransaction,
1993 input_objects: InputObjects,
1994 expected_effects_digest: Option<ExpectedEffectsDigest>,
1995 execution_env: ExecutionEnv,
1996 epoch_store: &Arc<AuthorityPerEpochStore>,
1997 ) -> ExecutionOutput<(
1998 TransactionOutputs,
1999 Vec<ExecutionTiming>,
2000 Option<ExecutionError>,
2001 )> {
2002 let _scope = monitored_scope("Execution::prepare_certificate");
2003 let _metrics_guard = self.metrics.prepare_certificate_latency.start_timer();
2004 let prepare_certificate_start_time = tokio::time::Instant::now();
2005
2006 let tx_data = certificate.data().transaction_data();
2008
2009 if let Err(e) = tx_data.validity_check(&epoch_store.tx_validity_check_context()) {
2010 return ExecutionOutput::Fatal(e);
2011 }
2012
2013 let (gas_status, input_objects) = match sui_transaction_checks::check_certificate_input(
2017 certificate,
2018 input_objects,
2019 epoch_store.protocol_config(),
2020 epoch_store.reference_gas_price(),
2021 ) {
2022 Ok(result) => result,
2023 Err(e) => return ExecutionOutput::Fatal(e),
2024 };
2025
2026 let tx_digest = *certificate.digest();
2027 let protocol_config = epoch_store.protocol_config();
2028 let transaction_data = &certificate.data().intent_message().value;
2029 let sender = transaction_data.sender();
2030 let (mut kind, signer, gas_data) = transaction_data.execution_parts();
2031 let early_execution_error = get_early_execution_error(
2032 &tx_digest,
2033 &input_objects,
2034 self.config.certificate_deny_config.certificate_deny_set(),
2035 &execution_env.funds_withdraw_status,
2036 );
2037 let system_object_versions = execution_env.assigned_versions.system_object_versions;
2038 let accumulator_version = execution_env.assigned_versions.accumulator_version();
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 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 #[allow(unused_mut)]
2062 let (inner_temp_store, _, mut effects, timings, execution_error_opt) = self
2063 .execute_transaction_to_effects(
2064 &**epoch_store.executor(),
2065 &tracking_store,
2066 protocol_config,
2067 self.config
2070 .expensive_safety_check_config
2071 .enable_deep_per_tx_sui_conservation_check(),
2072 execution_params,
2073 &epoch_store.epoch_start_config().epoch_data().epoch_id(),
2074 epoch_store
2075 .epoch_start_config()
2076 .epoch_data()
2077 .epoch_start_timestamp(),
2078 input_objects,
2079 system_object_versions,
2080 gas_data,
2081 gas_status,
2082 kind,
2083 rewritten_inputs,
2084 signer,
2085 tx_digest,
2086 );
2087
2088 let object_funds_checker = self.object_funds_checker.load();
2089 if let Some(object_funds_checker) = object_funds_checker.as_ref()
2090 && !object_funds_checker.should_commit_object_funds_withdraws(
2091 certificate,
2092 &effects,
2093 &inner_temp_store.accumulator_running_max_withdraws,
2094 &execution_env,
2095 self.get_account_funds_read(),
2096 &self.execution_scheduler,
2097 epoch_store,
2098 )
2099 {
2100 assert_reachable!("retry object withdraw later");
2101 return ExecutionOutput::RetryLater;
2102 }
2103
2104 fail_point_arg!("simulate_fork_during_execution", |(
2110 forked_validators,
2111 full_halt,
2112 effects_overrides,
2113 fork_probability,
2114 executor_path_only,
2115 ): (
2116 std::sync::Arc<
2117 std::sync::Mutex<std::collections::HashSet<sui_types::base_types::AuthorityName>>,
2118 >,
2119 bool,
2120 std::sync::Arc<std::sync::Mutex<std::collections::BTreeMap<String, String>>>,
2121 f32,
2122 bool,
2123 )| {
2124 #[cfg(msim)]
2125 if !executor_path_only || expected_effects_digest.is_some() {
2129 self.simulate_fork_during_execution(
2130 certificate,
2131 epoch_store,
2132 &mut effects,
2133 forked_validators,
2134 full_halt,
2135 effects_overrides,
2136 fork_probability,
2137 );
2138 }
2139 });
2140
2141 if let Some(expected) = expected_effects_digest
2142 && effects.digest() != expected.digest()
2143 {
2144 let expected_effects_digest = expected.digest();
2145 match self.debug_dump_transaction_state(
2147 &tx_digest,
2148 &effects,
2149 expected_effects_digest,
2150 &inner_temp_store,
2151 certificate,
2152 &self.config.state_debug_dump_config,
2153 ) {
2154 Ok(out_path) => {
2155 info!(
2156 "Dumped node state for transaction {} to {}",
2157 tx_digest,
2158 out_path.as_path().display().to_string()
2159 );
2160 }
2161 Err(e) => {
2162 error!("Error dumping state for transaction {}: {e}", tx_digest);
2163 }
2164 }
2165 let expected_effects = self
2166 .get_transaction_cache_reader()
2167 .get_effects(&expected_effects_digest);
2168 error!(
2169 ?tx_digest,
2170 ?expected,
2171 actual_effects = ?effects,
2172 expected_effects = ?expected_effects,
2173 "fork detected!"
2174 );
2175 if let Err(e) = self.checkpoint_store.record_transaction_fork_detected(
2176 tx_digest,
2177 expected_effects_digest,
2178 effects.digest(),
2179 expected.checkpoint_seq(),
2180 ) {
2181 error!("Failed to record transaction fork: {e}");
2182 }
2183
2184 fail_point_if!("kill_transaction_fork_node", || {
2185 #[cfg(msim)]
2186 {
2187 tracing::error!(
2188 fatal = true,
2189 "Fork recovery test: killing node due to transaction effects fork for digest: {}",
2190 tx_digest
2191 );
2192 sui_simulator::task::shutdown_current_node();
2193 }
2194 });
2195
2196 fatal!(
2197 "Transaction {} is expected to have effects digest {}, but got {}!",
2198 tx_digest,
2199 expected_effects_digest,
2200 effects.digest()
2201 );
2202 }
2203
2204 let unchanged_loaded_runtime_objects =
2205 crate::transaction_outputs::unchanged_loaded_runtime_objects(
2206 certificate.transaction_data(),
2207 &effects,
2208 &tracking_store.into_read_objects(),
2209 );
2210
2211 let _ = self
2213 .post_process_one_tx(certificate, &effects, &inner_temp_store, epoch_store)
2214 .tap_err(|e| {
2215 self.metrics.post_processing_total_failures.inc();
2216 error!(?tx_digest, "tx post processing failed: {e}");
2217 });
2218
2219 self.update_metrics(certificate, &inner_temp_store, &effects);
2220
2221 let transaction_outputs = TransactionOutputs::build_transaction_outputs(
2222 certificate.clone().into_unsigned(),
2223 effects,
2224 inner_temp_store,
2225 unchanged_loaded_runtime_objects,
2226 );
2227
2228 let elapsed = prepare_certificate_start_time.elapsed().as_micros() as f64;
2229 if elapsed > 0.0 {
2230 self.metrics.prepare_cert_gas_latency_ratio.observe(
2231 transaction_outputs
2232 .effects
2233 .gas_cost_summary()
2234 .computation_cost as f64
2235 / elapsed,
2236 );
2237 }
2238
2239 ExecutionOutput::Success((transaction_outputs, timings, execution_error_opt.err()))
2240 }
2241
2242 pub fn prepare_certificate_for_benchmark(
2243 &self,
2244 certificate: &VerifiedExecutableTransaction,
2245 input_objects: InputObjects,
2246 epoch_store: &Arc<AuthorityPerEpochStore>,
2247 ) -> SuiResult<(TransactionOutputs, Option<ExecutionError>)> {
2248 let lock = RwLock::new(epoch_store.epoch());
2249 let execution_guard = lock.try_read().unwrap();
2250
2251 let (transaction_outputs, _timings, execution_error_opt) = self
2252 .execute_certificate(
2253 &execution_guard,
2254 certificate,
2255 input_objects,
2256 None,
2257 ExecutionEnv::default(),
2258 epoch_store,
2259 )
2260 .unwrap();
2261 Ok((transaction_outputs, execution_error_opt))
2262 }
2263
2264 #[instrument(skip_all)]
2265 #[allow(clippy::type_complexity)]
2266 pub async fn dry_exec_transaction(
2267 &self,
2268 transaction: TransactionData,
2269 ) -> SuiResult<(
2270 DryRunTransactionBlockResponse,
2271 BTreeMap<ObjectID, (ObjectRef, Object, WriteKind)>,
2272 TransactionEffects,
2273 Option<ObjectID>,
2274 )> {
2275 let epoch_store = self.load_epoch_store_one_call_per_task();
2276 if !self.is_fullnode(&epoch_store) {
2277 return Err(SuiErrorKind::UnsupportedFeatureError {
2278 error: "dry-exec is only supported on fullnodes".to_string(),
2279 }
2280 .into());
2281 }
2282
2283 if transaction.kind().is_system_tx() {
2284 return Err(SuiErrorKind::UnsupportedFeatureError {
2285 error: "dry-exec does not support system transactions".to_string(),
2286 }
2287 .into());
2288 }
2289
2290 self.dry_exec_transaction_impl(&epoch_store, transaction)
2291 }
2292
2293 #[allow(clippy::type_complexity)]
2294 fn dry_exec_transaction_impl(
2295 &self,
2296 epoch_store: &AuthorityPerEpochStore,
2297 transaction: TransactionData,
2298 ) -> SuiResult<(
2299 DryRunTransactionBlockResponse,
2300 BTreeMap<ObjectID, (ObjectRef, Object, WriteKind)>,
2301 TransactionEffects,
2302 Option<ObjectID>,
2303 )> {
2304 let sim = self.simulate_transaction(
2309 transaction.clone(),
2310 TransactionChecks::Enabled,
2311 true,
2312 )?;
2313
2314 self.build_dry_run_response(epoch_store, transaction, sim)
2315 }
2316
2317 #[allow(clippy::type_complexity)]
2329 fn build_dry_run_response(
2330 &self,
2331 epoch_store: &AuthorityPerEpochStore,
2332 transaction: TransactionData,
2333 sim: SimulateTransactionResult,
2334 ) -> SuiResult<(
2335 DryRunTransactionBlockResponse,
2336 BTreeMap<ObjectID, (ObjectRef, Object, WriteKind)>,
2337 TransactionEffects,
2338 Option<ObjectID>,
2339 )> {
2340 let SimulateTransactionResult {
2341 effects,
2342 events,
2343 objects,
2344 execution_result,
2345 mock_gas_id,
2346 suggested_gas_price,
2347 ..
2348 } = sim;
2349
2350 let tx_digest = *effects.transaction_digest();
2351
2352 let written_with_kind: BTreeMap<ObjectID, (ObjectRef, Object, WriteKind)> = effects
2357 .created()
2358 .into_iter()
2359 .map(|(oref, _)| (oref, WriteKind::Create))
2360 .chain(
2361 effects
2362 .unwrapped()
2363 .into_iter()
2364 .map(|(oref, _)| (oref, WriteKind::Unwrap)),
2365 )
2366 .chain(
2367 effects
2368 .mutated()
2369 .into_iter()
2370 .map(|(oref, _)| (oref, WriteKind::Mutate)),
2371 )
2372 .filter_map(|(oref, kind)| {
2373 objects
2374 .get(&ObjectKey(oref.0, oref.1))
2375 .map(|obj| (oref.0, (oref, obj.clone(), kind)))
2376 })
2377 .collect();
2378
2379 let mut layout_resolver = epoch_store.executor().type_layout_resolver(
2383 epoch_store.protocol_config(),
2384 Box::new(OverlayBackingPackageStore::new(
2385 &objects,
2386 self.get_backing_package_store(),
2387 )),
2388 );
2389
2390 let execution_error_source = execution_result
2391 .as_ref()
2392 .err()
2393 .and_then(|e| e.source().as_ref().map(|e| e.to_string()));
2394
2395 let response = DryRunTransactionBlockResponse {
2396 suggested_gas_price,
2397 input: SuiTransactionBlockData::try_from_with_module_cache(
2398 transaction,
2399 &epoch_store.module_cache().clone(),
2400 )
2401 .map_err(|e| SuiErrorKind::TransactionSerializationError {
2402 error: format!("Failed to convert transaction to SuiTransactionBlockData: {e}"),
2403 })?,
2404 effects: effects.clone().try_into()?,
2405 events: SuiTransactionBlockEvents::try_from(
2406 events.unwrap_or_default(),
2407 tx_digest,
2408 None,
2409 layout_resolver.as_mut(),
2410 )?,
2411 object_changes: Vec::new(),
2414 balance_changes: Vec::new(),
2415 execution_error_source,
2416 };
2417
2418 Ok((response, written_with_kind, effects, mock_gas_id))
2419 }
2420
2421 pub fn simulate_transaction(
2422 &self,
2423 transaction: TransactionData,
2424 checks: TransactionChecks,
2425 allow_mock_gas_coin: bool,
2426 ) -> SuiResult<SimulateTransactionResult> {
2427 if transaction.kind().is_system_tx() {
2428 return Err(SuiErrorKind::UnsupportedFeatureError {
2429 error: "simulate does not support system transactions".to_string(),
2430 }
2431 .into());
2432 }
2433
2434 let epoch_store = self.load_epoch_store_one_call_per_task();
2435 if !self.is_fullnode(&epoch_store) {
2436 return Err(SuiErrorKind::UnsupportedFeatureError {
2437 error: "simulate is only supported on fullnodes".to_string(),
2438 }
2439 .into());
2440 }
2441
2442 if checks.disabled() && self.config.dev_inspect_disabled {
2443 return Err(SuiErrorKind::UnsupportedFeatureError {
2444 error: "simulate with checks disabled is not allowed on this node".to_string(),
2445 }
2446 .into());
2447 }
2448
2449 let transaction_deny_config = self
2450 .transaction_deny_config_manager
2451 .effective_config()
2452 .load();
2453 let epoch_data = epoch_store.epoch_start_config().epoch_data();
2454 let suggested_gas_price = self
2455 .congestion_tracker
2456 .get_suggested_gas_prices(&transaction);
2457
2458 crate::transaction_simulation::simulate_transaction(
2459 transaction,
2460 checks,
2461 allow_mock_gas_coin,
2462 suggested_gas_price,
2463 epoch_store.tx_validity_check_context(),
2464 epoch_data.epoch_id(),
2465 epoch_data.epoch_start_timestamp(),
2466 self.chain_identifier,
2467 transaction_deny_config.as_ref(),
2468 self.config.certificate_deny_config.certificate_deny_set(),
2469 &self.input_loader,
2470 self.get_backing_store().as_ref(),
2471 self.get_backing_package_store().as_ref(),
2472 epoch_store.simulate_executor().as_ref(),
2473 self.coin_reservation_resolver.as_ref(),
2474 self.get_account_funds_read().as_ref(),
2475 &self.config.verifier_signing_config,
2476 &self.metrics.bytecode_verifier_metrics,
2477 &self.metrics.execution_metrics,
2478 )
2479 }
2480
2481 #[instrument(skip_all)]
2483 pub async fn dev_inspect_transaction_block(
2484 &self,
2485 sender: SuiAddress,
2486 transaction_kind: TransactionKind,
2487 gas_price: Option<u64>,
2488 gas_budget: Option<u64>,
2489 gas_sponsor: Option<SuiAddress>,
2490 gas_objects: Option<Vec<ObjectRef>>,
2491 show_raw_txn_data_and_effects: Option<bool>,
2492 skip_checks: Option<bool>,
2493 ) -> SuiResult<DevInspectResults> {
2494 let epoch_store = self.load_epoch_store_one_call_per_task();
2495 let protocol_config = epoch_store.protocol_config();
2496 let reference_gas_price = epoch_store.reference_gas_price();
2497
2498 let skip_checks = skip_checks.unwrap_or(true);
2499 let show_raw_txn_data_and_effects = show_raw_txn_data_and_effects.unwrap_or(false);
2500
2501 let price = gas_price.unwrap_or(reference_gas_price);
2503 let budget = gas_budget.unwrap_or(protocol_config.max_tx_gas());
2504 let owner = gas_sponsor.unwrap_or(sender);
2505 let payment = gas_objects.unwrap_or_default();
2506 let transaction = TransactionData::V1(TransactionDataV1 {
2507 kind: transaction_kind,
2508 sender,
2509 gas_data: GasData {
2510 payment,
2511 owner,
2512 price,
2513 budget,
2514 },
2515 expiration: TransactionExpiration::None,
2516 });
2517
2518 let raw_txn_data = if show_raw_txn_data_and_effects {
2521 bcs::to_bytes(&transaction).map_err(|_| {
2522 SuiErrorKind::TransactionSerializationError {
2523 error: "Failed to serialize transaction during dev inspect".to_string(),
2524 }
2525 })?
2526 } else {
2527 vec![]
2528 };
2529
2530 let checks = if skip_checks {
2536 TransactionChecks::Disabled
2537 } else {
2538 TransactionChecks::Enabled
2539 };
2540 let sim =
2541 self.simulate_transaction(transaction, checks, true)?;
2542
2543 let raw_effects = if show_raw_txn_data_and_effects {
2544 bcs::to_bytes(&sim.effects).map_err(|_| {
2545 SuiErrorKind::TransactionSerializationError {
2546 error: "Failed to serialize transaction effects during dev inspect".to_string(),
2547 }
2548 })?
2549 } else {
2550 vec![]
2551 };
2552
2553 let mut layout_resolver = epoch_store.executor().type_layout_resolver(
2557 epoch_store.protocol_config(),
2558 Box::new(OverlayBackingPackageStore::new(
2559 &sim.objects,
2560 self.get_backing_package_store(),
2561 )),
2562 );
2563
2564 DevInspectResults::new(
2565 sim.effects,
2566 sim.events.unwrap_or_default(),
2567 sim.execution_result,
2568 raw_txn_data,
2569 raw_effects,
2570 layout_resolver.as_mut(),
2571 )
2572 }
2573
2574 pub fn reference_gas_price_for_testing(&self) -> Result<u64, anyhow::Error> {
2576 let epoch_store = self.epoch_store_for_testing();
2577 Ok(epoch_store.reference_gas_price())
2578 }
2579
2580 pub fn is_tx_already_executed(&self, digest: &TransactionDigest) -> bool {
2581 self.get_transaction_cache_reader()
2582 .is_tx_already_executed(digest)
2583 }
2584
2585 #[instrument(level = "debug", skip_all, err(level = "debug"))]
2586 fn index_tx(
2587 sequence: u64,
2588 backing_package_store: &Arc<dyn BackingPackageStore + Send + Sync>,
2589 object_store: &Arc<dyn ObjectStore + Send + Sync>,
2590 indexes: &IndexStore,
2591 digest: &TransactionDigest,
2592 cert: &VerifiedExecutableTransaction,
2594 effects: &TransactionEffects,
2595 events: &TransactionEvents,
2596 timestamp_ms: u64,
2597 tx_coins: Option<TxCoins>,
2598 written: &WrittenObjects,
2599 inner_temporary_store: &InnerTemporaryStore,
2600 epoch_store: &Arc<AuthorityPerEpochStore>,
2601 acquire_locks: bool,
2602 ) -> SuiResult<(StagedBatch, IndexStoreCacheUpdatesWithLocks)> {
2603 let changes = Self::process_object_index(backing_package_store, object_store, effects, written, inner_temporary_store, epoch_store)
2604 .tap_err(|e| warn!(tx_digest=?digest, "Failed to process object index, index_tx is skipped: {e}"))?;
2605
2606 indexes.index_tx(
2607 sequence,
2608 cert.data().intent_message().value.sender(),
2609 cert.data()
2610 .intent_message()
2611 .value
2612 .input_objects()?
2613 .iter()
2614 .map(|o| o.object_id()),
2615 effects
2616 .all_changed_objects()
2617 .into_iter()
2618 .map(|(obj_ref, owner, _kind)| (obj_ref, owner)),
2619 cert.data()
2620 .intent_message()
2621 .value
2622 .move_calls()
2623 .into_iter()
2624 .map(|(_cmd_idx, package, module, function)| {
2625 (*package, module.to_owned(), function.to_owned())
2626 }),
2627 events,
2628 changes,
2629 digest,
2630 timestamp_ms,
2631 tx_coins,
2632 effects.accumulator_events(),
2633 acquire_locks,
2634 )
2635 }
2636
2637 #[cfg(msim)]
2638 fn simulate_fork_during_execution(
2639 &self,
2640 certificate: &VerifiedExecutableTransaction,
2641 epoch_store: &Arc<AuthorityPerEpochStore>,
2642 effects: &mut TransactionEffects,
2643 forked_validators: std::sync::Arc<
2644 std::sync::Mutex<std::collections::HashSet<sui_types::base_types::AuthorityName>>,
2645 >,
2646 full_halt: bool,
2647 effects_overrides: std::sync::Arc<
2648 std::sync::Mutex<std::collections::BTreeMap<String, String>>,
2649 >,
2650 fork_probability: f32,
2651 ) {
2652 static TOTAL_FAILING_STAKE: std::sync::Mutex<u64> = std::sync::Mutex::new(0);
2653 if !certificate.data().intent_message().value.is_system_tx() {
2654 let committee = epoch_store.committee();
2655 let cur_stake = (**committee).weight(&self.name);
2656 if cur_stake > 0 {
2657 {
2658 let mut total_stake = TOTAL_FAILING_STAKE.lock().unwrap();
2659 let total_stake = &mut *total_stake;
2660 let already_forked = forked_validators
2661 .lock()
2662 .ok()
2663 .map(|set| set.contains(&self.name))
2664 .unwrap_or(false);
2665
2666 if !already_forked {
2667 let should_fork = if full_halt {
2668 *total_stake <= committee.validity_threshold()
2670 } else {
2671 *total_stake + cur_stake < committee.validity_threshold()
2673 };
2674
2675 if should_fork {
2676 *total_stake += cur_stake;
2677
2678 if let Ok(mut external_set) = forked_validators.lock() {
2679 external_set.insert(self.name);
2680 info!("forked_validators: {:?}", external_set);
2681 }
2682 }
2683 }
2684
2685 if let Ok(external_set) = forked_validators.lock() {
2686 if external_set.contains(&self.name) {
2687 let tx_digest = certificate.digest().to_string();
2693 if let Ok(mut overrides) = effects_overrides.lock() {
2694 if overrides.contains_key(&tx_digest)
2695 || overrides.is_empty()
2696 && sui_simulator::random::deterministic_probability(
2697 &tx_digest,
2698 fork_probability,
2699 )
2700 {
2701 let original_effects_digest = effects.digest().to_string();
2702 overrides
2703 .insert(tx_digest.clone(), original_effects_digest.clone());
2704 info!(
2705 ?tx_digest,
2706 ?original_effects_digest,
2707 "Captured forked effects digest for transaction"
2708 );
2709 effects.gas_cost_summary_mut_for_testing().computation_cost +=
2710 1;
2711 }
2712 }
2713 }
2714 }
2715 }
2716 }
2717 }
2718 }
2719
2720 fn process_object_index(
2721 backing_package_store: &Arc<dyn BackingPackageStore + Send + Sync>,
2722 object_store: &Arc<dyn ObjectStore + Send + Sync>,
2723 effects: &TransactionEffects,
2724 written: &WrittenObjects,
2725 inner_temporary_store: &InnerTemporaryStore,
2726 epoch_store: &Arc<AuthorityPerEpochStore>,
2727 ) -> SuiResult<ObjectIndexChanges> {
2728 let mut layout_resolver = epoch_store.executor().type_layout_resolver(
2729 epoch_store.protocol_config(),
2730 Box::new(PackageStoreWithFallback::new(
2731 inner_temporary_store,
2732 backing_package_store,
2733 )),
2734 );
2735
2736 let modified_at_version = effects
2737 .modified_at_versions()
2738 .into_iter()
2739 .collect::<HashMap<_, _>>();
2740
2741 let tx_digest = effects.transaction_digest();
2742 let mut deleted_owners = vec![];
2743 let mut deleted_dynamic_fields = vec![];
2744 for (id, _, _) in effects.deleted().into_iter().chain(effects.wrapped()) {
2745 let old_version = modified_at_version.get(&id).unwrap();
2746 match Self::get_owner_at_version(object_store, &id, *old_version).unwrap_or_else(
2749 |e| panic!("tx_digest={:?}, error processing object owner index, cannot find owner for object {:?} at version {:?}. Err: {:?}", tx_digest, id, old_version, e),
2750 ) {
2751 Owner::AddressOwner(addr)
2752 | Owner::ConsensusAddressOwner { owner: addr, .. } => deleted_owners.push((addr, id)),
2753 Owner::ObjectOwner(object_id) => {
2754 deleted_dynamic_fields.push((ObjectID::from(object_id), id))
2755 }
2756 _ => {}
2757 }
2758 }
2759
2760 let mut new_owners = vec![];
2761 let mut new_dynamic_fields = vec![];
2762
2763 for (oref, owner, kind) in effects.all_changed_objects() {
2764 let id = &oref.0;
2765 if let WriteKind::Mutate = kind {
2767 let Some(old_version) = modified_at_version.get(id) else {
2768 panic!(
2769 "tx_digest={:?}, error processing object owner index, cannot find modified at version for mutated object [{id}].",
2770 tx_digest
2771 );
2772 };
2773 let Some(old_object) = object_store.get_object_by_key(id, *old_version) else {
2776 panic!(
2777 "tx_digest={:?}, error processing object owner index, cannot find owner for object {:?} at version {:?}",
2778 tx_digest, id, old_version
2779 );
2780 };
2781 if old_object.owner != owner {
2782 match old_object.owner {
2783 Owner::AddressOwner(addr)
2784 | Owner::ConsensusAddressOwner { owner: addr, .. } => {
2785 deleted_owners.push((addr, *id));
2786 }
2787 Owner::ObjectOwner(object_id) => {
2788 deleted_dynamic_fields.push((ObjectID::from(object_id), *id))
2789 }
2790 _ => {}
2791 }
2792 }
2793 }
2794
2795 match owner {
2796 Owner::AddressOwner(addr) | Owner::ConsensusAddressOwner { owner: addr, .. } => {
2797 let new_object = written.get(id).unwrap_or_else(
2799 || panic!("tx_digest={:?}, error processing object owner index, written does not contain object {:?}", tx_digest, id)
2800 );
2801 assert_eq!(
2802 new_object.version(),
2803 oref.1,
2804 "tx_digest={:?} error processing object owner index, object {:?} from written has mismatched version. Actual: {}, expected: {}",
2805 tx_digest,
2806 id,
2807 new_object.version(),
2808 oref.1
2809 );
2810
2811 let type_ = new_object
2812 .type_()
2813 .map(|type_| ObjectType::Struct(type_.clone()))
2814 .unwrap_or(ObjectType::Package);
2815
2816 new_owners.push((
2817 (addr, *id),
2818 ObjectInfo {
2819 object_id: *id,
2820 version: oref.1,
2821 digest: oref.2,
2822 type_,
2823 owner,
2824 previous_transaction: *effects.transaction_digest(),
2825 },
2826 ));
2827 }
2828 Owner::ObjectOwner(owner) => {
2829 let new_object = written.get(id).unwrap_or_else(
2830 || panic!("tx_digest={:?}, error processing object owner index, written does not contain object {:?}", tx_digest, id)
2831 );
2832 assert_eq!(
2833 new_object.version(),
2834 oref.1,
2835 "tx_digest={:?} error processing object owner index, object {:?} from written has mismatched version. Actual: {}, expected: {}",
2836 tx_digest,
2837 id,
2838 new_object.version(),
2839 oref.1
2840 );
2841
2842 let Some(df_info) = Self::try_create_dynamic_field_info(
2843 object_store,
2844 new_object,
2845 written,
2846 layout_resolver.as_mut(),
2847 )
2848 .unwrap_or_else(|e| {
2849 error!(
2850 "try_create_dynamic_field_info should not fail, {}, new_object={:?}",
2851 e, new_object
2852 );
2853 None
2854 }) else {
2855 continue;
2857 };
2858 new_dynamic_fields.push(((ObjectID::from(owner), *id), df_info))
2859 }
2860 _ => {}
2861 }
2862 }
2863
2864 Ok(ObjectIndexChanges {
2865 deleted_owners,
2866 deleted_dynamic_fields,
2867 new_owners,
2868 new_dynamic_fields,
2869 })
2870 }
2871
2872 fn try_create_dynamic_field_info(
2873 object_store: &Arc<dyn ObjectStore + Send + Sync>,
2874 o: &Object,
2875 written: &WrittenObjects,
2876 resolver: &mut dyn LayoutResolver,
2877 ) -> SuiResult<Option<DynamicFieldInfo>> {
2878 let Some(move_object) = o.data.try_as_move().cloned() else {
2880 return Ok(None);
2881 };
2882
2883 if !move_object.type_().is_dynamic_field() {
2885 return Ok(None);
2886 }
2887
2888 let layout = resolver
2889 .get_annotated_layout(&move_object.type_().clone().into())?
2890 .into_layout();
2891
2892 let field =
2893 DFV::FieldVisitor::deserialize(move_object.contents(), &layout).map_err(|e| {
2894 SuiErrorKind::ObjectDeserializationError {
2895 error: e.to_string(),
2896 }
2897 })?;
2898
2899 let type_ = field.kind;
2900 let name_type: TypeTag = field.name_layout.into();
2901 let bcs_name = field.name_bytes.to_owned();
2902
2903 let name_value = BoundedVisitor::deserialize_value(field.name_bytes, field.name_layout)
2904 .map_err(|e| {
2905 warn!("{e}");
2906 SuiErrorKind::ObjectDeserializationError {
2907 error: e.to_string(),
2908 }
2909 })?;
2910
2911 let name = DynamicFieldName {
2912 type_: name_type,
2913 value: SuiMoveValue::from(name_value).to_json_value(),
2914 };
2915
2916 let value_metadata = field.value_metadata().map_err(|e| {
2917 warn!("{e}");
2918 SuiErrorKind::ObjectDeserializationError {
2919 error: e.to_string(),
2920 }
2921 })?;
2922
2923 Ok(Some(match value_metadata {
2924 DFV::ValueMetadata::DynamicField(object_type) => DynamicFieldInfo {
2925 name,
2926 bcs_name,
2927 type_,
2928 object_type: object_type.to_canonical_string(true),
2929 object_id: o.id(),
2930 version: o.version(),
2931 digest: o.digest(),
2932 },
2933
2934 DFV::ValueMetadata::DynamicObjectField(object_id) => {
2935 let (version, digest, object_type) = if let Some(object) = written.get(&object_id) {
2939 let version = object.version();
2940 let digest = object.digest();
2941 let object_type = object.data.type_().unwrap().clone();
2942 (version, digest, object_type)
2943 } else {
2944 let object = object_store
2946 .get_object_by_key(&object_id, o.version())
2947 .ok_or_else(|| UserInputError::ObjectNotFound {
2948 object_id,
2949 version: Some(o.version()),
2950 })?;
2951 let version = object.version();
2952 let digest = object.digest();
2953 let object_type = object.data.type_().unwrap().clone();
2954 (version, digest, object_type)
2955 };
2956
2957 DynamicFieldInfo {
2958 name,
2959 bcs_name,
2960 type_,
2961 object_type: object_type.to_string(),
2962 object_id,
2963 version,
2964 digest,
2965 }
2966 }
2967 }))
2968 }
2969
2970 #[instrument(level = "trace", skip_all, err(level = "debug"))]
2971 fn post_process_one_tx(
2972 &self,
2973 certificate: &VerifiedExecutableTransaction,
2974 effects: &TransactionEffects,
2975 inner_temporary_store: &InnerTemporaryStore,
2976 epoch_store: &Arc<AuthorityPerEpochStore>,
2977 ) -> SuiResult {
2978 let Some(indexes) = &self.indexes else {
2979 return Ok(());
2980 };
2981
2982 let tx_digest = *certificate.digest();
2983
2984 let sequence = indexes.allocate_sequence_number();
2986
2987 if self.config.sync_post_process_one_tx {
2988 let result = Self::post_process_one_tx_impl(
2993 sequence,
2994 indexes,
2995 &self.subscription_handler,
2996 &self.metrics,
2997 self.name,
2998 self.get_backing_package_store(),
2999 self.get_object_store(),
3000 certificate,
3001 effects,
3002 inner_temporary_store,
3003 epoch_store,
3004 true, );
3006
3007 match result {
3008 Ok((raw_batch, cache_updates_with_locks)) => {
3009 let mut db_batch = indexes.new_db_batch();
3010 db_batch
3011 .concat(vec![raw_batch])
3012 .expect("failed to absorb raw index batch");
3013 let IndexStoreCacheUpdatesWithLocks { _locks, inner } =
3015 cache_updates_with_locks;
3016 indexes
3017 .commit_index_batch(db_batch, vec![inner])
3018 .expect("failed to commit index batch");
3019 }
3020 Err(e) => {
3021 self.metrics.post_processing_total_failures.inc();
3022 error!(?tx_digest, "tx post processing failed: {e}");
3023 return Err(e);
3024 }
3025 }
3026
3027 return Ok(());
3028 }
3029
3030 let (done_tx, done_rx) = tokio::sync::oneshot::channel::<PostProcessingOutput>();
3031 self.pending_post_processing.insert(tx_digest, done_rx);
3032
3033 let indexes = indexes.clone();
3034 let subscription_handler = self.subscription_handler.clone();
3035 let metrics = self.metrics.clone();
3036 let name = self.name;
3037 let backing_package_store = self.get_backing_package_store().clone();
3038 let object_store = self.get_object_store().clone();
3039 let semaphore = self.post_processing_semaphore.clone();
3040
3041 let certificate = certificate.clone();
3042 let effects = effects.clone();
3043 let inner_temporary_store = inner_temporary_store.clone();
3044 let epoch_store = epoch_store.clone();
3045
3046 tokio::spawn(async move {
3048 let permit = {
3049 let _scope = monitored_scope("Execution::post_process_one_tx::semaphore_acquire");
3050 semaphore
3051 .acquire_owned()
3052 .await
3053 .expect("post-processing semaphore should not be closed")
3054 };
3055
3056 let _ = tokio::task::spawn_blocking(move || {
3057 let _permit = permit;
3058
3059 let result = Self::post_process_one_tx_impl(
3060 sequence,
3061 &indexes,
3062 &subscription_handler,
3063 &metrics,
3064 name,
3065 &backing_package_store,
3066 &object_store,
3067 &certificate,
3068 &effects,
3069 &inner_temporary_store,
3070 &epoch_store,
3071 false, );
3073
3074 match result {
3075 Ok((raw_batch, cache_updates_with_locks)) => {
3076 fail_point!("crash-after-post-process-one-tx");
3077 let output = (raw_batch, cache_updates_with_locks.into_inner());
3078 let _ = done_tx.send(output);
3079 }
3080 Err(e) => {
3081 metrics.post_processing_total_failures.inc();
3082 error!(?tx_digest, "tx post processing failed: {e}");
3083 }
3084 }
3085 })
3086 .await;
3087 });
3088
3089 Ok(())
3090 }
3091
3092 fn post_process_one_tx_impl(
3093 sequence: u64,
3094 indexes: &Arc<IndexStore>,
3095 subscription_handler: &Arc<SubscriptionHandler>,
3096 metrics: &Arc<AuthorityMetrics>,
3097 name: AuthorityName,
3098 backing_package_store: &Arc<dyn BackingPackageStore + Send + Sync>,
3099 object_store: &Arc<dyn ObjectStore + Send + Sync>,
3100 certificate: &VerifiedExecutableTransaction,
3101 effects: &TransactionEffects,
3102 inner_temporary_store: &InnerTemporaryStore,
3103 epoch_store: &Arc<AuthorityPerEpochStore>,
3104 acquire_locks: bool,
3105 ) -> SuiResult<(StagedBatch, IndexStoreCacheUpdatesWithLocks)> {
3106 let _scope = monitored_scope("Execution::post_process_one_tx");
3107
3108 let tx_digest = certificate.digest();
3109 let timestamp_ms = Self::unixtime_now_ms();
3110 let events = &inner_temporary_store.events;
3111 let written = &inner_temporary_store.written;
3112 let tx_coins = Self::fullnode_only_get_tx_coins_for_indexing(
3113 name,
3114 object_store,
3115 effects,
3116 inner_temporary_store,
3117 epoch_store,
3118 );
3119
3120 let (raw_batch, cache_updates) = Self::index_tx(
3121 sequence,
3122 backing_package_store,
3123 object_store,
3124 indexes,
3125 tx_digest,
3126 certificate,
3127 effects,
3128 events,
3129 timestamp_ms,
3130 tx_coins,
3131 written,
3132 inner_temporary_store,
3133 epoch_store,
3134 acquire_locks,
3135 )
3136 .tap_ok(|_| metrics.post_processing_total_tx_indexed.inc())
3137 .tap_err(|e| error!(?tx_digest, "Post processing - Couldn't index tx: {e}"))
3138 .expect("Indexing tx should not fail");
3139
3140 let effects: SuiTransactionBlockEffects = effects.clone().try_into()?;
3141 let events = Self::make_transaction_block_events(
3142 backing_package_store,
3143 events.clone(),
3144 *tx_digest,
3145 timestamp_ms,
3146 epoch_store,
3147 inner_temporary_store,
3148 )?;
3149 subscription_handler
3151 .process_tx(certificate.data().transaction_data(), &effects, &events)
3152 .tap_ok(|_| metrics.post_processing_total_tx_had_event_processed.inc())
3153 .tap_err(|e| {
3154 warn!(
3155 ?tx_digest,
3156 "Post processing - Couldn't process events for tx: {}", e
3157 )
3158 })?;
3159
3160 metrics
3161 .post_processing_total_events_emitted
3162 .inc_by(events.data.len() as u64);
3163
3164 Ok((raw_batch, cache_updates))
3165 }
3166
3167 fn make_transaction_block_events(
3168 backing_package_store: &Arc<dyn BackingPackageStore + Send + Sync>,
3169 transaction_events: TransactionEvents,
3170 digest: TransactionDigest,
3171 timestamp_ms: u64,
3172 epoch_store: &Arc<AuthorityPerEpochStore>,
3173 inner_temporary_store: &InnerTemporaryStore,
3174 ) -> SuiResult<SuiTransactionBlockEvents> {
3175 let mut layout_resolver = epoch_store.executor().type_layout_resolver(
3176 epoch_store.protocol_config(),
3177 Box::new(PackageStoreWithFallback::new(
3178 inner_temporary_store,
3179 backing_package_store,
3180 )),
3181 );
3182 SuiTransactionBlockEvents::try_from(
3183 transaction_events,
3184 digest,
3185 Some(timestamp_ms),
3186 layout_resolver.as_mut(),
3187 )
3188 }
3189
3190 pub fn unixtime_now_ms() -> u64 {
3191 let now = SystemTime::now()
3192 .duration_since(UNIX_EPOCH)
3193 .expect("Time went backwards")
3194 .as_millis();
3195 u64::try_from(now).expect("Travelling in time machine")
3196 }
3197
3198 #[instrument(level = "trace", skip_all)]
3202 pub async fn handle_transaction_info_request(
3203 &self,
3204 request: TransactionInfoRequest,
3205 ) -> SuiResult<TransactionInfoResponse> {
3206 let epoch_store = self.load_epoch_store_one_call_per_task();
3207 let (transaction, status) = self
3208 .get_transaction_status(&request.transaction_digest, &epoch_store)?
3209 .ok_or(SuiErrorKind::TransactionNotFound {
3210 digest: request.transaction_digest,
3211 })?;
3212 Ok(TransactionInfoResponse {
3213 transaction,
3214 status,
3215 })
3216 }
3217
3218 #[instrument(level = "trace", skip_all)]
3219 pub async fn handle_object_info_request(
3220 &self,
3221 request: ObjectInfoRequest,
3222 ) -> SuiResult<ObjectInfoResponse> {
3223 let requested_object_seq = match request.request_kind {
3224 ObjectInfoRequestKind::LatestObjectInfo => {
3225 let (_, seq, _) =
3226 self.get_object_or_tombstone(request.object_id)
3227 .ok_or_else(|| {
3228 SuiError::from(UserInputError::ObjectNotFound {
3229 object_id: request.object_id,
3230 version: None,
3231 })
3232 })?;
3233 seq
3234 }
3235 ObjectInfoRequestKind::PastObjectInfoDebug(seq) => seq,
3236 };
3237
3238 let object = self
3239 .get_object_store()
3240 .get_object_by_key(&request.object_id, requested_object_seq)
3241 .ok_or_else(|| {
3242 SuiError::from(UserInputError::ObjectNotFound {
3243 object_id: request.object_id,
3244 version: Some(requested_object_seq),
3245 })
3246 })?;
3247
3248 let layout = if let (LayoutGenerationOption::Generate, Some(move_obj)) =
3249 (request.generate_layout, object.data.try_as_move())
3250 {
3251 let epoch_store = self.load_epoch_store_one_call_per_task();
3252 Some(into_struct_layout(
3253 epoch_store
3254 .executor()
3255 .type_layout_resolver(
3256 epoch_store.protocol_config(),
3257 Box::new(self.get_backing_package_store().as_ref()),
3258 )
3259 .get_annotated_layout(&move_obj.type_().clone().into())?,
3260 )?)
3261 } else {
3262 None
3263 };
3264
3265 Ok(ObjectInfoResponse {
3266 object,
3267 layout,
3268 lock_for_debugging: None,
3271 })
3272 }
3273
3274 #[instrument(level = "trace", skip_all)]
3275 pub fn handle_checkpoint_request(
3276 &self,
3277 request: &CheckpointRequest,
3278 ) -> SuiResult<CheckpointResponse> {
3279 let summary = match request.sequence_number {
3280 Some(seq) => self
3281 .checkpoint_store
3282 .get_checkpoint_by_sequence_number(seq)?,
3283 None => self.checkpoint_store.get_latest_certified_checkpoint()?,
3284 }
3285 .map(|v| v.into_inner());
3286 let contents = match &summary {
3287 Some(s) => self
3288 .checkpoint_store
3289 .get_checkpoint_contents(&s.content_digest)?,
3290 None => None,
3291 };
3292 Ok(CheckpointResponse {
3293 checkpoint: summary,
3294 contents,
3295 })
3296 }
3297
3298 #[instrument(level = "trace", skip_all)]
3299 pub fn handle_checkpoint_request_v2(
3300 &self,
3301 request: &CheckpointRequestV2,
3302 ) -> SuiResult<CheckpointResponseV2> {
3303 let summary = if request.certified {
3304 let summary = match request.sequence_number {
3305 Some(seq) => self
3306 .checkpoint_store
3307 .get_checkpoint_by_sequence_number(seq)?,
3308 None => self.checkpoint_store.get_latest_certified_checkpoint()?,
3309 }
3310 .map(|v| v.into_inner());
3311 summary.map(CheckpointSummaryResponse::Certified)
3312 } else {
3313 let summary = match request.sequence_number {
3314 Some(seq) => self.checkpoint_store.get_locally_computed_checkpoint(seq)?,
3315 None => self
3316 .checkpoint_store
3317 .get_latest_locally_computed_checkpoint()?,
3318 };
3319 summary.map(CheckpointSummaryResponse::Pending)
3320 };
3321 let contents = match &summary {
3322 Some(s) => self
3323 .checkpoint_store
3324 .get_checkpoint_contents(&s.content_digest())?,
3325 None => None,
3326 };
3327 Ok(CheckpointResponseV2 {
3328 checkpoint: summary,
3329 contents,
3330 })
3331 }
3332
3333 fn check_protocol_version(
3334 supported_protocol_versions: SupportedProtocolVersions,
3335 current_version: ProtocolVersion,
3336 ) {
3337 info!("current protocol version is now {:?}", current_version);
3338 info!("supported versions are: {:?}", supported_protocol_versions);
3339 if !supported_protocol_versions.is_version_supported(current_version) {
3340 let msg = format!(
3341 "Unsupported protocol version. The network is at {:?}, but this SuiNode only supports: {:?}. Shutting down.",
3342 current_version, supported_protocol_versions,
3343 );
3344
3345 error!("{}", msg);
3346 eprintln!("{}", msg);
3347
3348 #[cfg(not(msim))]
3349 std::process::exit(1);
3350
3351 #[cfg(msim)]
3352 sui_simulator::task::shutdown_current_node();
3353 }
3354 }
3355
3356 #[allow(clippy::disallowed_methods)] #[allow(clippy::too_many_arguments)]
3358 pub async fn new(
3359 name: AuthorityName,
3360 secret: StableSyncAuthoritySigner,
3361 supported_protocol_versions: SupportedProtocolVersions,
3362 store: Arc<AuthorityStore>,
3363 execution_cache_trait_pointers: ExecutionCacheTraitPointers,
3364 epoch_store: Arc<AuthorityPerEpochStore>,
3365 committee_store: Arc<CommitteeStore>,
3366 indexes: Option<Arc<IndexStore>>,
3367 rpc_store: Option<RpcStore>,
3368 checkpoint_store: Arc<CheckpointStore>,
3369 prometheus_registry: &Registry,
3370 genesis_objects: &[Object],
3371 db_checkpoint_config: &DBCheckpointConfig,
3372 config: NodeConfig,
3373 chain_identifier: ChainIdentifier,
3374 policy_config: Option<PolicyConfig>,
3375 firewall_config: Option<RemoteFirewallConfig>,
3376 pruner_watermarks: Arc<PrunerWatermarks>,
3377 ) -> Arc<Self> {
3378 Self::check_protocol_version(supported_protocol_versions, epoch_store.protocol_version());
3379
3380 let metrics = Arc::new(AuthorityMetrics::new(prometheus_registry));
3381 let (tx_ready_certificates, rx_ready_certificates) = unbounded_channel();
3382 let execution_scheduler = Arc::new(ExecutionScheduler::new(
3383 execution_cache_trait_pointers.object_cache_reader.clone(),
3384 execution_cache_trait_pointers.account_funds_read.clone(),
3385 execution_cache_trait_pointers
3386 .transaction_cache_reader
3387 .clone(),
3388 tx_ready_certificates,
3389 &epoch_store,
3390 config.funds_withdraw_scheduler_type,
3391 metrics.clone(),
3392 prometheus_registry,
3393 ));
3394 let (tx_execution_shutdown, rx_execution_shutdown) = oneshot::channel();
3395
3396 let _authority_per_epoch_pruner = AuthorityPerEpochStorePruner::new(
3397 epoch_store.get_parent_path(),
3398 &config.authority_store_pruning_config,
3399 );
3400 let _pruner = AuthorityStorePruner::new(
3401 store.perpetual_tables.clone(),
3402 checkpoint_store.clone(),
3403 rpc_store,
3404 indexes.clone(),
3405 config.authority_store_pruning_config.clone(),
3406 epoch_store.committee().authority_exists(&name),
3407 epoch_store.epoch_start_state().epoch_duration_ms(),
3408 prometheus_registry,
3409 pruner_watermarks,
3410 );
3411 let input_loader =
3412 TransactionInputLoader::new(execution_cache_trait_pointers.object_cache_reader.clone());
3413 let epoch = epoch_store.epoch();
3414 let traffic_controller_metrics =
3415 Arc::new(TrafficControllerMetrics::new(prometheus_registry));
3416 let traffic_controller = if let Some(policy_config) = policy_config {
3417 Some(Arc::new(
3418 TrafficController::init(
3419 policy_config,
3420 traffic_controller_metrics,
3421 firewall_config.clone(),
3422 )
3423 .await,
3424 ))
3425 } else {
3426 None
3427 };
3428
3429 let fork_recovery_state = config.fork_recovery.as_ref().map(|fork_config| {
3430 ForkRecoveryState::new(Some(fork_config))
3431 .expect("Failed to initialize fork recovery state")
3432 });
3433
3434 let coin_reservation_resolver = Arc::new(CachingCoinReservationResolver::new(
3435 execution_cache_trait_pointers
3436 .runtime_object_resolver
3437 .clone(),
3438 ));
3439
3440 let object_funds_checker_metrics =
3441 Arc::new(ObjectFundsCheckerMetrics::new(prometheus_registry));
3442
3443 let transaction_deny_config_manager = TransactionDenyConfigManager::new(
3444 name,
3445 config.transaction_deny_config.clone(),
3446 config.peer_deny_sync_config.clone(),
3447 epoch_store.committee().clone(),
3448 store.perpetual_tables.clone(),
3449 prometheus_registry,
3450 )
3451 .expect("Failed to initialize TransactionDenyConfigManager");
3452 if let Err(e) =
3454 transaction_deny_config_manager.update_for_committee(epoch_store.committee().clone())
3455 {
3456 warn!(
3457 "Initial update_for_committee failed during AuthorityState init: {:?}",
3458 e
3459 );
3460 }
3461
3462 let state = Arc::new(AuthorityState {
3463 name,
3464 secret,
3465 execution_lock: RwLock::new(epoch),
3466 epoch_store: ArcSwap::new(epoch_store.clone()),
3467 input_loader,
3468 execution_cache_trait_pointers,
3469 coin_reservation_resolver,
3470 indexes,
3471 subscription_handler: Arc::new(SubscriptionHandler::new(prometheus_registry)),
3472 checkpoint_store,
3473 committee_store,
3474 execution_scheduler,
3475 tx_execution_shutdown: Mutex::new(Some(tx_execution_shutdown)),
3476 metrics,
3477 _pruner,
3478 _authority_per_epoch_pruner,
3479 db_checkpoint_config: db_checkpoint_config.clone(),
3480 config,
3481 overload_info: AuthorityOverloadInfo::default(),
3482 chain_identifier,
3483 congestion_tracker: Arc::new(CongestionTracker::new()),
3484 consensus_gasless_counter: Arc::new(ConsensusGaslessCounter::default()),
3485 traffic_controller,
3486 fork_recovery_state,
3487 notify_epoch: tokio::sync::watch::channel(epoch).0,
3488 object_funds_checker: ArcSwapOption::empty(),
3489 unsettled_object_withdrawals: Arc::new(UnsettledObjectWithdrawals::new(
3493 object_funds_checker_metrics.clone(),
3494 )),
3495 object_funds_checker_metrics,
3496 pending_post_processing: Arc::new(DashMap::new()),
3497 post_processing_semaphore: Arc::new(tokio::sync::Semaphore::new(num_cpus::get())),
3498 transaction_deny_config_manager,
3499 });
3500 state.init_object_funds_checker().await;
3501
3502 let authority_state = Arc::downgrade(&state);
3504 spawn_monitored_task!(execution_process(
3505 authority_state,
3506 rx_ready_certificates,
3507 rx_execution_shutdown,
3508 ));
3509 state
3511 .create_owner_index_if_empty(genesis_objects, &epoch_store)
3512 .expect("Error indexing genesis objects.");
3513
3514 if epoch_store
3515 .protocol_config()
3516 .enable_multi_epoch_transaction_expiration()
3517 && epoch_store.epoch() > 0
3518 {
3519 use typed_store::Map;
3520 let previous_epoch = epoch_store.epoch() - 1;
3521 let start_key = (previous_epoch, TransactionDigest::ZERO);
3522 let end_key = (previous_epoch + 1, TransactionDigest::ZERO);
3523 let has_previous_epoch_data = store
3524 .perpetual_tables
3525 .executed_transaction_digests
3526 .safe_range_iter(start_key..end_key)
3527 .next()
3528 .is_some();
3529
3530 if !has_previous_epoch_data {
3531 panic!(
3532 "enable_multi_epoch_transaction_expiration is enabled but no transaction data found for previous epoch {}. \
3533 This indicates the node was restored using an old version of sui-tool that does not backfill the table. \
3534 Please restore from a snapshot using the latest version of sui-tool.",
3535 previous_epoch
3536 );
3537 }
3538 }
3539
3540 state
3541 }
3542
3543 async fn init_object_funds_checker(&self) {
3544 let epoch_store = self.epoch_store.load();
3545 if self.node_role(&epoch_store).runs_consensus()
3547 && epoch_store.protocol_config().enable_object_funds_withdraw()
3548 {
3549 if self.object_funds_checker.load().is_none() {
3550 let inner = self.get_object(&SUI_ACCUMULATOR_ROOT_OBJECT_ID).map(|o| {
3551 Arc::new(ObjectFundsChecker::new(
3552 o.version(),
3553 self.unsettled_object_withdrawals.clone(),
3554 self.object_funds_checker_metrics.clone(),
3555 ))
3556 });
3557 self.object_funds_checker.store(inner);
3558 }
3559 } else {
3560 self.object_funds_checker.store(None);
3561 }
3562 }
3563
3564 pub fn get_object_cache_reader(&self) -> &Arc<dyn ObjectCacheRead> {
3566 &self.execution_cache_trait_pointers.object_cache_reader
3567 }
3568
3569 pub fn get_transaction_cache_reader(&self) -> &Arc<dyn TransactionCacheRead> {
3570 &self.execution_cache_trait_pointers.transaction_cache_reader
3571 }
3572
3573 pub fn get_cache_writer(&self) -> &Arc<dyn ExecutionCacheWrite> {
3574 &self.execution_cache_trait_pointers.cache_writer
3575 }
3576
3577 pub fn get_backing_store(&self) -> &Arc<dyn BackingStore + Send + Sync> {
3578 &self.execution_cache_trait_pointers.backing_store
3579 }
3580
3581 pub fn get_runtime_object_resolver(&self) -> &Arc<dyn RuntimeObjectResolver + Send + Sync> {
3582 &self.execution_cache_trait_pointers.runtime_object_resolver
3583 }
3584
3585 pub(crate) fn get_account_funds_read(&self) -> &Arc<dyn AccountFundsRead> {
3586 &self.execution_cache_trait_pointers.account_funds_read
3587 }
3588
3589 pub fn get_backing_package_store(&self) -> &Arc<dyn BackingPackageStore + Send + Sync> {
3590 &self.execution_cache_trait_pointers.backing_package_store
3591 }
3592
3593 pub fn get_object_store(&self) -> &Arc<dyn ObjectStore + Send + Sync> {
3594 &self.execution_cache_trait_pointers.object_store
3595 }
3596
3597 pub async fn await_post_processing(
3598 &self,
3599 tx_digest: &TransactionDigest,
3600 ) -> Option<PostProcessingOutput> {
3601 if let Some((_, rx)) = self.pending_post_processing.remove(tx_digest) {
3602 rx.await.ok()
3604 } else {
3605 None
3607 }
3608 }
3609
3610 pub async fn flush_post_processing(&self, tx_digest: &TransactionDigest) {
3614 if let Some(indexes) = &self.indexes
3615 && let Some((raw_batch, cache_updates)) = self.await_post_processing(tx_digest).await
3616 {
3617 let mut db_batch = indexes.new_db_batch();
3618 db_batch
3619 .concat(vec![raw_batch])
3620 .expect("failed to build index batch");
3621 indexes
3622 .commit_index_batch(db_batch, vec![cache_updates])
3623 .expect("failed to commit index batch");
3624 }
3625 }
3626
3627 pub fn get_reconfig_api(&self) -> &Arc<dyn ExecutionCacheReconfigAPI> {
3628 &self.execution_cache_trait_pointers.reconfig_api
3629 }
3630
3631 pub fn get_global_state_hash_store(&self) -> &Arc<dyn GlobalStateHashStore> {
3632 &self.execution_cache_trait_pointers.global_state_hash_store
3633 }
3634
3635 pub fn get_checkpoint_cache(&self) -> &Arc<dyn CheckpointCache> {
3636 &self.execution_cache_trait_pointers.checkpoint_cache
3637 }
3638
3639 pub fn get_state_sync_store(&self) -> &Arc<dyn StateSyncAPI> {
3640 &self.execution_cache_trait_pointers.state_sync_store
3641 }
3642
3643 pub fn get_cache_commit(&self) -> &Arc<dyn ExecutionCacheCommit> {
3644 &self.execution_cache_trait_pointers.cache_commit
3645 }
3646
3647 pub fn database_for_testing(&self) -> Arc<AuthorityStore> {
3648 self.execution_cache_trait_pointers
3649 .testing_api
3650 .database_for_testing()
3651 }
3652
3653 pub fn authority_store(&self) -> Arc<AuthorityStore> {
3660 self.execution_cache_trait_pointers
3661 .testing_api
3662 .database_for_testing()
3663 }
3664
3665 pub fn cache_for_testing(&self) -> &WritebackCache {
3666 self.execution_cache_trait_pointers
3667 .testing_api
3668 .cache_for_testing()
3669 }
3670
3671 pub async fn prune_checkpoints_for_eligible_epochs_for_testing(
3672 &self,
3673 config: NodeConfig,
3674 metrics: Arc<AuthorityStorePruningMetrics>,
3675 ) -> anyhow::Result<()> {
3676 use crate::authority::authority_store_pruner::PrunerWatermarks;
3677 let watermarks = Arc::new(PrunerWatermarks::default());
3678 AuthorityStorePruner::prune_checkpoints_for_eligible_epochs(
3679 &self.database_for_testing().perpetual_tables,
3680 &self.checkpoint_store,
3681 None,
3682 config.authority_store_pruning_config,
3683 metrics,
3684 EPOCH_DURATION_MS_FOR_TESTING,
3685 &watermarks,
3686 )
3687 .await
3688 }
3689
3690 pub fn execution_scheduler(&self) -> &Arc<ExecutionScheduler> {
3691 &self.execution_scheduler
3692 }
3693
3694 fn create_owner_index_if_empty(
3695 &self,
3696 genesis_objects: &[Object],
3697 epoch_store: &Arc<AuthorityPerEpochStore>,
3698 ) -> SuiResult {
3699 let Some(index_store) = &self.indexes else {
3700 return Ok(());
3701 };
3702 if !index_store.is_empty() {
3703 return Ok(());
3704 }
3705
3706 let mut new_owners = vec![];
3707 let mut new_dynamic_fields = vec![];
3708 let mut layout_resolver = epoch_store.executor().type_layout_resolver(
3709 epoch_store.protocol_config(),
3710 Box::new(self.get_backing_package_store().as_ref()),
3711 );
3712 for o in genesis_objects.iter() {
3713 match o.owner {
3714 Owner::AddressOwner(addr) | Owner::ConsensusAddressOwner { owner: addr, .. } => {
3715 new_owners.push((
3716 (addr, o.id()),
3717 ObjectInfo::new(&o.compute_object_reference(), o),
3718 ))
3719 }
3720 Owner::ObjectOwner(object_id) => {
3721 let id = o.id();
3722 let Some(info) = Self::try_create_dynamic_field_info(
3723 self.get_object_store(),
3724 o,
3725 &BTreeMap::new(),
3726 layout_resolver.as_mut(),
3727 )?
3728 else {
3729 continue;
3730 };
3731 new_dynamic_fields.push(((ObjectID::from(object_id), id), info));
3732 }
3733 _ => {}
3734 }
3735 }
3736
3737 index_store.insert_genesis_objects(ObjectIndexChanges {
3738 deleted_owners: vec![],
3739 deleted_dynamic_fields: vec![],
3740 new_owners,
3741 new_dynamic_fields,
3742 })
3743 }
3744
3745 pub fn execution_lock_for_executable_transaction(
3749 &self,
3750 transaction: &VerifiedExecutableTransaction,
3751 ) -> Option<ExecutionLockReadGuard<'_>> {
3752 let lock = self.execution_lock.try_read().ok()?;
3753 if *lock == transaction.auth_sig().epoch() {
3754 Some(lock)
3755 } else {
3756 None
3758 }
3759 }
3760
3761 fn execution_lock_for_validation(&self) -> SuiResult<ExecutionLockReadGuard<'_>> {
3764 self.execution_lock
3765 .try_read()
3766 .map_err(|_| SuiErrorKind::ValidatorHaltedAtEpochEnd.into())
3767 }
3768
3769 pub async fn execution_lock_for_reconfiguration(&self) -> ExecutionLockWriteGuard<'_> {
3770 self.execution_lock.write().await
3771 }
3772
3773 #[instrument(level = "error", skip_all)]
3774 pub async fn reconfigure(
3775 &self,
3776 cur_epoch_store: &AuthorityPerEpochStore,
3777 supported_protocol_versions: SupportedProtocolVersions,
3778 new_committee: Committee,
3779 epoch_start_configuration: EpochStartConfiguration,
3780 state_hasher: Arc<GlobalStateHasher>,
3781 expensive_safety_check_config: &ExpensiveSafetyCheckConfig,
3782 epoch_last_checkpoint: CheckpointSequenceNumber,
3783 ) -> SuiResult<Arc<AuthorityPerEpochStore>> {
3784 Self::check_protocol_version(
3785 supported_protocol_versions,
3786 epoch_start_configuration
3787 .epoch_start_state()
3788 .protocol_version(),
3789 );
3790
3791 self.committee_store.insert_new_committee(&new_committee)?;
3792
3793 let mut execution_lock = self.execution_lock_for_reconfiguration().await;
3795
3796 cur_epoch_store.epoch_terminated().await;
3798
3799 cur_epoch_store.record_epoch_close_time_once();
3801
3802 self.get_reconfig_api()
3806 .clear_state_end_of_epoch(&execution_lock);
3807 self.check_system_consistency(cur_epoch_store, state_hasher, expensive_safety_check_config);
3808 self.maybe_reaccumulate_state_hash(
3809 cur_epoch_store,
3810 epoch_start_configuration
3811 .epoch_start_state()
3812 .protocol_version(),
3813 );
3814 self.get_reconfig_api()
3815 .set_epoch_start_configuration(&epoch_start_configuration);
3816 if let Some(checkpoint_path) = &self.db_checkpoint_config.checkpoint_path
3817 && self
3818 .db_checkpoint_config
3819 .perform_db_checkpoints_at_epoch_end
3820 {
3821 let checkpoint_indexes = self
3822 .db_checkpoint_config
3823 .perform_index_db_checkpoints_at_epoch_end
3824 .unwrap_or(false);
3825 let current_epoch = cur_epoch_store.epoch();
3826 let epoch_checkpoint_path = checkpoint_path.join(format!("epoch_{}", current_epoch));
3827 self.checkpoint_all_dbs(&epoch_checkpoint_path, cur_epoch_store, checkpoint_indexes)?;
3828 }
3829
3830 self.get_reconfig_api()
3831 .reconfigure_cache(&epoch_start_configuration)
3832 .await;
3833
3834 let new_epoch = new_committee.epoch;
3835 let new_epoch_store = self
3836 .reopen_epoch_db(
3837 cur_epoch_store,
3838 new_committee,
3839 epoch_start_configuration,
3840 expensive_safety_check_config,
3841 epoch_last_checkpoint,
3842 )
3843 .await?;
3844 assert_eq!(new_epoch_store.epoch(), new_epoch);
3845 self.execution_scheduler
3846 .reconfigure(&new_epoch_store, self.get_account_funds_read());
3847 self.init_object_funds_checker().await;
3848
3849 if let Err(e) = self
3852 .transaction_deny_config_manager
3853 .update_for_committee(new_epoch_store.committee().clone())
3854 {
3855 warn!(
3856 "TransactionDenyConfigManager update_for_committee failed at reconfigure: {:?}",
3857 e
3858 );
3859 }
3860
3861 *execution_lock = new_epoch;
3862
3863 self.notify_epoch(new_epoch);
3864 Ok(new_epoch_store)
3868 }
3869
3870 fn notify_epoch(&self, new_epoch: EpochId) {
3871 self.notify_epoch.send_modify(|epoch| *epoch = new_epoch);
3872 }
3873
3874 pub async fn wait_for_epoch(&self, target_epoch: EpochId) -> Result<EpochId, RecvError> {
3875 let mut rx = self.notify_epoch.subscribe();
3876 loop {
3877 let epoch = *rx.borrow();
3878 if epoch >= target_epoch {
3879 return Ok(epoch);
3880 }
3881 rx.changed().await?;
3882 }
3883 }
3884
3885 pub async fn settle_accumulator_for_testing(
3889 &self,
3890 effects: &[TransactionEffects],
3891 checkpoint_seq: Option<u64>,
3892 ) -> Vec<(VerifiedExecutableTransaction, ExecutionEnv)> {
3893 let accumulator_version = self
3894 .get_object(&SUI_ACCUMULATOR_ROOT_OBJECT_ID)
3895 .unwrap()
3896 .version();
3897 let ckpt_seq = checkpoint_seq.unwrap_or_else(|| accumulator_version.value());
3899 let builder = AccumulatorSettlementTxBuilder::new(
3900 Some(self.get_transaction_cache_reader().as_ref()),
3901 effects,
3902 ckpt_seq,
3903 0,
3904 );
3905 let balance_changes = builder.collect_funds_changes();
3906 let epoch_store = self.epoch_store_for_testing();
3907 let epoch = epoch_store.epoch();
3908 let accumulator_root_obj_initial_shared_version = epoch_store
3909 .epoch_start_config()
3910 .accumulator_root_obj_initial_shared_version()
3911 .unwrap();
3912 let settlements = builder.build_tx(
3913 epoch_store.protocol_config(),
3914 epoch,
3915 accumulator_root_obj_initial_shared_version,
3916 ckpt_seq,
3917 ckpt_seq,
3918 );
3919
3920 let settlements: Vec<_> = settlements
3921 .into_iter()
3922 .map(|tx| {
3923 VerifiedExecutableTransaction::new_system(
3924 VerifiedTransaction::new_system_transaction(tx),
3925 epoch,
3926 )
3927 })
3928 .collect();
3929
3930 let assigned_versions = epoch_store
3931 .assign_shared_object_versions_for_tests(
3932 self.get_object_cache_reader().as_ref(),
3933 &settlements,
3934 )
3935 .unwrap();
3936 let version_map = assigned_versions.into_map();
3937
3938 let mut replay_txns = Vec::new();
3939 let mut settlement_effects = Vec::with_capacity(settlements.len());
3940 for tx in settlements {
3941 let assigned = version_map.get(&tx.key()).unwrap().clone();
3942 let env = ExecutionEnv::new().with_assigned_versions(assigned);
3943 let (effects, _) = self
3944 .try_execute_immediately(&tx.clone(), env.clone(), &epoch_store)
3945 .unwrap();
3946 assert!(effects.status().is_ok());
3947 replay_txns.push((tx, env));
3948 settlement_effects.push(effects);
3949 }
3950
3951 let barrier = accumulators::build_accumulator_barrier_tx(
3952 epoch,
3953 accumulator_root_obj_initial_shared_version,
3954 ckpt_seq,
3955 &settlement_effects,
3956 );
3957 let barrier = VerifiedExecutableTransaction::new_system(
3958 VerifiedTransaction::new_system_transaction(barrier),
3959 epoch,
3960 );
3961
3962 let assigned_versions = epoch_store
3963 .assign_shared_object_versions_for_tests(
3964 self.get_object_cache_reader().as_ref(),
3965 std::slice::from_ref(&barrier),
3966 )
3967 .unwrap();
3968 let version_map = assigned_versions.into_map();
3969
3970 let barrier_assigned = version_map.get(&barrier.key()).unwrap().clone();
3971 let env = ExecutionEnv::new().with_assigned_versions(barrier_assigned);
3972 let (effects, _) = self
3973 .try_execute_immediately(&barrier.clone(), env.clone(), &epoch_store)
3974 .unwrap();
3975 assert!(effects.status().is_ok());
3976 replay_txns.push((barrier, env));
3977
3978 let next_accumulator_version = accumulator_version.next();
3979 self.execution_scheduler
3980 .settle_address_funds(FundsSettlement {
3981 funds_changes: balance_changes,
3982 next_accumulator_version,
3983 });
3984 replay_txns
3987 }
3988
3989 pub async fn replay_settlement_for_testing(
3992 &self,
3993 txns: &[(VerifiedExecutableTransaction, ExecutionEnv)],
3994 ) {
3995 let epoch_store = self.epoch_store_for_testing();
3996 for (tx, env) in txns {
3997 let (effects, _) = self
3998 .try_execute_immediately(tx, env.clone(), &epoch_store)
3999 .unwrap();
4000 assert!(effects.status().is_ok());
4001 }
4002 }
4003
4004 pub async fn reconfigure_for_testing(&self) {
4008 let mut execution_lock = self.execution_lock_for_reconfiguration().await;
4009 let epoch_store = self.epoch_store_for_testing().clone();
4010 let protocol_config = epoch_store.protocol_config().clone();
4011 let _guard =
4018 ProtocolConfig::apply_overrides_for_testing(move |_, _| protocol_config.clone());
4019 let new_epoch_store = epoch_store.new_at_next_epoch_for_testing(
4020 self.get_backing_package_store().clone(),
4021 self.get_object_store().clone(),
4022 &self.config.expensive_safety_check_config,
4023 self.checkpoint_store
4024 .get_epoch_last_checkpoint(epoch_store.epoch())
4025 .unwrap()
4026 .map(|c| *c.sequence_number())
4027 .unwrap_or_default(),
4028 );
4029 self.execution_scheduler
4030 .reconfigure(&new_epoch_store, self.get_account_funds_read());
4031 let new_epoch = new_epoch_store.epoch();
4032 self.epoch_store.store(new_epoch_store);
4033 epoch_store.epoch_terminated().await;
4034
4035 *execution_lock = new_epoch;
4036 }
4037
4038 #[instrument(level = "error", skip_all)]
4041 fn maybe_reaccumulate_state_hash(
4042 &self,
4043 cur_epoch_store: &AuthorityPerEpochStore,
4044 new_protocol_version: ProtocolVersion,
4045 ) {
4046 self.get_reconfig_api()
4047 .maybe_reaccumulate_state_hash(cur_epoch_store, new_protocol_version);
4048 }
4049
4050 #[instrument(level = "error", skip_all)]
4051 fn check_system_consistency(
4052 &self,
4053 cur_epoch_store: &AuthorityPerEpochStore,
4054 state_hasher: Arc<GlobalStateHasher>,
4055 expensive_safety_check_config: &ExpensiveSafetyCheckConfig,
4056 ) {
4057 info!(
4058 "Performing sui conservation consistency check for epoch {}",
4059 cur_epoch_store.epoch()
4060 );
4061
4062 if let Err(err) = self
4063 .get_reconfig_api()
4064 .expensive_check_sui_conservation(cur_epoch_store)
4065 {
4066 if cfg!(debug_assertions) {
4067 panic!("{}", err);
4068 } else {
4069 warn!("Sui conservation consistency check failed: {}", err);
4072 }
4073 } else {
4074 info!("Sui conservation consistency check passed");
4075 }
4076
4077 if expensive_safety_check_config.enable_state_consistency_check() {
4079 info!(
4080 "Performing state consistency check for epoch {}",
4081 cur_epoch_store.epoch()
4082 );
4083 self.expensive_check_is_consistent_state(state_hasher, cur_epoch_store);
4084 }
4085
4086 if expensive_safety_check_config.enable_secondary_index_checks()
4090 && let Some(indexes) = self.indexes.clone()
4091 {
4092 let epoch = cur_epoch_store.epoch();
4093 let first_checkpoint = if epoch == 0 {
4097 0
4098 } else {
4099 self.checkpoint_store
4100 .get_epoch_last_checkpoint_seq_number(epoch - 1)
4101 .expect("Failed to get previous epoch's last checkpoint")
4102 .expect("Previous epoch's last checkpoint missing")
4103 + 1
4104 };
4105 let highest_executed = self
4106 .checkpoint_store
4107 .get_highest_executed_checkpoint_seq_number()
4108 .expect("Failed to get highest executed checkpoint")
4109 .expect("No executed checkpoints");
4110
4111 info!(
4112 "Verifying checkpointed transactions are in transactions_seq \
4113 (checkpoints {first_checkpoint}..={highest_executed})"
4114 );
4115 for seq in first_checkpoint..=highest_executed {
4116 let checkpoint = self
4117 .checkpoint_store
4118 .get_checkpoint_by_sequence_number(seq)
4119 .expect("Failed to get checkpoint")
4120 .expect("Checkpoint missing");
4121 let contents = self
4122 .checkpoint_store
4123 .get_checkpoint_contents(&checkpoint.content_digest)
4124 .expect("Failed to get checkpoint contents")
4125 .expect("Checkpoint contents missing");
4126 for digests in contents.iter() {
4127 let tx_digest = digests.transaction;
4128 assert!(
4129 indexes
4130 .get_transaction_seq(&tx_digest)
4131 .expect("Failed to read transactions_seq")
4132 .is_some(),
4133 "Transaction {tx_digest} from checkpoint {seq} missing from transactions_seq"
4134 );
4135 }
4136 }
4137 info!("All checkpointed transactions verified in transactions_seq");
4138 }
4139 }
4140
4141 fn expensive_check_is_consistent_state(
4142 &self,
4143 state_hasher: Arc<GlobalStateHasher>,
4144 cur_epoch_store: &AuthorityPerEpochStore,
4145 ) {
4146 let live_object_set_hash = state_hasher.digest_live_object_set(
4147 !cur_epoch_store
4148 .protocol_config()
4149 .simplified_unwrap_then_delete(),
4150 );
4151
4152 let root_state_hash: ECMHLiveObjectSetDigest = self
4153 .get_global_state_hash_store()
4154 .get_root_state_hash_for_epoch(cur_epoch_store.epoch())
4155 .expect("Retrieving root state hash cannot fail")
4156 .expect("Root state hash for epoch must exist")
4157 .1
4158 .digest()
4159 .into();
4160
4161 let is_inconsistent = root_state_hash != live_object_set_hash;
4162 if is_inconsistent {
4163 debug_fatal!(
4164 "Inconsistent state detected: root state hash: {:?}, live object set hash: {:?}",
4165 root_state_hash,
4166 live_object_set_hash
4167 );
4168 } else {
4169 info!("State consistency check passed");
4170 }
4171
4172 state_hasher.set_inconsistent_state(is_inconsistent);
4173 }
4174
4175 pub fn current_epoch_for_testing(&self) -> EpochId {
4176 self.epoch_store_for_testing().epoch()
4177 }
4178
4179 #[instrument(level = "error", skip_all)]
4180 pub fn checkpoint_all_dbs(
4181 &self,
4182 checkpoint_path: &Path,
4183 cur_epoch_store: &AuthorityPerEpochStore,
4184 checkpoint_indexes: bool,
4185 ) -> SuiResult {
4186 let _metrics_guard = self.metrics.db_checkpoint_latency.start_timer();
4187 let current_epoch = cur_epoch_store.epoch();
4188
4189 if checkpoint_path.exists() {
4190 info!("Skipping db checkpoint as it already exists for epoch: {current_epoch}");
4191 return Ok(());
4192 }
4193
4194 let checkpoint_path_tmp = checkpoint_path.with_extension("tmp");
4195 let store_checkpoint_path_tmp = checkpoint_path_tmp.join("store");
4196
4197 if checkpoint_path_tmp.exists() {
4198 fs::remove_dir_all(&checkpoint_path_tmp)
4199 .map_err(|e| SuiErrorKind::FileIOError(e.to_string()))?;
4200 }
4201
4202 fs::create_dir_all(&checkpoint_path_tmp)
4203 .map_err(|e| SuiErrorKind::FileIOError(e.to_string()))?;
4204 fs::create_dir(&store_checkpoint_path_tmp)
4205 .map_err(|e| SuiErrorKind::FileIOError(e.to_string()))?;
4206
4207 self.checkpoint_store
4210 .checkpoint_db(&checkpoint_path_tmp.join("checkpoints"))?;
4211
4212 self.get_reconfig_api()
4213 .checkpoint_db(&store_checkpoint_path_tmp.join("perpetual"))?;
4214
4215 self.committee_store
4216 .checkpoint_db(&checkpoint_path_tmp.join("epochs"))?;
4217
4218 if checkpoint_indexes && let Some(indexes) = self.indexes.as_ref() {
4219 indexes.checkpoint_db(&checkpoint_path_tmp.join("indexes"))?;
4220 }
4221
4222 fs::rename(checkpoint_path_tmp, checkpoint_path)
4223 .map_err(|e| SuiErrorKind::FileIOError(e.to_string()))?;
4224 Ok(())
4225 }
4226
4227 pub fn load_epoch_store_one_call_per_task(&self) -> Guard<Arc<AuthorityPerEpochStore>> {
4233 self.epoch_store.load()
4234 }
4235
4236 pub fn epoch_store_for_testing(&self) -> Guard<Arc<AuthorityPerEpochStore>> {
4238 self.load_epoch_store_one_call_per_task()
4239 }
4240
4241 pub fn transaction_deny_config_manager(&self) -> &Arc<TransactionDenyConfigManager> {
4242 &self.transaction_deny_config_manager
4243 }
4244
4245 pub fn local_transaction_deny_config(&self) -> &Arc<TransactionDenyConfig> {
4248 self.transaction_deny_config_manager.local()
4249 }
4250
4251 pub fn clone_committee_for_testing(&self) -> Committee {
4252 Committee::clone(self.epoch_store_for_testing().committee())
4253 }
4254
4255 #[instrument(level = "trace", skip_all)]
4256 pub fn get_object(&self, object_id: &ObjectID) -> Option<Object> {
4257 self.get_object_store().get_object(object_id)
4258 }
4259
4260 pub fn get_sui_system_package_object_ref(&self) -> SuiResult<ObjectRef> {
4261 Ok(self
4262 .get_object(&SUI_SYSTEM_ADDRESS.into())
4263 .expect("framework object should always exist")
4264 .compute_object_reference())
4265 }
4266
4267 pub fn get_sui_system_state_object_for_testing(&self) -> SuiResult<SuiSystemState> {
4269 self.get_object_cache_reader()
4270 .get_sui_system_state_object_unsafe()
4271 }
4272
4273 #[instrument(level = "trace", skip_all)]
4274 fn get_transaction_checkpoint_sequence(
4275 &self,
4276 digest: &TransactionDigest,
4277 epoch_store: &AuthorityPerEpochStore,
4278 ) -> SuiResult<Option<CheckpointSequenceNumber>> {
4279 epoch_store.get_transaction_checkpoint(digest)
4280 }
4281
4282 #[instrument(level = "trace", skip_all)]
4283 pub fn get_checkpoint_by_sequence_number(
4284 &self,
4285 sequence_number: CheckpointSequenceNumber,
4286 ) -> SuiResult<Option<VerifiedCheckpoint>> {
4287 Ok(self
4288 .checkpoint_store
4289 .get_checkpoint_by_sequence_number(sequence_number)?)
4290 }
4291
4292 #[instrument(level = "trace", skip_all)]
4293 pub fn get_transaction_checkpoint_for_tests(
4294 &self,
4295 digest: &TransactionDigest,
4296 epoch_store: &AuthorityPerEpochStore,
4297 ) -> SuiResult<Option<VerifiedCheckpoint>> {
4298 let checkpoint = self.get_transaction_checkpoint_sequence(digest, epoch_store)?;
4299 let Some(checkpoint) = checkpoint else {
4300 return Ok(None);
4301 };
4302 let checkpoint = self
4303 .checkpoint_store
4304 .get_checkpoint_by_sequence_number(checkpoint)?;
4305 Ok(checkpoint)
4306 }
4307
4308 #[instrument(level = "trace", skip_all)]
4309 pub fn get_object_read(&self, object_id: &ObjectID) -> SuiResult<ObjectRead> {
4310 Ok(
4311 match self
4312 .get_object_cache_reader()
4313 .get_latest_object_or_tombstone(*object_id)
4314 {
4315 Some((_, ObjectOrTombstone::Object(object))) => {
4316 let layout = self.get_object_layout(&object)?;
4317 ObjectRead::Exists(object.compute_object_reference(), object, layout)
4318 }
4319 Some((_, ObjectOrTombstone::Tombstone(objref))) => ObjectRead::Deleted(objref),
4320 None => ObjectRead::NotExists(*object_id),
4321 },
4322 )
4323 }
4324
4325 pub fn get_chain_identifier(&self) -> ChainIdentifier {
4327 self.chain_identifier
4328 }
4329
4330 #[instrument(level = "trace", skip_all)]
4336 pub fn get_past_object_read(
4337 &self,
4338 object_id: &ObjectID,
4339 version: SequenceNumber,
4340 ) -> SuiResult<PastObjectRead> {
4341 let Some(obj_ref) = self
4343 .get_object_cache_reader()
4344 .get_latest_object_ref_or_tombstone(*object_id)
4345 else {
4346 return Ok(PastObjectRead::ObjectNotExists(*object_id));
4347 };
4348
4349 if version > obj_ref.1 {
4350 return Ok(PastObjectRead::VersionTooHigh {
4351 object_id: *object_id,
4352 asked_version: version,
4353 latest_version: obj_ref.1,
4354 });
4355 }
4356
4357 if version < obj_ref.1 {
4358 return Ok(match self.read_object_at_version(object_id, version)? {
4360 Some((object, layout)) => {
4361 let obj_ref = object.compute_object_reference();
4362 PastObjectRead::VersionFound(obj_ref, object, layout)
4363 }
4364
4365 None => PastObjectRead::VersionNotFound(*object_id, version),
4366 });
4367 }
4368
4369 if !obj_ref.2.is_alive() {
4370 return Ok(PastObjectRead::ObjectDeleted(obj_ref));
4371 }
4372
4373 match self.read_object_at_version(object_id, obj_ref.1)? {
4374 Some((object, layout)) => Ok(PastObjectRead::VersionFound(obj_ref, object, layout)),
4375 None => {
4376 debug_fatal!(
4377 "Object with in parent_entry is missing from object store, datastore is \
4378 inconsistent"
4379 );
4380 Err(UserInputError::ObjectNotFound {
4381 object_id: *object_id,
4382 version: Some(obj_ref.1),
4383 }
4384 .into())
4385 }
4386 }
4387 }
4388
4389 #[instrument(level = "trace", skip_all)]
4390 fn read_object_at_version(
4391 &self,
4392 object_id: &ObjectID,
4393 version: SequenceNumber,
4394 ) -> SuiResult<Option<(Object, Option<MoveStructLayout>)>> {
4395 let Some(object) = self
4396 .get_object_cache_reader()
4397 .get_object_by_key(object_id, version)
4398 else {
4399 return Ok(None);
4400 };
4401
4402 let layout = self.get_object_layout(&object)?;
4403 Ok(Some((object, layout)))
4404 }
4405
4406 pub fn get_object_layout(&self, object: &Object) -> SuiResult<Option<MoveStructLayout>> {
4407 let layout = object
4408 .data
4409 .try_as_move()
4410 .map(|object| {
4411 let epoch_store = self.load_epoch_store_one_call_per_task();
4412 into_struct_layout(
4413 epoch_store
4414 .executor()
4415 .type_layout_resolver(
4417 epoch_store.protocol_config(),
4418 Box::new(self.get_backing_package_store().as_ref()),
4419 )
4420 .get_annotated_layout(&object.type_().clone().into())?,
4421 )
4422 })
4423 .transpose()?;
4424 Ok(layout)
4425 }
4426
4427 #[instrument(level = "trace", skip_all)]
4431 pub fn get_address_balance_coin_info(
4432 &self,
4433 owner: SuiAddress,
4434 balance_type: TypeTag,
4435 ) -> SuiResult<Option<(ObjectRef, u64, TransactionDigest)>> {
4436 let accumulator_id = AccumulatorValue::get_field_id(owner, &balance_type)?;
4437 let accumulator_obj = AccumulatorValue::load_object_by_id(
4438 self.get_runtime_object_resolver().as_ref(),
4439 None,
4440 *accumulator_id.inner(),
4441 )?;
4442
4443 let Some(accumulator_obj) = accumulator_obj else {
4444 return Ok(None);
4445 };
4446
4447 let currency_type =
4450 Balance::maybe_get_balance_type_param(&balance_type).unwrap_or(balance_type);
4451
4452 let balance = crate::accumulators::balances::get_balance(
4453 owner,
4454 self.get_runtime_object_resolver().as_ref(),
4455 currency_type,
4456 )?;
4457
4458 if balance == 0 {
4459 return Ok(None);
4460 };
4461
4462 let object_ref = coin_reservation::encode_object_ref(
4463 accumulator_obj.id(),
4464 accumulator_obj.version(),
4465 self.load_epoch_store_one_call_per_task().epoch(),
4466 balance,
4467 self.get_chain_identifier(),
4468 );
4469
4470 Ok(Some((
4471 object_ref,
4472 balance,
4473 accumulator_obj.previous_transaction,
4474 )))
4475 }
4476
4477 #[instrument(level = "trace", skip_all)]
4480 pub fn get_all_address_balance_coin_infos(
4481 &self,
4482 owner: SuiAddress,
4483 ) -> SuiResult<std::collections::HashMap<String, (ObjectRef, u64, TransactionDigest)>> {
4484 let indexes = self
4485 .indexes
4486 .as_ref()
4487 .ok_or(SuiErrorKind::IndexStoreNotAvailable)?;
4488
4489 let mut result = std::collections::HashMap::new();
4490 for currency_type in indexes.get_address_balance_coin_types_iter(owner) {
4491 let balance_type = sui_types::balance::Balance::type_tag(currency_type.clone());
4492 if let Some((obj_ref, balance, prev_tx)) =
4493 self.get_address_balance_coin_info(owner, balance_type)?
4494 {
4495 result.insert(currency_type.to_string(), (obj_ref, balance, prev_tx));
4498 }
4499 }
4500 Ok(result)
4501 }
4502
4503 fn get_owner_at_version(
4504 object_store: &Arc<dyn ObjectStore + Send + Sync>,
4505 object_id: &ObjectID,
4506 version: SequenceNumber,
4507 ) -> SuiResult<Owner> {
4508 object_store
4509 .get_object_by_key(object_id, version)
4510 .ok_or_else(|| {
4511 SuiError::from(UserInputError::ObjectNotFound {
4512 object_id: *object_id,
4513 version: Some(version),
4514 })
4515 })
4516 .map(|o| o.owner.clone())
4517 }
4518
4519 #[instrument(level = "trace", skip_all)]
4520 pub fn get_owner_objects(
4521 &self,
4522 owner: SuiAddress,
4523 cursor: Option<ObjectID>,
4525 limit: usize,
4526 filter: Option<SuiObjectDataFilter>,
4527 ) -> SuiResult<Vec<ObjectInfo>> {
4528 if let Some(indexes) = &self.indexes {
4529 indexes.get_owner_objects(owner, cursor, limit, filter)
4530 } else {
4531 Err(SuiErrorKind::IndexStoreNotAvailable.into())
4532 }
4533 }
4534
4535 #[instrument(level = "trace", skip_all)]
4536 pub fn get_owned_coins_iterator_with_cursor(
4537 &self,
4538 owner: SuiAddress,
4539 cursor: (String, u64, ObjectID),
4541 limit: usize,
4542 one_coin_type_only: bool,
4543 ) -> SuiResult<impl Iterator<Item = (CoinIndexKey2, CoinInfo)> + '_> {
4544 if let Some(indexes) = &self.indexes {
4545 indexes.get_owned_coins_iterator_with_cursor(owner, cursor, limit, one_coin_type_only)
4546 } else {
4547 Err(SuiErrorKind::IndexStoreNotAvailable.into())
4548 }
4549 }
4550
4551 #[instrument(level = "trace", skip_all)]
4552 pub fn get_owner_objects_iterator(
4553 &self,
4554 owner: SuiAddress,
4555 cursor: Option<ObjectID>,
4557 filter: Option<SuiObjectDataFilter>,
4558 ) -> SuiResult<impl Iterator<Item = ObjectInfo> + '_> {
4559 let cursor_u = cursor.unwrap_or(ObjectID::ZERO);
4560 if let Some(indexes) = &self.indexes {
4561 indexes.get_owner_objects_iterator(owner, cursor_u, filter)
4562 } else {
4563 Err(SuiErrorKind::IndexStoreNotAvailable.into())
4564 }
4565 }
4566
4567 #[instrument(level = "trace", skip_all)]
4568 pub fn get_move_objects<T>(&self, owner: SuiAddress, type_: MoveObjectType) -> SuiResult<Vec<T>>
4569 where
4570 T: DeserializeOwned,
4571 {
4572 let object_ids = self
4573 .get_owner_objects_iterator(owner, None, None)?
4574 .filter(|o| match &o.type_ {
4575 ObjectType::Struct(s) => &type_ == s,
4576 ObjectType::Package => false,
4577 })
4578 .map(|info| ObjectKey(info.object_id, info.version))
4579 .collect::<Vec<_>>();
4580 let mut move_objects = vec![];
4581
4582 let objects = self
4583 .get_object_store()
4584 .multi_get_objects_by_key(&object_ids);
4585
4586 for (o, id) in objects.into_iter().zip_debug_eq(object_ids) {
4587 let object = o.ok_or_else(|| {
4588 SuiError::from(UserInputError::ObjectNotFound {
4589 object_id: id.0,
4590 version: Some(id.1),
4591 })
4592 })?;
4593 let move_object = object.data.try_as_move().ok_or_else(|| {
4594 SuiError::from(UserInputError::MovePackageAsObject { object_id: id.0 })
4595 })?;
4596 move_objects.push(bcs::from_bytes(move_object.contents()).map_err(|e| {
4597 SuiErrorKind::ObjectDeserializationError {
4598 error: format!("{e}"),
4599 }
4600 })?);
4601 }
4602 Ok(move_objects)
4603 }
4604
4605 #[instrument(level = "trace", skip_all)]
4606 pub fn get_dynamic_fields(
4607 &self,
4608 owner: ObjectID,
4609 cursor: Option<ObjectID>,
4611 limit: usize,
4612 ) -> SuiResult<Vec<(ObjectID, DynamicFieldInfo)>> {
4613 Ok(self
4614 .get_dynamic_fields_iterator(owner, cursor)?
4615 .take(limit)
4616 .collect::<Result<Vec<_>, _>>()?)
4617 }
4618
4619 fn get_dynamic_fields_iterator(
4620 &self,
4621 owner: ObjectID,
4622 cursor: Option<ObjectID>,
4624 ) -> SuiResult<impl Iterator<Item = Result<(ObjectID, DynamicFieldInfo), TypedStoreError>> + '_>
4625 {
4626 if let Some(indexes) = &self.indexes {
4627 indexes.get_dynamic_fields_iterator(owner, cursor)
4628 } else {
4629 Err(SuiErrorKind::IndexStoreNotAvailable.into())
4630 }
4631 }
4632
4633 #[instrument(level = "trace", skip_all)]
4634 pub fn get_dynamic_field_object_id(
4635 &self,
4636 owner: ObjectID,
4637 name_type: TypeTag,
4638 name_bcs_bytes: &[u8],
4639 ) -> SuiResult<Option<ObjectID>> {
4640 if let Some(indexes) = &self.indexes {
4641 indexes.get_dynamic_field_object_id(owner, name_type, name_bcs_bytes)
4642 } else {
4643 Err(SuiErrorKind::IndexStoreNotAvailable.into())
4644 }
4645 }
4646
4647 #[instrument(level = "trace", skip_all)]
4648 pub fn get_total_transaction_blocks(&self) -> SuiResult<u64> {
4649 Ok(self.get_indexes()?.next_sequence_number())
4650 }
4651
4652 #[instrument(level = "trace", skip_all)]
4653 pub async fn get_executed_transaction_and_effects(
4654 &self,
4655 digest: TransactionDigest,
4656 kv_store: Arc<TransactionKeyValueStore>,
4657 ) -> SuiResult<(Transaction, TransactionEffects)> {
4658 let transaction = kv_store.get_tx(digest).await?;
4659 let effects = kv_store.get_fx_by_tx_digest(digest).await?;
4660 Ok((transaction, effects))
4661 }
4662
4663 #[instrument(level = "trace", skip_all)]
4664 pub fn multi_get_checkpoint_by_sequence_number(
4665 &self,
4666 sequence_numbers: &[CheckpointSequenceNumber],
4667 ) -> SuiResult<Vec<Option<VerifiedCheckpoint>>> {
4668 Ok(self
4669 .checkpoint_store
4670 .multi_get_checkpoint_by_sequence_number(sequence_numbers)?)
4671 }
4672
4673 #[instrument(level = "trace", skip_all)]
4674 pub fn get_transaction_events(
4675 &self,
4676 digest: &TransactionDigest,
4677 ) -> SuiResult<TransactionEvents> {
4678 self.get_transaction_cache_reader()
4679 .get_events(digest)
4680 .ok_or(SuiErrorKind::TransactionEventsNotFound { digest: *digest }.into())
4681 }
4682
4683 pub fn get_transaction_input_objects(
4684 &self,
4685 effects: &TransactionEffects,
4686 ) -> SuiResult<Vec<Object>> {
4687 sui_types::storage::get_transaction_input_objects(self.get_object_store(), effects)
4688 .map_err(Into::into)
4689 }
4690
4691 pub fn get_transaction_output_objects(
4692 &self,
4693 effects: &TransactionEffects,
4694 ) -> SuiResult<Vec<Object>> {
4695 sui_types::storage::get_transaction_output_objects(self.get_object_store(), effects)
4696 .map_err(Into::into)
4697 }
4698
4699 fn get_indexes(&self) -> SuiResult<Arc<IndexStore>> {
4700 match &self.indexes {
4701 Some(i) => Ok(i.clone()),
4702 None => Err(SuiErrorKind::UnsupportedFeatureError {
4703 error: "extended object indexing is not enabled on this server".into(),
4704 }
4705 .into()),
4706 }
4707 }
4708
4709 pub async fn get_transactions_for_tests(
4710 self: &Arc<Self>,
4711 filter: Option<TransactionFilter>,
4712 cursor: Option<TransactionDigest>,
4713 limit: Option<usize>,
4714 reverse: bool,
4715 ) -> SuiResult<Vec<TransactionDigest>> {
4716 let metrics = KeyValueStoreMetrics::new_for_tests();
4717 let kv_store = Arc::new(TransactionKeyValueStore::new(
4718 "rocksdb",
4719 metrics,
4720 self.clone(),
4721 ));
4722 self.get_transactions(&kv_store, filter, cursor, limit, reverse)
4723 .await
4724 }
4725
4726 #[instrument(level = "trace", skip_all)]
4727 pub async fn get_transactions(
4728 &self,
4729 kv_store: &Arc<TransactionKeyValueStore>,
4730 filter: Option<TransactionFilter>,
4731 cursor: Option<TransactionDigest>,
4733 limit: Option<usize>,
4734 reverse: bool,
4735 ) -> SuiResult<Vec<TransactionDigest>> {
4736 if let Some(TransactionFilter::Checkpoint(sequence_number)) = filter {
4737 let checkpoint_contents = kv_store.get_checkpoint_contents(sequence_number).await?;
4738 let iter = checkpoint_contents.iter().map(|c| c.transaction);
4739 if reverse {
4740 let iter = iter
4741 .rev()
4742 .skip_while(|d| cursor.is_some() && Some(*d) != cursor)
4743 .skip(usize::from(cursor.is_some()));
4744 return Ok(iter.take(limit.unwrap_or(usize::MAX)).collect());
4745 } else {
4746 let iter = iter
4747 .skip_while(|d| cursor.is_some() && Some(*d) != cursor)
4748 .skip(usize::from(cursor.is_some()));
4749 return Ok(iter.take(limit.unwrap_or(usize::MAX)).collect());
4750 }
4751 }
4752 self.get_indexes()?
4753 .get_transactions(filter, cursor, limit, reverse)
4754 }
4755
4756 pub fn get_checkpoint_store(&self) -> &Arc<CheckpointStore> {
4757 &self.checkpoint_store
4758 }
4759
4760 pub fn get_latest_checkpoint_sequence_number(&self) -> SuiResult<CheckpointSequenceNumber> {
4761 self.get_checkpoint_store()
4762 .get_highest_executed_checkpoint_seq_number()?
4763 .ok_or(
4764 SuiErrorKind::UserInputError {
4765 error: UserInputError::LatestCheckpointSequenceNumberNotFound,
4766 }
4767 .into(),
4768 )
4769 }
4770
4771 #[cfg(msim)]
4772 pub fn get_highest_pruned_checkpoint_for_testing(&self) -> SuiResult<CheckpointSequenceNumber> {
4773 self.database_for_testing()
4774 .perpetual_tables
4775 .get_highest_pruned_checkpoint()
4776 .map(|c| c.unwrap_or(0))
4777 .map_err(Into::into)
4778 }
4779
4780 #[instrument(level = "trace", skip_all)]
4781 pub fn get_checkpoint_summary_by_sequence_number(
4782 &self,
4783 sequence_number: CheckpointSequenceNumber,
4784 ) -> SuiResult<CheckpointSummary> {
4785 let verified_checkpoint = self
4786 .get_checkpoint_store()
4787 .get_checkpoint_by_sequence_number(sequence_number)?;
4788 match verified_checkpoint {
4789 Some(verified_checkpoint) => Ok(verified_checkpoint.into_inner().into_data()),
4790 None => Err(SuiErrorKind::UserInputError {
4791 error: UserInputError::VerifiedCheckpointNotFound(sequence_number),
4792 }
4793 .into()),
4794 }
4795 }
4796
4797 #[instrument(level = "trace", skip_all)]
4798 pub fn get_checkpoint_summary_by_digest(
4799 &self,
4800 digest: CheckpointDigest,
4801 ) -> SuiResult<CheckpointSummary> {
4802 let verified_checkpoint = self
4803 .get_checkpoint_store()
4804 .get_checkpoint_by_digest(&digest)?;
4805 match verified_checkpoint {
4806 Some(verified_checkpoint) => Ok(verified_checkpoint.into_inner().into_data()),
4807 None => Err(SuiErrorKind::UserInputError {
4808 error: UserInputError::VerifiedCheckpointDigestNotFound(Base58::encode(digest)),
4809 }
4810 .into()),
4811 }
4812 }
4813
4814 #[instrument(level = "trace", skip_all)]
4815 pub fn find_publish_txn_digest(&self, package_id: ObjectID) -> SuiResult<TransactionDigest> {
4816 if is_system_package(package_id) {
4817 return self.find_genesis_txn_digest();
4818 }
4819 Ok(self
4820 .get_object_read(&package_id)?
4821 .into_object()?
4822 .previous_transaction)
4823 }
4824
4825 #[instrument(level = "trace", skip_all)]
4826 pub fn find_genesis_txn_digest(&self) -> SuiResult<TransactionDigest> {
4827 let summary = self
4828 .get_verified_checkpoint_by_sequence_number(0)?
4829 .into_message();
4830 let content = self.get_checkpoint_contents(summary.content_digest)?;
4831 let genesis_transaction = content.enumerate_transactions(&summary).next();
4832 Ok(genesis_transaction
4833 .ok_or(SuiErrorKind::UserInputError {
4834 error: UserInputError::GenesisTransactionNotFound,
4835 })?
4836 .1
4837 .transaction)
4838 }
4839
4840 #[instrument(level = "trace", skip_all)]
4841 pub fn get_verified_checkpoint_by_sequence_number(
4842 &self,
4843 sequence_number: CheckpointSequenceNumber,
4844 ) -> SuiResult<VerifiedCheckpoint> {
4845 let verified_checkpoint = self
4846 .get_checkpoint_store()
4847 .get_checkpoint_by_sequence_number(sequence_number)?;
4848 match verified_checkpoint {
4849 Some(verified_checkpoint) => Ok(verified_checkpoint),
4850 None => Err(SuiErrorKind::UserInputError {
4851 error: UserInputError::VerifiedCheckpointNotFound(sequence_number),
4852 }
4853 .into()),
4854 }
4855 }
4856
4857 #[instrument(level = "trace", skip_all)]
4858 pub fn get_verified_checkpoint_summary_by_digest(
4859 &self,
4860 digest: CheckpointDigest,
4861 ) -> SuiResult<VerifiedCheckpoint> {
4862 let verified_checkpoint = self
4863 .get_checkpoint_store()
4864 .get_checkpoint_by_digest(&digest)?;
4865 match verified_checkpoint {
4866 Some(verified_checkpoint) => Ok(verified_checkpoint),
4867 None => Err(SuiErrorKind::UserInputError {
4868 error: UserInputError::VerifiedCheckpointDigestNotFound(Base58::encode(digest)),
4869 }
4870 .into()),
4871 }
4872 }
4873
4874 #[instrument(level = "trace", skip_all)]
4875 pub fn get_checkpoint_contents(
4876 &self,
4877 digest: CheckpointContentsDigest,
4878 ) -> SuiResult<CheckpointContents> {
4879 self.get_checkpoint_store()
4880 .get_checkpoint_contents(&digest)?
4881 .ok_or(
4882 SuiErrorKind::UserInputError {
4883 error: UserInputError::CheckpointContentsNotFound(digest),
4884 }
4885 .into(),
4886 )
4887 }
4888
4889 #[instrument(level = "trace", skip_all)]
4890 pub fn get_checkpoint_contents_by_sequence_number(
4891 &self,
4892 sequence_number: CheckpointSequenceNumber,
4893 ) -> SuiResult<CheckpointContents> {
4894 let verified_checkpoint = self
4895 .get_checkpoint_store()
4896 .get_checkpoint_by_sequence_number(sequence_number)?;
4897 match verified_checkpoint {
4898 Some(verified_checkpoint) => {
4899 let content_digest = verified_checkpoint.into_inner().content_digest;
4900 self.get_checkpoint_contents(content_digest)
4901 }
4902 None => Err(SuiErrorKind::UserInputError {
4903 error: UserInputError::VerifiedCheckpointNotFound(sequence_number),
4904 }
4905 .into()),
4906 }
4907 }
4908
4909 #[instrument(level = "trace", skip_all)]
4910 pub async fn query_events(
4911 &self,
4912 kv_store: &Arc<TransactionKeyValueStore>,
4913 query: EventFilter,
4914 cursor: Option<EventID>,
4916 limit: usize,
4917 descending: bool,
4918 ) -> SuiResult<Vec<SuiEvent>> {
4919 let index_store = self.get_indexes()?;
4920
4921 let (tx_num, event_num) = if let Some(cursor) = cursor.as_ref() {
4923 let tx_seq = index_store.get_transaction_seq(&cursor.tx_digest)?.ok_or(
4924 SuiErrorKind::TransactionNotFound {
4925 digest: cursor.tx_digest,
4926 },
4927 )?;
4928 (tx_seq, cursor.event_seq as usize)
4929 } else if descending {
4930 (u64::MAX, usize::MAX)
4931 } else {
4932 (0, 0)
4933 };
4934
4935 let limit = limit + 1;
4936 let mut event_keys = match query {
4937 EventFilter::All([]) => index_store.all_events(tx_num, event_num, limit, descending)?,
4938 EventFilter::Transaction(digest) => {
4939 index_store.events_by_transaction(&digest, tx_num, event_num, limit, descending)?
4940 }
4941 EventFilter::MoveModule { package, module } => {
4942 let module_id = ModuleId::new(package.into(), module);
4943 index_store.events_by_module_id(&module_id, tx_num, event_num, limit, descending)?
4944 }
4945 EventFilter::MoveEventType(struct_name) => index_store
4946 .events_by_move_event_struct_name(
4947 &struct_name,
4948 tx_num,
4949 event_num,
4950 limit,
4951 descending,
4952 )?,
4953 EventFilter::Sender(sender) => {
4954 index_store.events_by_sender(&sender, tx_num, event_num, limit, descending)?
4955 }
4956 EventFilter::TimeRange {
4957 start_time,
4958 end_time,
4959 } => index_store
4960 .event_iterator(start_time, end_time, tx_num, event_num, limit, descending)?,
4961 EventFilter::MoveEventModule { package, module } => index_store
4962 .events_by_move_event_module(
4963 &ModuleId::new(package.into(), module),
4964 tx_num,
4965 event_num,
4966 limit,
4967 descending,
4968 )?,
4969 EventFilter::Any(_) => {
4971 return Err(SuiErrorKind::UserInputError {
4972 error: UserInputError::Unsupported(
4973 "'Any' queries are not supported by the fullnode.".to_string(),
4974 ),
4975 }
4976 .into());
4977 }
4978 };
4979
4980 if cursor.is_some() {
4983 if !event_keys.is_empty() {
4984 event_keys.remove(0);
4985 }
4986 } else {
4987 event_keys.truncate(limit - 1);
4988 }
4989
4990 let transaction_digests = event_keys
4992 .iter()
4993 .map(|(_, digest, _, _)| *digest)
4994 .collect::<HashSet<_>>()
4995 .into_iter()
4996 .collect::<Vec<_>>();
4997
4998 let events = kv_store
4999 .multi_get_events_by_tx_digests(&transaction_digests)
5000 .await?;
5001
5002 let events_map: HashMap<_, _> = transaction_digests
5003 .iter()
5004 .zip_debug_eq(events.into_iter())
5005 .collect();
5006
5007 let stored_events = event_keys
5008 .into_iter()
5009 .map(|k| {
5010 (
5011 k,
5012 events_map
5013 .get(&k.1)
5014 .expect("fetched digest is missing")
5015 .clone()
5016 .and_then(|e| e.data.get(k.2).cloned()),
5017 )
5018 })
5019 .map(
5020 |((_event_digest, tx_digest, event_seq, timestamp), event)| {
5021 event
5022 .map(|e| (e, tx_digest, event_seq, timestamp))
5023 .ok_or_else(|| {
5024 SuiError::from(SuiErrorKind::TransactionEventsNotFound {
5025 digest: tx_digest,
5026 })
5027 })
5028 },
5029 )
5030 .collect::<Result<Vec<_>, _>>()?;
5031
5032 let epoch_store = self.load_epoch_store_one_call_per_task();
5033 let backing_store = self.get_backing_package_store().as_ref();
5034 let mut layout_resolver = epoch_store
5035 .executor()
5036 .type_layout_resolver(epoch_store.protocol_config(), Box::new(backing_store));
5037 let mut events = vec![];
5038 for (e, tx_digest, event_seq, timestamp) in stored_events.into_iter() {
5039 events.push(SuiEvent::try_from(
5040 e.clone(),
5041 tx_digest,
5042 event_seq as u64,
5043 Some(timestamp),
5044 layout_resolver.get_annotated_layout(&e.type_)?,
5045 )?)
5046 }
5047 Ok(events)
5048 }
5049
5050 pub fn insert_genesis_object(&self, object: Object) {
5051 self.get_reconfig_api().insert_genesis_object(object);
5052 }
5053
5054 pub fn insert_genesis_objects(&self, objects: &[Object]) {
5055 for o in objects {
5056 self.insert_genesis_object(o.clone());
5057 }
5058 }
5059
5060 #[instrument(level = "trace", skip_all)]
5062 pub fn get_transaction_status(
5063 &self,
5064 transaction_digest: &TransactionDigest,
5065 epoch_store: &Arc<AuthorityPerEpochStore>,
5066 ) -> SuiResult<Option<(SenderSignedData, TransactionStatus)>> {
5067 if let Some(effects) =
5069 self.get_signed_effects_and_maybe_resign(transaction_digest, epoch_store)?
5070 {
5071 if let Some(transaction) = self
5072 .get_transaction_cache_reader()
5073 .get_transaction_block(transaction_digest)
5074 {
5075 let events = if effects.events_digest().is_some() {
5076 self.get_transaction_events(effects.transaction_digest())?
5077 } else {
5078 TransactionEvents::default()
5079 };
5080 return Ok(Some((
5083 (*transaction).clone().into_message(),
5084 TransactionStatus::Executed(None, effects.into_inner(), events),
5085 )));
5086 } else {
5087 debug!(tx_digest=?transaction_digest, "Signed effects exist but no transaction found");
5091 }
5092 }
5093 Ok(None)
5096 }
5097
5098 #[instrument(level = "trace", skip_all)]
5102 pub fn get_signed_effects_and_maybe_resign(
5103 &self,
5104 transaction_digest: &TransactionDigest,
5105 epoch_store: &Arc<AuthorityPerEpochStore>,
5106 ) -> SuiResult<Option<VerifiedSignedTransactionEffects>> {
5107 let effects = self
5108 .get_transaction_cache_reader()
5109 .get_executed_effects(transaction_digest);
5110 match effects {
5111 Some(effects) => {
5112 if effects.executed_epoch() != epoch_store.epoch() {
5132 debug!(
5133 tx_digest=?transaction_digest,
5134 effects_epoch=?effects.executed_epoch(),
5135 epoch=?epoch_store.epoch(),
5136 "Re-signing the effects with the current epoch"
5137 );
5138 }
5139 Ok(Some(self.sign_effects(effects, epoch_store)?))
5140 }
5141 None => Ok(None),
5142 }
5143 }
5144
5145 pub fn check_effects_against_previously_signed(
5153 &self,
5154 epoch_store: &AuthorityPerEpochStore,
5155 tx_digest: &TransactionDigest,
5156 effects_digest: &TransactionEffectsDigest,
5157 surface: &'static str,
5158 ) -> SuiResult<()> {
5159 if let Some(previously_signed_digest) = epoch_store.get_signed_effects_digest(tx_digest)?
5160 && previously_signed_digest != *effects_digest
5161 {
5162 self.metrics
5163 .signed_effects_equivocation_prevented
5164 .with_label_values(&[surface])
5165 .inc();
5166 error!(
5167 ?tx_digest,
5168 ?previously_signed_digest,
5169 executed_digest = ?effects_digest,
5170 surface,
5171 "refusing to report effects that differ from previously signed effects"
5172 );
5173 return Err(SuiErrorKind::GenericAuthorityError {
5174 error: format!(
5175 "Refusing to report effects for transaction {tx_digest}: effects digest \
5176 {effects_digest} differs from previously signed effects digest \
5177 {previously_signed_digest}"
5178 ),
5179 }
5180 .into());
5181 }
5182 Ok(())
5183 }
5184
5185 #[instrument(level = "trace", skip_all)]
5186 pub(crate) fn sign_effects(
5187 &self,
5188 effects: TransactionEffects,
5189 epoch_store: &Arc<AuthorityPerEpochStore>,
5190 ) -> SuiResult<VerifiedSignedTransactionEffects> {
5191 let tx_digest = *effects.transaction_digest();
5192
5193 self.check_effects_against_previously_signed(
5194 epoch_store,
5195 &tx_digest,
5196 &effects.digest(),
5197 "sign_effects",
5198 )?;
5199
5200 let signed_effects = match epoch_store.get_effects_signature(&tx_digest)? {
5201 Some(sig) => {
5202 debug_assert!(sig.epoch == epoch_store.epoch());
5203 SignedTransactionEffects::new_from_data_and_sig(effects, sig)
5204 }
5205 _ => {
5206 let sig = AuthoritySignInfo::new(
5207 epoch_store.epoch(),
5208 &effects,
5209 Intent::sui_app(IntentScope::TransactionEffects),
5210 self.name,
5211 &*self.secret,
5212 );
5213
5214 let effects = SignedTransactionEffects::new_from_data_and_sig(effects, sig.clone());
5215
5216 epoch_store.insert_effects_digest_and_signature(
5217 &tx_digest,
5218 effects.digest(),
5219 &sig,
5220 )?;
5221
5222 effects
5223 }
5224 };
5225
5226 Ok(VerifiedSignedTransactionEffects::new_unchecked(
5227 signed_effects,
5228 ))
5229 }
5230
5231 #[instrument(level = "trace", skip_all)]
5233 fn fullnode_only_get_tx_coins_for_indexing(
5234 name: AuthorityName,
5235 object_store: &Arc<dyn ObjectStore + Send + Sync>,
5236 effects: &TransactionEffects,
5237 inner_temporary_store: &InnerTemporaryStore,
5238 epoch_store: &Arc<AuthorityPerEpochStore>,
5239 ) -> Option<TxCoins> {
5240 if epoch_store.committee().authority_exists(&name) {
5241 return None;
5242 }
5243 let written_coin_objects = inner_temporary_store
5244 .written
5245 .iter()
5246 .filter_map(|(k, v)| {
5247 if v.is_coin() {
5248 Some((*k, v.clone()))
5249 } else {
5250 None
5251 }
5252 })
5253 .collect();
5254 let mut input_coin_objects = inner_temporary_store
5255 .input_objects
5256 .iter()
5257 .filter_map(|(k, v)| {
5258 if v.is_coin() {
5259 Some((*k, v.clone()))
5260 } else {
5261 None
5262 }
5263 })
5264 .collect::<ObjectMap>();
5265
5266 for (object_id, version) in effects.modified_at_versions() {
5270 if inner_temporary_store
5271 .loaded_runtime_objects
5272 .contains_key(&object_id)
5273 && let Some(object) = object_store.get_object_by_key(&object_id, version)
5274 && object.is_coin()
5275 {
5276 input_coin_objects.insert(object_id, object);
5277 }
5278 }
5279
5280 Some((input_coin_objects, written_coin_objects))
5281 }
5282
5283 pub fn get_objects(&self, objects: &[ObjectID]) -> Vec<Option<Object>> {
5284 self.get_object_cache_reader().get_objects(objects)
5285 }
5286
5287 pub fn get_object_or_tombstone(&self, object_id: ObjectID) -> Option<ObjectRef> {
5288 self.get_object_cache_reader()
5289 .get_latest_object_ref_or_tombstone(object_id)
5290 }
5291
5292 pub fn set_override_protocol_upgrade_buffer_stake(
5301 &self,
5302 expected_epoch: EpochId,
5303 buffer_stake_bps: u64,
5304 ) -> SuiResult {
5305 let epoch_store = self.load_epoch_store_one_call_per_task();
5306 let actual_epoch = epoch_store.epoch();
5307 if actual_epoch != expected_epoch {
5308 return Err(SuiErrorKind::WrongEpoch {
5309 expected_epoch,
5310 actual_epoch,
5311 }
5312 .into());
5313 }
5314
5315 epoch_store.set_override_protocol_upgrade_buffer_stake(buffer_stake_bps)
5316 }
5317
5318 pub fn clear_override_protocol_upgrade_buffer_stake(
5319 &self,
5320 expected_epoch: EpochId,
5321 ) -> SuiResult {
5322 let epoch_store = self.load_epoch_store_one_call_per_task();
5323 let actual_epoch = epoch_store.epoch();
5324 if actual_epoch != expected_epoch {
5325 return Err(SuiErrorKind::WrongEpoch {
5326 expected_epoch,
5327 actual_epoch,
5328 }
5329 .into());
5330 }
5331
5332 epoch_store.clear_override_protocol_upgrade_buffer_stake()
5333 }
5334
5335 pub async fn get_available_system_packages(
5338 &self,
5339 binary_config: &BinaryConfig,
5340 ) -> Vec<ObjectRef> {
5341 let mut results = vec![];
5342
5343 let system_packages = BuiltInFramework::iter_system_packages();
5344
5345 #[cfg(msim)]
5347 let extra_packages = framework_injection::get_extra_packages(self.name);
5348 #[cfg(msim)]
5349 let system_packages = system_packages.map(|p| p).chain(extra_packages.iter());
5350
5351 for system_package in system_packages {
5352 let modules = system_package.modules().to_vec();
5353 #[cfg(msim)]
5355 let modules =
5356 match framework_injection::get_override_modules(&system_package.id, self.name) {
5357 Some(overrides) if overrides.is_empty() => continue,
5358 Some(overrides) => overrides,
5359 None => modules,
5360 };
5361
5362 let Some(obj_ref) = sui_framework::compare_system_package(
5363 &self.get_object_store(),
5364 &system_package.id,
5365 &modules,
5366 system_package.dependencies.to_vec(),
5367 binary_config,
5368 )
5369 .await
5370 else {
5371 return vec![];
5372 };
5373 results.push(obj_ref);
5374 }
5375
5376 results
5377 }
5378
5379 async fn get_system_package_bytes(
5399 &self,
5400 system_packages: Vec<ObjectRef>,
5401 binary_config: &BinaryConfig,
5402 ) -> Option<Vec<(SequenceNumber, Vec<Vec<u8>>, Vec<ObjectID>)>> {
5403 let object_store = self.get_object_cache_reader();
5404
5405 let mut res = Vec::with_capacity(system_packages.len());
5406 for system_package_ref in system_packages {
5407 if let Some(object) =
5408 object_store.get_object_by_key(&system_package_ref.0, system_package_ref.1)
5409 && object.compute_object_reference() == system_package_ref
5410 {
5411 info!("Framework {} does not need updating", system_package_ref.0);
5413 continue;
5414 }
5415
5416 let prev_transaction = if system_package_ref.1 == OBJECT_START_VERSION {
5421 TransactionDigest::genesis_marker()
5422 } else {
5423 let prev_version = system_package_ref
5424 .1
5425 .one_before()
5426 .expect("version is greater than OBJECT_START_VERSION");
5427 let Some(prev_object) =
5428 object_store.get_object_by_key(&system_package_ref.0, prev_version)
5429 else {
5430 error!(
5431 "Framework {} not available locally at version {:?}, cannot derive \
5432 upgrade to {system_package_ref:?}",
5433 system_package_ref.0, prev_version
5434 );
5435 return None;
5436 };
5437 prev_object.previous_transaction
5438 };
5439
5440 #[cfg(msim)]
5441 let SystemPackage {
5442 id: _,
5443 bytes,
5444 dependencies,
5445 } = framework_injection::get_override_system_package(&system_package_ref.0, self.name)
5446 .unwrap_or_else(|| {
5447 BuiltInFramework::get_package_by_id(&system_package_ref.0).clone()
5448 });
5449
5450 #[cfg(not(msim))]
5451 let SystemPackage {
5452 id: _,
5453 bytes,
5454 dependencies,
5455 } = BuiltInFramework::get_package_by_id(&system_package_ref.0).clone();
5456
5457 let modules: Vec<_> = bytes
5458 .iter()
5459 .map(|m| CompiledModule::deserialize_with_config(m, binary_config).unwrap())
5460 .collect();
5461
5462 let new_object = Object::new_system_package(
5463 &modules,
5464 system_package_ref.1,
5465 dependencies.clone(),
5466 prev_transaction,
5467 );
5468
5469 let new_ref = new_object.compute_object_reference();
5470 if new_ref != system_package_ref {
5471 if cfg!(msim) {
5472 debug_fatal!(
5474 "Framework mismatch -- binary: {new_ref:?}\n upgrade: {system_package_ref:?}"
5475 );
5476 } else {
5477 error!(
5478 "Framework mismatch -- binary: {new_ref:?}\n upgrade: {system_package_ref:?}"
5479 );
5480 }
5481 return None;
5482 }
5483
5484 res.push((system_package_ref.1, bytes, dependencies));
5485 }
5486
5487 Some(res)
5488 }
5489
5490 fn is_protocol_version_supported_v2(
5491 current_protocol_version: ProtocolVersion,
5492 proposed_protocol_version: ProtocolVersion,
5493 protocol_config: &ProtocolConfig,
5494 committee: &Committee,
5495 capabilities: Vec<AuthorityCapabilitiesV2>,
5496 mut buffer_stake_bps: u64,
5497 ) -> Option<(ProtocolVersion, Vec<ObjectRef>)> {
5498 if proposed_protocol_version > current_protocol_version + 1
5499 && !protocol_config.advance_to_highest_supported_protocol_version()
5500 {
5501 return None;
5502 }
5503
5504 if buffer_stake_bps > 10000 {
5505 warn!("clamping buffer_stake_bps to 10000");
5506 buffer_stake_bps = 10000;
5507 }
5508
5509 let mut desired_upgrades: Vec<_> = capabilities
5512 .into_iter()
5513 .filter_map(|mut cap| {
5514 if cap.available_system_packages.is_empty() {
5516 return None;
5517 }
5518
5519 cap.available_system_packages.sort();
5520
5521 info!(
5522 "validator {:?} supports {:?} with system packages: {:?}",
5523 cap.authority.concise(),
5524 cap.supported_protocol_versions,
5525 cap.available_system_packages,
5526 );
5527
5528 cap.supported_protocol_versions
5532 .get_version_digest(proposed_protocol_version)
5533 .map(|digest| (digest, cap.available_system_packages, cap.authority))
5534 })
5535 .collect();
5536
5537 desired_upgrades.sort();
5539 desired_upgrades
5540 .into_iter()
5541 .chunk_by(|(digest, packages, _authority)| (*digest, packages.clone()))
5542 .into_iter()
5543 .find_map(|((digest, packages), group)| {
5544 assert!(!packages.is_empty());
5546
5547 let mut stake_aggregator: StakeAggregator<(), true> =
5548 StakeAggregator::new(Arc::new(committee.clone()));
5549
5550 for (_, _, authority) in group {
5551 stake_aggregator.insert_generic(authority, ());
5552 }
5553
5554 let total_votes = stake_aggregator.total_votes();
5555 let quorum_threshold = committee.quorum_threshold();
5556 let f = committee.total_votes() - committee.quorum_threshold();
5557
5558 let buffer_stake = (f * buffer_stake_bps).div_ceil(10000);
5560 let effective_threshold = quorum_threshold + buffer_stake;
5561
5562 info!(
5563 protocol_config_digest = ?digest,
5564 ?total_votes,
5565 ?quorum_threshold,
5566 ?buffer_stake_bps,
5567 ?effective_threshold,
5568 ?proposed_protocol_version,
5569 ?packages,
5570 "support for upgrade"
5571 );
5572
5573 let has_support = total_votes >= effective_threshold;
5574 has_support.then_some((proposed_protocol_version, packages))
5575 })
5576 }
5577
5578 fn choose_protocol_version_and_system_packages_v2(
5579 current_protocol_version: ProtocolVersion,
5580 protocol_config: &ProtocolConfig,
5581 committee: &Committee,
5582 capabilities: Vec<AuthorityCapabilitiesV2>,
5583 buffer_stake_bps: u64,
5584 ) -> (ProtocolVersion, Vec<ObjectRef>) {
5585 assert!(protocol_config.authority_capabilities_v2());
5586 let mut next_protocol_version = current_protocol_version;
5587 let mut system_packages = vec![];
5588
5589 while let Some((version, packages)) = Self::is_protocol_version_supported_v2(
5590 current_protocol_version,
5591 next_protocol_version + 1,
5592 protocol_config,
5593 committee,
5594 capabilities.clone(),
5595 buffer_stake_bps,
5596 ) {
5597 next_protocol_version = version;
5598 system_packages = packages;
5599 }
5600
5601 (next_protocol_version, system_packages)
5602 }
5603
5604 #[instrument(level = "debug", skip_all)]
5605 fn create_authenticator_state_tx(
5606 &self,
5607 epoch_store: &Arc<AuthorityPerEpochStore>,
5608 ) -> Option<EndOfEpochTransactionKind> {
5609 if !epoch_store.protocol_config().enable_jwk_consensus_updates() {
5610 info!("authenticator state transactions not enabled");
5611 return None;
5612 }
5613
5614 let authenticator_state_exists = epoch_store.authenticator_state_exists();
5615 let tx = if authenticator_state_exists {
5616 let next_epoch = epoch_store.epoch().checked_add(1).expect("epoch overflow");
5617 let min_epoch =
5618 next_epoch.saturating_sub(epoch_store.protocol_config().max_age_of_jwk_in_epochs());
5619 let authenticator_obj_initial_shared_version = epoch_store
5620 .epoch_start_config()
5621 .authenticator_obj_initial_shared_version()
5622 .expect("initial version must exist");
5623
5624 let tx = EndOfEpochTransactionKind::new_authenticator_state_expire(
5625 min_epoch,
5626 authenticator_obj_initial_shared_version,
5627 );
5628
5629 info!(?min_epoch, "Creating AuthenticatorStateExpire tx",);
5630
5631 tx
5632 } else {
5633 let tx = EndOfEpochTransactionKind::new_authenticator_state_create();
5634 info!("Creating AuthenticatorStateCreate tx");
5635 tx
5636 };
5637 Some(tx)
5638 }
5639
5640 #[instrument(level = "debug", skip_all)]
5641 fn create_randomness_state_tx(
5642 &self,
5643 epoch_store: &Arc<AuthorityPerEpochStore>,
5644 ) -> Option<EndOfEpochTransactionKind> {
5645 if !epoch_store.protocol_config().random_beacon() {
5646 info!("randomness state transactions not enabled");
5647 return None;
5648 }
5649
5650 if epoch_store.randomness_state_exists() {
5651 return None;
5652 }
5653
5654 let tx = EndOfEpochTransactionKind::new_randomness_state_create();
5655 info!("Creating RandomnessStateCreate tx");
5656 Some(tx)
5657 }
5658
5659 #[instrument(level = "debug", skip_all)]
5660 fn create_accumulator_root_tx(
5661 &self,
5662 epoch_store: &Arc<AuthorityPerEpochStore>,
5663 ) -> Option<EndOfEpochTransactionKind> {
5664 if !epoch_store
5665 .protocol_config()
5666 .create_root_accumulator_object()
5667 {
5668 info!("accumulator root creation not enabled");
5669 return None;
5670 }
5671
5672 if epoch_store.accumulator_root_exists() {
5673 return None;
5674 }
5675
5676 let tx = EndOfEpochTransactionKind::new_accumulator_root_create();
5677 info!("Creating AccumulatorRootCreate tx");
5678 Some(tx)
5679 }
5680
5681 #[instrument(level = "debug", skip_all)]
5682 fn create_write_accumulator_storage_cost_tx(
5683 &self,
5684 epoch_store: &Arc<AuthorityPerEpochStore>,
5685 ) -> Option<EndOfEpochTransactionKind> {
5686 if !epoch_store.accumulator_root_exists() {
5687 info!("accumulator root does not exist yet");
5688 return None;
5689 }
5690 if !epoch_store.protocol_config().enable_accumulators() {
5691 info!("accumulators not enabled");
5692 return None;
5693 }
5694
5695 let object_store = self.get_object_store();
5696 let object_count =
5697 match accumulator_metadata::get_accumulator_object_count(object_store.as_ref()) {
5698 Ok(Some(count)) => count,
5699 Ok(None) => return None,
5700 Err(e) => {
5701 fatal!("failed to read accumulator object count: {e}");
5702 }
5703 };
5704
5705 let storage_cost = object_count.saturating_mul(
5706 epoch_store
5707 .protocol_config()
5708 .accumulator_object_storage_cost(),
5709 );
5710
5711 let tx = EndOfEpochTransactionKind::new_write_accumulator_storage_cost(storage_cost);
5712 info!(
5713 object_count,
5714 storage_cost, "Creating WriteAccumulatorStorageCost tx"
5715 );
5716 Some(tx)
5717 }
5718
5719 #[instrument(level = "debug", skip_all)]
5720 fn create_coin_registry_tx(
5721 &self,
5722 epoch_store: &Arc<AuthorityPerEpochStore>,
5723 ) -> Option<EndOfEpochTransactionKind> {
5724 if !epoch_store.protocol_config().enable_coin_registry() {
5725 info!("coin registry not enabled");
5726 return None;
5727 }
5728
5729 if epoch_store.coin_registry_exists() {
5730 return None;
5731 }
5732
5733 let tx = EndOfEpochTransactionKind::new_coin_registry_create();
5734 info!("Creating CoinRegistryCreate tx");
5735 Some(tx)
5736 }
5737
5738 #[instrument(level = "debug", skip_all)]
5739 fn create_display_registry_tx(
5740 &self,
5741 epoch_store: &Arc<AuthorityPerEpochStore>,
5742 ) -> Option<EndOfEpochTransactionKind> {
5743 if !epoch_store.protocol_config().enable_display_registry() {
5744 info!("display registry not enabled");
5745 return None;
5746 }
5747
5748 if epoch_store.display_registry_exists() {
5749 return None;
5750 }
5751
5752 let tx = EndOfEpochTransactionKind::new_display_registry_create();
5753 info!("Creating DisplayRegistryCreate tx");
5754 Some(tx)
5755 }
5756
5757 #[instrument(level = "debug", skip_all)]
5758 fn create_bridge_tx(
5759 &self,
5760 epoch_store: &Arc<AuthorityPerEpochStore>,
5761 ) -> Option<EndOfEpochTransactionKind> {
5762 if !epoch_store.protocol_config().bridge() {
5763 info!("bridge not enabled");
5764 return None;
5765 }
5766 if epoch_store.bridge_exists() {
5767 return None;
5768 }
5769 let tx = EndOfEpochTransactionKind::new_bridge_create(epoch_store.get_chain_identifier());
5770 info!("Creating Bridge Create tx");
5771 Some(tx)
5772 }
5773
5774 #[instrument(level = "debug", skip_all)]
5775 fn init_bridge_committee_tx(
5776 &self,
5777 epoch_store: &Arc<AuthorityPerEpochStore>,
5778 ) -> Option<EndOfEpochTransactionKind> {
5779 if !epoch_store.protocol_config().bridge() {
5780 info!("bridge not enabled");
5781 return None;
5782 }
5783 if !epoch_store
5784 .protocol_config()
5785 .should_try_to_finalize_bridge_committee()
5786 {
5787 info!("should not try to finalize bridge committee yet");
5788 return None;
5789 }
5790 if !epoch_store.bridge_exists() {
5792 return None;
5793 }
5794
5795 if epoch_store.bridge_committee_initiated() {
5796 return None;
5797 }
5798
5799 let bridge_initial_shared_version = epoch_store
5800 .epoch_start_config()
5801 .bridge_obj_initial_shared_version()
5802 .expect("initial version must exist");
5803 let tx = EndOfEpochTransactionKind::init_bridge_committee(bridge_initial_shared_version);
5804 info!("Init Bridge committee tx");
5805 Some(tx)
5806 }
5807
5808 #[instrument(level = "debug", skip_all)]
5809 fn create_deny_list_state_tx(
5810 &self,
5811 epoch_store: &Arc<AuthorityPerEpochStore>,
5812 ) -> Option<EndOfEpochTransactionKind> {
5813 if !epoch_store.protocol_config().enable_coin_deny_list() {
5814 return None;
5815 }
5816
5817 if epoch_store.coin_deny_list_state_exists() {
5818 return None;
5819 }
5820
5821 let tx = EndOfEpochTransactionKind::new_deny_list_state_create();
5822 info!("Creating DenyListStateCreate tx");
5823 Some(tx)
5824 }
5825
5826 #[instrument(level = "debug", skip_all)]
5827 fn create_address_alias_state_tx(
5828 &self,
5829 epoch_store: &Arc<AuthorityPerEpochStore>,
5830 ) -> Option<EndOfEpochTransactionKind> {
5831 if !epoch_store.protocol_config().address_aliases() {
5832 info!("address aliases not enabled");
5833 return None;
5834 }
5835
5836 if epoch_store.address_alias_state_exists() {
5837 return None;
5838 }
5839
5840 let tx = EndOfEpochTransactionKind::new_address_alias_state_create();
5841 info!("Creating AddressAliasStateCreate tx");
5842 Some(tx)
5843 }
5844
5845 #[instrument(level = "debug", skip_all)]
5846 fn create_forwarding_address_registry_tx(
5847 &self,
5848 epoch_store: &Arc<AuthorityPerEpochStore>,
5849 ) -> Option<EndOfEpochTransactionKind> {
5850 if !epoch_store
5851 .protocol_config()
5852 .create_forwarding_address_registry()
5853 {
5854 info!("forwarding address registry creation not enabled");
5855 return None;
5856 }
5857
5858 if epoch_store.forwarding_address_registry_exists() {
5859 return None;
5860 }
5861
5862 let tx = EndOfEpochTransactionKind::new_forwarding_address_registry_create();
5863 info!("Creating ForwardingAddressRegistryCreate tx");
5864 Some(tx)
5865 }
5866
5867 #[instrument(level = "debug", skip_all)]
5868 fn create_execution_time_observations_tx(
5869 &self,
5870 epoch_store: &Arc<AuthorityPerEpochStore>,
5871 end_of_epoch_observation_keys: Vec<ExecutionTimeObservationKey>,
5872 last_checkpoint_before_end_of_epoch: CheckpointSequenceNumber,
5873 ) -> Option<EndOfEpochTransactionKind> {
5874 let PerObjectCongestionControlMode::ExecutionTimeEstimate(params) = epoch_store
5875 .protocol_config()
5876 .per_object_congestion_control_mode()
5877 else {
5878 return None;
5879 };
5880
5881 let start_checkpoint = std::cmp::max(
5884 last_checkpoint_before_end_of_epoch
5885 .saturating_sub(params.stored_observations_num_included_checkpoints - 1),
5886 epoch_store
5888 .epoch()
5889 .checked_sub(1)
5890 .map(|prev_epoch| {
5891 self.checkpoint_store
5892 .get_epoch_last_checkpoint_seq_number(prev_epoch)
5893 .expect("typed store must not fail")
5894 .expect(
5895 "sequence number of last checkpoint of preceding epoch must be saved",
5896 )
5897 + 1
5898 })
5899 .unwrap_or(1),
5900 );
5901 info!(
5902 "reading checkpoint range {:?}..={:?}",
5903 start_checkpoint, last_checkpoint_before_end_of_epoch
5904 );
5905 let sequence_numbers =
5906 (start_checkpoint..=last_checkpoint_before_end_of_epoch).collect::<Vec<_>>();
5907 let contents_digests: Vec<_> = self
5908 .checkpoint_store
5909 .multi_get_locally_computed_checkpoints(&sequence_numbers)
5910 .expect("typed store must not fail")
5911 .into_iter()
5912 .zip_debug_eq(sequence_numbers)
5913 .map(|(maybe_checkpoint, sequence_number)| {
5914 if let Some(checkpoint) = maybe_checkpoint {
5915 checkpoint.content_digest
5916 } else {
5917 self.checkpoint_store
5920 .get_checkpoint_by_sequence_number(sequence_number)
5921 .expect("typed store must not fail")
5922 .unwrap_or_else(|| {
5923 fatal!("preceding checkpoints must exist by end of epoch")
5924 })
5925 .data()
5926 .content_digest
5927 }
5928 })
5929 .collect();
5930 let tx_digests: Vec<_> = self
5931 .checkpoint_store
5932 .multi_get_checkpoint_content(&contents_digests)
5933 .expect("typed store must not fail")
5934 .into_iter()
5935 .flat_map(|maybe_contents| {
5936 maybe_contents
5937 .expect("preceding checkpoint contents must exist by end of epoch")
5938 .into_inner()
5939 .into_iter()
5940 .map(|digests| digests.transaction)
5941 })
5942 .collect();
5943 let included_execution_time_observations: HashSet<_> = self
5944 .get_transaction_cache_reader()
5945 .multi_get_transaction_blocks(&tx_digests)
5946 .into_iter()
5947 .flat_map(|maybe_tx| {
5948 if let TransactionKind::ProgrammableTransaction(ptb) = maybe_tx
5949 .expect("preceding transaction must exist by end of epoch")
5950 .transaction_data()
5951 .kind()
5952 {
5953 #[allow(clippy::unnecessary_to_owned)]
5954 itertools::Either::Left(
5955 ptb.commands
5956 .to_owned()
5957 .into_iter()
5958 .map(|cmd| ExecutionTimeObservationKey::from_command(&cmd)),
5959 )
5960 } else {
5961 itertools::Either::Right(std::iter::empty())
5962 }
5963 })
5964 .chain(end_of_epoch_observation_keys.into_iter())
5965 .collect();
5966
5967 let tx = EndOfEpochTransactionKind::new_store_execution_time_observations(
5968 epoch_store
5969 .get_end_of_epoch_execution_time_observations()
5970 .filter_and_sort_v1(
5971 |(key, _)| included_execution_time_observations.contains(key),
5972 params.stored_observations_limit.try_into().unwrap(),
5973 ),
5974 );
5975 info!("Creating StoreExecutionTimeObservations tx");
5976 Some(tx)
5977 }
5978
5979 #[instrument(level = "error", skip_all)]
5990 pub async fn create_and_execute_advance_epoch_tx(
5991 &self,
5992 epoch_store: &Arc<AuthorityPerEpochStore>,
5993 gas_cost_summary: &GasCostSummary,
5994 checkpoint: CheckpointSequenceNumber,
5995 epoch_start_timestamp_ms: CheckpointTimestamp,
5996 end_of_epoch_observation_keys: Vec<ExecutionTimeObservationKey>,
5997 last_checkpoint: CheckpointSequenceNumber,
6000 ) -> CheckpointBuilderResult<(SuiSystemState, TransactionEffects)> {
6001 let mut txns = Vec::new();
6002
6003 if let Some(tx) = self.create_authenticator_state_tx(epoch_store) {
6004 txns.push(tx);
6005 }
6006 if let Some(tx) = self.create_randomness_state_tx(epoch_store) {
6007 txns.push(tx);
6008 }
6009 if let Some(tx) = self.create_bridge_tx(epoch_store) {
6010 txns.push(tx);
6011 }
6012 if let Some(tx) = self.init_bridge_committee_tx(epoch_store) {
6013 txns.push(tx);
6014 }
6015 if let Some(tx) = self.create_deny_list_state_tx(epoch_store) {
6016 txns.push(tx);
6017 }
6018 if let Some(tx) = self.create_execution_time_observations_tx(
6019 epoch_store,
6020 end_of_epoch_observation_keys,
6021 last_checkpoint,
6022 ) {
6023 txns.push(tx);
6024 }
6025 if let Some(tx) = self.create_accumulator_root_tx(epoch_store) {
6026 txns.push(tx);
6027 }
6028
6029 if let Some(tx) = self.create_coin_registry_tx(epoch_store) {
6030 txns.push(tx);
6031 }
6032 if let Some(tx) = self.create_display_registry_tx(epoch_store) {
6033 txns.push(tx);
6034 }
6035 if let Some(tx) = self.create_address_alias_state_tx(epoch_store) {
6036 txns.push(tx);
6037 }
6038 if let Some(tx) = self.create_forwarding_address_registry_tx(epoch_store) {
6039 txns.push(tx);
6040 }
6041 if let Some(tx) = self.create_write_accumulator_storage_cost_tx(epoch_store) {
6042 txns.push(tx);
6043 }
6044
6045 let next_epoch = epoch_store.epoch() + 1;
6046
6047 let buffer_stake_bps = epoch_store.get_effective_buffer_stake_bps();
6048
6049 let (next_epoch_protocol_version, next_epoch_system_packages) =
6050 Self::choose_protocol_version_and_system_packages_v2(
6051 epoch_store.protocol_version(),
6052 epoch_store.protocol_config(),
6053 epoch_store.committee(),
6054 epoch_store
6055 .get_capabilities_v2()
6056 .expect("read capabilities from db cannot fail"),
6057 buffer_stake_bps,
6058 );
6059
6060 let config = epoch_store.protocol_config();
6063 let binary_config = config.binary_config(None);
6064 let Some(next_epoch_system_package_bytes) = self
6065 .get_system_package_bytes(next_epoch_system_packages.clone(), &binary_config)
6066 .await
6067 else {
6068 if next_epoch_protocol_version <= ProtocolVersion::MAX {
6069 debug_fatal!(
6073 "upgraded system packages {:?} are not locally available, cannot create \
6074 ChangeEpochTx. validator binary must be upgraded to the correct version!",
6075 next_epoch_system_packages
6076 );
6077 } else {
6078 error!(
6079 "validator does not support next_epoch_protocol_version {:?} - will shut down after reconfig unless upgraded",
6080 next_epoch_protocol_version
6081 );
6082 }
6083 return Err(CheckpointBuilderError::SystemPackagesMissing);
6092 };
6093
6094 let tx = if epoch_store
6095 .protocol_config()
6096 .end_of_epoch_transaction_supported()
6097 {
6098 txns.push(EndOfEpochTransactionKind::new_change_epoch(
6099 next_epoch,
6100 next_epoch_protocol_version,
6101 gas_cost_summary.storage_cost,
6102 gas_cost_summary.computation_cost,
6103 gas_cost_summary.storage_rebate,
6104 gas_cost_summary.non_refundable_storage_fee,
6105 epoch_start_timestamp_ms,
6106 next_epoch_system_package_bytes,
6107 ));
6108
6109 VerifiedTransaction::new_end_of_epoch_transaction(txns)
6110 } else {
6111 VerifiedTransaction::new_change_epoch(
6112 next_epoch,
6113 next_epoch_protocol_version,
6114 gas_cost_summary.storage_cost,
6115 gas_cost_summary.computation_cost,
6116 gas_cost_summary.storage_rebate,
6117 gas_cost_summary.non_refundable_storage_fee,
6118 epoch_start_timestamp_ms,
6119 next_epoch_system_package_bytes,
6120 )
6121 };
6122
6123 let executable_tx = VerifiedExecutableTransaction::new_from_checkpoint(
6124 tx.clone(),
6125 epoch_store.epoch(),
6126 checkpoint,
6127 );
6128
6129 let tx_digest = executable_tx.digest();
6130
6131 info!(
6132 ?next_epoch,
6133 ?next_epoch_protocol_version,
6134 ?next_epoch_system_packages,
6135 computation_cost=?gas_cost_summary.computation_cost,
6136 storage_cost=?gas_cost_summary.storage_cost,
6137 storage_rebate=?gas_cost_summary.storage_rebate,
6138 non_refundable_storage_fee=?gas_cost_summary.non_refundable_storage_fee,
6139 ?tx_digest,
6140 "Creating advance epoch transaction"
6141 );
6142
6143 fail_point_async!("change_epoch_tx_delay");
6144 let tx_lock = epoch_store.acquire_tx_lock(tx_digest);
6145
6146 if self
6149 .get_transaction_cache_reader()
6150 .is_tx_already_executed(tx_digest)
6151 {
6152 warn!("change epoch tx has already been executed via state sync");
6153 return Err(CheckpointBuilderError::ChangeEpochTxAlreadyExecuted);
6154 }
6155
6156 let Some(execution_guard) = self.execution_lock_for_executable_transaction(&executable_tx)
6157 else {
6158 return Err(CheckpointBuilderError::ChangeEpochTxAlreadyExecuted);
6159 };
6160
6161 let assigned_versions = epoch_store.assign_shared_object_versions_idempotent(
6164 self.get_object_cache_reader().as_ref(),
6165 std::iter::once(&Schedulable::Transaction(&executable_tx)),
6166 )?;
6167
6168 assert_eq!(assigned_versions.0.len(), 1);
6169 let assigned_versions = assigned_versions.0.into_iter().next().unwrap().1;
6170
6171 let input_objects = self.read_objects_for_execution(
6172 &tx_lock,
6173 &executable_tx,
6174 &assigned_versions,
6175 epoch_store,
6176 )?;
6177
6178 let (transaction_outputs, _timings, _execution_error_opt) = self
6179 .execute_certificate(
6180 &execution_guard,
6181 &executable_tx,
6182 input_objects,
6183 None,
6184 ExecutionEnv::default(),
6185 epoch_store,
6186 )
6187 .unwrap();
6188 let system_obj = get_sui_system_state(&transaction_outputs.written)
6189 .expect("change epoch tx must write to system object");
6190
6191 let effects = transaction_outputs.effects;
6192 self.get_state_sync_store()
6196 .insert_transaction_and_effects(&tx, &effects);
6197
6198 info!(
6199 "Effects summary of the change epoch transaction: {:?}",
6200 effects.summary_for_debug()
6201 );
6202 epoch_store.record_checkpoint_builder_is_safe_mode_metric(system_obj.safe_mode());
6203 assert!(effects.status().is_ok());
6205 Ok((system_obj, effects))
6206 }
6207
6208 #[instrument(level = "error", skip_all)]
6209 async fn reopen_epoch_db(
6210 &self,
6211 cur_epoch_store: &AuthorityPerEpochStore,
6212 new_committee: Committee,
6213 epoch_start_configuration: EpochStartConfiguration,
6214 expensive_safety_check_config: &ExpensiveSafetyCheckConfig,
6215 epoch_last_checkpoint: CheckpointSequenceNumber,
6216 ) -> SuiResult<Arc<AuthorityPerEpochStore>> {
6217 let new_epoch = new_committee.epoch;
6218 info!(new_epoch = ?new_epoch, "re-opening AuthorityEpochTables for new epoch");
6219 assert_eq!(
6220 epoch_start_configuration.epoch_start_state().epoch(),
6221 new_committee.epoch
6222 );
6223 fail_point!("before-open-new-epoch-store");
6224 let new_epoch_store = cur_epoch_store.new_at_next_epoch(
6225 self.name,
6226 new_committee,
6227 epoch_start_configuration,
6228 self.get_backing_package_store().clone(),
6229 self.get_object_store().clone(),
6230 expensive_safety_check_config,
6231 epoch_last_checkpoint,
6232 self.config.fullnode_sync_mode,
6233 )?;
6234 self.epoch_store.store(new_epoch_store.clone());
6235 Ok(new_epoch_store)
6236 }
6237
6238 #[cfg(test)]
6239 pub(crate) fn iter_live_object_set_for_testing(
6240 &self,
6241 ) -> impl Iterator<Item = authority_store_tables::LiveObject> + '_ {
6242 let include_wrapped_object = !self
6243 .epoch_store_for_testing()
6244 .protocol_config()
6245 .simplified_unwrap_then_delete();
6246 self.get_global_state_hash_store()
6247 .iter_cached_live_object_set_for_testing(include_wrapped_object)
6248 }
6249
6250 #[cfg(test)]
6251 pub(crate) fn shutdown_execution_for_test(&self) {
6252 self.tx_execution_shutdown
6253 .lock()
6254 .take()
6255 .unwrap()
6256 .send(())
6257 .unwrap();
6258 }
6259
6260 pub async fn insert_objects_unsafe_for_testing_only(&self, objects: &[Object]) -> SuiResult {
6262 self.get_reconfig_api().bulk_insert_genesis_objects(objects);
6263 self.get_object_cache_reader()
6264 .force_reload_system_packages(&BuiltInFramework::all_package_ids());
6265 self.get_reconfig_api()
6266 .clear_state_end_of_epoch(&self.execution_lock_for_reconfiguration().await);
6267 Ok(())
6268 }
6269}
6270
6271#[async_trait]
6272impl TransactionKeyValueStoreTrait for AuthorityState {
6273 #[instrument(skip(self))]
6274 async fn multi_get(
6275 &self,
6276 transactions: &[TransactionDigest],
6277 effects: &[TransactionDigest],
6278 ) -> SuiResult<(Vec<Option<Transaction>>, Vec<Option<TransactionEffects>>)> {
6279 let txns = if !transactions.is_empty() {
6280 self.get_transaction_cache_reader()
6281 .multi_get_transaction_blocks(transactions)
6282 .into_iter()
6283 .map(|t| t.map(|t| (*t).clone().into_inner()))
6284 .collect()
6285 } else {
6286 vec![]
6287 };
6288
6289 let fx = if !effects.is_empty() {
6290 self.get_transaction_cache_reader()
6291 .multi_get_executed_effects(effects)
6292 } else {
6293 vec![]
6294 };
6295
6296 Ok((txns, fx))
6297 }
6298
6299 #[instrument(skip(self))]
6300 async fn multi_get_checkpoints(
6301 &self,
6302 checkpoint_summaries: &[CheckpointSequenceNumber],
6303 checkpoint_contents: &[CheckpointSequenceNumber],
6304 checkpoint_summaries_by_digest: &[CheckpointDigest],
6305 ) -> SuiResult<(
6306 Vec<Option<CertifiedCheckpointSummary>>,
6307 Vec<Option<CheckpointContents>>,
6308 Vec<Option<CertifiedCheckpointSummary>>,
6309 )> {
6310 let mut summaries = Vec::with_capacity(checkpoint_summaries.len());
6312 let store = self.get_checkpoint_store();
6313 for seq in checkpoint_summaries {
6314 let checkpoint = store
6315 .get_checkpoint_by_sequence_number(*seq)?
6316 .map(|c| c.into_inner());
6317
6318 summaries.push(checkpoint);
6319 }
6320
6321 let mut contents = Vec::with_capacity(checkpoint_contents.len());
6322 for seq in checkpoint_contents {
6323 let checkpoint = store
6324 .get_checkpoint_by_sequence_number(*seq)?
6325 .and_then(|summary| {
6326 store
6327 .get_checkpoint_contents(&summary.content_digest)
6328 .expect("db read cannot fail")
6329 });
6330 contents.push(checkpoint);
6331 }
6332
6333 let mut summaries_by_digest = Vec::with_capacity(checkpoint_summaries_by_digest.len());
6334 for digest in checkpoint_summaries_by_digest {
6335 let checkpoint = store
6336 .get_checkpoint_by_digest(digest)?
6337 .map(|c| c.into_inner());
6338 summaries_by_digest.push(checkpoint);
6339 }
6340 Ok((summaries, contents, summaries_by_digest))
6341 }
6342
6343 #[instrument(skip(self))]
6344 async fn deprecated_get_transaction_checkpoint(
6345 &self,
6346 digest: TransactionDigest,
6347 ) -> SuiResult<Option<CheckpointSequenceNumber>> {
6348 Ok(self
6349 .get_checkpoint_cache()
6350 .deprecated_get_transaction_checkpoint(&digest)
6351 .map(|(_epoch, checkpoint)| checkpoint))
6352 }
6353
6354 #[instrument(skip(self))]
6355 async fn get_object(
6356 &self,
6357 object_id: ObjectID,
6358 version: VersionNumber,
6359 ) -> SuiResult<Option<Object>> {
6360 Ok(self
6361 .get_object_cache_reader()
6362 .get_object_by_key(&object_id, version))
6363 }
6364
6365 #[instrument(skip_all)]
6366 async fn multi_get_objects(&self, object_keys: &[ObjectKey]) -> SuiResult<Vec<Option<Object>>> {
6367 Ok(self
6368 .get_object_cache_reader()
6369 .multi_get_objects_by_key(object_keys))
6370 }
6371
6372 #[instrument(skip(self))]
6373 async fn multi_get_transaction_checkpoint(
6374 &self,
6375 digests: &[TransactionDigest],
6376 ) -> SuiResult<Vec<Option<CheckpointSequenceNumber>>> {
6377 let res = self
6378 .get_checkpoint_cache()
6379 .deprecated_multi_get_transaction_checkpoint(digests);
6380
6381 Ok(res
6382 .into_iter()
6383 .map(|maybe| maybe.map(|(_epoch, checkpoint)| checkpoint))
6384 .collect())
6385 }
6386
6387 #[instrument(skip(self))]
6388 async fn multi_get_events_by_tx_digests(
6389 &self,
6390 digests: &[TransactionDigest],
6391 ) -> SuiResult<Vec<Option<TransactionEvents>>> {
6392 if digests.is_empty() {
6393 return Ok(vec![]);
6394 }
6395
6396 Ok(self
6397 .get_transaction_cache_reader()
6398 .multi_get_events(digests))
6399 }
6400}
6401
6402#[cfg(msim)]
6403pub mod framework_injection {
6404 use move_binary_format::CompiledModule;
6405 use std::collections::BTreeMap;
6406 use std::collections::BTreeSet;
6407 use std::sync::Mutex;
6408 use sui_framework::{BuiltInFramework, SystemPackage};
6409 use sui_types::base_types::{AuthorityName, ObjectID};
6410 use sui_types::is_system_package;
6411
6412 type FrameworkOverrideConfig = BTreeMap<ObjectID, PackageOverrideConfig>;
6413
6414 static OVERRIDE: Mutex<FrameworkOverrideConfig> = Mutex::new(BTreeMap::new());
6415
6416 type Framework = Vec<CompiledModule>;
6417
6418 pub type PackageUpgradeCallback =
6419 Box<dyn Fn(AuthorityName) -> Option<Framework> + Send + Sync + 'static>;
6420
6421 enum PackageOverrideConfig {
6422 Global(Framework),
6423 PerValidator(PackageUpgradeCallback),
6424 }
6425
6426 fn compiled_modules_to_bytes(modules: &[CompiledModule]) -> Vec<Vec<u8>> {
6427 modules
6428 .iter()
6429 .map(|m| {
6430 let mut buf = Vec::new();
6431 m.serialize_with_version(m.version, &mut buf).unwrap();
6432 buf
6433 })
6434 .collect()
6435 }
6436
6437 pub fn set_override(package_id: ObjectID, modules: Vec<CompiledModule>) {
6438 OVERRIDE
6439 .lock()
6440 .unwrap()
6441 .insert(package_id, PackageOverrideConfig::Global(modules));
6442 }
6443
6444 pub fn set_override_cb(package_id: ObjectID, func: PackageUpgradeCallback) {
6445 OVERRIDE
6446 .lock()
6447 .unwrap()
6448 .insert(package_id, PackageOverrideConfig::PerValidator(func));
6449 }
6450
6451 pub fn set_system_packages(packages: Vec<SystemPackage>) {
6452 let mut cfg = OVERRIDE.lock().unwrap();
6453 let mut new_packages_not_to_include: BTreeSet<_> =
6454 BuiltInFramework::all_package_ids().into_iter().collect();
6455 for pkg in &packages {
6456 new_packages_not_to_include.remove(&pkg.id);
6457 }
6458 for pkg in packages {
6459 cfg.insert(pkg.id, PackageOverrideConfig::Global(pkg.modules()));
6460 }
6461 for empty_pkg in new_packages_not_to_include {
6462 cfg.insert(empty_pkg, PackageOverrideConfig::Global(vec![]));
6463 }
6464 }
6465
6466 pub fn get_override_bytes(package_id: &ObjectID, name: AuthorityName) -> Option<Vec<Vec<u8>>> {
6467 OVERRIDE
6468 .lock()
6469 .unwrap()
6470 .get(package_id)
6471 .and_then(|entry| match entry {
6472 PackageOverrideConfig::Global(framework) => {
6473 Some(compiled_modules_to_bytes(framework))
6474 }
6475 PackageOverrideConfig::PerValidator(func) => {
6476 func(name).map(|fw| compiled_modules_to_bytes(&fw))
6477 }
6478 })
6479 }
6480
6481 pub fn get_override_modules(
6482 package_id: &ObjectID,
6483 name: AuthorityName,
6484 ) -> Option<Vec<CompiledModule>> {
6485 OVERRIDE
6486 .lock()
6487 .unwrap()
6488 .get(package_id)
6489 .and_then(|entry| match entry {
6490 PackageOverrideConfig::Global(framework) => Some(framework.clone()),
6491 PackageOverrideConfig::PerValidator(func) => func(name),
6492 })
6493 }
6494
6495 pub fn get_override_system_package(
6496 package_id: &ObjectID,
6497 name: AuthorityName,
6498 ) -> Option<SystemPackage> {
6499 let bytes = get_override_bytes(package_id, name)?;
6500 let dependencies = if is_system_package(*package_id) {
6501 BuiltInFramework::get_package_by_id(package_id)
6502 .dependencies
6503 .to_vec()
6504 } else {
6505 BuiltInFramework::all_package_ids()
6507 };
6508 Some(SystemPackage {
6509 id: *package_id,
6510 bytes,
6511 dependencies,
6512 })
6513 }
6514
6515 pub fn get_extra_packages(name: AuthorityName) -> Vec<SystemPackage> {
6516 let built_in = BTreeSet::from_iter(BuiltInFramework::all_package_ids().into_iter());
6517 let extra: Vec<ObjectID> = OVERRIDE
6518 .lock()
6519 .unwrap()
6520 .keys()
6521 .filter_map(|package| (!built_in.contains(package)).then_some(*package))
6522 .collect();
6523
6524 extra
6525 .into_iter()
6526 .map(|package| SystemPackage {
6527 id: package,
6528 bytes: get_override_bytes(&package, name).unwrap(),
6529 dependencies: BuiltInFramework::all_package_ids(),
6530 })
6531 .collect()
6532 }
6533}
6534
6535#[derive(Debug, Serialize, Deserialize, Clone)]
6536pub struct ObjDumpFormat {
6537 pub id: ObjectID,
6538 pub version: VersionNumber,
6539 pub digest: ObjectDigest,
6540 pub object: Object,
6541}
6542
6543impl ObjDumpFormat {
6544 fn new(object: Object) -> Self {
6545 let oref = object.compute_object_reference();
6546 Self {
6547 id: oref.0,
6548 version: oref.1,
6549 digest: oref.2,
6550 object,
6551 }
6552 }
6553}
6554
6555#[derive(Debug, Serialize, Deserialize, Clone)]
6556pub struct NodeStateDump {
6557 pub tx_digest: TransactionDigest,
6558 pub sender_signed_data: SenderSignedData,
6559 pub executed_epoch: u64,
6560 pub reference_gas_price: u64,
6561 pub protocol_version: u64,
6562 pub epoch_start_timestamp_ms: u64,
6563 pub computed_effects: TransactionEffects,
6564 pub expected_effects_digest: TransactionEffectsDigest,
6565 pub relevant_system_packages: Vec<ObjDumpFormat>,
6566 pub shared_objects: Vec<ObjDumpFormat>,
6567 pub loaded_child_objects: Vec<ObjDumpFormat>,
6568 pub modified_at_versions: Vec<ObjDumpFormat>,
6569 pub runtime_reads: Vec<ObjDumpFormat>,
6570 pub input_objects: Vec<ObjDumpFormat>,
6571}
6572
6573impl NodeStateDump {
6574 pub fn new(
6575 tx_digest: &TransactionDigest,
6576 effects: &TransactionEffects,
6577 expected_effects_digest: TransactionEffectsDigest,
6578 object_store: &dyn ObjectStore,
6579 epoch_store: &Arc<AuthorityPerEpochStore>,
6580 inner_temporary_store: &InnerTemporaryStore,
6581 certificate: &VerifiedExecutableTransaction,
6582 ) -> SuiResult<Self> {
6583 let executed_epoch = epoch_store.epoch();
6585 let reference_gas_price = epoch_store.reference_gas_price();
6586 let epoch_start_config = epoch_store.epoch_start_config();
6587 let protocol_version = epoch_store.protocol_version().as_u64();
6588 let epoch_start_timestamp_ms = epoch_start_config.epoch_data().epoch_start_timestamp();
6589
6590 let mut relevant_system_packages = Vec::new();
6592 for sys_package_id in BuiltInFramework::all_package_ids() {
6593 if let Some(w) = object_store.get_object(&sys_package_id) {
6594 relevant_system_packages.push(ObjDumpFormat::new(w))
6595 }
6596 }
6597
6598 let mut shared_objects = Vec::new();
6600 for kind in effects.accessed_consensus_objects() {
6601 match kind {
6602 InputConsensusObject::Mutate(obj_ref) | InputConsensusObject::ReadOnly(obj_ref) => {
6603 if let Some(w) = object_store.get_object_by_key(&obj_ref.0, obj_ref.1) {
6604 shared_objects.push(ObjDumpFormat::new(w))
6605 }
6606 }
6607 InputConsensusObject::ReadConsensusStreamEnded(..)
6608 | InputConsensusObject::MutateConsensusStreamEnded(..)
6609 | InputConsensusObject::Cancelled(..) => (), }
6611 }
6612
6613 let mut loaded_child_objects = Vec::new();
6616 for (id, meta) in &inner_temporary_store.loaded_runtime_objects {
6617 if let Some(w) = object_store.get_object_by_key(id, meta.version) {
6618 loaded_child_objects.push(ObjDumpFormat::new(w))
6619 }
6620 }
6621
6622 let mut modified_at_versions = Vec::new();
6624 for (id, ver) in effects.modified_at_versions() {
6625 if let Some(w) = object_store.get_object_by_key(&id, ver) {
6626 modified_at_versions.push(ObjDumpFormat::new(w))
6627 }
6628 }
6629
6630 let mut runtime_reads = Vec::new();
6633 for obj in inner_temporary_store
6634 .runtime_packages_loaded_from_db
6635 .values()
6636 {
6637 runtime_reads.push(ObjDumpFormat::new(obj.object().clone()));
6638 }
6639
6640 Ok(Self {
6643 tx_digest: *tx_digest,
6644 executed_epoch,
6645 reference_gas_price,
6646 epoch_start_timestamp_ms,
6647 protocol_version,
6648 relevant_system_packages,
6649 shared_objects,
6650 loaded_child_objects,
6651 modified_at_versions,
6652 runtime_reads,
6653 sender_signed_data: certificate.clone().into_message(),
6654 input_objects: inner_temporary_store
6655 .input_objects
6656 .values()
6657 .map(|o| ObjDumpFormat::new(o.clone()))
6658 .collect(),
6659 computed_effects: effects.clone(),
6660 expected_effects_digest,
6661 })
6662 }
6663
6664 pub fn all_objects(&self) -> Vec<ObjDumpFormat> {
6665 let mut objects = Vec::new();
6666 objects.extend(self.relevant_system_packages.clone());
6667 objects.extend(self.shared_objects.clone());
6668 objects.extend(self.loaded_child_objects.clone());
6669 objects.extend(self.modified_at_versions.clone());
6670 objects.extend(self.runtime_reads.clone());
6671 objects.extend(self.input_objects.clone());
6672 objects
6673 }
6674
6675 pub fn write_to_file(&self, path: &Path) -> Result<PathBuf, anyhow::Error> {
6676 let file_name = format!(
6677 "{}_{}_NODE_DUMP.json",
6678 self.tx_digest,
6679 AuthorityState::unixtime_now_ms()
6680 );
6681 let mut path = path.to_path_buf();
6682 path.push(&file_name);
6683 let mut file = File::create(path.clone())?;
6684 file.write_all(serde_json::to_string_pretty(self)?.as_bytes())?;
6685 Ok(path)
6686 }
6687
6688 pub fn read_from_file(path: &PathBuf) -> Result<Self, anyhow::Error> {
6689 let file = File::open(path)?;
6690 serde_json::from_reader(file).map_err(|e| anyhow::anyhow!(e))
6691 }
6692}
6693
6694pub(crate) fn pre_object_load_checks(
6696 tx_data: &TransactionData,
6697 tx_signatures: &[GenericSignature],
6698 input_object_kinds: &[InputObjectKind],
6699 receiving_objects_refs: &[ObjectRef],
6700 protocol_config: &ProtocolConfig,
6701 transaction_deny_config: &TransactionDenyConfig,
6702 backing_package_store: &dyn BackingPackageStore,
6703 chain_identifier: ChainIdentifier,
6704 coin_reservation_resolver: &dyn CoinReservationResolverTrait,
6705 account_funds_read: &dyn AccountFundsRead,
6706) -> SuiResult<BTreeMap<AccumulatorObjId, (u64, TypeTag, SuiAddress)>> {
6707 sui_transaction_checks::deny::check_transaction_for_signing(
6711 tx_data,
6712 tx_signatures,
6713 input_object_kinds,
6714 receiving_objects_refs,
6715 transaction_deny_config,
6716 backing_package_store,
6717 )?;
6718
6719 let declared_withdrawals = tx_data
6720 .process_funds_withdrawals_for_signing(chain_identifier, coin_reservation_resolver)?;
6721
6722 account_funds_read.check_amounts_available(&declared_withdrawals)?;
6723
6724 if protocol_config.gasless_verify_remaining_balance() && tx_data.is_gasless_transaction() {
6725 let min_amounts = sui_types::transaction::get_gasless_allowed_token_types(protocol_config);
6726 account_funds_read
6727 .check_remaining_amounts_after_withdrawal(&declared_withdrawals, &min_amounts)?;
6728 }
6729
6730 Ok(declared_withdrawals)
6731}