1pub use checked::*;
5
6#[sui_macros::with_checked_arithmetic]
7mod checked {
8
9 use crate::execution_mode::{self, ExecutionMode};
10 use move_binary_format::CompiledModule;
11 use move_vm_runtime::move_vm::MoveVM;
12 use std::{collections::HashSet, sync::Arc};
13 use sui_types::balance::{
14 BALANCE_CREATE_REWARDS_FUNCTION_NAME, BALANCE_DESTROY_REBATES_FUNCTION_NAME,
15 BALANCE_MODULE_NAME,
16 };
17 use sui_types::execution_params::ExecutionOrEarlyError;
18 use sui_types::gas_coin::GAS;
19 use sui_types::messages_checkpoint::CheckpointTimestamp;
20 use sui_types::metrics::ExecutionMetrics;
21 use sui_types::object::OBJECT_START_VERSION;
22 use sui_types::programmable_transaction_builder::ProgrammableTransactionBuilder;
23 use sui_types::randomness_state::{
24 RANDOMNESS_MODULE_NAME, RANDOMNESS_STATE_CREATE_FUNCTION_NAME,
25 RANDOMNESS_STATE_UPDATE_FUNCTION_NAME,
26 };
27 use sui_types::SUI_RANDOMNESS_STATE_OBJECT_ID;
28 use tracing::{info, instrument, trace, warn};
29
30 use crate::programmable_transactions;
31 use crate::type_layout_resolver::TypeLayoutResolver;
32 use crate::{gas_charger::GasCharger, temporary_store::TemporaryStore};
33 use sui_protocol_config::{check_limit_by_meter, LimitThresholdCrossed, ProtocolConfig};
34 use sui_types::authenticator_state::{
35 AUTHENTICATOR_STATE_CREATE_FUNCTION_NAME, AUTHENTICATOR_STATE_EXPIRE_JWKS_FUNCTION_NAME,
36 AUTHENTICATOR_STATE_MODULE_NAME, AUTHENTICATOR_STATE_UPDATE_FUNCTION_NAME,
37 };
38 use sui_types::clock::{CLOCK_MODULE_NAME, CONSENSUS_COMMIT_PROLOGUE_FUNCTION_NAME};
39 use sui_types::committee::EpochId;
40 use sui_types::deny_list_v1::{DENY_LIST_CREATE_FUNC, DENY_LIST_MODULE};
41 use sui_types::effects::TransactionEffects;
42 use sui_types::error::{ExecutionError, ExecutionErrorTrait};
43 use sui_types::execution_status::{ExecutionErrorKind, ExecutionStatus};
44 use sui_types::gas::GasCostSummary;
45 use sui_types::gas::SuiGasStatus;
46 use sui_types::inner_temporary_store::InnerTemporaryStore;
47 use sui_types::storage::BackingStore;
48 #[cfg(msim)]
49 use sui_types::sui_system_state::advance_epoch_result_injection::maybe_modify_result_legacy;
50 use sui_types::sui_system_state::{AdvanceEpochParams, ADVANCE_EPOCH_SAFE_MODE_FUNCTION_NAME};
51 use sui_types::transaction::{
52 Argument, AuthenticatorStateExpire, AuthenticatorStateUpdate, CallArg, ChangeEpoch,
53 Command, EndOfEpochTransactionKind, GenesisTransaction, ObjectArg, ProgrammableTransaction,
54 TransactionKind,
55 };
56 use sui_types::transaction::{CheckedInputObjects, RandomnessStateUpdate};
57 use sui_types::{
58 base_types::{ObjectRef, SuiAddress, TransactionDigest, TxContext},
59 object::{Object, ObjectInner},
60 sui_system_state::{ADVANCE_EPOCH_FUNCTION_NAME, SUI_SYSTEM_MODULE_NAME},
61 SUI_AUTHENTICATOR_STATE_OBJECT_ID, SUI_FRAMEWORK_ADDRESS, SUI_FRAMEWORK_PACKAGE_ID,
62 SUI_SYSTEM_PACKAGE_ID,
63 };
64
65 #[instrument(name = "tx_execute_to_effects", level = "debug", skip_all)]
66 pub fn execute_transaction_to_effects<Mode: ExecutionMode>(
67 store: &dyn BackingStore,
68 input_objects: CheckedInputObjects,
69 gas_coins: Vec<ObjectRef>,
70 gas_status: SuiGasStatus,
71 transaction_kind: TransactionKind,
72 transaction_signer: SuiAddress,
73 transaction_digest: TransactionDigest,
74 move_vm: &Arc<MoveVM>,
75 epoch_id: &EpochId,
76 epoch_timestamp_ms: u64,
77 protocol_config: &ProtocolConfig,
78 metrics: Arc<ExecutionMetrics>,
79 enable_expensive_checks: bool,
80 execution_params: ExecutionOrEarlyError,
81 ) -> (
82 InnerTemporaryStore,
83 SuiGasStatus,
84 TransactionEffects,
85 Result<Mode::ExecutionResults, ExecutionError>,
86 ) {
87 let input_objects = input_objects.into_inner();
88 let mutable_inputs = if enable_expensive_checks {
89 input_objects.all_mutable_inputs().keys().copied().collect()
90 } else {
91 HashSet::new()
92 };
93 let shared_object_refs = input_objects.filter_shared_objects();
94 let receiving_objects = transaction_kind.receiving_objects();
95 let mut transaction_dependencies = input_objects.transaction_dependencies();
96
97 let mut temporary_store = TemporaryStore::new(
98 store,
99 input_objects,
100 receiving_objects,
101 transaction_digest,
102 protocol_config,
103 );
104
105 let mut gas_charger =
106 GasCharger::new(transaction_digest, gas_coins, gas_status, protocol_config);
107
108 let mut tx_ctx = TxContext::new_from_components(
109 &transaction_signer,
110 &transaction_digest,
111 epoch_id,
112 epoch_timestamp_ms,
113 1,
115 1,
116 1_000_000,
117 None,
118 protocol_config,
119 );
120
121 let is_epoch_change = transaction_kind.is_end_of_epoch_tx();
122
123 let (gas_cost_summary, execution_result) = execute_transaction::<Mode>(
124 &mut temporary_store,
125 transaction_kind,
126 &mut gas_charger,
127 &mut tx_ctx,
128 move_vm,
129 protocol_config,
130 metrics,
131 enable_expensive_checks,
132 execution_params,
133 );
134
135 let status = if let Err(error) = &execution_result {
136 use ExecutionErrorKind as K;
138 match error.kind() {
139 K::InvariantViolation | K::VMInvariantViolation => {
140 #[skip_checked_arithmetic]
141 tracing::error!(
142 kind = ?error.kind(),
143 tx_digest = ?transaction_digest,
144 "INVARIANT VIOLATION! Source: {:?}",
145 error.source_ref(),
146 );
147 }
148
149 K::SuiMoveVerificationError | K::VMVerificationOrDeserializationError => {
150 #[skip_checked_arithmetic]
151 tracing::debug!(
152 kind = ?error.kind(),
153 tx_digest = ?transaction_digest,
154 "Verification Error. Source: {:?}",
155 error.source_ref(),
156 );
157 }
158
159 K::PublishUpgradeMissingDependency | K::PublishUpgradeDependencyDowngrade => {
160 #[skip_checked_arithmetic]
161 tracing::debug!(
162 kind = ?error.kind(),
163 tx_digest = ?transaction_digest,
164 "Publish/Upgrade Error. Source: {:?}",
165 error.source_ref(),
166 )
167 }
168
169 _ => (),
170 };
171
172 ExecutionStatus::new_failure(error.to_execution_failure())
173 } else {
174 ExecutionStatus::Success
175 };
176
177 #[skip_checked_arithmetic]
178 trace!(
179 tx_digest = ?transaction_digest,
180 computation_gas_cost = gas_cost_summary.computation_cost,
181 storage_gas_cost = gas_cost_summary.storage_cost,
182 storage_gas_rebate = gas_cost_summary.storage_rebate,
183 "Finished execution of transaction with status {:?}",
184 status
185 );
186
187 transaction_dependencies.remove(&TransactionDigest::genesis_marker());
191
192 if enable_expensive_checks && !Mode::allow_arbitrary_function_calls() {
193 temporary_store
194 .check_ownership_invariants(
195 &transaction_signer,
196 &mut gas_charger,
197 &mutable_inputs,
198 is_epoch_change,
199 )
200 .unwrap()
201 } let (inner, effects) = temporary_store.into_effects(
204 shared_object_refs,
205 &transaction_digest,
206 transaction_dependencies,
207 gas_cost_summary,
208 status,
209 &mut gas_charger,
210 *epoch_id,
211 );
212
213 (
214 inner,
215 gas_charger.into_gas_status(),
216 effects,
217 execution_result,
218 )
219 }
220
221 pub fn execute_genesis_state_update(
222 store: &dyn BackingStore,
223 protocol_config: &ProtocolConfig,
224 metrics: Arc<ExecutionMetrics>,
225 move_vm: &Arc<MoveVM>,
226 tx_context: &mut TxContext,
227 input_objects: CheckedInputObjects,
228 pt: ProgrammableTransaction,
229 ) -> Result<InnerTemporaryStore, ExecutionError> {
230 let input_objects = input_objects.into_inner();
231 let mut temporary_store = TemporaryStore::new(
232 store,
233 input_objects,
234 vec![],
235 tx_context.digest(),
236 protocol_config,
237 );
238 let mut gas_charger = GasCharger::new_unmetered(tx_context.digest());
239 programmable_transactions::execution::execute::<execution_mode::Genesis>(
240 protocol_config,
241 metrics,
242 move_vm,
243 &mut temporary_store,
244 tx_context,
245 &mut gas_charger,
246 pt,
247 )?;
248 temporary_store.update_object_version_and_prev_tx();
249 Ok(temporary_store.into_inner())
250 }
251
252 #[instrument(name = "tx_execute", level = "debug", skip_all)]
253 fn execute_transaction<Mode: ExecutionMode>(
254 temporary_store: &mut TemporaryStore<'_>,
255 transaction_kind: TransactionKind,
256 gas_charger: &mut GasCharger,
257 tx_ctx: &mut TxContext,
258 move_vm: &Arc<MoveVM>,
259 protocol_config: &ProtocolConfig,
260 metrics: Arc<ExecutionMetrics>,
261 enable_expensive_checks: bool,
262 execution_params: ExecutionOrEarlyError,
263 ) -> (
264 GasCostSummary,
265 Result<Mode::ExecutionResults, ExecutionError>,
266 ) {
267 gas_charger.smash_gas(temporary_store);
268
269 debug_assert!(
271 gas_charger.no_charges(),
272 "No gas charges must be applied yet"
273 );
274
275 let is_genesis_tx = matches!(transaction_kind, TransactionKind::Genesis(_));
276 let advance_epoch_gas_summary = transaction_kind.get_advance_epoch_tx_gas_summary();
277
278 let result = gas_charger.charge_input_objects(temporary_store);
281 let mut result = result.and_then(|()| {
282 let mut execution_result = match execution_params {
283 ExecutionOrEarlyError::Err(early_execution_error) => {
284 Err(ExecutionError::new(early_execution_error, None))
285 }
286 ExecutionOrEarlyError::Ok(()) => execution_loop::<Mode>(
287 temporary_store,
288 transaction_kind,
289 tx_ctx,
290 move_vm,
291 gas_charger,
292 protocol_config,
293 metrics.clone(),
294 ),
295 };
296
297 let meter_check = check_meter_limit(
298 temporary_store,
299 gas_charger,
300 protocol_config,
301 metrics.clone(),
302 );
303 if let Err(e) = meter_check {
304 execution_result = Err(e);
305 }
306
307 if execution_result.is_ok() {
308 let gas_check = check_written_objects_limit(
309 temporary_store,
310 gas_charger,
311 protocol_config,
312 metrics,
313 );
314 if let Err(e) = gas_check {
315 execution_result = Err(e);
316 }
317 }
318
319 execution_result
320 });
321
322 let cost_summary = gas_charger.charge_gas(temporary_store, &mut result);
323 temporary_store.conserve_unmetered_storage_rebate(gas_charger.unmetered_storage_rebate());
331
332 if let Err(e) = run_conservation_checks::<Mode>(
333 temporary_store,
334 gas_charger,
335 tx_ctx,
336 move_vm,
337 protocol_config.simple_conservation_checks(),
338 enable_expensive_checks,
339 &cost_summary,
340 is_genesis_tx,
341 advance_epoch_gas_summary,
342 ) {
343 result = Err(e);
345 }
346
347 (cost_summary, result)
348 }
349
350 #[instrument(name = "run_conservation_checks", level = "debug", skip_all)]
351 fn run_conservation_checks<Mode: ExecutionMode>(
352 temporary_store: &mut TemporaryStore<'_>,
353 gas_charger: &mut GasCharger,
354 tx_ctx: &mut TxContext,
355 move_vm: &Arc<MoveVM>,
356 simple_conservation_checks: bool,
357 enable_expensive_checks: bool,
358 cost_summary: &GasCostSummary,
359 is_genesis_tx: bool,
360 advance_epoch_gas_summary: Option<(u64, u64)>,
361 ) -> Result<(), ExecutionError> {
362 let mut result: std::result::Result<(), sui_types::error::ExecutionError> = Ok(());
363 if !is_genesis_tx && !Mode::skip_conservation_checks() {
364 let conservation_result = {
366 temporary_store
367 .check_sui_conserved(simple_conservation_checks, cost_summary)
368 .and_then(|()| {
369 if enable_expensive_checks {
370 let mut layout_resolver =
372 TypeLayoutResolver::new(move_vm, Box::new(&*temporary_store));
373 temporary_store.check_sui_conserved_expensive(
374 cost_summary,
375 advance_epoch_gas_summary,
376 &mut layout_resolver,
377 )
378 } else {
379 Ok(())
380 }
381 })
382 };
383 if let Err(conservation_err) = conservation_result {
384 result = Err(conservation_err);
387 gas_charger.reset(temporary_store);
388 gas_charger.charge_gas(temporary_store, &mut result);
389 if let Err(recovery_err) = {
391 temporary_store
392 .check_sui_conserved(simple_conservation_checks, cost_summary)
393 .and_then(|()| {
394 if enable_expensive_checks {
395 let mut layout_resolver =
397 TypeLayoutResolver::new(move_vm, Box::new(&*temporary_store));
398 temporary_store.check_sui_conserved_expensive(
399 cost_summary,
400 advance_epoch_gas_summary,
401 &mut layout_resolver,
402 )
403 } else {
404 Ok(())
405 }
406 })
407 } {
408 panic!(
412 "SUI conservation fail in tx block {}: {}\nGas status is {}\nTx was ",
413 tx_ctx.digest(),
414 recovery_err,
415 gas_charger.summary()
416 )
417 }
418 }
419 } result
422 }
423
424 #[instrument(name = "check_meter_limit", level = "debug", skip_all)]
425 fn check_meter_limit(
426 temporary_store: &mut TemporaryStore<'_>,
427 gas_charger: &mut GasCharger,
428 protocol_config: &ProtocolConfig,
429 metrics: Arc<ExecutionMetrics>,
430 ) -> Result<(), ExecutionError> {
431 let effects_estimated_size = temporary_store.estimate_effects_size_upperbound();
432
433 match check_limit_by_meter!(
437 !gas_charger.is_unmetered(),
438 effects_estimated_size,
439 protocol_config.max_serialized_tx_effects_size_bytes(),
440 protocol_config.max_serialized_tx_effects_size_bytes_system_tx(),
441 metrics.limits_metrics.excessive_estimated_effects_size
442 ) {
443 LimitThresholdCrossed::None => Ok(()),
444 LimitThresholdCrossed::Soft(_, limit) => {
445 warn!(
446 effects_estimated_size = effects_estimated_size,
447 soft_limit = limit,
448 "Estimated transaction effects size crossed soft limit",
449 );
450 Ok(())
451 }
452 LimitThresholdCrossed::Hard(_, lim) => Err(ExecutionError::new_with_source(
453 ExecutionErrorKind::EffectsTooLarge {
454 current_size: effects_estimated_size as u64,
455 max_size: lim as u64,
456 },
457 "Transaction effects are too large",
458 )),
459 }
460 }
461
462 #[instrument(name = "check_written_objects_limit", level = "debug", skip_all)]
463 fn check_written_objects_limit(
464 temporary_store: &mut TemporaryStore<'_>,
465 gas_charger: &mut GasCharger,
466 protocol_config: &ProtocolConfig,
467 metrics: Arc<ExecutionMetrics>,
468 ) -> Result<(), ExecutionError> {
469 if let (Some(normal_lim), Some(system_lim)) = (
470 protocol_config.max_size_written_objects_as_option(),
471 protocol_config.max_size_written_objects_system_tx_as_option(),
472 ) {
473 let written_objects_size = temporary_store.written_objects_size();
474
475 match check_limit_by_meter!(
476 !gas_charger.is_unmetered(),
477 written_objects_size,
478 normal_lim,
479 system_lim,
480 metrics.limits_metrics.excessive_written_objects_size
481 ) {
482 LimitThresholdCrossed::None => (),
483 LimitThresholdCrossed::Soft(_, limit) => {
484 warn!(
485 written_objects_size = written_objects_size,
486 soft_limit = limit,
487 "Written objects size crossed soft limit",
488 )
489 }
490 LimitThresholdCrossed::Hard(_, lim) => {
491 return Err(ExecutionError::new_with_source(
492 ExecutionErrorKind::WrittenObjectsTooLarge {
493 current_size: written_objects_size as u64,
494 max_size: lim as u64,
495 },
496 "Written objects size crossed hard limit",
497 ));
498 }
499 };
500 }
501
502 Ok(())
503 }
504
505 #[instrument(level = "debug", skip_all)]
506 fn execution_loop<Mode: ExecutionMode>(
507 temporary_store: &mut TemporaryStore<'_>,
508 transaction_kind: TransactionKind,
509 tx_ctx: &mut TxContext,
510 move_vm: &Arc<MoveVM>,
511 gas_charger: &mut GasCharger,
512 protocol_config: &ProtocolConfig,
513 metrics: Arc<ExecutionMetrics>,
514 ) -> Result<Mode::ExecutionResults, ExecutionError> {
515 let result = match transaction_kind {
516 TransactionKind::ChangeEpoch(change_epoch) => {
517 let builder = ProgrammableTransactionBuilder::new();
518 advance_epoch(
519 builder,
520 change_epoch,
521 temporary_store,
522 tx_ctx,
523 move_vm,
524 gas_charger,
525 protocol_config,
526 metrics,
527 )?;
528 Ok(Mode::empty_results())
529 }
530 TransactionKind::Genesis(GenesisTransaction { objects }) => {
531 if tx_ctx.epoch() != 0 {
532 panic!("BUG: Genesis Transactions can only be executed in epoch 0");
533 }
534
535 for genesis_object in objects {
536 match genesis_object {
537 sui_types::transaction::GenesisObject::RawObject { data, owner } => {
538 let object = ObjectInner {
539 data,
540 owner,
541 previous_transaction: tx_ctx.digest(),
542 storage_rebate: 0,
543 };
544 temporary_store.create_object(object.into());
545 }
546 }
547 }
548 Ok(Mode::empty_results())
549 }
550 TransactionKind::ConsensusCommitPrologue(prologue) => {
551 setup_consensus_commit(
552 prologue.commit_timestamp_ms,
553 temporary_store,
554 tx_ctx,
555 move_vm,
556 gas_charger,
557 protocol_config,
558 metrics,
559 )
560 .expect("ConsensusCommitPrologue cannot fail");
561 Ok(Mode::empty_results())
562 }
563 TransactionKind::ConsensusCommitPrologueV2(prologue) => {
564 setup_consensus_commit(
565 prologue.commit_timestamp_ms,
566 temporary_store,
567 tx_ctx,
568 move_vm,
569 gas_charger,
570 protocol_config,
571 metrics,
572 )
573 .expect("ConsensusCommitPrologueV2 cannot fail");
574 Ok(Mode::empty_results())
575 }
576 TransactionKind::ConsensusCommitPrologueV3(prologue) => {
577 setup_consensus_commit(
578 prologue.commit_timestamp_ms,
579 temporary_store,
580 tx_ctx,
581 move_vm,
582 gas_charger,
583 protocol_config,
584 metrics,
585 )
586 .expect("ConsensusCommitPrologueV3 cannot fail");
587 Ok(Mode::empty_results())
588 }
589 TransactionKind::ConsensusCommitPrologueV4(prologue) => {
590 setup_consensus_commit(
591 prologue.commit_timestamp_ms,
592 temporary_store,
593 tx_ctx,
594 move_vm,
595 gas_charger,
596 protocol_config,
597 metrics,
598 )
599 .expect("ConsensusCommitPrologue cannot fail");
600 Ok(Mode::empty_results())
601 }
602 TransactionKind::ProgrammableTransaction(pt) => {
603 programmable_transactions::execution::execute::<Mode>(
604 protocol_config,
605 metrics,
606 move_vm,
607 temporary_store,
608 tx_ctx,
609 gas_charger,
610 pt,
611 )
612 }
613 TransactionKind::EndOfEpochTransaction(txns) => {
614 let mut builder = ProgrammableTransactionBuilder::new();
615 let len = txns.len();
616 for (i, tx) in txns.into_iter().enumerate() {
617 match tx {
618 EndOfEpochTransactionKind::ChangeEpoch(change_epoch) => {
619 assert_eq!(i, len - 1);
620 advance_epoch(
621 builder,
622 change_epoch,
623 temporary_store,
624 tx_ctx,
625 move_vm,
626 gas_charger,
627 protocol_config,
628 metrics,
629 )?;
630 return Ok(Mode::empty_results());
631 }
632 EndOfEpochTransactionKind::AuthenticatorStateCreate => {
633 assert!(protocol_config.enable_jwk_consensus_updates());
634 builder = setup_authenticator_state_create(builder);
635 }
636 EndOfEpochTransactionKind::AuthenticatorStateExpire(expire) => {
637 assert!(protocol_config.enable_jwk_consensus_updates());
638
639 builder = setup_authenticator_state_expire(builder, expire);
642 }
643 EndOfEpochTransactionKind::RandomnessStateCreate => {
644 assert!(protocol_config.random_beacon());
645 builder = setup_randomness_state_create(builder);
646 }
647 EndOfEpochTransactionKind::DenyListStateCreate => {
648 assert!(protocol_config.enable_coin_deny_list_v1());
649 builder = setup_coin_deny_list_state_create(builder);
650 }
651 EndOfEpochTransactionKind::BridgeStateCreate(_) => {
652 panic!(
653 "EndOfEpochTransactionKind::BridgeStateCreate should not exist in v2"
654 );
655 }
656 EndOfEpochTransactionKind::BridgeCommitteeInit(_) => {
657 panic!(
658 "EndOfEpochTransactionKind::BridgeCommitteeInit should not exist in v2"
659 );
660 }
661 EndOfEpochTransactionKind::StoreExecutionTimeObservations(_) => {
662 panic!(
663 "EndOfEpochTransactionKind::StoreExecutionTimeEstimates should not exist in v2"
664 );
665 }
666 EndOfEpochTransactionKind::AccumulatorRootCreate => {
667 panic!(
668 "EndOfEpochTransactionKind::AccumulatorRootCreate should not exist in v2"
669 );
670 }
671 EndOfEpochTransactionKind::WriteAccumulatorStorageCost(_) => {
672 panic!(
673 "EndOfEpochTransactionKind::WriteAccumulatorStorageCost should not exist in v2"
674 );
675 }
676 EndOfEpochTransactionKind::CoinRegistryCreate => {
677 panic!(
678 "EndOfEpochTransactionKind::CoinRegistryCreate should not exist in v2"
679 );
680 }
681 EndOfEpochTransactionKind::DisplayRegistryCreate => {
682 panic!(
683 "EndOfEpochTransactionKind::DisplayRegistryCreate should not exist in v2"
684 );
685 }
686 EndOfEpochTransactionKind::AddressAliasStateCreate => {
687 panic!(
688 "EndOfEpochTransactionKind::AddressAliasStateCreate should not exist in v2"
689 );
690 }
691 }
692 }
693 unreachable!(
694 "EndOfEpochTransactionKind::ChangeEpoch should be the last transaction in the list"
695 )
696 }
697 TransactionKind::AuthenticatorStateUpdate(auth_state_update) => {
698 setup_authenticator_state_update(
699 auth_state_update,
700 temporary_store,
701 tx_ctx,
702 move_vm,
703 gas_charger,
704 protocol_config,
705 metrics,
706 )?;
707 Ok(Mode::empty_results())
708 }
709 TransactionKind::RandomnessStateUpdate(randomness_state_update) => {
710 setup_randomness_state_update(
711 randomness_state_update,
712 temporary_store,
713 tx_ctx,
714 move_vm,
715 gas_charger,
716 protocol_config,
717 metrics,
718 )?;
719 Ok(Mode::empty_results())
720 }
721 TransactionKind::ProgrammableSystemTransaction(_) => {
722 panic!("ProgrammableSystemTransaction should not exist in execution layer v2");
723 }
724 }?;
725 temporary_store.check_execution_results_consistency()?;
726 Ok(result)
727 }
728
729 fn mint_epoch_rewards_in_pt(
730 builder: &mut ProgrammableTransactionBuilder,
731 params: &AdvanceEpochParams,
732 ) -> (Argument, Argument) {
733 let storage_charge_arg = builder
735 .input(CallArg::Pure(
736 bcs::to_bytes(¶ms.storage_charge).unwrap(),
737 ))
738 .unwrap();
739 let storage_rewards = builder.programmable_move_call(
740 SUI_FRAMEWORK_PACKAGE_ID,
741 BALANCE_MODULE_NAME.to_owned(),
742 BALANCE_CREATE_REWARDS_FUNCTION_NAME.to_owned(),
743 vec![GAS::type_tag()],
744 vec![storage_charge_arg],
745 );
746
747 let computation_charge_arg = builder
749 .input(CallArg::Pure(
750 bcs::to_bytes(¶ms.computation_charge).unwrap(),
751 ))
752 .unwrap();
753 let computation_rewards = builder.programmable_move_call(
754 SUI_FRAMEWORK_PACKAGE_ID,
755 BALANCE_MODULE_NAME.to_owned(),
756 BALANCE_CREATE_REWARDS_FUNCTION_NAME.to_owned(),
757 vec![GAS::type_tag()],
758 vec![computation_charge_arg],
759 );
760 (storage_rewards, computation_rewards)
761 }
762
763 pub fn construct_advance_epoch_pt(
764 mut builder: ProgrammableTransactionBuilder,
765 params: &AdvanceEpochParams,
766 ) -> Result<ProgrammableTransaction, ExecutionError> {
767 let (storage_rewards, computation_rewards) = mint_epoch_rewards_in_pt(&mut builder, params);
769
770 let mut arguments = vec![storage_rewards, computation_rewards];
772 let call_arg_arguments = vec![
773 CallArg::SUI_SYSTEM_MUT,
774 CallArg::Pure(bcs::to_bytes(¶ms.epoch).unwrap()),
775 CallArg::Pure(bcs::to_bytes(¶ms.next_protocol_version.as_u64()).unwrap()),
776 CallArg::Pure(bcs::to_bytes(¶ms.storage_rebate).unwrap()),
777 CallArg::Pure(bcs::to_bytes(¶ms.non_refundable_storage_fee).unwrap()),
778 CallArg::Pure(bcs::to_bytes(¶ms.storage_fund_reinvest_rate).unwrap()),
779 CallArg::Pure(bcs::to_bytes(¶ms.reward_slashing_rate).unwrap()),
780 CallArg::Pure(bcs::to_bytes(¶ms.epoch_start_timestamp_ms).unwrap()),
781 ]
782 .into_iter()
783 .map(|a| builder.input(a))
784 .collect::<Result<_, _>>();
785
786 assert_invariant!(
787 call_arg_arguments.is_ok(),
788 "Unable to generate args for advance_epoch transaction!"
789 );
790
791 arguments.append(&mut call_arg_arguments.unwrap());
792
793 info!("Call arguments to advance_epoch transaction: {:?}", params);
794
795 let storage_rebates = builder.programmable_move_call(
796 SUI_SYSTEM_PACKAGE_ID,
797 SUI_SYSTEM_MODULE_NAME.to_owned(),
798 ADVANCE_EPOCH_FUNCTION_NAME.to_owned(),
799 vec![],
800 arguments,
801 );
802
803 builder.programmable_move_call(
805 SUI_FRAMEWORK_PACKAGE_ID,
806 BALANCE_MODULE_NAME.to_owned(),
807 BALANCE_DESTROY_REBATES_FUNCTION_NAME.to_owned(),
808 vec![GAS::type_tag()],
809 vec![storage_rebates],
810 );
811 Ok(builder.finish())
812 }
813
814 pub fn construct_advance_epoch_safe_mode_pt(
815 params: &AdvanceEpochParams,
816 protocol_config: &ProtocolConfig,
817 ) -> Result<ProgrammableTransaction, ExecutionError> {
818 let mut builder = ProgrammableTransactionBuilder::new();
819 let (storage_rewards, computation_rewards) = mint_epoch_rewards_in_pt(&mut builder, params);
821
822 let mut arguments = vec![storage_rewards, computation_rewards];
824
825 let mut args = vec![
826 CallArg::SUI_SYSTEM_MUT,
827 CallArg::Pure(bcs::to_bytes(¶ms.epoch).unwrap()),
828 CallArg::Pure(bcs::to_bytes(¶ms.next_protocol_version.as_u64()).unwrap()),
829 CallArg::Pure(bcs::to_bytes(¶ms.storage_rebate).unwrap()),
830 CallArg::Pure(bcs::to_bytes(¶ms.non_refundable_storage_fee).unwrap()),
831 ];
832
833 if protocol_config.get_advance_epoch_start_time_in_safe_mode() {
834 args.push(CallArg::Pure(
835 bcs::to_bytes(¶ms.epoch_start_timestamp_ms).unwrap(),
836 ));
837 }
838
839 let call_arg_arguments = args
840 .into_iter()
841 .map(|a| builder.input(a))
842 .collect::<Result<_, _>>();
843
844 assert_invariant!(
845 call_arg_arguments.is_ok(),
846 "Unable to generate args for advance_epoch transaction!"
847 );
848
849 arguments.append(&mut call_arg_arguments.unwrap());
850
851 info!("Call arguments to advance_epoch transaction: {:?}", params);
852
853 builder.programmable_move_call(
854 SUI_SYSTEM_PACKAGE_ID,
855 SUI_SYSTEM_MODULE_NAME.to_owned(),
856 ADVANCE_EPOCH_SAFE_MODE_FUNCTION_NAME.to_owned(),
857 vec![],
858 arguments,
859 );
860
861 Ok(builder.finish())
862 }
863
864 fn advance_epoch(
865 builder: ProgrammableTransactionBuilder,
866 change_epoch: ChangeEpoch,
867 temporary_store: &mut TemporaryStore<'_>,
868 tx_ctx: &mut TxContext,
869 move_vm: &Arc<MoveVM>,
870 gas_charger: &mut GasCharger,
871 protocol_config: &ProtocolConfig,
872 metrics: Arc<ExecutionMetrics>,
873 ) -> Result<(), ExecutionError> {
874 let params = AdvanceEpochParams {
875 epoch: change_epoch.epoch,
876 next_protocol_version: change_epoch.protocol_version,
877 storage_charge: change_epoch.storage_charge,
878 computation_charge: change_epoch.computation_charge,
879 storage_rebate: change_epoch.storage_rebate,
880 non_refundable_storage_fee: change_epoch.non_refundable_storage_fee,
881 storage_fund_reinvest_rate: protocol_config.storage_fund_reinvest_rate(),
882 reward_slashing_rate: protocol_config.reward_slashing_rate(),
883 epoch_start_timestamp_ms: change_epoch.epoch_start_timestamp_ms,
884 };
885 let advance_epoch_pt = construct_advance_epoch_pt(builder, ¶ms)?;
886 let result = programmable_transactions::execution::execute::<execution_mode::System>(
887 protocol_config,
888 metrics.clone(),
889 move_vm,
890 temporary_store,
891 tx_ctx,
892 gas_charger,
893 advance_epoch_pt,
894 );
895
896 #[cfg(msim)]
897 let result = maybe_modify_result_legacy(result, change_epoch.epoch);
898
899 if result.is_err() {
900 tracing::error!(
901 "Failed to execute advance epoch transaction. Switching to safe mode. Error: {:?}. Input objects: {:?}. Tx data: {:?}",
902 result.as_ref().err(),
903 temporary_store.objects(),
904 change_epoch,
905 );
906 temporary_store.drop_writes();
907 gas_charger.reset_storage_cost_and_rebate();
909
910 if protocol_config.get_advance_epoch_start_time_in_safe_mode() {
911 temporary_store.advance_epoch_safe_mode(¶ms, protocol_config);
912 } else {
913 let advance_epoch_safe_mode_pt =
914 construct_advance_epoch_safe_mode_pt(¶ms, protocol_config)?;
915 programmable_transactions::execution::execute::<execution_mode::System>(
916 protocol_config,
917 metrics.clone(),
918 move_vm,
919 temporary_store,
920 tx_ctx,
921 gas_charger,
922 advance_epoch_safe_mode_pt,
923 )
924 .expect("Advance epoch with safe mode must succeed");
925 }
926 }
927
928 let binary_config = protocol_config.binary_config(None);
929 for (version, modules, dependencies) in change_epoch.system_packages.into_iter() {
930 let deserialized_modules: Vec<_> = modules
931 .iter()
932 .map(|m| CompiledModule::deserialize_with_config(m, &binary_config).unwrap())
933 .collect();
934
935 if version == OBJECT_START_VERSION {
936 let package_id = deserialized_modules.first().unwrap().address();
937 info!("adding new system package {package_id}");
938
939 let publish_pt = {
940 let mut b = ProgrammableTransactionBuilder::new();
941 b.command(Command::Publish(modules, dependencies));
942 b.finish()
943 };
944
945 programmable_transactions::execution::execute::<execution_mode::System>(
946 protocol_config,
947 metrics.clone(),
948 move_vm,
949 temporary_store,
950 tx_ctx,
951 gas_charger,
952 publish_pt,
953 )
954 .expect("System Package Publish must succeed");
955 } else {
956 let mut new_package = Object::new_system_package(
957 &deserialized_modules,
958 version,
959 dependencies,
960 tx_ctx.digest(),
961 );
962
963 info!(
964 "upgraded system package {:?}",
965 new_package.compute_object_reference()
966 );
967
968 new_package
971 .data
972 .try_as_package_mut()
973 .unwrap()
974 .decrement_version();
975
976 temporary_store.upgrade_system_package(new_package);
978 }
979 }
980
981 Ok(())
982 }
983
984 fn setup_consensus_commit(
989 consensus_commit_timestamp_ms: CheckpointTimestamp,
990 temporary_store: &mut TemporaryStore<'_>,
991 tx_ctx: &mut TxContext,
992 move_vm: &Arc<MoveVM>,
993 gas_charger: &mut GasCharger,
994 protocol_config: &ProtocolConfig,
995 metrics: Arc<ExecutionMetrics>,
996 ) -> Result<(), ExecutionError> {
997 let pt = {
998 let mut builder = ProgrammableTransactionBuilder::new();
999 let res = builder.move_call(
1000 SUI_FRAMEWORK_ADDRESS.into(),
1001 CLOCK_MODULE_NAME.to_owned(),
1002 CONSENSUS_COMMIT_PROLOGUE_FUNCTION_NAME.to_owned(),
1003 vec![],
1004 vec![
1005 CallArg::CLOCK_MUT,
1006 CallArg::Pure(bcs::to_bytes(&consensus_commit_timestamp_ms).unwrap()),
1007 ],
1008 );
1009 assert_invariant!(
1010 res.is_ok(),
1011 "Unable to generate consensus_commit_prologue transaction!"
1012 );
1013 builder.finish()
1014 };
1015 programmable_transactions::execution::execute::<execution_mode::System>(
1016 protocol_config,
1017 metrics,
1018 move_vm,
1019 temporary_store,
1020 tx_ctx,
1021 gas_charger,
1022 pt,
1023 )
1024 }
1025
1026 fn setup_authenticator_state_create(
1027 mut builder: ProgrammableTransactionBuilder,
1028 ) -> ProgrammableTransactionBuilder {
1029 builder
1030 .move_call(
1031 SUI_FRAMEWORK_ADDRESS.into(),
1032 AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1033 AUTHENTICATOR_STATE_CREATE_FUNCTION_NAME.to_owned(),
1034 vec![],
1035 vec![],
1036 )
1037 .expect("Unable to generate authenticator_state_create transaction!");
1038 builder
1039 }
1040
1041 fn setup_randomness_state_create(
1042 mut builder: ProgrammableTransactionBuilder,
1043 ) -> ProgrammableTransactionBuilder {
1044 builder
1045 .move_call(
1046 SUI_FRAMEWORK_ADDRESS.into(),
1047 RANDOMNESS_MODULE_NAME.to_owned(),
1048 RANDOMNESS_STATE_CREATE_FUNCTION_NAME.to_owned(),
1049 vec![],
1050 vec![],
1051 )
1052 .expect("Unable to generate randomness_state_create transaction!");
1053 builder
1054 }
1055
1056 fn setup_authenticator_state_update(
1057 update: AuthenticatorStateUpdate,
1058 temporary_store: &mut TemporaryStore<'_>,
1059 tx_ctx: &mut TxContext,
1060 move_vm: &Arc<MoveVM>,
1061 gas_charger: &mut GasCharger,
1062 protocol_config: &ProtocolConfig,
1063 metrics: Arc<ExecutionMetrics>,
1064 ) -> Result<(), ExecutionError> {
1065 let pt = {
1066 let mut builder = ProgrammableTransactionBuilder::new();
1067 let res = builder.move_call(
1068 SUI_FRAMEWORK_ADDRESS.into(),
1069 AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1070 AUTHENTICATOR_STATE_UPDATE_FUNCTION_NAME.to_owned(),
1071 vec![],
1072 vec![
1073 CallArg::Object(ObjectArg::SharedObject {
1074 id: SUI_AUTHENTICATOR_STATE_OBJECT_ID,
1075 initial_shared_version: update.authenticator_obj_initial_shared_version,
1076 mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1077 }),
1078 CallArg::Pure(bcs::to_bytes(&update.new_active_jwks).unwrap()),
1079 ],
1080 );
1081 assert_invariant!(
1082 res.is_ok(),
1083 "Unable to generate authenticator_state_update transaction!"
1084 );
1085 builder.finish()
1086 };
1087 programmable_transactions::execution::execute::<execution_mode::System>(
1088 protocol_config,
1089 metrics,
1090 move_vm,
1091 temporary_store,
1092 tx_ctx,
1093 gas_charger,
1094 pt,
1095 )
1096 }
1097
1098 fn setup_authenticator_state_expire(
1099 mut builder: ProgrammableTransactionBuilder,
1100 expire: AuthenticatorStateExpire,
1101 ) -> ProgrammableTransactionBuilder {
1102 builder
1103 .move_call(
1104 SUI_FRAMEWORK_ADDRESS.into(),
1105 AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1106 AUTHENTICATOR_STATE_EXPIRE_JWKS_FUNCTION_NAME.to_owned(),
1107 vec![],
1108 vec![
1109 CallArg::Object(ObjectArg::SharedObject {
1110 id: SUI_AUTHENTICATOR_STATE_OBJECT_ID,
1111 initial_shared_version: expire.authenticator_obj_initial_shared_version,
1112 mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1113 }),
1114 CallArg::Pure(bcs::to_bytes(&expire.min_epoch).unwrap()),
1115 ],
1116 )
1117 .expect("Unable to generate authenticator_state_expire transaction!");
1118 builder
1119 }
1120
1121 fn setup_randomness_state_update(
1122 update: RandomnessStateUpdate,
1123 temporary_store: &mut TemporaryStore<'_>,
1124 tx_ctx: &mut TxContext,
1125 move_vm: &Arc<MoveVM>,
1126 gas_charger: &mut GasCharger,
1127 protocol_config: &ProtocolConfig,
1128 metrics: Arc<ExecutionMetrics>,
1129 ) -> Result<(), ExecutionError> {
1130 let pt = {
1131 let mut builder = ProgrammableTransactionBuilder::new();
1132 let res = builder.move_call(
1133 SUI_FRAMEWORK_ADDRESS.into(),
1134 RANDOMNESS_MODULE_NAME.to_owned(),
1135 RANDOMNESS_STATE_UPDATE_FUNCTION_NAME.to_owned(),
1136 vec![],
1137 vec![
1138 CallArg::Object(ObjectArg::SharedObject {
1139 id: SUI_RANDOMNESS_STATE_OBJECT_ID,
1140 initial_shared_version: update.randomness_obj_initial_shared_version,
1141 mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1142 }),
1143 CallArg::Pure(bcs::to_bytes(&update.randomness_round).unwrap()),
1144 CallArg::Pure(bcs::to_bytes(&update.random_bytes).unwrap()),
1145 ],
1146 );
1147 assert_invariant!(
1148 res.is_ok(),
1149 "Unable to generate randomness_state_update transaction!"
1150 );
1151 builder.finish()
1152 };
1153 programmable_transactions::execution::execute::<execution_mode::System>(
1154 protocol_config,
1155 metrics,
1156 move_vm,
1157 temporary_store,
1158 tx_ctx,
1159 gas_charger,
1160 pt,
1161 )
1162 }
1163
1164 fn setup_coin_deny_list_state_create(
1165 mut builder: ProgrammableTransactionBuilder,
1166 ) -> ProgrammableTransactionBuilder {
1167 builder
1168 .move_call(
1169 SUI_FRAMEWORK_ADDRESS.into(),
1170 DENY_LIST_MODULE.to_owned(),
1171 DENY_LIST_CREATE_FUNC.to_owned(),
1172 vec![],
1173 vec![],
1174 )
1175 .expect("Unable to generate coin_deny_list_create transaction!");
1176 builder
1177 }
1178}