1pub use checked::*;
5
6#[sui_macros::with_checked_arithmetic]
7mod checked {
8
9 use crate::adapter::new_move_runtime;
10 use crate::execution_mode::{self, ExecutionMode};
11 use crate::execution_value::SuiResolver;
12 use crate::gas_charger::{PaymentKind, PaymentMethod};
13 use move_binary_format::CompiledModule;
14 use move_trace_format::format::MoveTraceBuilder;
15 use move_vm_runtime::runtime::MoveRuntime;
16 use mysten_common::debug_fatal;
17 use std::collections::BTreeMap;
18 use std::{cell::RefCell, collections::HashSet, rc::Rc, sync::Arc};
19 use sui_types::accumulator_root::{ACCUMULATOR_ROOT_CREATE_FUNC, ACCUMULATOR_ROOT_MODULE};
20 use sui_types::balance::{
21 BALANCE_CREATE_REWARDS_FUNCTION_NAME, BALANCE_DESTROY_REBATES_FUNCTION_NAME,
22 BALANCE_MODULE_NAME,
23 };
24 use sui_types::coin_reservation::ParsedDigest;
25 use sui_types::execution_params::ExecutionOrEarlyError;
26 use sui_types::gas_coin::GAS;
27 use sui_types::messages_checkpoint::CheckpointTimestamp;
28 use sui_types::metrics::ExecutionMetrics;
29 use sui_types::object::OBJECT_START_VERSION;
30 use sui_types::programmable_transaction_builder::ProgrammableTransactionBuilder;
31 use sui_types::randomness_state::{
32 RANDOMNESS_MODULE_NAME, RANDOMNESS_STATE_CREATE_FUNCTION_NAME,
33 RANDOMNESS_STATE_UPDATE_FUNCTION_NAME,
34 };
35 use sui_types::{BRIDGE_ADDRESS, SUI_BRIDGE_OBJECT_ID, SUI_RANDOMNESS_STATE_OBJECT_ID};
36 use tracing::{info, instrument, trace, warn};
37
38 use crate::static_programmable_transactions as SPT;
39 use crate::sui_types::gas::SuiGasStatusAPI;
40 use crate::type_layout_resolver::TypeLayoutResolver;
41 use crate::{gas_charger::GasCharger, temporary_store::TemporaryStore};
42 use move_core_types::ident_str;
43 use move_core_types::language_storage::TypeTag;
44 use sui_move_natives::all_natives;
45 use sui_protocol_config::{
46 LimitThresholdCrossed, PerObjectCongestionControlMode, ProtocolConfig, check_limit_by_meter,
47 };
48 use sui_types::authenticator_state::{
49 AUTHENTICATOR_STATE_CREATE_FUNCTION_NAME, AUTHENTICATOR_STATE_EXPIRE_JWKS_FUNCTION_NAME,
50 AUTHENTICATOR_STATE_MODULE_NAME, AUTHENTICATOR_STATE_UPDATE_FUNCTION_NAME,
51 };
52 use sui_types::base_types::SequenceNumber;
53 use sui_types::bridge::BRIDGE_COMMITTEE_MINIMAL_VOTING_POWER;
54 use sui_types::bridge::{
55 BRIDGE_CREATE_FUNCTION_NAME, BRIDGE_INIT_COMMITTEE_FUNCTION_NAME, BRIDGE_MODULE_NAME,
56 BridgeChainId,
57 };
58 use sui_types::clock::{CLOCK_MODULE_NAME, CONSENSUS_COMMIT_PROLOGUE_FUNCTION_NAME};
59 use sui_types::committee::EpochId;
60 use sui_types::deny_list_v1::{DENY_LIST_CREATE_FUNC, DENY_LIST_MODULE};
61 use sui_types::digests::{
62 ChainIdentifier, get_mainnet_chain_identifier, get_testnet_chain_identifier,
63 };
64 use sui_types::effects::TransactionEffects;
65 use sui_types::error::{ExecutionError, ExecutionErrorTrait};
66 use sui_types::execution::{ExecutionTiming, ResultWithTimings};
67 use sui_types::execution_status::{ExecutionErrorKind, ExecutionStatus};
68 use sui_types::gas::GasCostSummary;
69 use sui_types::gas::SuiGasStatus;
70 use sui_types::id::UID;
71 use sui_types::inner_temporary_store::InnerTemporaryStore;
72 use sui_types::storage::BackingStore;
73 #[cfg(msim)]
74 use sui_types::sui_system_state::advance_epoch_result_injection::maybe_modify_result_for;
75 use sui_types::sui_system_state::{ADVANCE_EPOCH_SAFE_MODE_FUNCTION_NAME, AdvanceEpochParams};
76 use sui_types::transaction::{
77 Argument, AuthenticatorStateExpire, AuthenticatorStateUpdate, CallArg, ChangeEpoch,
78 Command, EndOfEpochTransactionKind, GasData, GenesisTransaction, ObjectArg,
79 ProgrammableTransaction, Reservation, StoredExecutionTimeObservations, TransactionKind,
80 WithdrawFrom, WriteAccumulatorStorageCost, is_gasless_transaction,
81 };
82 use sui_types::transaction::{CheckedInputObjects, RandomnessStateUpdate};
83 use sui_types::{
84 SUI_AUTHENTICATOR_STATE_OBJECT_ID, SUI_FRAMEWORK_ADDRESS, SUI_FRAMEWORK_PACKAGE_ID,
85 SUI_SYSTEM_PACKAGE_ID,
86 base_types::{SuiAddress, TransactionDigest, TxContext},
87 object::{Object, ObjectInner},
88 sui_system_state::{ADVANCE_EPOCH_FUNCTION_NAME, SUI_SYSTEM_MODULE_NAME},
89 };
90
91 fn payment_kind(
92 gas_data: &GasData,
93 transaction_kind: &TransactionKind,
94 protocol_config: &ProtocolConfig,
95 ) -> PaymentKind {
96 if gas_data.is_unmetered() || transaction_kind.is_system_tx() {
97 PaymentKind::unmetered()
98 } else if protocol_config.enable_gasless()
99 && is_gasless_transaction(gas_data, transaction_kind)
100 {
101 PaymentKind::gasless()
102 } else if gas_data.payment.is_empty() {
103 PaymentKind::smash(vec![PaymentMethod::AddressBalance(
104 gas_data.owner,
105 gas_data.budget,
106 )])
107 .expect("unable to create a payment kind with a single address balance")
108 } else {
109 let payment_methods = gas_data
110 .payment
111 .iter()
112 .map(|entry| {
113 if let Ok(parsed) = ParsedDigest::try_from(entry.2) {
114 PaymentMethod::AddressBalance(gas_data.owner, parsed.reservation_amount())
115 } else {
116 PaymentMethod::Coin(*entry)
117 }
118 })
119 .collect();
120 PaymentKind::smash(payment_methods).expect(
121 "unable to create a payment kind from payment methods. \
122 Should not be possible wit ha non-empty vector",
123 )
124 }
125 }
126
127 fn compute_input_reservations(
136 transaction_kind: &TransactionKind,
137 gas_data: &GasData,
138 transaction_signer: SuiAddress,
139 ) -> BTreeMap<(SuiAddress, TypeTag), u64> {
140 use sui_types::balance::Balance;
141 use sui_types::gas_coin::GAS;
142 use sui_types::transaction::{Reservation, WithdrawFrom, is_gas_paid_from_address_balance};
143
144 let mut reservations: BTreeMap<(SuiAddress, TypeTag), u64> = BTreeMap::new();
145 let sui_balance_type = Balance::type_tag(GAS::type_tag());
146
147 for arg in transaction_kind.get_funds_withdrawals() {
148 let owner = match arg.withdraw_from {
149 WithdrawFrom::Sender => transaction_signer,
150 WithdrawFrom::Sponsor => gas_data.owner,
151 };
152 let Reservation::MaxAmountU64(reservation) = arg.reservation;
153 *reservations
154 .entry((owner, arg.type_arg.to_type_tag()))
155 .or_insert(0) += reservation;
156 }
157
158 if is_gas_paid_from_address_balance(gas_data, transaction_kind) {
159 *reservations
160 .entry((gas_data.owner, sui_balance_type.clone()))
161 .or_insert(0) += gas_data.budget;
162 }
163
164 for entry in &gas_data.payment {
165 if let Ok(parsed) = ParsedDigest::try_from(entry.2) {
166 *reservations
167 .entry((gas_data.owner, sui_balance_type.clone()))
168 .or_insert(0) += parsed.reservation_amount();
169 }
170 }
171
172 reservations
173 }
174
175 #[allow(clippy::type_complexity)]
176 #[instrument(name = "tx_execute_to_effects", level = "debug", skip_all)]
177 pub fn execute_transaction_to_effects<Mode: ExecutionMode>(
178 store: &dyn BackingStore,
179 input_objects: CheckedInputObjects,
180 gas_data: GasData,
181 gas_status: SuiGasStatus,
182 transaction_kind: TransactionKind,
183 rewritten_inputs: Option<Vec<bool>>,
184 transaction_signer: SuiAddress,
185 transaction_digest: TransactionDigest,
186 move_vm: &Arc<MoveRuntime>,
187 epoch_id: &EpochId,
188 epoch_timestamp_ms: u64,
189 protocol_config: &ProtocolConfig,
190 metrics: Arc<ExecutionMetrics>,
191 enable_expensive_checks: bool,
192 execution_params: ExecutionOrEarlyError,
193 trace_builder_opt: &mut Option<MoveTraceBuilder>,
194 ) -> (
195 InnerTemporaryStore,
196 SuiGasStatus,
197 TransactionEffects,
198 Vec<ExecutionTiming>,
199 Result<Mode::ExecutionResults, Mode::Error>,
200 ) {
201 let input_objects = input_objects.into_inner();
202 let mutable_inputs = if enable_expensive_checks {
203 input_objects.all_mutable_inputs().keys().copied().collect()
204 } else {
205 HashSet::new()
206 };
207 let shared_object_refs = input_objects.filter_shared_objects();
208 let receiving_objects = transaction_kind.receiving_objects();
209 let mut transaction_dependencies = input_objects.transaction_dependencies();
210
211 let mut temporary_store = TemporaryStore::new(
212 store,
213 input_objects,
214 receiving_objects,
215 transaction_digest,
216 protocol_config,
217 *epoch_id,
218 );
219
220 let sponsor = {
221 let gas_owner = gas_data.owner;
222 if gas_owner == transaction_signer {
223 None
224 } else {
225 Some(gas_owner)
226 }
227 };
228 let gas_price = gas_status.gas_price();
229 let rgp = gas_status.reference_gas_price();
230
231 let mut gas_charger = GasCharger::new(
232 transaction_digest,
233 payment_kind(&gas_data, &transaction_kind, protocol_config),
234 gas_status,
235 &mut temporary_store,
236 protocol_config,
237 );
238
239 let tx_ctx = TxContext::new_from_components(
240 &transaction_signer,
241 &transaction_digest,
242 epoch_id,
243 epoch_timestamp_ms,
244 rgp,
245 gas_price,
246 gas_data.budget,
247 sponsor,
248 protocol_config,
249 );
250 let tx_ctx = Rc::new(RefCell::new(tx_ctx));
251
252 let is_gasless = protocol_config.enable_gasless()
253 && is_gasless_transaction(&gas_data, &transaction_kind);
254 let is_epoch_change = transaction_kind.is_end_of_epoch_tx();
255
256 let input_reservations =
257 compute_input_reservations(&transaction_kind, &gas_data, transaction_signer);
258
259 let (gas_cost_summary, execution_result, timings) = execute_transaction::<Mode>(
260 store,
261 &mut temporary_store,
262 transaction_kind,
263 rewritten_inputs,
264 &mut gas_charger,
265 tx_ctx,
266 move_vm,
267 protocol_config,
268 metrics.clone(),
269 enable_expensive_checks,
270 execution_params,
271 trace_builder_opt,
272 is_gasless,
273 &input_reservations,
274 );
275
276 let status = if let Err(error) = &execution_result {
277 ExecutionStatus::new_failure(error.to_execution_failure())
278 } else {
279 ExecutionStatus::Success
280 };
281
282 #[skip_checked_arithmetic]
283 trace!(
284 tx_digest = ?transaction_digest,
285 computation_gas_cost = gas_cost_summary.computation_cost,
286 storage_gas_cost = gas_cost_summary.storage_cost,
287 storage_gas_rebate = gas_cost_summary.storage_rebate,
288 "Finished execution of transaction with status {:?}",
289 status
290 );
291
292 transaction_dependencies.remove(&TransactionDigest::genesis_marker());
296
297 if enable_expensive_checks && !Mode::allow_arbitrary_function_calls() {
298 temporary_store
299 .check_ownership_invariants(
300 &transaction_signer,
301 &sponsor,
302 &gas_charger,
303 &mutable_inputs,
304 &input_reservations,
305 is_epoch_change,
306 )
307 .unwrap()
308 } let (inner, effects) = temporary_store.into_effects(
311 shared_object_refs,
312 &transaction_digest,
313 transaction_dependencies,
314 gas_cost_summary,
315 status,
316 &mut gas_charger,
317 *epoch_id,
318 );
319
320 metrics.vm_telemetry_metrics.try_update(|vm_metrics| {
321 let t = move_vm.get_telemetry_report();
322 vm_metrics
323 .move_vm_package_cache_count
324 .set(t.package_cache_count as i64);
325 vm_metrics
326 .move_vm_total_arena_size_bytes
327 .set(t.total_arena_size as i64);
328 vm_metrics.move_vm_module_count.set(t.module_count as i64);
329 vm_metrics
330 .move_vm_function_count
331 .set(t.function_count as i64);
332 vm_metrics.move_vm_type_count.set(t.type_count as i64);
333 vm_metrics.move_vm_interner_size.set(t.interner_size as i64);
334 vm_metrics
335 .move_vm_vtable_cache_count
336 .set(t.vtable_cache_count as i64);
337 vm_metrics
338 .move_vm_vtable_cache_hits
339 .set(t.vtable_cache_hits as i64);
340 vm_metrics
341 .move_vm_vtable_cache_misses
342 .set(t.vtable_cache_misses as i64);
343 vm_metrics
344 .move_vm_load_time_ms
345 .set(t.total_load_time as i64);
346 vm_metrics.move_vm_load_count.set(t.load_count as i64);
347 vm_metrics
348 .move_vm_validation_time_ms
349 .set(t.total_validation_time as i64);
350 vm_metrics
351 .move_vm_validation_count
352 .set(t.validation_count as i64);
353 vm_metrics.move_vm_jit_time_ms.set(t.total_jit_time as i64);
354 vm_metrics.move_vm_jit_count.set(t.jit_count as i64);
355 vm_metrics
356 .move_vm_execution_time_ms
357 .set(t.total_execution_time as i64);
358 vm_metrics
359 .move_vm_execution_count
360 .set(t.execution_count as i64);
361 vm_metrics
362 .move_vm_interpreter_time_ms
363 .set(t.total_interpreter_time as i64);
364 vm_metrics
365 .move_vm_interpreter_count
366 .set(t.interpreter_count as i64);
367 vm_metrics
368 .move_vm_max_callstack_size
369 .set(t.max_callstack_size as i64);
370 vm_metrics
371 .move_vm_max_valuestack_size
372 .set(t.max_valuestack_size as i64);
373 vm_metrics.move_vm_total_time_ms.set(t.total_time as i64);
374 vm_metrics.move_vm_total_count.set(t.total_count as i64);
375 });
376
377 (
378 inner,
379 gas_charger.into_gas_status(),
380 effects,
381 timings,
382 execution_result,
383 )
384 }
385
386 pub fn execute_genesis_state_update(
387 store: &dyn BackingStore,
388 protocol_config: &ProtocolConfig,
389 metrics: Arc<ExecutionMetrics>,
390 move_vm: &Arc<MoveRuntime>,
391 tx_context: Rc<RefCell<TxContext>>,
392 input_objects: CheckedInputObjects,
393 pt: ProgrammableTransaction,
394 ) -> Result<InnerTemporaryStore, ExecutionError> {
395 let input_objects = input_objects.into_inner();
396 let mut temporary_store = TemporaryStore::new(
397 store,
398 input_objects,
399 vec![],
400 tx_context.borrow().digest(),
401 protocol_config,
402 0,
403 );
404 let mut gas_charger = GasCharger::new_unmetered(tx_context.borrow().digest());
405 SPT::execute::<execution_mode::Genesis>(
406 protocol_config,
407 metrics,
408 move_vm,
409 &mut temporary_store,
410 store.as_backing_package_store(),
411 tx_context,
412 &mut gas_charger,
413 None,
414 pt,
415 &mut None,
416 )
417 .map_err(|(e, _)| e)?;
418 temporary_store.update_object_version_and_prev_tx();
419 Ok(temporary_store.into_inner(BTreeMap::new()))
420 }
421
422 #[instrument(name = "tx_execute", level = "debug", skip_all)]
423 fn execute_transaction<Mode: ExecutionMode>(
424 store: &dyn BackingStore,
425 temporary_store: &mut TemporaryStore<'_>,
426 transaction_kind: TransactionKind,
427 rewritten_inputs: Option<Vec<bool>>,
428 gas_charger: &mut GasCharger,
429 tx_ctx: Rc<RefCell<TxContext>>,
430 move_vm: &Arc<MoveRuntime>,
431 protocol_config: &ProtocolConfig,
432 metrics: Arc<ExecutionMetrics>,
433 enable_expensive_checks: bool,
434 execution_params: ExecutionOrEarlyError,
435 trace_builder_opt: &mut Option<MoveTraceBuilder>,
436 is_gasless: bool,
437 input_reservations: &BTreeMap<(SuiAddress, TypeTag), u64>,
438 ) -> (
439 GasCostSummary,
440 Result<Mode::ExecutionResults, Mode::Error>,
441 Vec<ExecutionTiming>,
442 ) {
443 debug_assert!(
445 gas_charger.no_charges(),
446 "No gas charges must be applied yet"
447 );
448
449 let is_genesis_tx = matches!(transaction_kind, TransactionKind::Genesis(_));
450 let advance_epoch_gas_summary = transaction_kind.get_advance_epoch_tx_gas_summary();
451 let digest = tx_ctx.borrow().digest();
452 let withdrawal_reservations =
453 if is_gasless && protocol_config.gasless_verify_remaining_balance() {
454 gasless_withdrawal_reservations(&transaction_kind, &tx_ctx.borrow())
455 } else {
456 None
457 };
458
459 let result = gas_charger.charge_input_objects(temporary_store);
462
463 let result: ResultWithTimings<Mode::ExecutionResults, Mode::Error> =
464 result.map_err(|e| (e.into(), vec![])).and_then(
465 |()| -> ResultWithTimings<Mode::ExecutionResults, Mode::Error> {
466 let mut execution_result: ResultWithTimings<
467 Mode::ExecutionResults,
468 Mode::Error,
469 > = match execution_params {
470 ExecutionOrEarlyError::Err(early_execution_error) => {
471 Err((Mode::Error::from_kind(early_execution_error), vec![]))
472 }
473 ExecutionOrEarlyError::Ok(()) => execution_loop::<Mode>(
474 store,
475 temporary_store,
476 transaction_kind,
477 rewritten_inputs,
478 tx_ctx,
479 move_vm,
480 gas_charger,
481 protocol_config,
482 metrics.clone(),
483 trace_builder_opt,
484 ),
485 };
486
487 let meter_check = check_meter_limit::<Mode>(
488 temporary_store,
489 gas_charger,
490 protocol_config,
491 metrics.clone(),
492 );
493 if let Err(e) = meter_check {
494 execution_result = Err((e, vec![]));
495 }
496
497 if execution_result.is_ok() {
498 let gas_check = check_written_objects_limit::<Mode>(
499 temporary_store,
500 gas_charger,
501 protocol_config,
502 metrics,
503 );
504 if let Err(e) = gas_check {
505 execution_result = Err((e, vec![]));
506 }
507 }
508
509 execution_result
510 },
511 );
512
513 let (mut result, timings) = match result {
514 Ok((r, t)) => (Ok(r), t),
515 Err((e, t)) => (Err(e), t),
516 };
517 if is_gasless
518 && result.is_ok()
519 && let Err(msg) = temporary_store
520 .check_gasless_execution_requirements(withdrawal_reservations.as_ref())
521 {
522 result = Err(Mode::Error::new_with_source(
523 ExecutionErrorKind::InsufficientGas,
524 msg,
525 ));
526 }
527
528 let cost_summary = gas_charger.charge_gas(temporary_store, &mut result);
529 temporary_store.conserve_unmetered_storage_rebate(gas_charger.unmetered_storage_rebate());
537
538 if let Err(e) = run_conservation_checks::<Mode>(
539 temporary_store,
540 gas_charger,
541 digest,
542 move_vm,
543 protocol_config.simple_conservation_checks(),
544 enable_expensive_checks,
545 &cost_summary,
546 is_genesis_tx,
547 advance_epoch_gas_summary,
548 input_reservations,
549 ) {
550 result = Err(e);
552 }
553
554 (cost_summary, result, timings)
555 }
556
557 #[instrument(name = "run_conservation_checks", level = "debug", skip_all)]
558 fn run_conservation_checks<Mode: ExecutionMode>(
559 temporary_store: &mut TemporaryStore<'_>,
560 gas_charger: &mut GasCharger,
561 tx_digest: TransactionDigest,
562 move_vm: &Arc<MoveRuntime>,
563 simple_conservation_checks: bool,
564 enable_expensive_checks: bool,
565 cost_summary: &GasCostSummary,
566 is_genesis_tx: bool,
567 advance_epoch_gas_summary: Option<(u64, u64)>,
568 input_reservations: &BTreeMap<(SuiAddress, TypeTag), u64>,
569 ) -> Result<(), Mode::Error> {
570 let mut result: Result<(), Mode::Error> = Ok(());
571 if !is_genesis_tx && !Mode::skip_conservation_checks() {
572 let run_checks = |store: &TemporaryStore<'_>| -> Result<(), ExecutionError> {
573 store
574 .check_sui_conserved(simple_conservation_checks, cost_summary)
575 .and_then(|()| {
576 if enable_expensive_checks {
577 let mut layout_resolver = TypeLayoutResolver::new(
578 move_vm,
579 store.protocol_config(),
580 Box::new(store),
581 );
582 store.check_sui_conserved_expensive(
583 cost_summary,
584 advance_epoch_gas_summary,
585 &mut layout_resolver,
586 )
587 } else {
588 Ok(())
589 }
590 })
591 .and_then(|()| {
592 store.check_address_balance_changes(
593 store.protocol_config(),
594 input_reservations,
595 )
596 })
597 };
598
599 if let Err(conservation_err) = run_checks(temporary_store) {
600 result = Err(conservation_err.into());
604 gas_charger.reset(temporary_store);
605 gas_charger.charge_gas(temporary_store, &mut result);
606 if let Err(recovery_err) = run_checks(temporary_store) {
607 panic!(
611 "SUI conservation fail in tx block {}: {}\nGas status is {}\nTx was ",
612 tx_digest,
613 recovery_err,
614 gas_charger.summary()
615 )
616 }
617 }
618 } result
621 }
622
623 #[instrument(name = "check_meter_limit", level = "debug", skip_all)]
624 fn check_meter_limit<Mode: ExecutionMode>(
625 temporary_store: &mut TemporaryStore<'_>,
626 gas_charger: &mut GasCharger,
627 protocol_config: &ProtocolConfig,
628 metrics: Arc<ExecutionMetrics>,
629 ) -> Result<(), Mode::Error> {
630 let effects_estimated_size = temporary_store.estimate_effects_size_upperbound();
631
632 match check_limit_by_meter!(
636 !gas_charger.is_unmetered(),
637 effects_estimated_size,
638 protocol_config.max_serialized_tx_effects_size_bytes(),
639 protocol_config.max_serialized_tx_effects_size_bytes_system_tx(),
640 metrics.limits_metrics.excessive_estimated_effects_size
641 ) {
642 LimitThresholdCrossed::None => Ok(()),
643 LimitThresholdCrossed::Soft(_, limit) => {
644 warn!(
645 effects_estimated_size = effects_estimated_size,
646 soft_limit = limit,
647 "Estimated transaction effects size crossed soft limit",
648 );
649 Ok(())
650 }
651 LimitThresholdCrossed::Hard(_, lim) => Err(Mode::Error::new_with_source(
652 ExecutionErrorKind::EffectsTooLarge {
653 current_size: effects_estimated_size as u64,
654 max_size: lim as u64,
655 },
656 "Transaction effects are too large",
657 )),
658 }
659 }
660
661 #[instrument(name = "check_written_objects_limit", level = "debug", skip_all)]
662 fn check_written_objects_limit<Mode: ExecutionMode>(
663 temporary_store: &mut TemporaryStore<'_>,
664 gas_charger: &mut GasCharger,
665 protocol_config: &ProtocolConfig,
666 metrics: Arc<ExecutionMetrics>,
667 ) -> Result<(), Mode::Error> {
668 if let (Some(normal_lim), Some(system_lim)) = (
669 protocol_config.max_size_written_objects_as_option(),
670 protocol_config.max_size_written_objects_system_tx_as_option(),
671 ) {
672 let written_objects_size = temporary_store.written_objects_size();
673
674 match check_limit_by_meter!(
675 !gas_charger.is_unmetered(),
676 written_objects_size,
677 normal_lim,
678 system_lim,
679 metrics.limits_metrics.excessive_written_objects_size
680 ) {
681 LimitThresholdCrossed::None => (),
682 LimitThresholdCrossed::Soft(_, limit) => {
683 warn!(
684 written_objects_size = written_objects_size,
685 soft_limit = limit,
686 "Written objects size crossed soft limit",
687 )
688 }
689 LimitThresholdCrossed::Hard(_, lim) => {
690 return Err(Mode::Error::new_with_source(
691 ExecutionErrorKind::WrittenObjectsTooLarge {
692 current_size: written_objects_size as u64,
693 max_size: lim as u64,
694 },
695 "Written objects size crossed hard limit",
696 ));
697 }
698 };
699 }
700
701 Ok(())
702 }
703
704 fn gasless_withdrawal_reservations(
705 transaction_kind: &TransactionKind,
706 tx_ctx: &TxContext,
707 ) -> Option<BTreeMap<(SuiAddress, TypeTag), u64>> {
708 let TransactionKind::ProgrammableTransaction(pt) = transaction_kind else {
709 debug_fatal!("Gasless transaction must be a ProgrammableTransaction");
710 return None;
711 };
712 let sender = tx_ctx.sender();
713 let mut reservations = BTreeMap::<(SuiAddress, TypeTag), u64>::new();
714 for input in &pt.inputs {
715 let CallArg::FundsWithdrawal(fw) = input else {
716 continue;
717 };
718 let Some(coin_type) = fw.type_arg.get_balance_type_param() else {
719 debug_fatal!("expected Balance type for withdrawal");
720 continue;
721 };
722 let owner = match fw.withdraw_from {
723 WithdrawFrom::Sender => sender,
724 WithdrawFrom::Sponsor => {
725 debug_fatal!("WithdrawFrom::Sponsor is not expected in gasless transactions");
726 tx_ctx.sponsor().unwrap_or(sender)
727 }
728 };
729 let Reservation::MaxAmountU64(amount) = fw.reservation;
730 let entry = reservations.entry((owner, coin_type)).or_insert(0);
731 *entry = entry.saturating_add(amount);
732 }
733 Some(reservations)
734 }
735
736 #[instrument(level = "debug", skip_all)]
737 fn execution_loop<Mode: ExecutionMode>(
738 store: &dyn BackingStore,
739 temporary_store: &mut TemporaryStore<'_>,
740 transaction_kind: TransactionKind,
741 rewritten_inputs: Option<Vec<bool>>,
742 tx_ctx: Rc<RefCell<TxContext>>,
743 move_vm: &Arc<MoveRuntime>,
744 gas_charger: &mut GasCharger,
745 protocol_config: &ProtocolConfig,
746 metrics: Arc<ExecutionMetrics>,
747 trace_builder_opt: &mut Option<MoveTraceBuilder>,
748 ) -> ResultWithTimings<Mode::ExecutionResults, Mode::Error> {
749 let result = match transaction_kind {
750 TransactionKind::ChangeEpoch(change_epoch) => {
751 let builder = ProgrammableTransactionBuilder::new();
752 advance_epoch::<Mode>(
753 builder,
754 change_epoch,
755 temporary_store,
756 store,
757 tx_ctx,
758 move_vm,
759 gas_charger,
760 protocol_config,
761 metrics,
762 trace_builder_opt,
763 )
764 .map_err(|e| (e, vec![]))?;
765 Ok((Mode::empty_results(), vec![]))
766 }
767 TransactionKind::Genesis(GenesisTransaction { objects }) => {
768 if tx_ctx.borrow().epoch() != 0 {
769 panic!("BUG: Genesis Transactions can only be executed in epoch 0");
770 }
771
772 for genesis_object in objects {
773 match genesis_object {
774 sui_types::transaction::GenesisObject::RawObject { data, owner } => {
775 let object = ObjectInner {
776 data,
777 owner,
778 previous_transaction: tx_ctx.borrow().digest(),
779 storage_rebate: 0,
780 };
781 temporary_store.create_object(object.into());
782 }
783 }
784 }
785 Ok((Mode::empty_results(), vec![]))
786 }
787 TransactionKind::ConsensusCommitPrologue(prologue) => {
788 setup_consensus_commit::<Mode>(
789 prologue.commit_timestamp_ms,
790 temporary_store,
791 store,
792 tx_ctx,
793 move_vm,
794 gas_charger,
795 protocol_config,
796 metrics,
797 trace_builder_opt,
798 )
799 .expect("ConsensusCommitPrologue cannot fail");
800 Ok((Mode::empty_results(), vec![]))
801 }
802 TransactionKind::ConsensusCommitPrologueV2(prologue) => {
803 setup_consensus_commit::<Mode>(
804 prologue.commit_timestamp_ms,
805 temporary_store,
806 store,
807 tx_ctx,
808 move_vm,
809 gas_charger,
810 protocol_config,
811 metrics,
812 trace_builder_opt,
813 )
814 .expect("ConsensusCommitPrologueV2 cannot fail");
815 Ok((Mode::empty_results(), vec![]))
816 }
817 TransactionKind::ConsensusCommitPrologueV3(prologue) => {
818 setup_consensus_commit::<Mode>(
819 prologue.commit_timestamp_ms,
820 temporary_store,
821 store,
822 tx_ctx,
823 move_vm,
824 gas_charger,
825 protocol_config,
826 metrics,
827 trace_builder_opt,
828 )
829 .expect("ConsensusCommitPrologueV3 cannot fail");
830 Ok((Mode::empty_results(), vec![]))
831 }
832 TransactionKind::ConsensusCommitPrologueV4(prologue) => {
833 setup_consensus_commit::<Mode>(
834 prologue.commit_timestamp_ms,
835 temporary_store,
836 store,
837 tx_ctx,
838 move_vm,
839 gas_charger,
840 protocol_config,
841 metrics,
842 trace_builder_opt,
843 )
844 .expect("ConsensusCommitPrologue cannot fail");
845 Ok((Mode::empty_results(), vec![]))
846 }
847 TransactionKind::ProgrammableTransaction(pt) => SPT::execute::<Mode>(
848 protocol_config,
849 metrics,
850 move_vm,
851 temporary_store,
852 store.as_backing_package_store(),
853 tx_ctx,
854 gas_charger,
855 rewritten_inputs,
856 pt,
857 trace_builder_opt,
858 ),
859 TransactionKind::ProgrammableSystemTransaction(pt) => {
860 SPT::execute::<execution_mode::System<Mode::Error>>(
861 protocol_config,
862 metrics,
863 move_vm,
864 temporary_store,
865 store.as_backing_package_store(),
866 tx_ctx,
867 gas_charger,
868 None,
869 pt,
870 trace_builder_opt,
871 )
872 .map_err(|(e, _)| (e, vec![]))?;
873 Ok((Mode::empty_results(), vec![]))
874 }
875 TransactionKind::EndOfEpochTransaction(txns) => {
876 let mut builder = ProgrammableTransactionBuilder::new();
877 let len = txns.len();
878 for (i, tx) in txns.into_iter().enumerate() {
879 match tx {
880 EndOfEpochTransactionKind::ChangeEpoch(change_epoch) => {
881 assert_eq!(i, len - 1);
882 advance_epoch::<Mode>(
883 builder,
884 change_epoch,
885 temporary_store,
886 store,
887 tx_ctx,
888 move_vm,
889 gas_charger,
890 protocol_config,
891 metrics,
892 trace_builder_opt,
893 )
894 .map_err(|e| (e, vec![]))?;
895 return Ok((Mode::empty_results(), vec![]));
896 }
897 EndOfEpochTransactionKind::AuthenticatorStateCreate => {
898 assert!(protocol_config.enable_jwk_consensus_updates());
899 builder = setup_authenticator_state_create(builder);
900 }
901 EndOfEpochTransactionKind::AuthenticatorStateExpire(expire) => {
902 assert!(protocol_config.enable_jwk_consensus_updates());
903
904 builder = setup_authenticator_state_expire(builder, expire);
907 }
908 EndOfEpochTransactionKind::RandomnessStateCreate => {
909 assert!(protocol_config.random_beacon());
910 builder = setup_randomness_state_create(builder);
911 }
912 EndOfEpochTransactionKind::DenyListStateCreate => {
913 assert!(protocol_config.enable_coin_deny_list_v1());
914 builder = setup_coin_deny_list_state_create(builder);
915 }
916 EndOfEpochTransactionKind::BridgeStateCreate(chain_id) => {
917 assert!(protocol_config.enable_bridge());
918 builder = setup_bridge_create(builder, chain_id)
919 }
920 EndOfEpochTransactionKind::BridgeCommitteeInit(bridge_shared_version) => {
921 assert!(protocol_config.enable_bridge());
922 assert!(protocol_config.should_try_to_finalize_bridge_committee());
923 builder = setup_bridge_committee_update(builder, bridge_shared_version)
924 }
925 EndOfEpochTransactionKind::StoreExecutionTimeObservations(estimates) => {
926 if let PerObjectCongestionControlMode::ExecutionTimeEstimate(params) =
927 protocol_config.per_object_congestion_control_mode()
928 {
929 if let Some(chunk_size) = params.observations_chunk_size {
930 builder = setup_store_execution_time_estimates_v2(
931 builder,
932 estimates,
933 chunk_size as usize,
934 );
935 } else {
936 builder =
937 setup_store_execution_time_estimates(builder, estimates);
938 }
939 }
940 }
941 EndOfEpochTransactionKind::AccumulatorRootCreate => {
942 assert!(protocol_config.create_root_accumulator_object());
943 builder = setup_accumulator_root_create(builder);
944 }
945 EndOfEpochTransactionKind::WriteAccumulatorStorageCost(
946 write_storage_cost,
947 ) => {
948 assert!(protocol_config.enable_accumulators());
949 builder =
950 setup_write_accumulator_storage_cost(builder, &write_storage_cost);
951 }
952 EndOfEpochTransactionKind::CoinRegistryCreate => {
953 assert!(protocol_config.enable_coin_registry());
954 builder = setup_coin_registry_create(builder);
955 }
956 EndOfEpochTransactionKind::DisplayRegistryCreate => {
957 assert!(protocol_config.enable_display_registry());
958 builder = setup_display_registry_create(builder);
959 }
960 EndOfEpochTransactionKind::AddressAliasStateCreate => {
961 assert!(protocol_config.address_aliases());
962 builder = setup_address_alias_state_create(builder);
963 }
964 }
965 }
966 unreachable!(
967 "EndOfEpochTransactionKind::ChangeEpoch should be the last transaction in the list"
968 )
969 }
970 TransactionKind::AuthenticatorStateUpdate(auth_state_update) => {
971 setup_authenticator_state_update::<Mode>(
972 auth_state_update,
973 temporary_store,
974 store,
975 tx_ctx,
976 move_vm,
977 gas_charger,
978 protocol_config,
979 metrics,
980 trace_builder_opt,
981 )
982 .map_err(|e| (e, vec![]))?;
983 Ok((Mode::empty_results(), vec![]))
984 }
985 TransactionKind::RandomnessStateUpdate(randomness_state_update) => {
986 setup_randomness_state_update::<Mode>(
987 randomness_state_update,
988 temporary_store,
989 store,
990 tx_ctx,
991 move_vm,
992 gas_charger,
993 protocol_config,
994 metrics,
995 trace_builder_opt,
996 )
997 .map_err(|e| (e, vec![]))?;
998 Ok((Mode::empty_results(), vec![]))
999 }
1000 }?;
1001 temporary_store
1002 .check_execution_results_consistency::<Mode>()
1003 .map_err(|e| (e, vec![]))?;
1004 Ok(result)
1005 }
1006
1007 fn mint_epoch_rewards_in_pt(
1008 builder: &mut ProgrammableTransactionBuilder,
1009 params: &AdvanceEpochParams,
1010 ) -> (Argument, Argument) {
1011 let storage_charge_arg = builder
1013 .input(CallArg::Pure(
1014 bcs::to_bytes(¶ms.storage_charge).unwrap(),
1015 ))
1016 .unwrap();
1017 let storage_rewards = builder.programmable_move_call(
1018 SUI_FRAMEWORK_PACKAGE_ID,
1019 BALANCE_MODULE_NAME.to_owned(),
1020 BALANCE_CREATE_REWARDS_FUNCTION_NAME.to_owned(),
1021 vec![GAS::type_tag()],
1022 vec![storage_charge_arg],
1023 );
1024
1025 let computation_charge_arg = builder
1027 .input(CallArg::Pure(
1028 bcs::to_bytes(¶ms.computation_charge).unwrap(),
1029 ))
1030 .unwrap();
1031 let computation_rewards = builder.programmable_move_call(
1032 SUI_FRAMEWORK_PACKAGE_ID,
1033 BALANCE_MODULE_NAME.to_owned(),
1034 BALANCE_CREATE_REWARDS_FUNCTION_NAME.to_owned(),
1035 vec![GAS::type_tag()],
1036 vec![computation_charge_arg],
1037 );
1038 (storage_rewards, computation_rewards)
1039 }
1040
1041 pub fn construct_advance_epoch_pt<Mode: ExecutionMode>(
1042 mut builder: ProgrammableTransactionBuilder,
1043 params: &AdvanceEpochParams,
1044 ) -> Result<ProgrammableTransaction, Mode::Error> {
1045 let (storage_rewards, computation_rewards) = mint_epoch_rewards_in_pt(&mut builder, params);
1047
1048 let mut arguments = vec![storage_rewards, computation_rewards];
1050 let call_arg_arguments = vec![
1051 CallArg::SUI_SYSTEM_MUT,
1052 CallArg::Pure(bcs::to_bytes(¶ms.epoch).unwrap()),
1053 CallArg::Pure(bcs::to_bytes(¶ms.next_protocol_version.as_u64()).unwrap()),
1054 CallArg::Pure(bcs::to_bytes(¶ms.storage_rebate).unwrap()),
1055 CallArg::Pure(bcs::to_bytes(¶ms.non_refundable_storage_fee).unwrap()),
1056 CallArg::Pure(bcs::to_bytes(¶ms.storage_fund_reinvest_rate).unwrap()),
1057 CallArg::Pure(bcs::to_bytes(¶ms.reward_slashing_rate).unwrap()),
1058 CallArg::Pure(bcs::to_bytes(¶ms.epoch_start_timestamp_ms).unwrap()),
1059 ]
1060 .into_iter()
1061 .map(|a| builder.input(a))
1062 .collect::<Result<_, _>>();
1063
1064 assert_invariant!(
1065 call_arg_arguments.is_ok(),
1066 "Unable to generate args for advance_epoch transaction!"
1067 );
1068
1069 arguments.append(&mut call_arg_arguments.unwrap());
1070
1071 info!("Call arguments to advance_epoch transaction: {:?}", params);
1072
1073 let storage_rebates = builder.programmable_move_call(
1074 SUI_SYSTEM_PACKAGE_ID,
1075 SUI_SYSTEM_MODULE_NAME.to_owned(),
1076 ADVANCE_EPOCH_FUNCTION_NAME.to_owned(),
1077 vec![],
1078 arguments,
1079 );
1080
1081 builder.programmable_move_call(
1083 SUI_FRAMEWORK_PACKAGE_ID,
1084 BALANCE_MODULE_NAME.to_owned(),
1085 BALANCE_DESTROY_REBATES_FUNCTION_NAME.to_owned(),
1086 vec![GAS::type_tag()],
1087 vec![storage_rebates],
1088 );
1089 Ok(builder.finish())
1090 }
1091
1092 pub fn construct_advance_epoch_safe_mode_pt(
1093 params: &AdvanceEpochParams,
1094 ) -> Result<ProgrammableTransaction, ExecutionError> {
1095 let mut builder = ProgrammableTransactionBuilder::new();
1096 let (storage_rewards, computation_rewards) = mint_epoch_rewards_in_pt(&mut builder, params);
1098
1099 let mut arguments = vec![storage_rewards, computation_rewards];
1101
1102 let mut args = vec![
1103 CallArg::SUI_SYSTEM_MUT,
1104 CallArg::Pure(bcs::to_bytes(¶ms.epoch).unwrap()),
1105 CallArg::Pure(bcs::to_bytes(¶ms.next_protocol_version.as_u64()).unwrap()),
1106 CallArg::Pure(bcs::to_bytes(¶ms.storage_rebate).unwrap()),
1107 CallArg::Pure(bcs::to_bytes(¶ms.non_refundable_storage_fee).unwrap()),
1108 ];
1109
1110 args.push(CallArg::Pure(
1111 bcs::to_bytes(¶ms.epoch_start_timestamp_ms).unwrap(),
1112 ));
1113
1114 let call_arg_arguments = args
1115 .into_iter()
1116 .map(|a| builder.input(a))
1117 .collect::<Result<_, _>>();
1118
1119 assert_invariant!(
1120 call_arg_arguments.is_ok(),
1121 "Unable to generate args for advance_epoch transaction!"
1122 );
1123
1124 arguments.append(&mut call_arg_arguments.unwrap());
1125
1126 info!("Call arguments to advance_epoch transaction: {:?}", params);
1127
1128 builder.programmable_move_call(
1129 SUI_SYSTEM_PACKAGE_ID,
1130 SUI_SYSTEM_MODULE_NAME.to_owned(),
1131 ADVANCE_EPOCH_SAFE_MODE_FUNCTION_NAME.to_owned(),
1132 vec![],
1133 arguments,
1134 );
1135
1136 Ok(builder.finish())
1137 }
1138
1139 fn advance_epoch<Mode: ExecutionMode>(
1140 builder: ProgrammableTransactionBuilder,
1141 change_epoch: ChangeEpoch,
1142 temporary_store: &mut TemporaryStore<'_>,
1143 store: &dyn BackingStore,
1144 tx_ctx: Rc<RefCell<TxContext>>,
1145 move_vm: &Arc<MoveRuntime>,
1146 gas_charger: &mut GasCharger,
1147 protocol_config: &ProtocolConfig,
1148 metrics: Arc<ExecutionMetrics>,
1149 trace_builder_opt: &mut Option<MoveTraceBuilder>,
1150 ) -> Result<(), Mode::Error> {
1151 let params = AdvanceEpochParams {
1152 epoch: change_epoch.epoch,
1153 next_protocol_version: change_epoch.protocol_version,
1154 storage_charge: change_epoch.storage_charge,
1155 computation_charge: change_epoch.computation_charge,
1156 storage_rebate: change_epoch.storage_rebate,
1157 non_refundable_storage_fee: change_epoch.non_refundable_storage_fee,
1158 storage_fund_reinvest_rate: protocol_config.storage_fund_reinvest_rate(),
1159 reward_slashing_rate: protocol_config.reward_slashing_rate(),
1160 epoch_start_timestamp_ms: change_epoch.epoch_start_timestamp_ms,
1161 };
1162 let advance_epoch_pt = construct_advance_epoch_pt::<Mode>(builder, ¶ms)?;
1163 let result = SPT::execute::<execution_mode::System<Mode::Error>>(
1164 protocol_config,
1165 metrics.clone(),
1166 move_vm,
1167 temporary_store,
1168 store.as_backing_package_store(),
1169 tx_ctx.clone(),
1170 gas_charger,
1171 None,
1172 advance_epoch_pt,
1173 trace_builder_opt,
1174 );
1175
1176 #[cfg(msim)]
1177 let result = maybe_modify_result_for(result, change_epoch.epoch);
1178
1179 if let Err(err) = &result {
1180 tracing::error!(
1181 "Failed to execute advance epoch transaction. Switching to safe mode. Error: {:?}. Input objects: {:?}. Tx data: {:?}",
1182 err.0,
1183 temporary_store.objects(),
1184 change_epoch,
1185 );
1186 temporary_store.drop_writes();
1187 gas_charger.reset_storage_cost_and_rebate();
1189
1190 temporary_store.advance_epoch_safe_mode(¶ms, protocol_config);
1191 }
1192
1193 let new_vm = new_move_runtime(
1194 all_natives(true, protocol_config),
1195 protocol_config,
1196 )
1197 .expect("Failed to create new MoveRuntime");
1198 process_system_packages(
1199 change_epoch,
1200 temporary_store,
1201 store,
1202 tx_ctx,
1203 &new_vm,
1204 gas_charger,
1205 protocol_config,
1206 metrics,
1207 trace_builder_opt,
1208 );
1209 Ok(())
1210 }
1211
1212 fn process_system_packages(
1213 change_epoch: ChangeEpoch,
1214 temporary_store: &mut TemporaryStore<'_>,
1215 store: &dyn BackingStore,
1216 tx_ctx: Rc<RefCell<TxContext>>,
1217 move_vm: &MoveRuntime,
1218 gas_charger: &mut GasCharger,
1219 protocol_config: &ProtocolConfig,
1220 metrics: Arc<ExecutionMetrics>,
1221 trace_builder_opt: &mut Option<MoveTraceBuilder>,
1222 ) {
1223 let digest = tx_ctx.borrow().digest();
1224 let binary_config = protocol_config.binary_config(None);
1225 for (version, modules, dependencies) in change_epoch.system_packages.into_iter() {
1226 let deserialized_modules: Vec<_> = modules
1227 .iter()
1228 .map(|m| CompiledModule::deserialize_with_config(m, &binary_config).unwrap())
1229 .collect();
1230
1231 if version == OBJECT_START_VERSION {
1232 let package_id = deserialized_modules.first().unwrap().address();
1233 info!("adding new system package {package_id}");
1234
1235 let publish_pt = {
1236 let mut b = ProgrammableTransactionBuilder::new();
1237 b.command(Command::Publish(modules, dependencies));
1238 b.finish()
1239 };
1240
1241 SPT::execute::<execution_mode::System>(
1242 protocol_config,
1243 metrics.clone(),
1244 move_vm,
1245 temporary_store,
1246 store.as_backing_package_store(),
1247 tx_ctx.clone(),
1248 gas_charger,
1249 None,
1250 publish_pt,
1251 trace_builder_opt,
1252 )
1253 .map_err(|(e, _)| e)
1254 .expect("System Package Publish must succeed");
1255 } else {
1256 let mut new_package = Object::new_system_package(
1257 &deserialized_modules,
1258 version,
1259 dependencies,
1260 digest,
1261 );
1262
1263 info!(
1264 "upgraded system package {:?}",
1265 new_package.compute_object_reference()
1266 );
1267
1268 new_package
1271 .data
1272 .try_as_package_mut()
1273 .unwrap()
1274 .decrement_version();
1275
1276 temporary_store.upgrade_system_package(new_package);
1278 }
1279 }
1280 }
1281
1282 fn setup_consensus_commit<Mode: ExecutionMode>(
1287 consensus_commit_timestamp_ms: CheckpointTimestamp,
1288 temporary_store: &mut TemporaryStore<'_>,
1289 store: &dyn BackingStore,
1290 tx_ctx: Rc<RefCell<TxContext>>,
1291 move_vm: &Arc<MoveRuntime>,
1292 gas_charger: &mut GasCharger,
1293 protocol_config: &ProtocolConfig,
1294 metrics: Arc<ExecutionMetrics>,
1295 trace_builder_opt: &mut Option<MoveTraceBuilder>,
1296 ) -> Result<(), Mode::Error> {
1297 let pt = {
1298 let mut builder = ProgrammableTransactionBuilder::new();
1299 let res = builder.move_call(
1300 SUI_FRAMEWORK_ADDRESS.into(),
1301 CLOCK_MODULE_NAME.to_owned(),
1302 CONSENSUS_COMMIT_PROLOGUE_FUNCTION_NAME.to_owned(),
1303 vec![],
1304 vec![
1305 CallArg::CLOCK_MUT,
1306 CallArg::Pure(bcs::to_bytes(&consensus_commit_timestamp_ms).unwrap()),
1307 ],
1308 );
1309 assert_invariant!(
1310 res.is_ok(),
1311 "Unable to generate consensus_commit_prologue transaction!"
1312 );
1313 builder.finish()
1314 };
1315 SPT::execute::<execution_mode::System<Mode::Error>>(
1316 protocol_config,
1317 metrics,
1318 move_vm,
1319 temporary_store,
1320 store.as_backing_package_store(),
1321 tx_ctx,
1322 gas_charger,
1323 None,
1324 pt,
1325 trace_builder_opt,
1326 )
1327 .map_err(|(e, _)| e)?;
1328 Ok(())
1329 }
1330
1331 fn setup_authenticator_state_create(
1332 mut builder: ProgrammableTransactionBuilder,
1333 ) -> ProgrammableTransactionBuilder {
1334 builder
1335 .move_call(
1336 SUI_FRAMEWORK_ADDRESS.into(),
1337 AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1338 AUTHENTICATOR_STATE_CREATE_FUNCTION_NAME.to_owned(),
1339 vec![],
1340 vec![],
1341 )
1342 .expect("Unable to generate authenticator_state_create transaction!");
1343 builder
1344 }
1345
1346 fn setup_randomness_state_create(
1347 mut builder: ProgrammableTransactionBuilder,
1348 ) -> ProgrammableTransactionBuilder {
1349 builder
1350 .move_call(
1351 SUI_FRAMEWORK_ADDRESS.into(),
1352 RANDOMNESS_MODULE_NAME.to_owned(),
1353 RANDOMNESS_STATE_CREATE_FUNCTION_NAME.to_owned(),
1354 vec![],
1355 vec![],
1356 )
1357 .expect("Unable to generate randomness_state_create transaction!");
1358 builder
1359 }
1360
1361 fn setup_bridge_create(
1362 mut builder: ProgrammableTransactionBuilder,
1363 chain_id: ChainIdentifier,
1364 ) -> ProgrammableTransactionBuilder {
1365 let bridge_uid = builder
1366 .input(CallArg::Pure(UID::new(SUI_BRIDGE_OBJECT_ID).to_bcs_bytes()))
1367 .expect("Unable to create Bridge object UID!");
1368
1369 let bridge_chain_id = if chain_id == get_mainnet_chain_identifier() {
1370 BridgeChainId::SuiMainnet as u8
1371 } else if chain_id == get_testnet_chain_identifier() {
1372 BridgeChainId::SuiTestnet as u8
1373 } else {
1374 BridgeChainId::SuiCustom as u8
1376 };
1377
1378 let bridge_chain_id = builder.pure(bridge_chain_id).unwrap();
1379 builder.programmable_move_call(
1380 BRIDGE_ADDRESS.into(),
1381 BRIDGE_MODULE_NAME.to_owned(),
1382 BRIDGE_CREATE_FUNCTION_NAME.to_owned(),
1383 vec![],
1384 vec![bridge_uid, bridge_chain_id],
1385 );
1386 builder
1387 }
1388
1389 fn setup_bridge_committee_update(
1390 mut builder: ProgrammableTransactionBuilder,
1391 bridge_shared_version: SequenceNumber,
1392 ) -> ProgrammableTransactionBuilder {
1393 let bridge = builder
1394 .obj(ObjectArg::SharedObject {
1395 id: SUI_BRIDGE_OBJECT_ID,
1396 initial_shared_version: bridge_shared_version,
1397 mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1398 })
1399 .expect("Unable to create Bridge object arg!");
1400 let system_state = builder
1401 .obj(ObjectArg::SUI_SYSTEM_MUT)
1402 .expect("Unable to create System State object arg!");
1403
1404 let voting_power = builder.programmable_move_call(
1405 SUI_SYSTEM_PACKAGE_ID,
1406 SUI_SYSTEM_MODULE_NAME.to_owned(),
1407 ident_str!("validator_voting_powers").to_owned(),
1408 vec![],
1409 vec![system_state],
1410 );
1411
1412 let min_stake_participation_percentage = builder
1415 .input(CallArg::Pure(
1416 bcs::to_bytes(&BRIDGE_COMMITTEE_MINIMAL_VOTING_POWER).unwrap(),
1417 ))
1418 .unwrap();
1419
1420 builder.programmable_move_call(
1421 BRIDGE_ADDRESS.into(),
1422 BRIDGE_MODULE_NAME.to_owned(),
1423 BRIDGE_INIT_COMMITTEE_FUNCTION_NAME.to_owned(),
1424 vec![],
1425 vec![bridge, voting_power, min_stake_participation_percentage],
1426 );
1427 builder
1428 }
1429
1430 fn setup_authenticator_state_update<Mode: ExecutionMode>(
1431 update: AuthenticatorStateUpdate,
1432 temporary_store: &mut TemporaryStore<'_>,
1433 store: &dyn BackingStore,
1434 tx_ctx: Rc<RefCell<TxContext>>,
1435 move_vm: &Arc<MoveRuntime>,
1436 gas_charger: &mut GasCharger,
1437 protocol_config: &ProtocolConfig,
1438 metrics: Arc<ExecutionMetrics>,
1439 trace_builder_opt: &mut Option<MoveTraceBuilder>,
1440 ) -> Result<(), Mode::Error> {
1441 let pt = {
1442 let mut builder = ProgrammableTransactionBuilder::new();
1443 let res = builder.move_call(
1444 SUI_FRAMEWORK_ADDRESS.into(),
1445 AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1446 AUTHENTICATOR_STATE_UPDATE_FUNCTION_NAME.to_owned(),
1447 vec![],
1448 vec![
1449 CallArg::Object(ObjectArg::SharedObject {
1450 id: SUI_AUTHENTICATOR_STATE_OBJECT_ID,
1451 initial_shared_version: update.authenticator_obj_initial_shared_version,
1452 mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1453 }),
1454 CallArg::Pure(bcs::to_bytes(&update.new_active_jwks).unwrap()),
1455 ],
1456 );
1457 assert_invariant!(
1458 res.is_ok(),
1459 "Unable to generate authenticator_state_update transaction!"
1460 );
1461 builder.finish()
1462 };
1463 SPT::execute::<execution_mode::System<Mode::Error>>(
1464 protocol_config,
1465 metrics,
1466 move_vm,
1467 temporary_store,
1468 store.as_backing_package_store(),
1469 tx_ctx,
1470 gas_charger,
1471 None,
1472 pt,
1473 trace_builder_opt,
1474 )
1475 .map_err(|(e, _)| e)?;
1476 Ok(())
1477 }
1478
1479 fn setup_authenticator_state_expire(
1480 mut builder: ProgrammableTransactionBuilder,
1481 expire: AuthenticatorStateExpire,
1482 ) -> ProgrammableTransactionBuilder {
1483 builder
1484 .move_call(
1485 SUI_FRAMEWORK_ADDRESS.into(),
1486 AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1487 AUTHENTICATOR_STATE_EXPIRE_JWKS_FUNCTION_NAME.to_owned(),
1488 vec![],
1489 vec![
1490 CallArg::Object(ObjectArg::SharedObject {
1491 id: SUI_AUTHENTICATOR_STATE_OBJECT_ID,
1492 initial_shared_version: expire.authenticator_obj_initial_shared_version,
1493 mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1494 }),
1495 CallArg::Pure(bcs::to_bytes(&expire.min_epoch).unwrap()),
1496 ],
1497 )
1498 .expect("Unable to generate authenticator_state_expire transaction!");
1499 builder
1500 }
1501
1502 fn setup_randomness_state_update<Mode: ExecutionMode>(
1503 update: RandomnessStateUpdate,
1504 temporary_store: &mut TemporaryStore<'_>,
1505 store: &dyn BackingStore,
1506 tx_ctx: Rc<RefCell<TxContext>>,
1507 move_vm: &Arc<MoveRuntime>,
1508 gas_charger: &mut GasCharger,
1509 protocol_config: &ProtocolConfig,
1510 metrics: Arc<ExecutionMetrics>,
1511 trace_builder_opt: &mut Option<MoveTraceBuilder>,
1512 ) -> Result<(), Mode::Error> {
1513 let pt = {
1514 let mut builder = ProgrammableTransactionBuilder::new();
1515 let res = builder.move_call(
1516 SUI_FRAMEWORK_ADDRESS.into(),
1517 RANDOMNESS_MODULE_NAME.to_owned(),
1518 RANDOMNESS_STATE_UPDATE_FUNCTION_NAME.to_owned(),
1519 vec![],
1520 vec![
1521 CallArg::Object(ObjectArg::SharedObject {
1522 id: SUI_RANDOMNESS_STATE_OBJECT_ID,
1523 initial_shared_version: update.randomness_obj_initial_shared_version,
1524 mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1525 }),
1526 CallArg::Pure(bcs::to_bytes(&update.randomness_round).unwrap()),
1527 CallArg::Pure(bcs::to_bytes(&update.random_bytes).unwrap()),
1528 ],
1529 );
1530 assert_invariant!(
1531 res.is_ok(),
1532 "Unable to generate randomness_state_update transaction!"
1533 );
1534 builder.finish()
1535 };
1536 SPT::execute::<execution_mode::System<Mode::Error>>(
1537 protocol_config,
1538 metrics,
1539 move_vm,
1540 temporary_store,
1541 store.as_backing_package_store(),
1542 tx_ctx,
1543 gas_charger,
1544 None,
1545 pt,
1546 trace_builder_opt,
1547 )
1548 .map_err(|(e, _)| e)?;
1549 Ok(())
1550 }
1551
1552 fn setup_coin_deny_list_state_create(
1553 mut builder: ProgrammableTransactionBuilder,
1554 ) -> ProgrammableTransactionBuilder {
1555 builder
1556 .move_call(
1557 SUI_FRAMEWORK_ADDRESS.into(),
1558 DENY_LIST_MODULE.to_owned(),
1559 DENY_LIST_CREATE_FUNC.to_owned(),
1560 vec![],
1561 vec![],
1562 )
1563 .expect("Unable to generate coin_deny_list_create transaction!");
1564 builder
1565 }
1566
1567 fn setup_store_execution_time_estimates(
1568 mut builder: ProgrammableTransactionBuilder,
1569 estimates: StoredExecutionTimeObservations,
1570 ) -> ProgrammableTransactionBuilder {
1571 let system_state = builder.obj(ObjectArg::SUI_SYSTEM_MUT).unwrap();
1572 let estimates_bytes = bcs::to_bytes(&estimates).unwrap();
1575 let estimates_arg = builder.pure(estimates_bytes).unwrap();
1576 builder.programmable_move_call(
1577 SUI_SYSTEM_PACKAGE_ID,
1578 SUI_SYSTEM_MODULE_NAME.to_owned(),
1579 ident_str!("store_execution_time_estimates").to_owned(),
1580 vec![],
1581 vec![system_state, estimates_arg],
1582 );
1583 builder
1584 }
1585
1586 fn setup_store_execution_time_estimates_v2(
1587 mut builder: ProgrammableTransactionBuilder,
1588 estimates: StoredExecutionTimeObservations,
1589 chunk_size: usize,
1590 ) -> ProgrammableTransactionBuilder {
1591 let system_state = builder.obj(ObjectArg::SUI_SYSTEM_MUT).unwrap();
1592
1593 let estimate_chunks = estimates.chunk_observations(chunk_size);
1594
1595 let chunk_bytes: Vec<Vec<u8>> = estimate_chunks
1596 .into_iter()
1597 .map(|chunk| bcs::to_bytes(&chunk).unwrap())
1598 .collect();
1599
1600 let chunks_arg = builder.pure(chunk_bytes).unwrap();
1601
1602 builder.programmable_move_call(
1603 SUI_SYSTEM_PACKAGE_ID,
1604 SUI_SYSTEM_MODULE_NAME.to_owned(),
1605 ident_str!("store_execution_time_estimates_v2").to_owned(),
1606 vec![],
1607 vec![system_state, chunks_arg],
1608 );
1609 builder
1610 }
1611
1612 fn setup_accumulator_root_create(
1613 mut builder: ProgrammableTransactionBuilder,
1614 ) -> ProgrammableTransactionBuilder {
1615 builder
1616 .move_call(
1617 SUI_FRAMEWORK_ADDRESS.into(),
1618 ACCUMULATOR_ROOT_MODULE.to_owned(),
1619 ACCUMULATOR_ROOT_CREATE_FUNC.to_owned(),
1620 vec![],
1621 vec![],
1622 )
1623 .expect("Unable to generate accumulator_root_create transaction!");
1624 builder
1625 }
1626
1627 fn setup_write_accumulator_storage_cost(
1628 mut builder: ProgrammableTransactionBuilder,
1629 write_storage_cost: &WriteAccumulatorStorageCost,
1630 ) -> ProgrammableTransactionBuilder {
1631 let system_state = builder.obj(ObjectArg::SUI_SYSTEM_MUT).unwrap();
1632 let storage_cost_arg = builder.pure(write_storage_cost.storage_cost).unwrap();
1633 builder.programmable_move_call(
1634 SUI_SYSTEM_PACKAGE_ID,
1635 SUI_SYSTEM_MODULE_NAME.to_owned(),
1636 ident_str!("write_accumulator_storage_cost").to_owned(),
1637 vec![],
1638 vec![system_state, storage_cost_arg],
1639 );
1640 builder
1641 }
1642
1643 fn setup_coin_registry_create(
1644 mut builder: ProgrammableTransactionBuilder,
1645 ) -> ProgrammableTransactionBuilder {
1646 builder
1647 .move_call(
1648 SUI_FRAMEWORK_ADDRESS.into(),
1649 ident_str!("coin_registry").to_owned(),
1650 ident_str!("create").to_owned(),
1651 vec![],
1652 vec![],
1653 )
1654 .expect("Unable to generate coin_registry_create transaction!");
1655 builder
1656 }
1657
1658 fn setup_display_registry_create(
1659 mut builder: ProgrammableTransactionBuilder,
1660 ) -> ProgrammableTransactionBuilder {
1661 builder
1662 .move_call(
1663 SUI_FRAMEWORK_ADDRESS.into(),
1664 ident_str!("display_registry").to_owned(),
1665 ident_str!("create").to_owned(),
1666 vec![],
1667 vec![],
1668 )
1669 .expect("Unable to generate display_registry_create transaction!");
1670 builder
1671 }
1672
1673 fn setup_address_alias_state_create(
1674 mut builder: ProgrammableTransactionBuilder,
1675 ) -> ProgrammableTransactionBuilder {
1676 builder
1677 .move_call(
1678 SUI_FRAMEWORK_ADDRESS.into(),
1679 ident_str!("address_alias").to_owned(),
1680 ident_str!("create").to_owned(),
1681 vec![],
1682 vec![],
1683 )
1684 .expect("Unable to generate address_alias_state_create transaction!");
1685 builder
1686 }
1687}