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