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