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