1pub use checked::*;
5
6#[sui_macros::with_checked_arithmetic]
7pub(crate) mod checked {
8
9 use crate::adapter::new_move_runtime;
10 use crate::execution_mode::{self, ExecutionMode};
11 use crate::execution_value::SuiResolver;
12 use crate::gas_charger::{PaymentKind, PaymentMethod};
13 use move_binary_format::CompiledModule;
14 use move_trace_format::format::MoveTraceBuilder;
15 use move_vm_runtime::runtime::MoveRuntime;
16 use mysten_common::{assert_reachable, debug_fatal, in_test_configuration};
17 use std::collections::{BTreeMap, BTreeSet};
18 use std::{cell::RefCell, collections::HashSet, rc::Rc, sync::Arc};
19 use sui_types::accumulator_root::{ACCUMULATOR_ROOT_CREATE_FUNC, ACCUMULATOR_ROOT_MODULE};
20 use sui_types::balance::{
21 BALANCE_CREATE_REWARDS_FUNCTION_NAME, BALANCE_DESTROY_REBATES_FUNCTION_NAME,
22 BALANCE_MODULE_NAME,
23 };
24 use sui_types::coin_reservation::ParsedDigest;
25 use sui_types::execution_params::ExecutionOrEarlyError;
26 use sui_types::gas_coin::GAS;
27 use sui_types::messages_checkpoint::CheckpointTimestamp;
28 use sui_types::metrics::ExecutionMetrics;
29 use sui_types::object::OBJECT_START_VERSION;
30 use sui_types::programmable_transaction_builder::ProgrammableTransactionBuilder;
31 use sui_types::randomness_state::{
32 RANDOMNESS_MODULE_NAME, RANDOMNESS_STATE_CREATE_FUNCTION_NAME,
33 RANDOMNESS_STATE_UPDATE_FUNCTION_NAME,
34 };
35 use sui_types::{BRIDGE_ADDRESS, SUI_BRIDGE_OBJECT_ID, SUI_RANDOMNESS_STATE_OBJECT_ID};
36 use tracing::{info, instrument, trace, warn};
37
38 use crate::static_programmable_transactions as SPT;
39 use crate::sui_types::gas::SuiGasStatusAPI;
40 use crate::{gas_charger::GasCharger, temporary_store::TemporaryStore};
41 use move_core_types::ident_str;
42 use move_core_types::language_storage::TypeTag;
43 use sui_move_natives::all_natives;
44 use sui_protocol_config::{
45 Chain, LimitThresholdCrossed, PerObjectCongestionControlMode, ProtocolConfig,
46 check_limit_by_meter,
47 };
48 use sui_types::authenticator_state::{
49 AUTHENTICATOR_STATE_CREATE_FUNCTION_NAME, AUTHENTICATOR_STATE_EXPIRE_JWKS_FUNCTION_NAME,
50 AUTHENTICATOR_STATE_MODULE_NAME, AUTHENTICATOR_STATE_UPDATE_FUNCTION_NAME,
51 };
52 use sui_types::base_types::{ObjectID, SequenceNumber};
53 use sui_types::bridge::BRIDGE_COMMITTEE_MINIMAL_VOTING_POWER;
54 use sui_types::bridge::{
55 BRIDGE_CREATE_FUNCTION_NAME, BRIDGE_INIT_COMMITTEE_FUNCTION_NAME, BRIDGE_MODULE_NAME,
56 BridgeChainId,
57 };
58 use sui_types::clock::{CLOCK_MODULE_NAME, CONSENSUS_COMMIT_PROLOGUE_FUNCTION_NAME};
59 use sui_types::committee::EpochId;
60 use sui_types::deny_list_v1::{DENY_LIST_CREATE_FUNC, DENY_LIST_MODULE};
61 use sui_types::digests::{
62 ChainIdentifier, get_mainnet_chain_identifier, get_testnet_chain_identifier,
63 };
64 use sui_types::effects::TransactionEffects;
65 use sui_types::error::{ExecutionError, ExecutionErrorTrait};
66 use sui_types::execution::{ExecutionTiming, ResultWithTimings, SharedInput};
67 use sui_types::execution_status::{ExecutionErrorKind, ExecutionStatus};
68 use sui_types::gas::GasCostSummary;
69 use sui_types::gas::SuiGasStatus;
70 use sui_types::id::UID;
71 use sui_types::inner_temporary_store::InnerTemporaryStore;
72 use sui_types::storage::BackingStore;
73 #[cfg(msim)]
74 use sui_types::sui_system_state::advance_epoch_result_injection::maybe_modify_result_for;
75 use sui_types::sui_system_state::{ADVANCE_EPOCH_SAFE_MODE_FUNCTION_NAME, AdvanceEpochParams};
76 use sui_types::transaction::{
77 Argument, AuthenticatorStateExpire, AuthenticatorStateUpdate, CallArg, ChangeEpoch,
78 Command, EndOfEpochTransactionKind, GasData, GenesisTransaction, ObjectArg,
79 ProgrammableTransaction, Reservation, StoredExecutionTimeObservations, TransactionKind,
80 WithdrawFrom, WriteAccumulatorStorageCost, is_gasless_transaction,
81 };
82 use sui_types::transaction::{CheckedInputObjects, RandomnessStateUpdate};
83 use sui_types::{
84 SUI_AUTHENTICATOR_STATE_OBJECT_ID, SUI_FRAMEWORK_ADDRESS, SUI_FRAMEWORK_PACKAGE_ID,
85 SUI_SYSTEM_PACKAGE_ID,
86 base_types::{SuiAddress, TransactionDigest, TxContext},
87 object::{Object, ObjectInner},
88 sui_system_state::{ADVANCE_EPOCH_FUNCTION_NAME, SUI_SYSTEM_MODULE_NAME},
89 };
90
91 fn head_error_is_insufficient_funds_for_withdraw(
96 execution_params: &ExecutionOrEarlyError,
97 ) -> bool {
98 execution_params.early_errors().is_some_and(|errors| {
99 matches!(
100 errors.head,
101 ExecutionErrorKind::InsufficientFundsForWithdraw
102 )
103 })
104 }
105
106 fn payment_kind(
107 gas_data: &GasData,
108 transaction_kind: &TransactionKind,
109 protocol_config: &ProtocolConfig,
110 ) -> PaymentKind {
111 if gas_data.is_unmetered() || transaction_kind.is_system_tx() {
112 PaymentKind::unmetered()
113 } else if protocol_config.enable_gasless()
114 && is_gasless_transaction(gas_data, transaction_kind)
115 {
116 PaymentKind::gasless()
117 } else if gas_data.payment.is_empty() {
118 PaymentKind::smash(vec![PaymentMethod::AddressBalance(
119 gas_data.owner,
120 gas_data.budget,
121 )])
122 .expect("unable to create a payment kind with a single address balance")
123 } else {
124 let payment_methods = gas_data
125 .payment
126 .iter()
127 .map(|entry| {
128 if let Ok(parsed) = ParsedDigest::try_from(entry.2) {
129 PaymentMethod::AddressBalance(gas_data.owner, parsed.reservation_amount())
130 } else {
131 PaymentMethod::Coin(*entry)
132 }
133 })
134 .collect();
135 PaymentKind::smash(payment_methods).expect(
136 "unable to create a payment kind from payment methods. \
137 Should not be possible wit ha non-empty vector",
138 )
139 }
140 }
141
142 type ExecutionOutput<Mode> = (
143 InnerTemporaryStore,
144 SuiGasStatus,
145 TransactionEffects,
146 Vec<ExecutionTiming>,
147 Result<<Mode as ExecutionMode>::ExecutionResults, <Mode as ExecutionMode>::Error>,
148 );
149 #[instrument(name = "tx_execute_to_effects", level = "debug", skip_all)]
150 pub fn execute_transaction_to_effects<Mode: ExecutionMode>(
151 store: &dyn BackingStore,
152 input_objects: CheckedInputObjects,
153 system_object_versions: BTreeMap<ObjectID, SequenceNumber>,
154 gas_data: GasData,
155 gas_status: SuiGasStatus,
156 transaction_kind: TransactionKind,
157 rewritten_inputs: Option<Vec<bool>>,
158 transaction_signer: SuiAddress,
159 transaction_digest: TransactionDigest,
160 move_vm: &Arc<MoveRuntime>,
161 epoch_id: &EpochId,
162 epoch_timestamp_ms: u64,
163 protocol_config: &ProtocolConfig,
164 metrics: Arc<ExecutionMetrics>,
165 enable_expensive_checks: bool,
166 execution_params: ExecutionOrEarlyError,
167 trace_builder_opt: &mut Option<MoveTraceBuilder>,
168 ) -> ExecutionOutput<Mode> {
169 let input_objects = input_objects.into_inner();
170 let mutable_inputs = if enable_expensive_checks {
171 input_objects.all_mutable_inputs().keys().copied().collect()
172 } else {
173 HashSet::new()
174 };
175 let shared_object_refs = input_objects.filter_shared_objects();
176 let receiving_objects = transaction_kind.receiving_objects();
177 let transaction_dependencies = input_objects.transaction_dependencies();
178
179 let temporary_store = TemporaryStore::new(
180 store,
181 input_objects,
182 receiving_objects,
183 transaction_digest,
184 protocol_config,
185 *epoch_id,
186 system_object_versions,
187 );
188
189 legacy::execute_transaction_inner::<Mode>(
191 store,
192 temporary_store,
193 gas_data,
194 gas_status,
195 transaction_kind,
196 rewritten_inputs,
197 transaction_signer,
198 transaction_digest,
199 move_vm,
200 epoch_id,
201 epoch_timestamp_ms,
202 protocol_config,
203 metrics,
204 enable_expensive_checks,
205 execution_params,
206 trace_builder_opt,
207 shared_object_refs,
208 transaction_dependencies,
209 mutable_inputs,
210 )
211 }
212
213 fn update_vm_telemetry_metrics(metrics: &ExecutionMetrics, move_vm: &MoveRuntime) {
214 metrics.vm_telemetry_metrics.try_update(|vm_metrics| {
215 let t = move_vm.get_telemetry_report();
216 vm_metrics
217 .move_vm_package_cache_count
218 .set(t.package_cache_count as i64);
219 vm_metrics
220 .move_vm_total_arena_size_bytes
221 .set(t.total_arena_size as i64);
222 vm_metrics.move_vm_module_count.set(t.module_count as i64);
223 vm_metrics
224 .move_vm_function_count
225 .set(t.function_count as i64);
226 vm_metrics.move_vm_type_count.set(t.type_count as i64);
227 vm_metrics.move_vm_interner_size.set(t.interner_size as i64);
228 vm_metrics
229 .move_vm_vtable_cache_count
230 .set(t.vtable_cache_count as i64);
231 vm_metrics
232 .move_vm_vtable_cache_hits
233 .set(t.vtable_cache_hits as i64);
234 vm_metrics
235 .move_vm_vtable_cache_misses
236 .set(t.vtable_cache_misses as i64);
237 vm_metrics
238 .move_vm_load_time_ms
239 .set(t.total_load_time as i64);
240 vm_metrics.move_vm_load_count.set(t.load_count as i64);
241 vm_metrics
242 .move_vm_validation_time_ms
243 .set(t.total_validation_time as i64);
244 vm_metrics
245 .move_vm_validation_count
246 .set(t.validation_count as i64);
247 vm_metrics.move_vm_jit_time_ms.set(t.total_jit_time as i64);
248 vm_metrics.move_vm_jit_count.set(t.jit_count as i64);
249 vm_metrics
250 .move_vm_execution_time_ms
251 .set(t.total_execution_time as i64);
252 vm_metrics
253 .move_vm_execution_count
254 .set(t.execution_count as i64);
255 vm_metrics
256 .move_vm_interpreter_time_ms
257 .set(t.total_interpreter_time as i64);
258 vm_metrics
259 .move_vm_interpreter_count
260 .set(t.interpreter_count as i64);
261 vm_metrics
262 .move_vm_max_callstack_size
263 .set(t.max_callstack_size as i64);
264 vm_metrics
265 .move_vm_max_valuestack_size
266 .set(t.max_valuestack_size as i64);
267 vm_metrics.move_vm_total_time_ms.set(t.total_time as i64);
268 vm_metrics.move_vm_total_count.set(t.total_count as i64);
269 });
270 }
271
272 pub fn execute_genesis_state_update(
273 store: &dyn BackingStore,
274 protocol_config: &ProtocolConfig,
275 metrics: Arc<ExecutionMetrics>,
276 move_vm: &Arc<MoveRuntime>,
277 tx_context: Rc<RefCell<TxContext>>,
278 input_objects: CheckedInputObjects,
279 pt: ProgrammableTransaction,
280 ) -> Result<InnerTemporaryStore, ExecutionError> {
281 let input_objects = input_objects.into_inner();
282 let mut temporary_store = TemporaryStore::new(
283 store,
284 input_objects,
285 vec![],
286 tx_context.borrow().digest(),
287 protocol_config,
288 0,
289 BTreeMap::new(),
290 );
291 let mut gas_charger = GasCharger::new_unmetered(tx_context.borrow().digest());
292 SPT::execute::<execution_mode::Genesis>(
293 protocol_config,
294 metrics,
295 move_vm,
296 &mut temporary_store,
297 store.as_backing_package_store(),
298 tx_context,
299 &mut gas_charger,
300 None,
301 pt,
302 &mut None,
303 )
304 .map_err(|(e, _)| e)?;
305 temporary_store.update_object_version_and_prev_tx();
306 Ok(temporary_store.into_inner(BTreeMap::new()))
307 }
308
309 pub(crate) mod legacy {
312 use super::*;
313
314 pub(crate) const ADDRESS_BALANCE_SMASH_FIX_MIN_ACCUMULATOR_VERSION: SequenceNumber =
321 SequenceNumber::from_u64(692949576);
322
323 pub(crate) const ADDRESS_BALANCE_SMASH_SHORT_CIRCUIT_MIN_ACCUMULATOR_VERSION:
333 SequenceNumber = SequenceNumber::from_u64(693531074);
334
335 pub(crate) fn should_filter_address_balance_gas_smash(
340 execution_params: &ExecutionOrEarlyError,
341 protocol_config: &ProtocolConfig,
342 ) -> bool {
343 if !head_error_is_insufficient_funds_for_withdraw(execution_params) {
344 return false;
345 }
346 debug_assert!(
347 !protocol_config.early_exit_on_iffw(),
348 "Should not reach gas smashing filtering address balances if IFFW early exit is enabled"
349 );
350 in_test_configuration()
353 || protocol_config.early_exit_on_iffw()
354 || (protocol_config.chain() == Chain::Mainnet
355 && execution_params
356 .accumulator_version()
357 .is_some_and(|v| v >= ADDRESS_BALANCE_SMASH_FIX_MIN_ACCUMULATOR_VERSION))
358 }
359
360 pub(crate) fn should_short_circuit_insufficient_funds(
365 execution_params: &ExecutionOrEarlyError,
366 protocol_config: &ProtocolConfig,
367 ) -> bool {
368 if !execution_params.early_errors().is_some_and(|errors| {
370 errors
371 .iter()
372 .any(|e| matches!(e, ExecutionErrorKind::InsufficientFundsForWithdraw))
373 }) {
374 return false;
375 }
376
377 if in_test_configuration() {
380 return true;
381 }
382
383 protocol_config.early_exit_on_iffw()
385 || (protocol_config.chain() == Chain::Mainnet
386 && execution_params.accumulator_version().is_some_and(|v| {
387 v >= ADDRESS_BALANCE_SMASH_SHORT_CIRCUIT_MIN_ACCUMULATOR_VERSION
388 }))
389 }
390
391 #[allow(clippy::too_many_arguments)]
393 pub(super) fn execute_transaction_inner<Mode: ExecutionMode>(
394 store: &dyn BackingStore,
395 mut temporary_store: TemporaryStore<'_>,
396 mut gas_data: GasData,
397 gas_status: SuiGasStatus,
398 transaction_kind: TransactionKind,
399 rewritten_inputs: Option<Vec<bool>>,
400 transaction_signer: SuiAddress,
401 transaction_digest: TransactionDigest,
402 move_vm: &Arc<MoveRuntime>,
403 epoch_id: &EpochId,
404 epoch_timestamp_ms: u64,
405 protocol_config: &ProtocolConfig,
406 metrics: Arc<ExecutionMetrics>,
407 enable_expensive_checks: bool,
408 execution_params: ExecutionOrEarlyError,
409 trace_builder_opt: &mut Option<MoveTraceBuilder>,
410 shared_object_refs: Vec<SharedInput>,
411 mut transaction_dependencies: BTreeSet<TransactionDigest>,
412 mutable_inputs: HashSet<ObjectID>,
413 ) -> ExecutionOutput<Mode> {
414 if should_short_circuit_insufficient_funds(&execution_params, protocol_config) {
421 assert_reachable!("IFFW short-circuit fired");
422 temporary_store.ensure_active_inputs_mutated();
423 transaction_dependencies.remove(&TransactionDigest::genesis_marker());
424
425 let execution_error: Mode::Error =
426 ExecutionError::from_kind(ExecutionErrorKind::InsufficientFundsForWithdraw)
427 .into();
428 let status = ExecutionStatus::new_failure(execution_error.to_execution_failure());
429 let gas_meter = GasCharger::new(
430 transaction_digest,
431 PaymentKind::gasless(),
432 gas_status,
433 &mut temporary_store,
434 protocol_config,
435 );
436
437 let gas_coin = gas_meter.gas_coin();
438 let (inner, effects) = temporary_store.into_effects(
439 shared_object_refs,
440 &transaction_digest,
441 transaction_dependencies,
442 GasCostSummary::default(),
443 status,
444 gas_coin,
445 *epoch_id,
446 );
447
448 return (
449 inner,
450 gas_meter.into_gas_status(),
451 effects,
452 vec![],
453 Err(execution_error),
454 );
455 }
456
457 let sponsor = {
458 let gas_owner = gas_data.owner;
459 if gas_owner == transaction_signer {
460 None
461 } else {
462 Some(gas_owner)
463 }
464 };
465 let gas_price = gas_status.gas_price();
466 let rgp = gas_status.reference_gas_price();
467
468 if should_filter_address_balance_gas_smash(&execution_params, protocol_config)
472 && gas_data.payment.len() > 1
473 && ParsedDigest::try_from(gas_data.payment[0].2).is_err()
474 {
475 gas_data
476 .payment
477 .retain(|entry| ParsedDigest::try_from(entry.2).is_err());
478 }
479
480 let mut gas_charger = GasCharger::new(
481 transaction_digest,
482 payment_kind(&gas_data, &transaction_kind, protocol_config),
483 gas_status,
484 &mut temporary_store,
485 protocol_config,
486 );
487
488 let tx_ctx = TxContext::new_from_components(
489 &transaction_signer,
490 &transaction_digest,
491 epoch_id,
492 epoch_timestamp_ms,
493 rgp,
494 gas_price,
495 gas_data.budget,
496 sponsor,
497 protocol_config,
498 );
499 let tx_ctx = Rc::new(RefCell::new(tx_ctx));
500
501 let is_gasless = protocol_config.enable_gasless()
502 && is_gasless_transaction(&gas_data, &transaction_kind);
503 let is_epoch_change = transaction_kind.is_end_of_epoch_tx();
504
505 temporary_store.set_invariant_inputs(&transaction_kind, &gas_data, transaction_signer);
509
510 let (gas_cost_summary, mut execution_result, timings) = execute_transaction::<Mode>(
511 store,
512 &mut temporary_store,
513 transaction_kind,
514 rewritten_inputs,
515 &mut gas_charger,
516 tx_ctx,
517 move_vm,
518 protocol_config,
519 metrics.clone(),
520 execution_params,
521 trace_builder_opt,
522 is_gasless,
523 );
524
525 if let Err(e) = run_invariant_checks::<Mode>(
528 &mut temporary_store,
529 &mut gas_charger,
530 transaction_digest,
531 move_vm,
532 protocol_config,
533 enable_expensive_checks,
534 &gas_cost_summary,
535 &transaction_signer,
536 &sponsor,
537 &mutable_inputs,
538 is_epoch_change,
539 ) {
540 execution_result = Err(e);
542 }
543
544 let status = if let Err(error) = &execution_result {
545 ExecutionStatus::new_failure(error.to_execution_failure())
546 } else {
547 ExecutionStatus::Success
548 };
549
550 #[skip_checked_arithmetic]
551 trace!(
552 tx_digest = ?transaction_digest,
553 computation_gas_cost = gas_cost_summary.computation_cost,
554 storage_gas_cost = gas_cost_summary.storage_cost,
555 storage_gas_rebate = gas_cost_summary.storage_rebate,
556 "Finished execution of transaction with status {:?}",
557 status
558 );
559
560 transaction_dependencies.remove(&TransactionDigest::genesis_marker());
564
565 let gas_coin = gas_charger.gas_coin();
566 let (inner, effects) = temporary_store.into_effects(
567 shared_object_refs,
568 &transaction_digest,
569 transaction_dependencies,
570 gas_cost_summary,
571 status,
572 gas_coin,
573 *epoch_id,
574 );
575
576 if !Mode::TRACK_EXECUTION {
579 update_vm_telemetry_metrics(&metrics, move_vm);
580 }
581
582 (
583 inner,
584 gas_charger.into_gas_status(),
585 effects,
586 timings,
587 execution_result,
588 )
589 }
590
591 #[instrument(name = "tx_execute", level = "debug", skip_all)]
592 fn execute_transaction<Mode: ExecutionMode>(
593 store: &dyn BackingStore,
594 temporary_store: &mut TemporaryStore<'_>,
595 transaction_kind: TransactionKind,
596 rewritten_inputs: Option<Vec<bool>>,
597 gas_charger: &mut GasCharger,
598 tx_ctx: Rc<RefCell<TxContext>>,
599 move_vm: &Arc<MoveRuntime>,
600 protocol_config: &ProtocolConfig,
601 metrics: Arc<ExecutionMetrics>,
602 execution_params: ExecutionOrEarlyError,
603 trace_builder_opt: &mut Option<MoveTraceBuilder>,
604 is_gasless: bool,
605 ) -> (
606 GasCostSummary,
607 Result<Mode::ExecutionResults, Mode::Error>,
608 Vec<ExecutionTiming>,
609 ) {
610 debug_assert!(
612 gas_charger.no_charges(),
613 "No gas charges must be applied yet"
614 );
615
616 let withdrawal_reservations =
617 if is_gasless && protocol_config.gasless_verify_remaining_balance() {
618 gasless_withdrawal_reservations(&transaction_kind, &tx_ctx.borrow())
619 } else {
620 None
621 };
622
623 let result = gas_charger.charge_input_objects_legacy(temporary_store);
626
627 let result: ResultWithTimings<Mode::ExecutionResults, Mode::Error> =
628 result.map_err(|e| (e.into(), vec![])).and_then(
629 |()| -> ResultWithTimings<Mode::ExecutionResults, Mode::Error> {
630 let mut execution_result: ResultWithTimings<
631 Mode::ExecutionResults,
632 Mode::Error,
633 > = match execution_params.into_early_errors() {
634 Some(early_execution_errors) => {
635 Err((Mode::Error::from_kind(early_execution_errors.head), vec![]))
636 }
637 None => execution_loop::<Mode>(
638 store,
639 temporary_store,
640 transaction_kind,
641 rewritten_inputs,
642 tx_ctx,
643 move_vm,
644 gas_charger,
645 protocol_config,
646 metrics.clone(),
647 trace_builder_opt,
648 ),
649 };
650
651 let meter_check = check_meter_limit::<Mode>(
652 temporary_store,
653 gas_charger,
654 protocol_config,
655 metrics.clone(),
656 );
657 if let Err(e) = meter_check {
658 execution_result = Err((e, vec![]));
659 }
660
661 if execution_result.is_ok() {
662 let gas_check = check_written_objects_limit::<Mode>(
663 temporary_store,
664 gas_charger,
665 protocol_config,
666 metrics,
667 );
668 if let Err(e) = gas_check {
669 execution_result = Err((e, vec![]));
670 }
671 }
672
673 execution_result
674 },
675 );
676
677 let (mut result, timings) = match result {
678 Ok((r, t)) => (Ok(r), t),
679 Err((e, t)) => (Err(e), t),
680 };
681 if is_gasless
682 && result.is_ok()
683 && let Err(msg) = temporary_store
684 .check_gasless_execution_requirements(withdrawal_reservations.as_ref())
685 {
686 result = Err(Mode::Error::new_with_source(
687 ExecutionErrorKind::InsufficientGas,
688 msg,
689 ));
690 }
691
692 if result.is_ok()
705 && let Err(e) = temporary_store.check_accumulator_amounts_representable()
706 {
707 result = Err(e.into());
708 }
709
710 let cost_summary =
711 gas_charger.legacy_charge_gas(temporary_store, protocol_config, &mut result);
712 temporary_store
720 .conserve_unmetered_storage_rebate(gas_charger.unmetered_storage_rebate());
721
722 (cost_summary, result, timings)
723 }
724
725 #[allow(clippy::too_many_arguments)]
738 fn run_invariant_checks<Mode: ExecutionMode>(
739 temporary_store: &mut TemporaryStore<'_>,
740 gas_charger: &mut GasCharger,
741 tx_digest: TransactionDigest,
742 move_vm: &Arc<MoveRuntime>,
743 protocol_config: &ProtocolConfig,
744 enable_expensive_checks: bool,
745 cost_summary: &GasCostSummary,
746 sender: &SuiAddress,
747 sponsor: &Option<SuiAddress>,
748 mutable_inputs: &HashSet<ObjectID>,
749 is_epoch_change: bool,
750 ) -> Result<(), Mode::Error> {
751 let conservation = run_conservation_checks::<Mode>(
752 temporary_store,
753 gas_charger,
754 tx_digest,
755 move_vm,
756 protocol_config,
757 enable_expensive_checks,
758 cost_summary,
759 );
760 if enable_expensive_checks && !Mode::allow_arbitrary_function_calls() {
761 temporary_store
762 .check_ownership_invariants(
763 sender,
764 sponsor,
765 gas_charger,
766 mutable_inputs,
767 is_epoch_change,
768 )
769 .unwrap()
770 } conservation
772 }
773
774 #[instrument(name = "run_conservation_checks", level = "debug", skip_all)]
781 fn run_conservation_checks<Mode: ExecutionMode>(
782 temporary_store: &mut TemporaryStore<'_>,
783 gas_charger: &mut GasCharger,
784 tx_digest: TransactionDigest,
785 move_vm: &Arc<MoveRuntime>,
786 protocol_config: &ProtocolConfig,
787 enable_expensive_checks: bool,
788 cost_summary: &GasCostSummary,
789 ) -> Result<(), Mode::Error> {
790 let Err(conservation_err) = temporary_store.check_conservation_invariants::<Mode>(
791 move_vm,
792 enable_expensive_checks,
793 cost_summary,
794 ) else {
795 return Ok(());
796 };
797
798 let mut result: Result<(), Mode::Error> = Err(conservation_err.into());
802 gas_charger.reset(temporary_store);
803 gas_charger.legacy_charge_gas(temporary_store, protocol_config, &mut result);
804 if let Err(recovery_err) = temporary_store.check_conservation_invariants::<Mode>(
805 move_vm,
806 enable_expensive_checks,
807 cost_summary,
808 ) {
809 panic!(
813 "SUI conservation fail in tx block {}: {}\nGas status is {}\nTx was ",
814 tx_digest,
815 recovery_err,
816 gas_charger.summary()
817 )
818 }
819 result
820 }
821 }
822
823 #[instrument(name = "check_meter_limit", level = "debug", skip_all)]
824 fn check_meter_limit<Mode: ExecutionMode>(
825 temporary_store: &mut TemporaryStore<'_>,
826 gas_charger: &mut GasCharger,
827 protocol_config: &ProtocolConfig,
828 metrics: Arc<ExecutionMetrics>,
829 ) -> Result<(), Mode::Error> {
830 let effects_estimated_size = temporary_store.estimate_effects_size_upperbound();
831
832 match check_limit_by_meter!(
836 !gas_charger.is_unmetered(),
837 effects_estimated_size,
838 protocol_config.max_serialized_tx_effects_size_bytes(),
839 protocol_config.max_serialized_tx_effects_size_bytes_system_tx(),
840 metrics.limits_metrics.excessive_estimated_effects_size
841 ) {
842 LimitThresholdCrossed::None => Ok(()),
843 LimitThresholdCrossed::Soft(_, limit) => {
844 warn!(
845 effects_estimated_size = effects_estimated_size,
846 soft_limit = limit,
847 "Estimated transaction effects size crossed soft limit",
848 );
849 Ok(())
850 }
851 LimitThresholdCrossed::Hard(_, lim) => Err(Mode::Error::new_with_source(
852 ExecutionErrorKind::EffectsTooLarge {
853 current_size: effects_estimated_size as u64,
854 max_size: lim as u64,
855 },
856 "Transaction effects are too large",
857 )),
858 }
859 }
860
861 #[instrument(name = "check_written_objects_limit", level = "debug", skip_all)]
862 fn check_written_objects_limit<Mode: ExecutionMode>(
863 temporary_store: &mut TemporaryStore<'_>,
864 gas_charger: &mut GasCharger,
865 protocol_config: &ProtocolConfig,
866 metrics: Arc<ExecutionMetrics>,
867 ) -> Result<(), Mode::Error> {
868 if let (Some(normal_lim), Some(system_lim)) = (
869 protocol_config.max_size_written_objects_as_option(),
870 protocol_config.max_size_written_objects_system_tx_as_option(),
871 ) {
872 let written_objects_size = temporary_store.written_objects_size();
873
874 match check_limit_by_meter!(
875 !gas_charger.is_unmetered(),
876 written_objects_size,
877 normal_lim,
878 system_lim,
879 metrics.limits_metrics.excessive_written_objects_size
880 ) {
881 LimitThresholdCrossed::None => (),
882 LimitThresholdCrossed::Soft(_, limit) => {
883 warn!(
884 written_objects_size = written_objects_size,
885 soft_limit = limit,
886 "Written objects size crossed soft limit",
887 )
888 }
889 LimitThresholdCrossed::Hard(_, lim) => {
890 return Err(Mode::Error::new_with_source(
891 ExecutionErrorKind::WrittenObjectsTooLarge {
892 current_size: written_objects_size as u64,
893 max_size: lim as u64,
894 },
895 "Written objects size crossed hard limit",
896 ));
897 }
898 };
899 }
900
901 Ok(())
902 }
903
904 fn gasless_withdrawal_reservations(
905 transaction_kind: &TransactionKind,
906 tx_ctx: &TxContext,
907 ) -> Option<BTreeMap<(SuiAddress, TypeTag), u64>> {
908 let TransactionKind::ProgrammableTransaction(pt) = transaction_kind else {
909 debug_fatal!("Gasless transaction must be a ProgrammableTransaction");
910 return None;
911 };
912 let sender = tx_ctx.sender();
913 let mut reservations = BTreeMap::<(SuiAddress, TypeTag), u64>::new();
914 for input in &pt.inputs {
915 let CallArg::FundsWithdrawal(fw) = input else {
916 continue;
917 };
918 let Some(coin_type) = fw.type_arg.get_balance_type_param() else {
919 debug_fatal!("expected Balance type for withdrawal");
920 continue;
921 };
922 let owner = match fw.withdraw_from {
923 WithdrawFrom::Sender => sender,
924 WithdrawFrom::Sponsor => {
925 debug_fatal!("WithdrawFrom::Sponsor is not expected in gasless transactions");
926 tx_ctx.sponsor().unwrap_or(sender)
927 }
928 };
929 let Reservation::MaxAmountU64(amount) = fw.reservation;
930 let entry = reservations.entry((owner, coin_type)).or_insert(0);
931 *entry = entry.saturating_add(amount);
932 }
933 Some(reservations)
934 }
935
936 #[instrument(level = "debug", skip_all)]
937 fn execution_loop<Mode: ExecutionMode>(
938 store: &dyn BackingStore,
939 temporary_store: &mut TemporaryStore<'_>,
940 transaction_kind: TransactionKind,
941 rewritten_inputs: Option<Vec<bool>>,
942 tx_ctx: Rc<RefCell<TxContext>>,
943 move_vm: &Arc<MoveRuntime>,
944 gas_charger: &mut GasCharger,
945 protocol_config: &ProtocolConfig,
946 metrics: Arc<ExecutionMetrics>,
947 trace_builder_opt: &mut Option<MoveTraceBuilder>,
948 ) -> ResultWithTimings<Mode::ExecutionResults, Mode::Error> {
949 let result = match transaction_kind {
950 TransactionKind::ChangeEpoch(change_epoch) => {
951 let builder = ProgrammableTransactionBuilder::new();
952 advance_epoch::<Mode>(
953 builder,
954 change_epoch,
955 temporary_store,
956 store,
957 tx_ctx,
958 move_vm,
959 gas_charger,
960 protocol_config,
961 metrics,
962 trace_builder_opt,
963 )
964 .map_err(|e| (e, vec![]))?;
965 Ok((Mode::empty_results(), vec![]))
966 }
967 TransactionKind::Genesis(GenesisTransaction { objects }) => {
968 if tx_ctx.borrow().epoch() != 0 {
969 panic!("BUG: Genesis Transactions can only be executed in epoch 0");
970 }
971
972 for genesis_object in objects {
973 match genesis_object {
974 sui_types::transaction::GenesisObject::RawObject { data, owner } => {
975 let object = ObjectInner {
976 data,
977 owner,
978 previous_transaction: tx_ctx.borrow().digest(),
979 storage_rebate: 0,
980 };
981 temporary_store.create_object(object.into());
982 }
983 }
984 }
985 Ok((Mode::empty_results(), vec![]))
986 }
987 TransactionKind::ConsensusCommitPrologue(prologue) => {
988 setup_consensus_commit::<Mode>(
989 prologue.commit_timestamp_ms,
990 temporary_store,
991 store,
992 tx_ctx,
993 move_vm,
994 gas_charger,
995 protocol_config,
996 metrics,
997 trace_builder_opt,
998 )
999 .expect("ConsensusCommitPrologue cannot fail");
1000 Ok((Mode::empty_results(), vec![]))
1001 }
1002 TransactionKind::ConsensusCommitPrologueV2(prologue) => {
1003 setup_consensus_commit::<Mode>(
1004 prologue.commit_timestamp_ms,
1005 temporary_store,
1006 store,
1007 tx_ctx,
1008 move_vm,
1009 gas_charger,
1010 protocol_config,
1011 metrics,
1012 trace_builder_opt,
1013 )
1014 .expect("ConsensusCommitPrologueV2 cannot fail");
1015 Ok((Mode::empty_results(), vec![]))
1016 }
1017 TransactionKind::ConsensusCommitPrologueV3(prologue) => {
1018 setup_consensus_commit::<Mode>(
1019 prologue.commit_timestamp_ms,
1020 temporary_store,
1021 store,
1022 tx_ctx,
1023 move_vm,
1024 gas_charger,
1025 protocol_config,
1026 metrics,
1027 trace_builder_opt,
1028 )
1029 .expect("ConsensusCommitPrologueV3 cannot fail");
1030 Ok((Mode::empty_results(), vec![]))
1031 }
1032 TransactionKind::ConsensusCommitPrologueV4(prologue) => {
1033 setup_consensus_commit::<Mode>(
1034 prologue.commit_timestamp_ms,
1035 temporary_store,
1036 store,
1037 tx_ctx,
1038 move_vm,
1039 gas_charger,
1040 protocol_config,
1041 metrics,
1042 trace_builder_opt,
1043 )
1044 .expect("ConsensusCommitPrologue cannot fail");
1045 Ok((Mode::empty_results(), vec![]))
1046 }
1047 TransactionKind::ProgrammableTransaction(pt) => SPT::execute::<Mode>(
1048 protocol_config,
1049 metrics,
1050 move_vm,
1051 temporary_store,
1052 store.as_backing_package_store(),
1053 tx_ctx,
1054 gas_charger,
1055 rewritten_inputs,
1056 pt,
1057 trace_builder_opt,
1058 ),
1059 TransactionKind::ProgrammableSystemTransaction(pt) => {
1060 SPT::execute::<execution_mode::System<Mode::Error>>(
1061 protocol_config,
1062 metrics,
1063 move_vm,
1064 temporary_store,
1065 store.as_backing_package_store(),
1066 tx_ctx,
1067 gas_charger,
1068 None,
1069 pt,
1070 trace_builder_opt,
1071 )
1072 .map_err(|(e, _)| (e, vec![]))?;
1073 Ok((Mode::empty_results(), vec![]))
1074 }
1075 TransactionKind::EndOfEpochTransaction(txns) => {
1076 let mut builder = ProgrammableTransactionBuilder::new();
1077 let len = txns.len();
1078 for (i, tx) in txns.into_iter().enumerate() {
1079 match tx {
1080 EndOfEpochTransactionKind::ChangeEpoch(change_epoch) => {
1081 assert_eq!(i, len - 1);
1082 advance_epoch::<Mode>(
1083 builder,
1084 change_epoch,
1085 temporary_store,
1086 store,
1087 tx_ctx,
1088 move_vm,
1089 gas_charger,
1090 protocol_config,
1091 metrics,
1092 trace_builder_opt,
1093 )
1094 .map_err(|e| (e, vec![]))?;
1095 return Ok((Mode::empty_results(), vec![]));
1096 }
1097 EndOfEpochTransactionKind::AuthenticatorStateCreate => {
1098 assert!(protocol_config.enable_jwk_consensus_updates());
1099 builder = setup_authenticator_state_create(builder);
1100 }
1101 EndOfEpochTransactionKind::AuthenticatorStateExpire(expire) => {
1102 assert!(protocol_config.enable_jwk_consensus_updates());
1103
1104 builder = setup_authenticator_state_expire(builder, expire);
1107 }
1108 EndOfEpochTransactionKind::RandomnessStateCreate => {
1109 assert!(protocol_config.random_beacon());
1110 builder = setup_randomness_state_create(builder);
1111 }
1112 EndOfEpochTransactionKind::DenyListStateCreate => {
1113 assert!(protocol_config.enable_coin_deny_list());
1114 builder = setup_coin_deny_list_state_create(builder);
1115 }
1116 EndOfEpochTransactionKind::BridgeStateCreate(chain_id) => {
1117 assert!(protocol_config.bridge());
1118 builder = setup_bridge_create(builder, chain_id)
1119 }
1120 EndOfEpochTransactionKind::BridgeCommitteeInit(bridge_shared_version) => {
1121 assert!(protocol_config.bridge());
1122 assert!(protocol_config.should_try_to_finalize_bridge_committee());
1123 builder = setup_bridge_committee_update(builder, bridge_shared_version)
1124 }
1125 EndOfEpochTransactionKind::StoreExecutionTimeObservations(estimates) => {
1126 if let PerObjectCongestionControlMode::ExecutionTimeEstimate(params) =
1127 protocol_config.per_object_congestion_control_mode()
1128 {
1129 let chunk_size = params
1130 .observations_chunk_size
1131 .expect("observation chunking is enabled at all protocol versions handled by this execution layer");
1132 builder = setup_store_execution_time_estimates(
1133 builder,
1134 estimates,
1135 chunk_size as usize,
1136 );
1137 }
1138 }
1139 EndOfEpochTransactionKind::AccumulatorRootCreate => {
1140 assert!(protocol_config.create_root_accumulator_object());
1141 builder = setup_accumulator_root_create(builder);
1142 }
1143 EndOfEpochTransactionKind::WriteAccumulatorStorageCost(
1144 write_storage_cost,
1145 ) => {
1146 assert!(protocol_config.enable_accumulators());
1147 builder =
1148 setup_write_accumulator_storage_cost(builder, &write_storage_cost);
1149 }
1150 EndOfEpochTransactionKind::CoinRegistryCreate => {
1151 assert!(protocol_config.enable_coin_registry());
1152 builder = setup_coin_registry_create(builder);
1153 }
1154 EndOfEpochTransactionKind::DisplayRegistryCreate => {
1155 assert!(protocol_config.enable_display_registry());
1156 builder = setup_display_registry_create(builder);
1157 }
1158 EndOfEpochTransactionKind::AddressAliasStateCreate => {
1159 assert!(protocol_config.address_aliases());
1160 builder = setup_address_alias_state_create(builder);
1161 }
1162 EndOfEpochTransactionKind::ForwardingAddressRegistryCreate => {
1163 assert!(protocol_config.create_forwarding_address_registry());
1164 builder = setup_forwarding_address_registry_create(builder);
1165 }
1166 }
1167 }
1168 unreachable!(
1169 "EndOfEpochTransactionKind::ChangeEpoch should be the last transaction in the list"
1170 )
1171 }
1172 TransactionKind::AuthenticatorStateUpdate(auth_state_update) => {
1173 setup_authenticator_state_update::<Mode>(
1174 auth_state_update,
1175 temporary_store,
1176 store,
1177 tx_ctx,
1178 move_vm,
1179 gas_charger,
1180 protocol_config,
1181 metrics,
1182 trace_builder_opt,
1183 )
1184 .map_err(|e| (e, vec![]))?;
1185 Ok((Mode::empty_results(), vec![]))
1186 }
1187 TransactionKind::RandomnessStateUpdate(randomness_state_update) => {
1188 setup_randomness_state_update::<Mode>(
1189 randomness_state_update,
1190 temporary_store,
1191 store,
1192 tx_ctx,
1193 move_vm,
1194 gas_charger,
1195 protocol_config,
1196 metrics,
1197 trace_builder_opt,
1198 )
1199 .map_err(|e| (e, vec![]))?;
1200 Ok((Mode::empty_results(), vec![]))
1201 }
1202 }?;
1203 temporary_store
1204 .check_execution_results_consistency::<Mode>()
1205 .map_err(|e| (e, vec![]))?;
1206 Ok(result)
1207 }
1208
1209 fn mint_epoch_rewards_in_pt(
1210 builder: &mut ProgrammableTransactionBuilder,
1211 params: &AdvanceEpochParams,
1212 ) -> (Argument, Argument) {
1213 let storage_charge_arg = builder
1215 .input(CallArg::Pure(
1216 bcs::to_bytes(¶ms.storage_charge).unwrap(),
1217 ))
1218 .unwrap();
1219 let storage_rewards = builder.programmable_move_call(
1220 SUI_FRAMEWORK_PACKAGE_ID,
1221 BALANCE_MODULE_NAME.to_owned(),
1222 BALANCE_CREATE_REWARDS_FUNCTION_NAME.to_owned(),
1223 vec![GAS::type_tag()],
1224 vec![storage_charge_arg],
1225 );
1226
1227 let computation_charge_arg = builder
1229 .input(CallArg::Pure(
1230 bcs::to_bytes(¶ms.computation_charge).unwrap(),
1231 ))
1232 .unwrap();
1233 let computation_rewards = builder.programmable_move_call(
1234 SUI_FRAMEWORK_PACKAGE_ID,
1235 BALANCE_MODULE_NAME.to_owned(),
1236 BALANCE_CREATE_REWARDS_FUNCTION_NAME.to_owned(),
1237 vec![GAS::type_tag()],
1238 vec![computation_charge_arg],
1239 );
1240 (storage_rewards, computation_rewards)
1241 }
1242
1243 pub fn construct_advance_epoch_pt<Mode: ExecutionMode>(
1244 mut builder: ProgrammableTransactionBuilder,
1245 params: &AdvanceEpochParams,
1246 ) -> Result<ProgrammableTransaction, Mode::Error> {
1247 let (storage_rewards, computation_rewards) = mint_epoch_rewards_in_pt(&mut builder, params);
1249
1250 let mut arguments = vec![storage_rewards, computation_rewards];
1252 let call_arg_arguments = vec![
1253 CallArg::SUI_SYSTEM_MUT,
1254 CallArg::Pure(bcs::to_bytes(¶ms.epoch).unwrap()),
1255 CallArg::Pure(bcs::to_bytes(¶ms.next_protocol_version.as_u64()).unwrap()),
1256 CallArg::Pure(bcs::to_bytes(¶ms.storage_rebate).unwrap()),
1257 CallArg::Pure(bcs::to_bytes(¶ms.non_refundable_storage_fee).unwrap()),
1258 CallArg::Pure(bcs::to_bytes(¶ms.storage_fund_reinvest_rate).unwrap()),
1259 CallArg::Pure(bcs::to_bytes(¶ms.reward_slashing_rate).unwrap()),
1260 CallArg::Pure(bcs::to_bytes(¶ms.epoch_start_timestamp_ms).unwrap()),
1261 ]
1262 .into_iter()
1263 .map(|a| builder.input(a))
1264 .collect::<Result<_, _>>();
1265
1266 assert_invariant!(
1267 call_arg_arguments.is_ok(),
1268 "Unable to generate args for advance_epoch transaction!"
1269 );
1270
1271 arguments.append(&mut call_arg_arguments.unwrap());
1272
1273 info!("Call arguments to advance_epoch transaction: {:?}", params);
1274
1275 let storage_rebates = builder.programmable_move_call(
1276 SUI_SYSTEM_PACKAGE_ID,
1277 SUI_SYSTEM_MODULE_NAME.to_owned(),
1278 ADVANCE_EPOCH_FUNCTION_NAME.to_owned(),
1279 vec![],
1280 arguments,
1281 );
1282
1283 builder.programmable_move_call(
1285 SUI_FRAMEWORK_PACKAGE_ID,
1286 BALANCE_MODULE_NAME.to_owned(),
1287 BALANCE_DESTROY_REBATES_FUNCTION_NAME.to_owned(),
1288 vec![GAS::type_tag()],
1289 vec![storage_rebates],
1290 );
1291 Ok(builder.finish())
1292 }
1293
1294 pub fn construct_advance_epoch_safe_mode_pt(
1295 params: &AdvanceEpochParams,
1296 ) -> Result<ProgrammableTransaction, ExecutionError> {
1297 let mut builder = ProgrammableTransactionBuilder::new();
1298 let (storage_rewards, computation_rewards) = mint_epoch_rewards_in_pt(&mut builder, params);
1300
1301 let mut arguments = vec![storage_rewards, computation_rewards];
1303
1304 let mut args = vec![
1305 CallArg::SUI_SYSTEM_MUT,
1306 CallArg::Pure(bcs::to_bytes(¶ms.epoch).unwrap()),
1307 CallArg::Pure(bcs::to_bytes(¶ms.next_protocol_version.as_u64()).unwrap()),
1308 CallArg::Pure(bcs::to_bytes(¶ms.storage_rebate).unwrap()),
1309 CallArg::Pure(bcs::to_bytes(¶ms.non_refundable_storage_fee).unwrap()),
1310 ];
1311
1312 args.push(CallArg::Pure(
1313 bcs::to_bytes(¶ms.epoch_start_timestamp_ms).unwrap(),
1314 ));
1315
1316 let call_arg_arguments = args
1317 .into_iter()
1318 .map(|a| builder.input(a))
1319 .collect::<Result<_, _>>();
1320
1321 assert_invariant!(
1322 call_arg_arguments.is_ok(),
1323 "Unable to generate args for advance_epoch transaction!"
1324 );
1325
1326 arguments.append(&mut call_arg_arguments.unwrap());
1327
1328 info!("Call arguments to advance_epoch transaction: {:?}", params);
1329
1330 builder.programmable_move_call(
1331 SUI_SYSTEM_PACKAGE_ID,
1332 SUI_SYSTEM_MODULE_NAME.to_owned(),
1333 ADVANCE_EPOCH_SAFE_MODE_FUNCTION_NAME.to_owned(),
1334 vec![],
1335 arguments,
1336 );
1337
1338 Ok(builder.finish())
1339 }
1340
1341 fn advance_epoch<Mode: ExecutionMode>(
1342 builder: ProgrammableTransactionBuilder,
1343 change_epoch: ChangeEpoch,
1344 temporary_store: &mut TemporaryStore<'_>,
1345 store: &dyn BackingStore,
1346 tx_ctx: Rc<RefCell<TxContext>>,
1347 move_vm: &Arc<MoveRuntime>,
1348 gas_charger: &mut GasCharger,
1349 protocol_config: &ProtocolConfig,
1350 metrics: Arc<ExecutionMetrics>,
1351 trace_builder_opt: &mut Option<MoveTraceBuilder>,
1352 ) -> Result<(), Mode::Error> {
1353 let params = AdvanceEpochParams {
1354 epoch: change_epoch.epoch,
1355 next_protocol_version: change_epoch.protocol_version,
1356 storage_charge: change_epoch.storage_charge,
1357 computation_charge: change_epoch.computation_charge,
1358 storage_rebate: change_epoch.storage_rebate,
1359 non_refundable_storage_fee: change_epoch.non_refundable_storage_fee,
1360 storage_fund_reinvest_rate: protocol_config.storage_fund_reinvest_rate(),
1361 reward_slashing_rate: protocol_config.reward_slashing_rate(),
1362 epoch_start_timestamp_ms: change_epoch.epoch_start_timestamp_ms,
1363 };
1364 let advance_epoch_pt = construct_advance_epoch_pt::<Mode>(builder, ¶ms)?;
1365 let result = SPT::execute::<execution_mode::System<Mode::Error>>(
1366 protocol_config,
1367 metrics.clone(),
1368 move_vm,
1369 temporary_store,
1370 store.as_backing_package_store(),
1371 tx_ctx.clone(),
1372 gas_charger,
1373 None,
1374 advance_epoch_pt,
1375 trace_builder_opt,
1376 );
1377
1378 #[cfg(msim)]
1379 let result = maybe_modify_result_for(result, change_epoch.epoch);
1380
1381 if let Err(err) = &result {
1382 tracing::error!(
1383 "Failed to execute advance epoch transaction. Switching to safe mode. Error: {:?}. Input objects: {:?}. Tx data: {:?}",
1384 err.0,
1385 temporary_store.objects(),
1386 change_epoch,
1387 );
1388 temporary_store.drop_writes();
1389 gas_charger.reset_storage_cost_and_rebate();
1391
1392 temporary_store.advance_epoch_safe_mode(¶ms, protocol_config);
1393 }
1394
1395 let new_vm = new_move_runtime(
1396 all_natives(true, protocol_config),
1397 protocol_config,
1398 )
1399 .expect("Failed to create new MoveRuntime");
1400 process_system_packages(
1401 change_epoch,
1402 temporary_store,
1403 store,
1404 tx_ctx,
1405 &new_vm,
1406 gas_charger,
1407 protocol_config,
1408 metrics,
1409 trace_builder_opt,
1410 );
1411 Ok(())
1412 }
1413
1414 fn process_system_packages(
1415 change_epoch: ChangeEpoch,
1416 temporary_store: &mut TemporaryStore<'_>,
1417 store: &dyn BackingStore,
1418 tx_ctx: Rc<RefCell<TxContext>>,
1419 move_vm: &MoveRuntime,
1420 gas_charger: &mut GasCharger,
1421 protocol_config: &ProtocolConfig,
1422 metrics: Arc<ExecutionMetrics>,
1423 trace_builder_opt: &mut Option<MoveTraceBuilder>,
1424 ) {
1425 let digest = tx_ctx.borrow().digest();
1426 let binary_config = protocol_config.binary_config(None);
1427 for (version, modules, dependencies) in change_epoch.system_packages.into_iter() {
1428 let deserialized_modules: Vec<_> = modules
1429 .iter()
1430 .map(|m| CompiledModule::deserialize_with_config(m, &binary_config).unwrap())
1431 .collect();
1432
1433 if version == OBJECT_START_VERSION {
1434 let package_id = deserialized_modules.first().unwrap().address();
1435 info!("adding new system package {package_id}");
1436
1437 let publish_pt = {
1438 let mut b = ProgrammableTransactionBuilder::new();
1439 b.command(Command::Publish(modules, dependencies));
1440 b.finish()
1441 };
1442
1443 SPT::execute::<execution_mode::System>(
1444 protocol_config,
1445 metrics.clone(),
1446 move_vm,
1447 temporary_store,
1448 store.as_backing_package_store(),
1449 tx_ctx.clone(),
1450 gas_charger,
1451 None,
1452 publish_pt,
1453 trace_builder_opt,
1454 )
1455 .map_err(|(e, _)| e)
1456 .expect("System Package Publish must succeed");
1457 } else {
1458 let mut new_package = Object::new_system_package(
1459 &deserialized_modules,
1460 version,
1461 dependencies,
1462 digest,
1463 );
1464
1465 info!(
1466 "upgraded system package {:?}",
1467 new_package.compute_object_reference()
1468 );
1469
1470 new_package
1473 .data
1474 .try_as_package_mut()
1475 .unwrap()
1476 .decrement_version();
1477
1478 temporary_store.upgrade_system_package(new_package);
1480 }
1481 }
1482 }
1483
1484 fn setup_consensus_commit<Mode: ExecutionMode>(
1489 consensus_commit_timestamp_ms: CheckpointTimestamp,
1490 temporary_store: &mut TemporaryStore<'_>,
1491 store: &dyn BackingStore,
1492 tx_ctx: Rc<RefCell<TxContext>>,
1493 move_vm: &Arc<MoveRuntime>,
1494 gas_charger: &mut GasCharger,
1495 protocol_config: &ProtocolConfig,
1496 metrics: Arc<ExecutionMetrics>,
1497 trace_builder_opt: &mut Option<MoveTraceBuilder>,
1498 ) -> Result<(), Mode::Error> {
1499 let pt = {
1500 let mut builder = ProgrammableTransactionBuilder::new();
1501 let res = builder.move_call(
1502 SUI_FRAMEWORK_ADDRESS.into(),
1503 CLOCK_MODULE_NAME.to_owned(),
1504 CONSENSUS_COMMIT_PROLOGUE_FUNCTION_NAME.to_owned(),
1505 vec![],
1506 vec![
1507 CallArg::CLOCK_MUT,
1508 CallArg::Pure(bcs::to_bytes(&consensus_commit_timestamp_ms).unwrap()),
1509 ],
1510 );
1511 assert_invariant!(
1512 res.is_ok(),
1513 "Unable to generate consensus_commit_prologue transaction!"
1514 );
1515 builder.finish()
1516 };
1517 SPT::execute::<execution_mode::System<Mode::Error>>(
1518 protocol_config,
1519 metrics,
1520 move_vm,
1521 temporary_store,
1522 store.as_backing_package_store(),
1523 tx_ctx,
1524 gas_charger,
1525 None,
1526 pt,
1527 trace_builder_opt,
1528 )
1529 .map_err(|(e, _)| e)?;
1530 Ok(())
1531 }
1532
1533 fn setup_authenticator_state_create(
1534 mut builder: ProgrammableTransactionBuilder,
1535 ) -> ProgrammableTransactionBuilder {
1536 builder
1537 .move_call(
1538 SUI_FRAMEWORK_ADDRESS.into(),
1539 AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1540 AUTHENTICATOR_STATE_CREATE_FUNCTION_NAME.to_owned(),
1541 vec![],
1542 vec![],
1543 )
1544 .expect("Unable to generate authenticator_state_create transaction!");
1545 builder
1546 }
1547
1548 fn setup_randomness_state_create(
1549 mut builder: ProgrammableTransactionBuilder,
1550 ) -> ProgrammableTransactionBuilder {
1551 builder
1552 .move_call(
1553 SUI_FRAMEWORK_ADDRESS.into(),
1554 RANDOMNESS_MODULE_NAME.to_owned(),
1555 RANDOMNESS_STATE_CREATE_FUNCTION_NAME.to_owned(),
1556 vec![],
1557 vec![],
1558 )
1559 .expect("Unable to generate randomness_state_create transaction!");
1560 builder
1561 }
1562
1563 fn setup_bridge_create(
1564 mut builder: ProgrammableTransactionBuilder,
1565 chain_id: ChainIdentifier,
1566 ) -> ProgrammableTransactionBuilder {
1567 let bridge_uid = builder
1568 .input(CallArg::Pure(UID::new(SUI_BRIDGE_OBJECT_ID).to_bcs_bytes()))
1569 .expect("Unable to create Bridge object UID!");
1570
1571 let bridge_chain_id = if chain_id == get_mainnet_chain_identifier() {
1572 BridgeChainId::SuiMainnet as u8
1573 } else if chain_id == get_testnet_chain_identifier() {
1574 BridgeChainId::SuiTestnet as u8
1575 } else {
1576 BridgeChainId::SuiCustom as u8
1578 };
1579
1580 let bridge_chain_id = builder.pure(bridge_chain_id).unwrap();
1581 builder.programmable_move_call(
1582 BRIDGE_ADDRESS.into(),
1583 BRIDGE_MODULE_NAME.to_owned(),
1584 BRIDGE_CREATE_FUNCTION_NAME.to_owned(),
1585 vec![],
1586 vec![bridge_uid, bridge_chain_id],
1587 );
1588 builder
1589 }
1590
1591 fn setup_bridge_committee_update(
1592 mut builder: ProgrammableTransactionBuilder,
1593 bridge_shared_version: SequenceNumber,
1594 ) -> ProgrammableTransactionBuilder {
1595 let bridge = builder
1596 .obj(ObjectArg::SharedObject {
1597 id: SUI_BRIDGE_OBJECT_ID,
1598 initial_shared_version: bridge_shared_version,
1599 mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1600 })
1601 .expect("Unable to create Bridge object arg!");
1602 let system_state = builder
1603 .obj(ObjectArg::SUI_SYSTEM_MUT)
1604 .expect("Unable to create System State object arg!");
1605
1606 let voting_power = builder.programmable_move_call(
1607 SUI_SYSTEM_PACKAGE_ID,
1608 SUI_SYSTEM_MODULE_NAME.to_owned(),
1609 ident_str!("validator_voting_powers").to_owned(),
1610 vec![],
1611 vec![system_state],
1612 );
1613
1614 let min_stake_participation_percentage = builder
1617 .input(CallArg::Pure(
1618 bcs::to_bytes(&BRIDGE_COMMITTEE_MINIMAL_VOTING_POWER).unwrap(),
1619 ))
1620 .unwrap();
1621
1622 builder.programmable_move_call(
1623 BRIDGE_ADDRESS.into(),
1624 BRIDGE_MODULE_NAME.to_owned(),
1625 BRIDGE_INIT_COMMITTEE_FUNCTION_NAME.to_owned(),
1626 vec![],
1627 vec![bridge, voting_power, min_stake_participation_percentage],
1628 );
1629 builder
1630 }
1631
1632 fn setup_authenticator_state_update<Mode: ExecutionMode>(
1633 update: AuthenticatorStateUpdate,
1634 temporary_store: &mut TemporaryStore<'_>,
1635 store: &dyn BackingStore,
1636 tx_ctx: Rc<RefCell<TxContext>>,
1637 move_vm: &Arc<MoveRuntime>,
1638 gas_charger: &mut GasCharger,
1639 protocol_config: &ProtocolConfig,
1640 metrics: Arc<ExecutionMetrics>,
1641 trace_builder_opt: &mut Option<MoveTraceBuilder>,
1642 ) -> Result<(), Mode::Error> {
1643 let pt = {
1644 let mut builder = ProgrammableTransactionBuilder::new();
1645 let res = builder.move_call(
1646 SUI_FRAMEWORK_ADDRESS.into(),
1647 AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1648 AUTHENTICATOR_STATE_UPDATE_FUNCTION_NAME.to_owned(),
1649 vec![],
1650 vec![
1651 CallArg::Object(ObjectArg::SharedObject {
1652 id: SUI_AUTHENTICATOR_STATE_OBJECT_ID,
1653 initial_shared_version: update.authenticator_obj_initial_shared_version,
1654 mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1655 }),
1656 CallArg::Pure(bcs::to_bytes(&update.new_active_jwks).unwrap()),
1657 ],
1658 );
1659 assert_invariant!(
1660 res.is_ok(),
1661 "Unable to generate authenticator_state_update transaction!"
1662 );
1663 builder.finish()
1664 };
1665 SPT::execute::<execution_mode::System<Mode::Error>>(
1666 protocol_config,
1667 metrics,
1668 move_vm,
1669 temporary_store,
1670 store.as_backing_package_store(),
1671 tx_ctx,
1672 gas_charger,
1673 None,
1674 pt,
1675 trace_builder_opt,
1676 )
1677 .map_err(|(e, _)| e)?;
1678 Ok(())
1679 }
1680
1681 fn setup_authenticator_state_expire(
1682 mut builder: ProgrammableTransactionBuilder,
1683 expire: AuthenticatorStateExpire,
1684 ) -> ProgrammableTransactionBuilder {
1685 builder
1686 .move_call(
1687 SUI_FRAMEWORK_ADDRESS.into(),
1688 AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1689 AUTHENTICATOR_STATE_EXPIRE_JWKS_FUNCTION_NAME.to_owned(),
1690 vec![],
1691 vec![
1692 CallArg::Object(ObjectArg::SharedObject {
1693 id: SUI_AUTHENTICATOR_STATE_OBJECT_ID,
1694 initial_shared_version: expire.authenticator_obj_initial_shared_version,
1695 mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1696 }),
1697 CallArg::Pure(bcs::to_bytes(&expire.min_epoch).unwrap()),
1698 ],
1699 )
1700 .expect("Unable to generate authenticator_state_expire transaction!");
1701 builder
1702 }
1703
1704 fn setup_randomness_state_update<Mode: ExecutionMode>(
1705 update: RandomnessStateUpdate,
1706 temporary_store: &mut TemporaryStore<'_>,
1707 store: &dyn BackingStore,
1708 tx_ctx: Rc<RefCell<TxContext>>,
1709 move_vm: &Arc<MoveRuntime>,
1710 gas_charger: &mut GasCharger,
1711 protocol_config: &ProtocolConfig,
1712 metrics: Arc<ExecutionMetrics>,
1713 trace_builder_opt: &mut Option<MoveTraceBuilder>,
1714 ) -> Result<(), Mode::Error> {
1715 let pt = {
1716 let mut builder = ProgrammableTransactionBuilder::new();
1717 let res = builder.move_call(
1718 SUI_FRAMEWORK_ADDRESS.into(),
1719 RANDOMNESS_MODULE_NAME.to_owned(),
1720 RANDOMNESS_STATE_UPDATE_FUNCTION_NAME.to_owned(),
1721 vec![],
1722 vec![
1723 CallArg::Object(ObjectArg::SharedObject {
1724 id: SUI_RANDOMNESS_STATE_OBJECT_ID,
1725 initial_shared_version: update.randomness_obj_initial_shared_version,
1726 mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1727 }),
1728 CallArg::Pure(bcs::to_bytes(&update.randomness_round).unwrap()),
1729 CallArg::Pure(bcs::to_bytes(&update.random_bytes).unwrap()),
1730 ],
1731 );
1732 assert_invariant!(
1733 res.is_ok(),
1734 "Unable to generate randomness_state_update transaction!"
1735 );
1736 builder.finish()
1737 };
1738 SPT::execute::<execution_mode::System<Mode::Error>>(
1739 protocol_config,
1740 metrics,
1741 move_vm,
1742 temporary_store,
1743 store.as_backing_package_store(),
1744 tx_ctx,
1745 gas_charger,
1746 None,
1747 pt,
1748 trace_builder_opt,
1749 )
1750 .map_err(|(e, _)| e)?;
1751 Ok(())
1752 }
1753
1754 fn setup_coin_deny_list_state_create(
1755 mut builder: ProgrammableTransactionBuilder,
1756 ) -> ProgrammableTransactionBuilder {
1757 builder
1758 .move_call(
1759 SUI_FRAMEWORK_ADDRESS.into(),
1760 DENY_LIST_MODULE.to_owned(),
1761 DENY_LIST_CREATE_FUNC.to_owned(),
1762 vec![],
1763 vec![],
1764 )
1765 .expect("Unable to generate coin_deny_list_create transaction!");
1766 builder
1767 }
1768
1769 fn setup_store_execution_time_estimates(
1770 mut builder: ProgrammableTransactionBuilder,
1771 estimates: StoredExecutionTimeObservations,
1772 chunk_size: usize,
1773 ) -> ProgrammableTransactionBuilder {
1774 let system_state = builder.obj(ObjectArg::SUI_SYSTEM_MUT).unwrap();
1775
1776 let estimate_chunks = estimates.chunk_observations(chunk_size);
1777
1778 let chunk_bytes: Vec<Vec<u8>> = estimate_chunks
1779 .into_iter()
1780 .map(|chunk| bcs::to_bytes(&chunk).unwrap())
1781 .collect();
1782
1783 let chunks_arg = builder.pure(chunk_bytes).unwrap();
1784
1785 builder.programmable_move_call(
1786 SUI_SYSTEM_PACKAGE_ID,
1787 SUI_SYSTEM_MODULE_NAME.to_owned(),
1788 ident_str!("store_execution_time_estimates_v2").to_owned(),
1789 vec![],
1790 vec![system_state, chunks_arg],
1791 );
1792 builder
1793 }
1794
1795 fn setup_accumulator_root_create(
1796 mut builder: ProgrammableTransactionBuilder,
1797 ) -> ProgrammableTransactionBuilder {
1798 builder
1799 .move_call(
1800 SUI_FRAMEWORK_ADDRESS.into(),
1801 ACCUMULATOR_ROOT_MODULE.to_owned(),
1802 ACCUMULATOR_ROOT_CREATE_FUNC.to_owned(),
1803 vec![],
1804 vec![],
1805 )
1806 .expect("Unable to generate accumulator_root_create transaction!");
1807 builder
1808 }
1809
1810 fn setup_write_accumulator_storage_cost(
1811 mut builder: ProgrammableTransactionBuilder,
1812 write_storage_cost: &WriteAccumulatorStorageCost,
1813 ) -> ProgrammableTransactionBuilder {
1814 let system_state = builder.obj(ObjectArg::SUI_SYSTEM_MUT).unwrap();
1815 let storage_cost_arg = builder.pure(write_storage_cost.storage_cost).unwrap();
1816 builder.programmable_move_call(
1817 SUI_SYSTEM_PACKAGE_ID,
1818 SUI_SYSTEM_MODULE_NAME.to_owned(),
1819 ident_str!("write_accumulator_storage_cost").to_owned(),
1820 vec![],
1821 vec![system_state, storage_cost_arg],
1822 );
1823 builder
1824 }
1825
1826 fn setup_coin_registry_create(
1827 mut builder: ProgrammableTransactionBuilder,
1828 ) -> ProgrammableTransactionBuilder {
1829 builder
1830 .move_call(
1831 SUI_FRAMEWORK_ADDRESS.into(),
1832 ident_str!("coin_registry").to_owned(),
1833 ident_str!("create").to_owned(),
1834 vec![],
1835 vec![],
1836 )
1837 .expect("Unable to generate coin_registry_create transaction!");
1838 builder
1839 }
1840
1841 fn setup_display_registry_create(
1842 mut builder: ProgrammableTransactionBuilder,
1843 ) -> ProgrammableTransactionBuilder {
1844 builder
1845 .move_call(
1846 SUI_FRAMEWORK_ADDRESS.into(),
1847 ident_str!("display_registry").to_owned(),
1848 ident_str!("create").to_owned(),
1849 vec![],
1850 vec![],
1851 )
1852 .expect("Unable to generate display_registry_create transaction!");
1853 builder
1854 }
1855
1856 fn setup_address_alias_state_create(
1857 mut builder: ProgrammableTransactionBuilder,
1858 ) -> ProgrammableTransactionBuilder {
1859 builder
1860 .move_call(
1861 SUI_FRAMEWORK_ADDRESS.into(),
1862 ident_str!("address_alias").to_owned(),
1863 ident_str!("create").to_owned(),
1864 vec![],
1865 vec![],
1866 )
1867 .expect("Unable to generate address_alias_state_create transaction!");
1868 builder
1869 }
1870 fn setup_forwarding_address_registry_create(
1871 mut builder: ProgrammableTransactionBuilder,
1872 ) -> ProgrammableTransactionBuilder {
1873 builder
1874 .move_call(
1875 SUI_FRAMEWORK_ADDRESS.into(),
1876 ident_str!("forwarding_address").to_owned(),
1877 ident_str!("create").to_owned(),
1878 vec![],
1879 vec![],
1880 )
1881 .expect("Unable to generate forwarding_address_registry_create transaction!");
1882 builder
1883 }
1884}