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.into_early_errors() {
247 Some(early_execution_errors) => {
248 Err(ExecutionError::new(early_execution_errors.head, None))
249 }
250 None => 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());
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 EndOfEpochTransactionKind::ForwardingAddressRegistryCreate => {
656 panic!(
657 "EndOfEpochTransactionKind::ForwardingAddressRegistryCreate should not exist in v2"
658 );
659 }
660 }
661 }
662 unreachable!(
663 "EndOfEpochTransactionKind::ChangeEpoch should be the last transaction in the list"
664 )
665 }
666 TransactionKind::AuthenticatorStateUpdate(auth_state_update) => {
667 setup_authenticator_state_update(
668 auth_state_update,
669 temporary_store,
670 tx_ctx,
671 move_vm,
672 gas_charger,
673 protocol_config,
674 metrics,
675 )?;
676 Ok(Mode::empty_results())
677 }
678 TransactionKind::RandomnessStateUpdate(randomness_state_update) => {
679 setup_randomness_state_update(
680 randomness_state_update,
681 temporary_store,
682 tx_ctx,
683 move_vm,
684 gas_charger,
685 protocol_config,
686 metrics,
687 )?;
688 Ok(Mode::empty_results())
689 }
690 TransactionKind::ProgrammableSystemTransaction(_) => {
691 panic!("ProgrammableSystemTransaction should not exist in execution layer v2");
692 }
693 }?;
694 temporary_store.check_execution_results_consistency()?;
695 Ok(result)
696 }
697
698 fn mint_epoch_rewards_in_pt(
699 builder: &mut ProgrammableTransactionBuilder,
700 params: &AdvanceEpochParams,
701 ) -> (Argument, Argument) {
702 let storage_charge_arg = builder
704 .input(CallArg::Pure(
705 bcs::to_bytes(¶ms.storage_charge).unwrap(),
706 ))
707 .unwrap();
708 let storage_rewards = builder.programmable_move_call(
709 SUI_FRAMEWORK_PACKAGE_ID,
710 BALANCE_MODULE_NAME.to_owned(),
711 BALANCE_CREATE_REWARDS_FUNCTION_NAME.to_owned(),
712 vec![GAS::type_tag()],
713 vec![storage_charge_arg],
714 );
715
716 let computation_charge_arg = builder
718 .input(CallArg::Pure(
719 bcs::to_bytes(¶ms.computation_charge).unwrap(),
720 ))
721 .unwrap();
722 let computation_rewards = builder.programmable_move_call(
723 SUI_FRAMEWORK_PACKAGE_ID,
724 BALANCE_MODULE_NAME.to_owned(),
725 BALANCE_CREATE_REWARDS_FUNCTION_NAME.to_owned(),
726 vec![GAS::type_tag()],
727 vec![computation_charge_arg],
728 );
729 (storage_rewards, computation_rewards)
730 }
731
732 pub fn construct_advance_epoch_pt(
733 mut builder: ProgrammableTransactionBuilder,
734 params: &AdvanceEpochParams,
735 ) -> Result<ProgrammableTransaction, ExecutionError> {
736 let (storage_rewards, computation_rewards) = mint_epoch_rewards_in_pt(&mut builder, params);
738
739 let mut arguments = vec![storage_rewards, computation_rewards];
741 let call_arg_arguments = vec![
742 CallArg::SUI_SYSTEM_MUT,
743 CallArg::Pure(bcs::to_bytes(¶ms.epoch).unwrap()),
744 CallArg::Pure(bcs::to_bytes(¶ms.next_protocol_version.as_u64()).unwrap()),
745 CallArg::Pure(bcs::to_bytes(¶ms.storage_rebate).unwrap()),
746 CallArg::Pure(bcs::to_bytes(¶ms.non_refundable_storage_fee).unwrap()),
747 CallArg::Pure(bcs::to_bytes(¶ms.storage_fund_reinvest_rate).unwrap()),
748 CallArg::Pure(bcs::to_bytes(¶ms.reward_slashing_rate).unwrap()),
749 CallArg::Pure(bcs::to_bytes(¶ms.epoch_start_timestamp_ms).unwrap()),
750 ]
751 .into_iter()
752 .map(|a| builder.input(a))
753 .collect::<Result<_, _>>();
754
755 assert_invariant!(
756 call_arg_arguments.is_ok(),
757 "Unable to generate args for advance_epoch transaction!"
758 );
759
760 arguments.append(&mut call_arg_arguments.unwrap());
761
762 info!("Call arguments to advance_epoch transaction: {:?}", params);
763
764 let storage_rebates = builder.programmable_move_call(
765 SUI_SYSTEM_PACKAGE_ID,
766 SUI_SYSTEM_MODULE_NAME.to_owned(),
767 ADVANCE_EPOCH_FUNCTION_NAME.to_owned(),
768 vec![],
769 arguments,
770 );
771
772 builder.programmable_move_call(
774 SUI_FRAMEWORK_PACKAGE_ID,
775 BALANCE_MODULE_NAME.to_owned(),
776 BALANCE_DESTROY_REBATES_FUNCTION_NAME.to_owned(),
777 vec![GAS::type_tag()],
778 vec![storage_rebates],
779 );
780 Ok(builder.finish())
781 }
782
783 pub fn construct_advance_epoch_safe_mode_pt(
784 params: &AdvanceEpochParams,
785 protocol_config: &ProtocolConfig,
786 ) -> Result<ProgrammableTransaction, ExecutionError> {
787 let mut builder = ProgrammableTransactionBuilder::new();
788 let (storage_rewards, computation_rewards) = mint_epoch_rewards_in_pt(&mut builder, params);
790
791 let mut arguments = vec![storage_rewards, computation_rewards];
793
794 let mut args = vec![
795 CallArg::SUI_SYSTEM_MUT,
796 CallArg::Pure(bcs::to_bytes(¶ms.epoch).unwrap()),
797 CallArg::Pure(bcs::to_bytes(¶ms.next_protocol_version.as_u64()).unwrap()),
798 CallArg::Pure(bcs::to_bytes(¶ms.storage_rebate).unwrap()),
799 CallArg::Pure(bcs::to_bytes(¶ms.non_refundable_storage_fee).unwrap()),
800 ];
801
802 if protocol_config.advance_epoch_start_time_in_safe_mode() {
803 args.push(CallArg::Pure(
804 bcs::to_bytes(¶ms.epoch_start_timestamp_ms).unwrap(),
805 ));
806 }
807
808 let call_arg_arguments = args
809 .into_iter()
810 .map(|a| builder.input(a))
811 .collect::<Result<_, _>>();
812
813 assert_invariant!(
814 call_arg_arguments.is_ok(),
815 "Unable to generate args for advance_epoch transaction!"
816 );
817
818 arguments.append(&mut call_arg_arguments.unwrap());
819
820 info!("Call arguments to advance_epoch transaction: {:?}", params);
821
822 builder.programmable_move_call(
823 SUI_SYSTEM_PACKAGE_ID,
824 SUI_SYSTEM_MODULE_NAME.to_owned(),
825 ADVANCE_EPOCH_SAFE_MODE_FUNCTION_NAME.to_owned(),
826 vec![],
827 arguments,
828 );
829
830 Ok(builder.finish())
831 }
832
833 fn advance_epoch(
834 builder: ProgrammableTransactionBuilder,
835 change_epoch: ChangeEpoch,
836 temporary_store: &mut TemporaryStore<'_>,
837 tx_ctx: &mut TxContext,
838 move_vm: &Arc<MoveVM>,
839 gas_charger: &mut GasCharger,
840 protocol_config: &ProtocolConfig,
841 metrics: Arc<ExecutionMetrics>,
842 ) -> Result<(), ExecutionError> {
843 let params = AdvanceEpochParams {
844 epoch: change_epoch.epoch,
845 next_protocol_version: change_epoch.protocol_version,
846 storage_charge: change_epoch.storage_charge,
847 computation_charge: change_epoch.computation_charge,
848 storage_rebate: change_epoch.storage_rebate,
849 non_refundable_storage_fee: change_epoch.non_refundable_storage_fee,
850 storage_fund_reinvest_rate: protocol_config.storage_fund_reinvest_rate(),
851 reward_slashing_rate: protocol_config.reward_slashing_rate(),
852 epoch_start_timestamp_ms: change_epoch.epoch_start_timestamp_ms,
853 };
854 let advance_epoch_pt = construct_advance_epoch_pt(builder, ¶ms)?;
855 let result = programmable_transactions::execution::execute::<execution_mode::System>(
856 protocol_config,
857 metrics.clone(),
858 move_vm,
859 temporary_store,
860 tx_ctx,
861 gas_charger,
862 advance_epoch_pt,
863 );
864
865 #[cfg(msim)]
866 let result = maybe_modify_result_legacy(result, change_epoch.epoch);
867
868 if result.is_err() {
869 tracing::error!(
870 "Failed to execute advance epoch transaction. Switching to safe mode. Error: {:?}. Input objects: {:?}. Tx data: {:?}",
871 result.as_ref().err(),
872 temporary_store.objects(),
873 change_epoch,
874 );
875 temporary_store.drop_writes();
876 gas_charger.reset_storage_cost_and_rebate();
878
879 if protocol_config.advance_epoch_start_time_in_safe_mode() {
880 temporary_store.advance_epoch_safe_mode(¶ms, protocol_config);
881 } else {
882 let advance_epoch_safe_mode_pt =
883 construct_advance_epoch_safe_mode_pt(¶ms, protocol_config)?;
884 programmable_transactions::execution::execute::<execution_mode::System>(
885 protocol_config,
886 metrics.clone(),
887 move_vm,
888 temporary_store,
889 tx_ctx,
890 gas_charger,
891 advance_epoch_safe_mode_pt,
892 )
893 .expect("Advance epoch with safe mode must succeed");
894 }
895 }
896
897 let binary_config = protocol_config.binary_config(None);
898 for (version, modules, dependencies) in change_epoch.system_packages.into_iter() {
899 let deserialized_modules: Vec<_> = modules
900 .iter()
901 .map(|m| CompiledModule::deserialize_with_config(m, &binary_config).unwrap())
902 .collect();
903
904 if version == OBJECT_START_VERSION {
905 let package_id = deserialized_modules.first().unwrap().address();
906 info!("adding new system package {package_id}");
907
908 let publish_pt = {
909 let mut b = ProgrammableTransactionBuilder::new();
910 b.command(Command::Publish(modules, dependencies));
911 b.finish()
912 };
913
914 programmable_transactions::execution::execute::<execution_mode::System>(
915 protocol_config,
916 metrics.clone(),
917 move_vm,
918 temporary_store,
919 tx_ctx,
920 gas_charger,
921 publish_pt,
922 )
923 .expect("System Package Publish must succeed");
924 } else {
925 let mut new_package = Object::new_system_package(
926 &deserialized_modules,
927 version,
928 dependencies,
929 tx_ctx.digest(),
930 );
931
932 info!(
933 "upgraded system package {:?}",
934 new_package.compute_object_reference()
935 );
936
937 new_package
940 .data
941 .try_as_package_mut()
942 .unwrap()
943 .decrement_version();
944
945 temporary_store.upgrade_system_package(new_package);
947 }
948 }
949
950 Ok(())
951 }
952
953 fn setup_consensus_commit(
958 consensus_commit_timestamp_ms: CheckpointTimestamp,
959 temporary_store: &mut TemporaryStore<'_>,
960 tx_ctx: &mut TxContext,
961 move_vm: &Arc<MoveVM>,
962 gas_charger: &mut GasCharger,
963 protocol_config: &ProtocolConfig,
964 metrics: Arc<ExecutionMetrics>,
965 ) -> Result<(), ExecutionError> {
966 let pt = {
967 let mut builder = ProgrammableTransactionBuilder::new();
968 let res = builder.move_call(
969 SUI_FRAMEWORK_ADDRESS.into(),
970 CLOCK_MODULE_NAME.to_owned(),
971 CONSENSUS_COMMIT_PROLOGUE_FUNCTION_NAME.to_owned(),
972 vec![],
973 vec![
974 CallArg::CLOCK_MUT,
975 CallArg::Pure(bcs::to_bytes(&consensus_commit_timestamp_ms).unwrap()),
976 ],
977 );
978 assert_invariant!(
979 res.is_ok(),
980 "Unable to generate consensus_commit_prologue transaction!"
981 );
982 builder.finish()
983 };
984 programmable_transactions::execution::execute::<execution_mode::System>(
985 protocol_config,
986 metrics,
987 move_vm,
988 temporary_store,
989 tx_ctx,
990 gas_charger,
991 pt,
992 )
993 }
994
995 fn setup_authenticator_state_create(
996 mut builder: ProgrammableTransactionBuilder,
997 ) -> ProgrammableTransactionBuilder {
998 builder
999 .move_call(
1000 SUI_FRAMEWORK_ADDRESS.into(),
1001 AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1002 AUTHENTICATOR_STATE_CREATE_FUNCTION_NAME.to_owned(),
1003 vec![],
1004 vec![],
1005 )
1006 .expect("Unable to generate authenticator_state_create transaction!");
1007 builder
1008 }
1009
1010 fn setup_randomness_state_create(
1011 mut builder: ProgrammableTransactionBuilder,
1012 ) -> ProgrammableTransactionBuilder {
1013 builder
1014 .move_call(
1015 SUI_FRAMEWORK_ADDRESS.into(),
1016 RANDOMNESS_MODULE_NAME.to_owned(),
1017 RANDOMNESS_STATE_CREATE_FUNCTION_NAME.to_owned(),
1018 vec![],
1019 vec![],
1020 )
1021 .expect("Unable to generate randomness_state_create transaction!");
1022 builder
1023 }
1024
1025 fn setup_authenticator_state_update(
1026 update: AuthenticatorStateUpdate,
1027 temporary_store: &mut TemporaryStore<'_>,
1028 tx_ctx: &mut TxContext,
1029 move_vm: &Arc<MoveVM>,
1030 gas_charger: &mut GasCharger,
1031 protocol_config: &ProtocolConfig,
1032 metrics: Arc<ExecutionMetrics>,
1033 ) -> Result<(), ExecutionError> {
1034 let pt = {
1035 let mut builder = ProgrammableTransactionBuilder::new();
1036 let res = builder.move_call(
1037 SUI_FRAMEWORK_ADDRESS.into(),
1038 AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1039 AUTHENTICATOR_STATE_UPDATE_FUNCTION_NAME.to_owned(),
1040 vec![],
1041 vec![
1042 CallArg::Object(ObjectArg::SharedObject {
1043 id: SUI_AUTHENTICATOR_STATE_OBJECT_ID,
1044 initial_shared_version: update.authenticator_obj_initial_shared_version,
1045 mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1046 }),
1047 CallArg::Pure(bcs::to_bytes(&update.new_active_jwks).unwrap()),
1048 ],
1049 );
1050 assert_invariant!(
1051 res.is_ok(),
1052 "Unable to generate authenticator_state_update transaction!"
1053 );
1054 builder.finish()
1055 };
1056 programmable_transactions::execution::execute::<execution_mode::System>(
1057 protocol_config,
1058 metrics,
1059 move_vm,
1060 temporary_store,
1061 tx_ctx,
1062 gas_charger,
1063 pt,
1064 )
1065 }
1066
1067 fn setup_authenticator_state_expire(
1068 mut builder: ProgrammableTransactionBuilder,
1069 expire: AuthenticatorStateExpire,
1070 ) -> ProgrammableTransactionBuilder {
1071 builder
1072 .move_call(
1073 SUI_FRAMEWORK_ADDRESS.into(),
1074 AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1075 AUTHENTICATOR_STATE_EXPIRE_JWKS_FUNCTION_NAME.to_owned(),
1076 vec![],
1077 vec![
1078 CallArg::Object(ObjectArg::SharedObject {
1079 id: SUI_AUTHENTICATOR_STATE_OBJECT_ID,
1080 initial_shared_version: expire.authenticator_obj_initial_shared_version,
1081 mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1082 }),
1083 CallArg::Pure(bcs::to_bytes(&expire.min_epoch).unwrap()),
1084 ],
1085 )
1086 .expect("Unable to generate authenticator_state_expire transaction!");
1087 builder
1088 }
1089
1090 fn setup_randomness_state_update(
1091 update: RandomnessStateUpdate,
1092 temporary_store: &mut TemporaryStore<'_>,
1093 tx_ctx: &mut TxContext,
1094 move_vm: &Arc<MoveVM>,
1095 gas_charger: &mut GasCharger,
1096 protocol_config: &ProtocolConfig,
1097 metrics: Arc<ExecutionMetrics>,
1098 ) -> Result<(), ExecutionError> {
1099 let pt = {
1100 let mut builder = ProgrammableTransactionBuilder::new();
1101 let res = builder.move_call(
1102 SUI_FRAMEWORK_ADDRESS.into(),
1103 RANDOMNESS_MODULE_NAME.to_owned(),
1104 RANDOMNESS_STATE_UPDATE_FUNCTION_NAME.to_owned(),
1105 vec![],
1106 vec![
1107 CallArg::Object(ObjectArg::SharedObject {
1108 id: SUI_RANDOMNESS_STATE_OBJECT_ID,
1109 initial_shared_version: update.randomness_obj_initial_shared_version,
1110 mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1111 }),
1112 CallArg::Pure(bcs::to_bytes(&update.randomness_round).unwrap()),
1113 CallArg::Pure(bcs::to_bytes(&update.random_bytes).unwrap()),
1114 ],
1115 );
1116 assert_invariant!(
1117 res.is_ok(),
1118 "Unable to generate randomness_state_update transaction!"
1119 );
1120 builder.finish()
1121 };
1122 programmable_transactions::execution::execute::<execution_mode::System>(
1123 protocol_config,
1124 metrics,
1125 move_vm,
1126 temporary_store,
1127 tx_ctx,
1128 gas_charger,
1129 pt,
1130 )
1131 }
1132
1133 fn setup_coin_deny_list_state_create(
1134 mut builder: ProgrammableTransactionBuilder,
1135 ) -> ProgrammableTransactionBuilder {
1136 builder
1137 .move_call(
1138 SUI_FRAMEWORK_ADDRESS.into(),
1139 DENY_LIST_MODULE.to_owned(),
1140 DENY_LIST_CREATE_FUNC.to_owned(),
1141 vec![],
1142 vec![],
1143 )
1144 .expect("Unable to generate coin_deny_list_create transaction!");
1145 builder
1146 }
1147}