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