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