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