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.into_early_errors() {
227 Some(early_execution_errors) => {
228 Err(ExecutionError::new(early_execution_errors.head, None))
229 }
230 None => 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 EndOfEpochTransactionKind::ForwardingAddressRegistryCreate => {
638 panic!(
639 "EndOfEpochTransactionKind::ForwardingAddressRegistryCreate should not exist in v1"
640 );
641 }
642 }
643 }
644 unreachable!(
645 "EndOfEpochTransactionKind::ChangeEpoch should be the last transaction in the list"
646 )
647 }
648 TransactionKind::AuthenticatorStateUpdate(auth_state_update) => {
649 setup_authenticator_state_update(
650 auth_state_update,
651 temporary_store,
652 tx_ctx,
653 move_vm,
654 gas_charger,
655 protocol_config,
656 metrics,
657 )?;
658 Ok(Mode::empty_results())
659 }
660 TransactionKind::RandomnessStateUpdate(_) => {
661 panic!("RandomnessStateUpdate should not exist in v1");
662 }
663 TransactionKind::ProgrammableSystemTransaction(_) => {
664 panic!("ProgrammableSystemTransaction should not exist in execution layer v1");
665 }
666 }?;
667 temporary_store.check_execution_results_consistency()?;
668 Ok(result)
669 }
670
671 fn mint_epoch_rewards_in_pt(
672 builder: &mut ProgrammableTransactionBuilder,
673 params: &AdvanceEpochParams,
674 ) -> (Argument, Argument) {
675 let storage_charge_arg = builder
677 .input(CallArg::Pure(
678 bcs::to_bytes(¶ms.storage_charge).unwrap(),
679 ))
680 .unwrap();
681 let storage_rewards = builder.programmable_move_call(
682 SUI_FRAMEWORK_PACKAGE_ID,
683 BALANCE_MODULE_NAME.to_owned(),
684 BALANCE_CREATE_REWARDS_FUNCTION_NAME.to_owned(),
685 vec![GAS::type_tag()],
686 vec![storage_charge_arg],
687 );
688
689 let computation_charge_arg = builder
691 .input(CallArg::Pure(
692 bcs::to_bytes(¶ms.computation_charge).unwrap(),
693 ))
694 .unwrap();
695 let computation_rewards = builder.programmable_move_call(
696 SUI_FRAMEWORK_PACKAGE_ID,
697 BALANCE_MODULE_NAME.to_owned(),
698 BALANCE_CREATE_REWARDS_FUNCTION_NAME.to_owned(),
699 vec![GAS::type_tag()],
700 vec![computation_charge_arg],
701 );
702 (storage_rewards, computation_rewards)
703 }
704
705 pub fn construct_advance_epoch_pt(
706 mut builder: ProgrammableTransactionBuilder,
707 params: &AdvanceEpochParams,
708 ) -> Result<ProgrammableTransaction, ExecutionError> {
709 let (storage_rewards, computation_rewards) = mint_epoch_rewards_in_pt(&mut builder, params);
711
712 let mut arguments = vec![storage_rewards, computation_rewards];
714 let call_arg_arguments = vec![
715 CallArg::SUI_SYSTEM_MUT,
716 CallArg::Pure(bcs::to_bytes(¶ms.epoch).unwrap()),
717 CallArg::Pure(bcs::to_bytes(¶ms.next_protocol_version.as_u64()).unwrap()),
718 CallArg::Pure(bcs::to_bytes(¶ms.storage_rebate).unwrap()),
719 CallArg::Pure(bcs::to_bytes(¶ms.non_refundable_storage_fee).unwrap()),
720 CallArg::Pure(bcs::to_bytes(¶ms.storage_fund_reinvest_rate).unwrap()),
721 CallArg::Pure(bcs::to_bytes(¶ms.reward_slashing_rate).unwrap()),
722 CallArg::Pure(bcs::to_bytes(¶ms.epoch_start_timestamp_ms).unwrap()),
723 ]
724 .into_iter()
725 .map(|a| builder.input(a))
726 .collect::<Result<_, _>>();
727
728 assert_invariant!(
729 call_arg_arguments.is_ok(),
730 "Unable to generate args for advance_epoch transaction!"
731 );
732
733 arguments.append(&mut call_arg_arguments.unwrap());
734
735 info!("Call arguments to advance_epoch transaction: {:?}", params);
736
737 let storage_rebates = builder.programmable_move_call(
738 SUI_SYSTEM_PACKAGE_ID,
739 SUI_SYSTEM_MODULE_NAME.to_owned(),
740 ADVANCE_EPOCH_FUNCTION_NAME.to_owned(),
741 vec![],
742 arguments,
743 );
744
745 builder.programmable_move_call(
747 SUI_FRAMEWORK_PACKAGE_ID,
748 BALANCE_MODULE_NAME.to_owned(),
749 BALANCE_DESTROY_REBATES_FUNCTION_NAME.to_owned(),
750 vec![GAS::type_tag()],
751 vec![storage_rebates],
752 );
753 Ok(builder.finish())
754 }
755
756 pub fn construct_advance_epoch_safe_mode_pt(
757 params: &AdvanceEpochParams,
758 protocol_config: &ProtocolConfig,
759 ) -> Result<ProgrammableTransaction, ExecutionError> {
760 let mut builder = ProgrammableTransactionBuilder::new();
761 let (storage_rewards, computation_rewards) = mint_epoch_rewards_in_pt(&mut builder, params);
763
764 let mut arguments = vec![storage_rewards, computation_rewards];
766
767 let mut args = vec![
768 CallArg::SUI_SYSTEM_MUT,
769 CallArg::Pure(bcs::to_bytes(¶ms.epoch).unwrap()),
770 CallArg::Pure(bcs::to_bytes(¶ms.next_protocol_version.as_u64()).unwrap()),
771 CallArg::Pure(bcs::to_bytes(¶ms.storage_rebate).unwrap()),
772 CallArg::Pure(bcs::to_bytes(¶ms.non_refundable_storage_fee).unwrap()),
773 ];
774
775 if protocol_config.advance_epoch_start_time_in_safe_mode() {
776 args.push(CallArg::Pure(
777 bcs::to_bytes(¶ms.epoch_start_timestamp_ms).unwrap(),
778 ));
779 }
780
781 let call_arg_arguments = args
782 .into_iter()
783 .map(|a| builder.input(a))
784 .collect::<Result<_, _>>();
785
786 assert_invariant!(
787 call_arg_arguments.is_ok(),
788 "Unable to generate args for advance_epoch transaction!"
789 );
790
791 arguments.append(&mut call_arg_arguments.unwrap());
792
793 info!("Call arguments to advance_epoch transaction: {:?}", params);
794
795 builder.programmable_move_call(
796 SUI_SYSTEM_PACKAGE_ID,
797 SUI_SYSTEM_MODULE_NAME.to_owned(),
798 ADVANCE_EPOCH_SAFE_MODE_FUNCTION_NAME.to_owned(),
799 vec![],
800 arguments,
801 );
802
803 Ok(builder.finish())
804 }
805
806 fn advance_epoch(
807 builder: ProgrammableTransactionBuilder,
808 change_epoch: ChangeEpoch,
809 temporary_store: &mut TemporaryStore<'_>,
810 tx_ctx: &mut TxContext,
811 move_vm: &Arc<MoveVM>,
812 gas_charger: &mut GasCharger,
813 protocol_config: &ProtocolConfig,
814 metrics: Arc<ExecutionMetrics>,
815 ) -> Result<(), ExecutionError> {
816 let params = AdvanceEpochParams {
817 epoch: change_epoch.epoch,
818 next_protocol_version: change_epoch.protocol_version,
819 storage_charge: change_epoch.storage_charge,
820 computation_charge: change_epoch.computation_charge,
821 storage_rebate: change_epoch.storage_rebate,
822 non_refundable_storage_fee: change_epoch.non_refundable_storage_fee,
823 storage_fund_reinvest_rate: protocol_config.storage_fund_reinvest_rate(),
824 reward_slashing_rate: protocol_config.reward_slashing_rate(),
825 epoch_start_timestamp_ms: change_epoch.epoch_start_timestamp_ms,
826 };
827 let advance_epoch_pt = construct_advance_epoch_pt(builder, ¶ms)?;
828 let result = programmable_transactions::execution::execute::<execution_mode::System>(
829 protocol_config,
830 metrics.clone(),
831 move_vm,
832 temporary_store,
833 tx_ctx,
834 gas_charger,
835 advance_epoch_pt,
836 );
837
838 #[cfg(msim)]
839 let result = maybe_modify_result_legacy(result, change_epoch.epoch);
840
841 if result.is_err() {
842 tracing::error!(
843 "Failed to execute advance epoch transaction. Switching to safe mode. Error: {:?}. Input objects: {:?}. Tx data: {:?}",
844 result.as_ref().err(),
845 temporary_store.objects(),
846 change_epoch,
847 );
848 temporary_store.drop_writes();
849 gas_charger.reset_storage_cost_and_rebate();
851
852 if protocol_config.advance_epoch_start_time_in_safe_mode() {
853 temporary_store.advance_epoch_safe_mode(¶ms, protocol_config);
854 } else {
855 let advance_epoch_safe_mode_pt =
856 construct_advance_epoch_safe_mode_pt(¶ms, protocol_config)?;
857 programmable_transactions::execution::execute::<execution_mode::System>(
858 protocol_config,
859 metrics.clone(),
860 move_vm,
861 temporary_store,
862 tx_ctx,
863 gas_charger,
864 advance_epoch_safe_mode_pt,
865 )
866 .expect("Advance epoch with safe mode must succeed");
867 }
868 }
869
870 let binary_config = protocol_config.binary_config(None);
871 for (version, modules, dependencies) in change_epoch.system_packages.into_iter() {
872 let deserialized_modules: Vec<_> = modules
873 .iter()
874 .map(|m| CompiledModule::deserialize_with_config(m, &binary_config).unwrap())
875 .collect();
876
877 if version == OBJECT_START_VERSION {
878 let package_id = deserialized_modules.first().unwrap().address();
879 info!("adding new system package {package_id}");
880
881 let publish_pt = {
882 let mut b = ProgrammableTransactionBuilder::new();
883 b.command(Command::Publish(modules, dependencies));
884 b.finish()
885 };
886
887 programmable_transactions::execution::execute::<execution_mode::System>(
888 protocol_config,
889 metrics.clone(),
890 move_vm,
891 temporary_store,
892 tx_ctx,
893 gas_charger,
894 publish_pt,
895 )
896 .expect("System Package Publish must succeed");
897 } else {
898 let mut new_package = Object::new_system_package(
899 &deserialized_modules,
900 version,
901 dependencies,
902 tx_ctx.digest(),
903 );
904
905 info!(
906 "upgraded system package {:?}",
907 new_package.compute_object_reference()
908 );
909
910 new_package
913 .data
914 .try_as_package_mut()
915 .unwrap()
916 .decrement_version();
917
918 temporary_store.upgrade_system_package(new_package);
920 }
921 }
922
923 Ok(())
924 }
925
926 fn setup_consensus_commit(
931 consensus_commit_timestamp_ms: CheckpointTimestamp,
932 temporary_store: &mut TemporaryStore<'_>,
933 tx_ctx: &mut TxContext,
934 move_vm: &Arc<MoveVM>,
935 gas_charger: &mut GasCharger,
936 protocol_config: &ProtocolConfig,
937 metrics: Arc<ExecutionMetrics>,
938 ) -> Result<(), ExecutionError> {
939 let pt = {
940 let mut builder = ProgrammableTransactionBuilder::new();
941 let res = builder.move_call(
942 SUI_FRAMEWORK_ADDRESS.into(),
943 CLOCK_MODULE_NAME.to_owned(),
944 CONSENSUS_COMMIT_PROLOGUE_FUNCTION_NAME.to_owned(),
945 vec![],
946 vec![
947 CallArg::CLOCK_MUT,
948 CallArg::Pure(bcs::to_bytes(&consensus_commit_timestamp_ms).unwrap()),
949 ],
950 );
951 assert_invariant!(
952 res.is_ok(),
953 "Unable to generate consensus_commit_prologue transaction!"
954 );
955 builder.finish()
956 };
957 programmable_transactions::execution::execute::<execution_mode::System>(
958 protocol_config,
959 metrics,
960 move_vm,
961 temporary_store,
962 tx_ctx,
963 gas_charger,
964 pt,
965 )
966 }
967
968 fn setup_authenticator_state_create(
969 mut builder: ProgrammableTransactionBuilder,
970 ) -> ProgrammableTransactionBuilder {
971 builder
972 .move_call(
973 SUI_FRAMEWORK_ADDRESS.into(),
974 AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
975 AUTHENTICATOR_STATE_CREATE_FUNCTION_NAME.to_owned(),
976 vec![],
977 vec![],
978 )
979 .expect("Unable to generate authenticator_state_create transaction!");
980 builder
981 }
982
983 fn setup_authenticator_state_update(
984 update: AuthenticatorStateUpdate,
985 temporary_store: &mut TemporaryStore<'_>,
986 tx_ctx: &mut TxContext,
987 move_vm: &Arc<MoveVM>,
988 gas_charger: &mut GasCharger,
989 protocol_config: &ProtocolConfig,
990 metrics: Arc<ExecutionMetrics>,
991 ) -> Result<(), ExecutionError> {
992 let pt = {
993 let mut builder = ProgrammableTransactionBuilder::new();
994 let res = builder.move_call(
995 SUI_FRAMEWORK_ADDRESS.into(),
996 AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
997 AUTHENTICATOR_STATE_UPDATE_FUNCTION_NAME.to_owned(),
998 vec![],
999 vec![
1000 CallArg::Object(ObjectArg::SharedObject {
1001 id: SUI_AUTHENTICATOR_STATE_OBJECT_ID,
1002 initial_shared_version: update.authenticator_obj_initial_shared_version,
1003 mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1004 }),
1005 CallArg::Pure(bcs::to_bytes(&update.new_active_jwks).unwrap()),
1006 ],
1007 );
1008 assert_invariant!(
1009 res.is_ok(),
1010 "Unable to generate authenticator_state_update transaction!"
1011 );
1012 builder.finish()
1013 };
1014 programmable_transactions::execution::execute::<execution_mode::System>(
1015 protocol_config,
1016 metrics,
1017 move_vm,
1018 temporary_store,
1019 tx_ctx,
1020 gas_charger,
1021 pt,
1022 )
1023 }
1024
1025 fn setup_authenticator_state_expire(
1026 mut builder: ProgrammableTransactionBuilder,
1027 expire: AuthenticatorStateExpire,
1028 ) -> ProgrammableTransactionBuilder {
1029 builder
1030 .move_call(
1031 SUI_FRAMEWORK_ADDRESS.into(),
1032 AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1033 AUTHENTICATOR_STATE_EXPIRE_JWKS_FUNCTION_NAME.to_owned(),
1034 vec![],
1035 vec![
1036 CallArg::Object(ObjectArg::SharedObject {
1037 id: SUI_AUTHENTICATOR_STATE_OBJECT_ID,
1038 initial_shared_version: expire.authenticator_obj_initial_shared_version,
1039 mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1040 }),
1041 CallArg::Pure(bcs::to_bytes(&expire.min_epoch).unwrap()),
1042 ],
1043 )
1044 .expect("Unable to generate authenticator_state_expire transaction!");
1045 builder
1046 }
1047}