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::<Mode>(
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<Mode: ExecutionMode>(
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!("EndOfEpochTransactionKind::BridgeCommitteeInit should not exist in v2");
659 }
660 EndOfEpochTransactionKind::StoreExecutionTimeObservations(_) => {
661 panic!("EndOfEpochTransactionKind::StoreExecutionTimeEstimates should not exist in v2");
662 }
663 EndOfEpochTransactionKind::AccumulatorRootCreate => {
664 panic!("EndOfEpochTransactionKind::AccumulatorRootCreate should not exist in v2");
665 }
666 EndOfEpochTransactionKind::WriteAccumulatorStorageCost(_) => {
667 panic!("EndOfEpochTransactionKind::WriteAccumulatorStorageCost should not exist in v2");
668 }
669 EndOfEpochTransactionKind::CoinRegistryCreate => {
670 panic!("EndOfEpochTransactionKind::CoinRegistryCreate should not exist in v2");
671 }
672 EndOfEpochTransactionKind::DisplayRegistryCreate => {
673 panic!("EndOfEpochTransactionKind::DisplayRegistryCreate should not exist in v2");
674 }
675 EndOfEpochTransactionKind::AddressAliasStateCreate => {
676 panic!("EndOfEpochTransactionKind::AddressAliasStateCreate should not exist in v2");
677 }
678 }
679 }
680 unreachable!("EndOfEpochTransactionKind::ChangeEpoch should be the last transaction in the list")
681 }
682 TransactionKind::AuthenticatorStateUpdate(auth_state_update) => {
683 setup_authenticator_state_update(
684 auth_state_update,
685 temporary_store,
686 tx_ctx,
687 move_vm,
688 gas_charger,
689 protocol_config,
690 metrics,
691 )?;
692 Ok(Mode::empty_results())
693 }
694 TransactionKind::RandomnessStateUpdate(randomness_state_update) => {
695 setup_randomness_state_update(
696 randomness_state_update,
697 temporary_store,
698 tx_ctx,
699 move_vm,
700 gas_charger,
701 protocol_config,
702 metrics,
703 )?;
704 Ok(Mode::empty_results())
705 }
706 TransactionKind::ProgrammableSystemTransaction(_) => {
707 panic!("ProgrammableSystemTransaction should not exist in execution layer v2");
708 }
709 }?;
710 temporary_store.check_execution_results_consistency()?;
711 Ok(result)
712 }
713
714 fn mint_epoch_rewards_in_pt(
715 builder: &mut ProgrammableTransactionBuilder,
716 params: &AdvanceEpochParams,
717 ) -> (Argument, Argument) {
718 let storage_charge_arg = builder
720 .input(CallArg::Pure(
721 bcs::to_bytes(¶ms.storage_charge).unwrap(),
722 ))
723 .unwrap();
724 let storage_rewards = builder.programmable_move_call(
725 SUI_FRAMEWORK_PACKAGE_ID,
726 BALANCE_MODULE_NAME.to_owned(),
727 BALANCE_CREATE_REWARDS_FUNCTION_NAME.to_owned(),
728 vec![GAS::type_tag()],
729 vec![storage_charge_arg],
730 );
731
732 let computation_charge_arg = builder
734 .input(CallArg::Pure(
735 bcs::to_bytes(¶ms.computation_charge).unwrap(),
736 ))
737 .unwrap();
738 let computation_rewards = builder.programmable_move_call(
739 SUI_FRAMEWORK_PACKAGE_ID,
740 BALANCE_MODULE_NAME.to_owned(),
741 BALANCE_CREATE_REWARDS_FUNCTION_NAME.to_owned(),
742 vec![GAS::type_tag()],
743 vec![computation_charge_arg],
744 );
745 (storage_rewards, computation_rewards)
746 }
747
748 pub fn construct_advance_epoch_pt(
749 mut builder: ProgrammableTransactionBuilder,
750 params: &AdvanceEpochParams,
751 ) -> Result<ProgrammableTransaction, ExecutionError> {
752 let (storage_rewards, computation_rewards) = mint_epoch_rewards_in_pt(&mut builder, params);
754
755 let mut arguments = vec![storage_rewards, computation_rewards];
757 let call_arg_arguments = vec![
758 CallArg::SUI_SYSTEM_MUT,
759 CallArg::Pure(bcs::to_bytes(¶ms.epoch).unwrap()),
760 CallArg::Pure(bcs::to_bytes(¶ms.next_protocol_version.as_u64()).unwrap()),
761 CallArg::Pure(bcs::to_bytes(¶ms.storage_rebate).unwrap()),
762 CallArg::Pure(bcs::to_bytes(¶ms.non_refundable_storage_fee).unwrap()),
763 CallArg::Pure(bcs::to_bytes(¶ms.storage_fund_reinvest_rate).unwrap()),
764 CallArg::Pure(bcs::to_bytes(¶ms.reward_slashing_rate).unwrap()),
765 CallArg::Pure(bcs::to_bytes(¶ms.epoch_start_timestamp_ms).unwrap()),
766 ]
767 .into_iter()
768 .map(|a| builder.input(a))
769 .collect::<Result<_, _>>();
770
771 assert_invariant!(
772 call_arg_arguments.is_ok(),
773 "Unable to generate args for advance_epoch transaction!"
774 );
775
776 arguments.append(&mut call_arg_arguments.unwrap());
777
778 info!("Call arguments to advance_epoch transaction: {:?}", params);
779
780 let storage_rebates = builder.programmable_move_call(
781 SUI_SYSTEM_PACKAGE_ID,
782 SUI_SYSTEM_MODULE_NAME.to_owned(),
783 ADVANCE_EPOCH_FUNCTION_NAME.to_owned(),
784 vec![],
785 arguments,
786 );
787
788 builder.programmable_move_call(
790 SUI_FRAMEWORK_PACKAGE_ID,
791 BALANCE_MODULE_NAME.to_owned(),
792 BALANCE_DESTROY_REBATES_FUNCTION_NAME.to_owned(),
793 vec![GAS::type_tag()],
794 vec![storage_rebates],
795 );
796 Ok(builder.finish())
797 }
798
799 pub fn construct_advance_epoch_safe_mode_pt(
800 params: &AdvanceEpochParams,
801 protocol_config: &ProtocolConfig,
802 ) -> Result<ProgrammableTransaction, ExecutionError> {
803 let mut builder = ProgrammableTransactionBuilder::new();
804 let (storage_rewards, computation_rewards) = mint_epoch_rewards_in_pt(&mut builder, params);
806
807 let mut arguments = vec![storage_rewards, computation_rewards];
809
810 let mut args = vec![
811 CallArg::SUI_SYSTEM_MUT,
812 CallArg::Pure(bcs::to_bytes(¶ms.epoch).unwrap()),
813 CallArg::Pure(bcs::to_bytes(¶ms.next_protocol_version.as_u64()).unwrap()),
814 CallArg::Pure(bcs::to_bytes(¶ms.storage_rebate).unwrap()),
815 CallArg::Pure(bcs::to_bytes(¶ms.non_refundable_storage_fee).unwrap()),
816 ];
817
818 if protocol_config.get_advance_epoch_start_time_in_safe_mode() {
819 args.push(CallArg::Pure(
820 bcs::to_bytes(¶ms.epoch_start_timestamp_ms).unwrap(),
821 ));
822 }
823
824 let call_arg_arguments = args
825 .into_iter()
826 .map(|a| builder.input(a))
827 .collect::<Result<_, _>>();
828
829 assert_invariant!(
830 call_arg_arguments.is_ok(),
831 "Unable to generate args for advance_epoch transaction!"
832 );
833
834 arguments.append(&mut call_arg_arguments.unwrap());
835
836 info!("Call arguments to advance_epoch transaction: {:?}", params);
837
838 builder.programmable_move_call(
839 SUI_SYSTEM_PACKAGE_ID,
840 SUI_SYSTEM_MODULE_NAME.to_owned(),
841 ADVANCE_EPOCH_SAFE_MODE_FUNCTION_NAME.to_owned(),
842 vec![],
843 arguments,
844 );
845
846 Ok(builder.finish())
847 }
848
849 fn advance_epoch(
850 builder: ProgrammableTransactionBuilder,
851 change_epoch: ChangeEpoch,
852 temporary_store: &mut TemporaryStore<'_>,
853 tx_ctx: &mut TxContext,
854 move_vm: &Arc<MoveVM>,
855 gas_charger: &mut GasCharger,
856 protocol_config: &ProtocolConfig,
857 metrics: Arc<LimitsMetrics>,
858 ) -> Result<(), ExecutionError> {
859 let params = AdvanceEpochParams {
860 epoch: change_epoch.epoch,
861 next_protocol_version: change_epoch.protocol_version,
862 storage_charge: change_epoch.storage_charge,
863 computation_charge: change_epoch.computation_charge,
864 storage_rebate: change_epoch.storage_rebate,
865 non_refundable_storage_fee: change_epoch.non_refundable_storage_fee,
866 storage_fund_reinvest_rate: protocol_config.storage_fund_reinvest_rate(),
867 reward_slashing_rate: protocol_config.reward_slashing_rate(),
868 epoch_start_timestamp_ms: change_epoch.epoch_start_timestamp_ms,
869 };
870 let advance_epoch_pt = construct_advance_epoch_pt(builder, ¶ms)?;
871 let result = programmable_transactions::execution::execute::<execution_mode::System>(
872 protocol_config,
873 metrics.clone(),
874 move_vm,
875 temporary_store,
876 tx_ctx,
877 gas_charger,
878 advance_epoch_pt,
879 );
880
881 #[cfg(msim)]
882 let result = maybe_modify_result_legacy(result, change_epoch.epoch);
883
884 if result.is_err() {
885 tracing::error!(
886 "Failed to execute advance epoch transaction. Switching to safe mode. Error: {:?}. Input objects: {:?}. Tx data: {:?}",
887 result.as_ref().err(),
888 temporary_store.objects(),
889 change_epoch,
890 );
891 temporary_store.drop_writes();
892 gas_charger.reset_storage_cost_and_rebate();
894
895 if protocol_config.get_advance_epoch_start_time_in_safe_mode() {
896 temporary_store.advance_epoch_safe_mode(¶ms, protocol_config);
897 } else {
898 let advance_epoch_safe_mode_pt =
899 construct_advance_epoch_safe_mode_pt(¶ms, protocol_config)?;
900 programmable_transactions::execution::execute::<execution_mode::System>(
901 protocol_config,
902 metrics.clone(),
903 move_vm,
904 temporary_store,
905 tx_ctx,
906 gas_charger,
907 advance_epoch_safe_mode_pt,
908 )
909 .expect("Advance epoch with safe mode must succeed");
910 }
911 }
912
913 let binary_config = protocol_config.binary_config(None);
914 for (version, modules, dependencies) in change_epoch.system_packages.into_iter() {
915 let deserialized_modules: Vec<_> = modules
916 .iter()
917 .map(|m| CompiledModule::deserialize_with_config(m, &binary_config).unwrap())
918 .collect();
919
920 if version == OBJECT_START_VERSION {
921 let package_id = deserialized_modules.first().unwrap().address();
922 info!("adding new system package {package_id}");
923
924 let publish_pt = {
925 let mut b = ProgrammableTransactionBuilder::new();
926 b.command(Command::Publish(modules, dependencies));
927 b.finish()
928 };
929
930 programmable_transactions::execution::execute::<execution_mode::System>(
931 protocol_config,
932 metrics.clone(),
933 move_vm,
934 temporary_store,
935 tx_ctx,
936 gas_charger,
937 publish_pt,
938 )
939 .expect("System Package Publish must succeed");
940 } else {
941 let mut new_package = Object::new_system_package(
942 &deserialized_modules,
943 version,
944 dependencies,
945 tx_ctx.digest(),
946 );
947
948 info!(
949 "upgraded system package {:?}",
950 new_package.compute_object_reference()
951 );
952
953 new_package
956 .data
957 .try_as_package_mut()
958 .unwrap()
959 .decrement_version();
960
961 temporary_store.upgrade_system_package(new_package);
963 }
964 }
965
966 Ok(())
967 }
968
969 fn setup_consensus_commit(
974 consensus_commit_timestamp_ms: CheckpointTimestamp,
975 temporary_store: &mut TemporaryStore<'_>,
976 tx_ctx: &mut TxContext,
977 move_vm: &Arc<MoveVM>,
978 gas_charger: &mut GasCharger,
979 protocol_config: &ProtocolConfig,
980 metrics: Arc<LimitsMetrics>,
981 ) -> Result<(), ExecutionError> {
982 let pt = {
983 let mut builder = ProgrammableTransactionBuilder::new();
984 let res = builder.move_call(
985 SUI_FRAMEWORK_ADDRESS.into(),
986 CLOCK_MODULE_NAME.to_owned(),
987 CONSENSUS_COMMIT_PROLOGUE_FUNCTION_NAME.to_owned(),
988 vec![],
989 vec![
990 CallArg::CLOCK_MUT,
991 CallArg::Pure(bcs::to_bytes(&consensus_commit_timestamp_ms).unwrap()),
992 ],
993 );
994 assert_invariant!(
995 res.is_ok(),
996 "Unable to generate consensus_commit_prologue transaction!"
997 );
998 builder.finish()
999 };
1000 programmable_transactions::execution::execute::<execution_mode::System>(
1001 protocol_config,
1002 metrics,
1003 move_vm,
1004 temporary_store,
1005 tx_ctx,
1006 gas_charger,
1007 pt,
1008 )
1009 }
1010
1011 fn setup_authenticator_state_create(
1012 mut builder: ProgrammableTransactionBuilder,
1013 ) -> ProgrammableTransactionBuilder {
1014 builder
1015 .move_call(
1016 SUI_FRAMEWORK_ADDRESS.into(),
1017 AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1018 AUTHENTICATOR_STATE_CREATE_FUNCTION_NAME.to_owned(),
1019 vec![],
1020 vec![],
1021 )
1022 .expect("Unable to generate authenticator_state_create transaction!");
1023 builder
1024 }
1025
1026 fn setup_randomness_state_create(
1027 mut builder: ProgrammableTransactionBuilder,
1028 ) -> ProgrammableTransactionBuilder {
1029 builder
1030 .move_call(
1031 SUI_FRAMEWORK_ADDRESS.into(),
1032 RANDOMNESS_MODULE_NAME.to_owned(),
1033 RANDOMNESS_STATE_CREATE_FUNCTION_NAME.to_owned(),
1034 vec![],
1035 vec![],
1036 )
1037 .expect("Unable to generate randomness_state_create transaction!");
1038 builder
1039 }
1040
1041 fn setup_authenticator_state_update(
1042 update: AuthenticatorStateUpdate,
1043 temporary_store: &mut TemporaryStore<'_>,
1044 tx_ctx: &mut TxContext,
1045 move_vm: &Arc<MoveVM>,
1046 gas_charger: &mut GasCharger,
1047 protocol_config: &ProtocolConfig,
1048 metrics: Arc<LimitsMetrics>,
1049 ) -> Result<(), ExecutionError> {
1050 let pt = {
1051 let mut builder = ProgrammableTransactionBuilder::new();
1052 let res = builder.move_call(
1053 SUI_FRAMEWORK_ADDRESS.into(),
1054 AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1055 AUTHENTICATOR_STATE_UPDATE_FUNCTION_NAME.to_owned(),
1056 vec![],
1057 vec![
1058 CallArg::Object(ObjectArg::SharedObject {
1059 id: SUI_AUTHENTICATOR_STATE_OBJECT_ID,
1060 initial_shared_version: update.authenticator_obj_initial_shared_version,
1061 mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1062 }),
1063 CallArg::Pure(bcs::to_bytes(&update.new_active_jwks).unwrap()),
1064 ],
1065 );
1066 assert_invariant!(
1067 res.is_ok(),
1068 "Unable to generate authenticator_state_update transaction!"
1069 );
1070 builder.finish()
1071 };
1072 programmable_transactions::execution::execute::<execution_mode::System>(
1073 protocol_config,
1074 metrics,
1075 move_vm,
1076 temporary_store,
1077 tx_ctx,
1078 gas_charger,
1079 pt,
1080 )
1081 }
1082
1083 fn setup_authenticator_state_expire(
1084 mut builder: ProgrammableTransactionBuilder,
1085 expire: AuthenticatorStateExpire,
1086 ) -> ProgrammableTransactionBuilder {
1087 builder
1088 .move_call(
1089 SUI_FRAMEWORK_ADDRESS.into(),
1090 AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1091 AUTHENTICATOR_STATE_EXPIRE_JWKS_FUNCTION_NAME.to_owned(),
1092 vec![],
1093 vec![
1094 CallArg::Object(ObjectArg::SharedObject {
1095 id: SUI_AUTHENTICATOR_STATE_OBJECT_ID,
1096 initial_shared_version: expire.authenticator_obj_initial_shared_version,
1097 mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1098 }),
1099 CallArg::Pure(bcs::to_bytes(&expire.min_epoch).unwrap()),
1100 ],
1101 )
1102 .expect("Unable to generate authenticator_state_expire transaction!");
1103 builder
1104 }
1105
1106 fn setup_randomness_state_update(
1107 update: RandomnessStateUpdate,
1108 temporary_store: &mut TemporaryStore<'_>,
1109 tx_ctx: &mut TxContext,
1110 move_vm: &Arc<MoveVM>,
1111 gas_charger: &mut GasCharger,
1112 protocol_config: &ProtocolConfig,
1113 metrics: Arc<LimitsMetrics>,
1114 ) -> Result<(), ExecutionError> {
1115 let pt = {
1116 let mut builder = ProgrammableTransactionBuilder::new();
1117 let res = builder.move_call(
1118 SUI_FRAMEWORK_ADDRESS.into(),
1119 RANDOMNESS_MODULE_NAME.to_owned(),
1120 RANDOMNESS_STATE_UPDATE_FUNCTION_NAME.to_owned(),
1121 vec![],
1122 vec![
1123 CallArg::Object(ObjectArg::SharedObject {
1124 id: SUI_RANDOMNESS_STATE_OBJECT_ID,
1125 initial_shared_version: update.randomness_obj_initial_shared_version,
1126 mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1127 }),
1128 CallArg::Pure(bcs::to_bytes(&update.randomness_round).unwrap()),
1129 CallArg::Pure(bcs::to_bytes(&update.random_bytes).unwrap()),
1130 ],
1131 );
1132 assert_invariant!(
1133 res.is_ok(),
1134 "Unable to generate randomness_state_update transaction!"
1135 );
1136 builder.finish()
1137 };
1138 programmable_transactions::execution::execute::<execution_mode::System>(
1139 protocol_config,
1140 metrics,
1141 move_vm,
1142 temporary_store,
1143 tx_ctx,
1144 gas_charger,
1145 pt,
1146 )
1147 }
1148
1149 fn setup_coin_deny_list_state_create(
1150 mut builder: ProgrammableTransactionBuilder,
1151 ) -> ProgrammableTransactionBuilder {
1152 builder
1153 .move_call(
1154 SUI_FRAMEWORK_ADDRESS.into(),
1155 DENY_LIST_MODULE.to_owned(),
1156 DENY_LIST_CREATE_FUNC.to_owned(),
1157 vec![],
1158 vec![],
1159 )
1160 .expect("Unable to generate coin_deny_list_create transaction!");
1161 builder
1162 }
1163}