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