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