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