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