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 #[allow(clippy::type_complexity)]
128 #[instrument(name = "tx_execute_to_effects", level = "debug", skip_all)]
129 pub fn execute_transaction_to_effects<Mode: ExecutionMode>(
130 store: &dyn BackingStore,
131 input_objects: CheckedInputObjects,
132 gas_data: GasData,
133 gas_status: SuiGasStatus,
134 transaction_kind: TransactionKind,
135 rewritten_inputs: Option<Vec<bool>>,
136 transaction_signer: SuiAddress,
137 transaction_digest: TransactionDigest,
138 move_vm: &Arc<MoveRuntime>,
139 epoch_id: &EpochId,
140 epoch_timestamp_ms: u64,
141 protocol_config: &ProtocolConfig,
142 metrics: Arc<ExecutionMetrics>,
143 enable_expensive_checks: bool,
144 execution_params: ExecutionOrEarlyError,
145 trace_builder_opt: &mut Option<MoveTraceBuilder>,
146 ) -> (
147 InnerTemporaryStore,
148 SuiGasStatus,
149 TransactionEffects,
150 Vec<ExecutionTiming>,
151 Result<Mode::ExecutionResults, Mode::Error>,
152 ) {
153 let input_objects = input_objects.into_inner();
154 let mutable_inputs = if enable_expensive_checks {
155 input_objects.all_mutable_inputs().keys().copied().collect()
156 } else {
157 HashSet::new()
158 };
159 let shared_object_refs = input_objects.filter_shared_objects();
160 let receiving_objects = transaction_kind.receiving_objects();
161 let mut transaction_dependencies = input_objects.transaction_dependencies();
162
163 let mut temporary_store = TemporaryStore::new(
164 store,
165 input_objects,
166 receiving_objects,
167 transaction_digest,
168 protocol_config,
169 *epoch_id,
170 );
171
172 let sponsor = {
173 let gas_owner = gas_data.owner;
174 if gas_owner == transaction_signer {
175 None
176 } else {
177 Some(gas_owner)
178 }
179 };
180 let gas_price = gas_status.gas_price();
181 let rgp = gas_status.reference_gas_price();
182
183 let mut gas_charger = GasCharger::new(
184 transaction_digest,
185 payment_kind(&gas_data, &transaction_kind, protocol_config),
186 gas_status,
187 &mut temporary_store,
188 protocol_config,
189 );
190
191 let tx_ctx = TxContext::new_from_components(
192 &transaction_signer,
193 &transaction_digest,
194 epoch_id,
195 epoch_timestamp_ms,
196 rgp,
197 gas_price,
198 gas_data.budget,
199 sponsor,
200 protocol_config,
201 );
202 let tx_ctx = Rc::new(RefCell::new(tx_ctx));
203
204 let is_gasless = protocol_config.enable_gasless()
205 && is_gasless_transaction(&gas_data, &transaction_kind);
206 let is_epoch_change = transaction_kind.is_end_of_epoch_tx();
207
208 let (gas_cost_summary, execution_result, timings) = execute_transaction::<Mode>(
209 store,
210 &mut temporary_store,
211 transaction_kind,
212 rewritten_inputs,
213 &mut gas_charger,
214 tx_ctx,
215 move_vm,
216 protocol_config,
217 metrics.clone(),
218 enable_expensive_checks,
219 execution_params,
220 trace_builder_opt,
221 is_gasless,
222 );
223
224 let status = if let Err(error) = &execution_result {
225 use ExecutionErrorKind as K;
227 match error.kind() {
228 K::InvariantViolation | K::VMInvariantViolation => {
229 debug_fatal!(
230 "INVARIANT VIOLATION! Txn Digest: {}, Source: {:?}",
231 transaction_digest,
232 error.source_ref(),
233 );
234 }
235
236 K::SuiMoveVerificationError | K::VMVerificationOrDeserializationError => {
237 #[skip_checked_arithmetic]
238 tracing::debug!(
239 kind = ?error.kind(),
240 tx_digest = ?transaction_digest,
241 "Verification Error. Source: {:?}",
242 error.source_ref(),
243 );
244 }
245
246 K::PublishUpgradeMissingDependency | K::PublishUpgradeDependencyDowngrade => {
247 #[skip_checked_arithmetic]
248 tracing::debug!(
249 kind = ?error.kind(),
250 tx_digest = ?transaction_digest,
251 "Publish/Upgrade Error. Source: {:?}",
252 error.source_ref(),
253 )
254 }
255
256 _ => (),
257 };
258
259 ExecutionStatus::new_failure(error.to_execution_failure())
260 } else {
261 ExecutionStatus::Success
262 };
263
264 #[skip_checked_arithmetic]
265 trace!(
266 tx_digest = ?transaction_digest,
267 computation_gas_cost = gas_cost_summary.computation_cost,
268 storage_gas_cost = gas_cost_summary.storage_cost,
269 storage_gas_rebate = gas_cost_summary.storage_rebate,
270 "Finished execution of transaction with status {:?}",
271 status
272 );
273
274 transaction_dependencies.remove(&TransactionDigest::genesis_marker());
278
279 if enable_expensive_checks && !Mode::allow_arbitrary_function_calls() {
280 temporary_store
281 .check_ownership_invariants(
282 &transaction_signer,
283 &sponsor,
284 &mut gas_charger,
285 &mutable_inputs,
286 is_epoch_change,
287 )
288 .unwrap()
289 } let (inner, effects) = temporary_store.into_effects(
292 shared_object_refs,
293 &transaction_digest,
294 transaction_dependencies,
295 gas_cost_summary,
296 status,
297 &mut gas_charger,
298 *epoch_id,
299 );
300
301 metrics.vm_telemetry_metrics.try_update(|vm_metrics| {
302 let t = move_vm.get_telemetry_report();
303 vm_metrics
304 .move_vm_package_cache_count
305 .set(t.package_cache_count as i64);
306 vm_metrics
307 .move_vm_total_arena_size_bytes
308 .set(t.total_arena_size as i64);
309 vm_metrics.move_vm_module_count.set(t.module_count as i64);
310 vm_metrics
311 .move_vm_function_count
312 .set(t.function_count as i64);
313 vm_metrics.move_vm_type_count.set(t.type_count as i64);
314 vm_metrics.move_vm_interner_size.set(t.interner_size as i64);
315 vm_metrics
316 .move_vm_vtable_cache_count
317 .set(t.vtable_cache_count as i64);
318 vm_metrics
319 .move_vm_vtable_cache_hits
320 .set(t.vtable_cache_hits as i64);
321 vm_metrics
322 .move_vm_vtable_cache_misses
323 .set(t.vtable_cache_misses as i64);
324 vm_metrics
325 .move_vm_load_time_ms
326 .set(t.total_load_time as i64);
327 vm_metrics.move_vm_load_count.set(t.load_count as i64);
328 vm_metrics
329 .move_vm_validation_time_ms
330 .set(t.total_validation_time as i64);
331 vm_metrics
332 .move_vm_validation_count
333 .set(t.validation_count as i64);
334 vm_metrics.move_vm_jit_time_ms.set(t.total_jit_time as i64);
335 vm_metrics.move_vm_jit_count.set(t.jit_count as i64);
336 vm_metrics
337 .move_vm_execution_time_ms
338 .set(t.total_execution_time as i64);
339 vm_metrics
340 .move_vm_execution_count
341 .set(t.execution_count as i64);
342 vm_metrics
343 .move_vm_interpreter_time_ms
344 .set(t.total_interpreter_time as i64);
345 vm_metrics
346 .move_vm_interpreter_count
347 .set(t.interpreter_count as i64);
348 vm_metrics
349 .move_vm_max_callstack_size
350 .set(t.max_callstack_size as i64);
351 vm_metrics
352 .move_vm_max_valuestack_size
353 .set(t.max_valuestack_size as i64);
354 vm_metrics.move_vm_total_time_ms.set(t.total_time as i64);
355 vm_metrics.move_vm_total_count.set(t.total_count as i64);
356 });
357
358 (
359 inner,
360 gas_charger.into_gas_status(),
361 effects,
362 timings,
363 execution_result,
364 )
365 }
366
367 pub fn execute_genesis_state_update(
368 store: &dyn BackingStore,
369 protocol_config: &ProtocolConfig,
370 metrics: Arc<ExecutionMetrics>,
371 move_vm: &Arc<MoveRuntime>,
372 tx_context: Rc<RefCell<TxContext>>,
373 input_objects: CheckedInputObjects,
374 pt: ProgrammableTransaction,
375 ) -> Result<InnerTemporaryStore, ExecutionError> {
376 let input_objects = input_objects.into_inner();
377 let mut temporary_store = TemporaryStore::new(
378 store,
379 input_objects,
380 vec![],
381 tx_context.borrow().digest(),
382 protocol_config,
383 0,
384 );
385 let mut gas_charger = GasCharger::new_unmetered(tx_context.borrow().digest());
386 SPT::execute::<execution_mode::Genesis>(
387 protocol_config,
388 metrics,
389 move_vm,
390 &mut temporary_store,
391 store.as_backing_package_store(),
392 tx_context,
393 &mut gas_charger,
394 None,
395 pt,
396 &mut None,
397 )
398 .map_err(|(e, _)| e)?;
399 temporary_store.update_object_version_and_prev_tx();
400 Ok(temporary_store.into_inner(BTreeMap::new()))
401 }
402
403 #[instrument(name = "tx_execute", level = "debug", skip_all)]
404 fn execute_transaction<Mode: ExecutionMode>(
405 store: &dyn BackingStore,
406 temporary_store: &mut TemporaryStore<'_>,
407 transaction_kind: TransactionKind,
408 rewritten_inputs: Option<Vec<bool>>,
409 gas_charger: &mut GasCharger,
410 tx_ctx: Rc<RefCell<TxContext>>,
411 move_vm: &Arc<MoveRuntime>,
412 protocol_config: &ProtocolConfig,
413 metrics: Arc<ExecutionMetrics>,
414 enable_expensive_checks: bool,
415 execution_params: ExecutionOrEarlyError,
416 trace_builder_opt: &mut Option<MoveTraceBuilder>,
417 is_gasless: bool,
418 ) -> (
419 GasCostSummary,
420 Result<Mode::ExecutionResults, Mode::Error>,
421 Vec<ExecutionTiming>,
422 ) {
423 debug_assert!(
425 gas_charger.no_charges(),
426 "No gas charges must be applied yet"
427 );
428
429 let is_genesis_tx = matches!(transaction_kind, TransactionKind::Genesis(_));
430 let advance_epoch_gas_summary = transaction_kind.get_advance_epoch_tx_gas_summary();
431 let digest = tx_ctx.borrow().digest();
432 let withdrawal_reservations =
433 if is_gasless && protocol_config.gasless_verify_remaining_balance() {
434 gasless_withdrawal_reservations(&transaction_kind, &tx_ctx.borrow())
435 } else {
436 None
437 };
438
439 let result = gas_charger.charge_input_objects(temporary_store);
442
443 let result: ResultWithTimings<Mode::ExecutionResults, Mode::Error> =
444 result.map_err(|e| (e.into(), vec![])).and_then(
445 |()| -> ResultWithTimings<Mode::ExecutionResults, Mode::Error> {
446 let mut execution_result: ResultWithTimings<
447 Mode::ExecutionResults,
448 Mode::Error,
449 > = match execution_params {
450 ExecutionOrEarlyError::Err(early_execution_error) => Err((
451 ExecutionError::new(early_execution_error, None).into(),
452 vec![],
453 )),
454 ExecutionOrEarlyError::Ok(()) => execution_loop::<Mode>(
455 store,
456 temporary_store,
457 transaction_kind,
458 rewritten_inputs,
459 tx_ctx,
460 move_vm,
461 gas_charger,
462 protocol_config,
463 metrics.clone(),
464 trace_builder_opt,
465 ),
466 };
467
468 let meter_check = check_meter_limit::<Mode>(
469 temporary_store,
470 gas_charger,
471 protocol_config,
472 metrics.clone(),
473 );
474 if let Err(e) = meter_check {
475 execution_result = Err((e, vec![]));
476 }
477
478 if execution_result.is_ok() {
479 let gas_check = check_written_objects_limit::<Mode>(
480 temporary_store,
481 gas_charger,
482 protocol_config,
483 metrics,
484 );
485 if let Err(e) = gas_check {
486 execution_result = Err((e, vec![]));
487 }
488 }
489
490 execution_result
491 },
492 );
493
494 let (mut result, timings) = match result {
495 Ok((r, t)) => (Ok(r), t),
496 Err((e, t)) => (Err(e), t),
497 };
498 if is_gasless
499 && result.is_ok()
500 && let Err(msg) = temporary_store
501 .check_gasless_execution_requirements(withdrawal_reservations.as_ref())
502 {
503 result = Err(
504 ExecutionError::new_with_source(ExecutionErrorKind::InsufficientGas, msg).into(),
505 );
506 }
507
508 let cost_summary = gas_charger.charge_gas(temporary_store, &mut result);
509 temporary_store.conserve_unmetered_storage_rebate(gas_charger.unmetered_storage_rebate());
517
518 if let Err(e) = run_conservation_checks::<Mode>(
519 temporary_store,
520 gas_charger,
521 digest,
522 move_vm,
523 protocol_config.simple_conservation_checks(),
524 enable_expensive_checks,
525 &cost_summary,
526 is_genesis_tx,
527 advance_epoch_gas_summary,
528 ) {
529 result = Err(e);
531 }
532
533 (cost_summary, result, timings)
534 }
535
536 #[instrument(name = "run_conservation_checks", level = "debug", skip_all)]
537 fn run_conservation_checks<Mode: ExecutionMode>(
538 temporary_store: &mut TemporaryStore<'_>,
539 gas_charger: &mut GasCharger,
540 tx_digest: TransactionDigest,
541 move_vm: &Arc<MoveRuntime>,
542 simple_conservation_checks: bool,
543 enable_expensive_checks: bool,
544 cost_summary: &GasCostSummary,
545 is_genesis_tx: bool,
546 advance_epoch_gas_summary: Option<(u64, u64)>,
547 ) -> Result<(), Mode::Error> {
548 let mut result: Result<(), Mode::Error> = Ok(());
549 if !is_genesis_tx && !Mode::skip_conservation_checks() {
550 let conservation_result = {
552 temporary_store
553 .check_sui_conserved(simple_conservation_checks, cost_summary)
554 .and_then(|()| {
555 if enable_expensive_checks {
556 let mut layout_resolver = TypeLayoutResolver::new(
558 move_vm,
559 temporary_store.protocol_config(),
560 Box::new(&*temporary_store),
561 );
562 temporary_store.check_sui_conserved_expensive(
563 cost_summary,
564 advance_epoch_gas_summary,
565 &mut layout_resolver,
566 )
567 } else {
568 Ok(())
569 }
570 })
571 };
572 if let Err(conservation_err) = conservation_result {
573 result = Err(conservation_err.into());
576 gas_charger.reset(temporary_store);
577 gas_charger.charge_gas(temporary_store, &mut result);
578 if let Err(recovery_err) = {
580 temporary_store
581 .check_sui_conserved(simple_conservation_checks, cost_summary)
582 .and_then(|()| {
583 if enable_expensive_checks {
584 let mut layout_resolver = TypeLayoutResolver::new(
586 move_vm,
587 temporary_store.protocol_config(),
588 Box::new(&*temporary_store),
589 );
590 temporary_store.check_sui_conserved_expensive(
591 cost_summary,
592 advance_epoch_gas_summary,
593 &mut layout_resolver,
594 )
595 } else {
596 Ok(())
597 }
598 })
599 } {
600 panic!(
604 "SUI conservation fail in tx block {}: {}\nGas status is {}\nTx was ",
605 tx_digest,
606 recovery_err,
607 gas_charger.summary()
608 )
609 }
610 }
611 } result
614 }
615
616 #[instrument(name = "check_meter_limit", level = "debug", skip_all)]
617 fn check_meter_limit<Mode: ExecutionMode>(
618 temporary_store: &mut TemporaryStore<'_>,
619 gas_charger: &mut GasCharger,
620 protocol_config: &ProtocolConfig,
621 metrics: Arc<ExecutionMetrics>,
622 ) -> Result<(), Mode::Error> {
623 let effects_estimated_size = temporary_store.estimate_effects_size_upperbound();
624
625 match check_limit_by_meter!(
629 !gas_charger.is_unmetered(),
630 effects_estimated_size,
631 protocol_config.max_serialized_tx_effects_size_bytes(),
632 protocol_config.max_serialized_tx_effects_size_bytes_system_tx(),
633 metrics.limits_metrics.excessive_estimated_effects_size
634 ) {
635 LimitThresholdCrossed::None => Ok(()),
636 LimitThresholdCrossed::Soft(_, limit) => {
637 warn!(
638 effects_estimated_size = effects_estimated_size,
639 soft_limit = limit,
640 "Estimated transaction effects size crossed soft limit",
641 );
642 Ok(())
643 }
644 LimitThresholdCrossed::Hard(_, lim) => Err(ExecutionError::new_with_source(
645 ExecutionErrorKind::EffectsTooLarge {
646 current_size: effects_estimated_size as u64,
647 max_size: lim as u64,
648 },
649 "Transaction effects are too large",
650 )
651 .into()),
652 }
653 }
654
655 #[instrument(name = "check_written_objects_limit", level = "debug", skip_all)]
656 fn check_written_objects_limit<Mode: ExecutionMode>(
657 temporary_store: &mut TemporaryStore<'_>,
658 gas_charger: &mut GasCharger,
659 protocol_config: &ProtocolConfig,
660 metrics: Arc<ExecutionMetrics>,
661 ) -> Result<(), Mode::Error> {
662 if let (Some(normal_lim), Some(system_lim)) = (
663 protocol_config.max_size_written_objects_as_option(),
664 protocol_config.max_size_written_objects_system_tx_as_option(),
665 ) {
666 let written_objects_size = temporary_store.written_objects_size();
667
668 match check_limit_by_meter!(
669 !gas_charger.is_unmetered(),
670 written_objects_size,
671 normal_lim,
672 system_lim,
673 metrics.limits_metrics.excessive_written_objects_size
674 ) {
675 LimitThresholdCrossed::None => (),
676 LimitThresholdCrossed::Soft(_, limit) => {
677 warn!(
678 written_objects_size = written_objects_size,
679 soft_limit = limit,
680 "Written objects size crossed soft limit",
681 )
682 }
683 LimitThresholdCrossed::Hard(_, lim) => {
684 return Err(ExecutionError::new_with_source(
685 ExecutionErrorKind::WrittenObjectsTooLarge {
686 current_size: written_objects_size as u64,
687 max_size: lim as u64,
688 },
689 "Written objects size crossed hard limit",
690 )
691 .into());
692 }
693 };
694 }
695
696 Ok(())
697 }
698
699 fn gasless_withdrawal_reservations(
700 transaction_kind: &TransactionKind,
701 tx_ctx: &TxContext,
702 ) -> Option<BTreeMap<(SuiAddress, TypeTag), u64>> {
703 let TransactionKind::ProgrammableTransaction(pt) = transaction_kind else {
704 debug_fatal!("Gasless transaction must be a ProgrammableTransaction");
705 return None;
706 };
707 let sender = tx_ctx.sender();
708 let mut reservations = BTreeMap::<(SuiAddress, TypeTag), u64>::new();
709 for input in &pt.inputs {
710 let CallArg::FundsWithdrawal(fw) = input else {
711 continue;
712 };
713 let Some(coin_type) = fw.type_arg.get_balance_type_param() else {
714 debug_fatal!("expected Balance type for withdrawal");
715 continue;
716 };
717 let owner = match fw.withdraw_from {
718 WithdrawFrom::Sender => sender,
719 WithdrawFrom::Sponsor => {
720 debug_fatal!("WithdrawFrom::Sponsor is not expected in gasless transactions");
721 tx_ctx.sponsor().unwrap_or(sender)
722 }
723 };
724 let Reservation::MaxAmountU64(amount) = fw.reservation;
725 let entry = reservations.entry((owner, coin_type)).or_insert(0);
726 *entry = entry.saturating_add(amount);
727 }
728 Some(reservations)
729 }
730
731 #[instrument(level = "debug", skip_all)]
732 fn execution_loop<Mode: ExecutionMode>(
733 store: &dyn BackingStore,
734 temporary_store: &mut TemporaryStore<'_>,
735 transaction_kind: TransactionKind,
736 rewritten_inputs: Option<Vec<bool>>,
737 tx_ctx: Rc<RefCell<TxContext>>,
738 move_vm: &Arc<MoveRuntime>,
739 gas_charger: &mut GasCharger,
740 protocol_config: &ProtocolConfig,
741 metrics: Arc<ExecutionMetrics>,
742 trace_builder_opt: &mut Option<MoveTraceBuilder>,
743 ) -> ResultWithTimings<Mode::ExecutionResults, Mode::Error> {
744 let result = match transaction_kind {
745 TransactionKind::ChangeEpoch(change_epoch) => {
746 let builder = ProgrammableTransactionBuilder::new();
747 advance_epoch::<Mode>(
748 builder,
749 change_epoch,
750 temporary_store,
751 store,
752 tx_ctx,
753 move_vm,
754 gas_charger,
755 protocol_config,
756 metrics,
757 trace_builder_opt,
758 )
759 .map_err(|e| (e, vec![]))?;
760 Ok((Mode::empty_results(), vec![]))
761 }
762 TransactionKind::Genesis(GenesisTransaction { objects }) => {
763 if tx_ctx.borrow().epoch() != 0 {
764 panic!("BUG: Genesis Transactions can only be executed in epoch 0");
765 }
766
767 for genesis_object in objects {
768 match genesis_object {
769 sui_types::transaction::GenesisObject::RawObject { data, owner } => {
770 let object = ObjectInner {
771 data,
772 owner,
773 previous_transaction: tx_ctx.borrow().digest(),
774 storage_rebate: 0,
775 };
776 temporary_store.create_object(object.into());
777 }
778 }
779 }
780 Ok((Mode::empty_results(), vec![]))
781 }
782 TransactionKind::ConsensusCommitPrologue(prologue) => {
783 setup_consensus_commit::<Mode>(
784 prologue.commit_timestamp_ms,
785 temporary_store,
786 store,
787 tx_ctx,
788 move_vm,
789 gas_charger,
790 protocol_config,
791 metrics,
792 trace_builder_opt,
793 )
794 .expect("ConsensusCommitPrologue cannot fail");
795 Ok((Mode::empty_results(), vec![]))
796 }
797 TransactionKind::ConsensusCommitPrologueV2(prologue) => {
798 setup_consensus_commit::<Mode>(
799 prologue.commit_timestamp_ms,
800 temporary_store,
801 store,
802 tx_ctx,
803 move_vm,
804 gas_charger,
805 protocol_config,
806 metrics,
807 trace_builder_opt,
808 )
809 .expect("ConsensusCommitPrologueV2 cannot fail");
810 Ok((Mode::empty_results(), vec![]))
811 }
812 TransactionKind::ConsensusCommitPrologueV3(prologue) => {
813 setup_consensus_commit::<Mode>(
814 prologue.commit_timestamp_ms,
815 temporary_store,
816 store,
817 tx_ctx,
818 move_vm,
819 gas_charger,
820 protocol_config,
821 metrics,
822 trace_builder_opt,
823 )
824 .expect("ConsensusCommitPrologueV3 cannot fail");
825 Ok((Mode::empty_results(), vec![]))
826 }
827 TransactionKind::ConsensusCommitPrologueV4(prologue) => {
828 setup_consensus_commit::<Mode>(
829 prologue.commit_timestamp_ms,
830 temporary_store,
831 store,
832 tx_ctx,
833 move_vm,
834 gas_charger,
835 protocol_config,
836 metrics,
837 trace_builder_opt,
838 )
839 .expect("ConsensusCommitPrologue cannot fail");
840 Ok((Mode::empty_results(), vec![]))
841 }
842 TransactionKind::ProgrammableTransaction(pt) => SPT::execute::<Mode>(
843 protocol_config,
844 metrics,
845 move_vm,
846 temporary_store,
847 store.as_backing_package_store(),
848 tx_ctx,
849 gas_charger,
850 rewritten_inputs,
851 pt,
852 trace_builder_opt,
853 )
854 .map_err(|(e, timings)| (e.into(), timings)),
856 TransactionKind::ProgrammableSystemTransaction(pt) => {
857 SPT::execute::<execution_mode::System<Mode::Error>>(
858 protocol_config,
859 metrics,
860 move_vm,
861 temporary_store,
862 store.as_backing_package_store(),
863 tx_ctx,
864 gas_charger,
865 None,
866 pt,
867 trace_builder_opt,
868 )
869 .map_err(|(e, _)| (e.into(), vec![]))?;
871 Ok((Mode::empty_results(), vec![]))
872 }
873 TransactionKind::EndOfEpochTransaction(txns) => {
874 let mut builder = ProgrammableTransactionBuilder::new();
875 let len = txns.len();
876 for (i, tx) in txns.into_iter().enumerate() {
877 match tx {
878 EndOfEpochTransactionKind::ChangeEpoch(change_epoch) => {
879 assert_eq!(i, len - 1);
880 advance_epoch::<Mode>(
881 builder,
882 change_epoch,
883 temporary_store,
884 store,
885 tx_ctx,
886 move_vm,
887 gas_charger,
888 protocol_config,
889 metrics,
890 trace_builder_opt,
891 )
892 .map_err(|e| (e, vec![]))?;
893 return Ok((Mode::empty_results(), vec![]));
894 }
895 EndOfEpochTransactionKind::AuthenticatorStateCreate => {
896 assert!(protocol_config.enable_jwk_consensus_updates());
897 builder = setup_authenticator_state_create(builder);
898 }
899 EndOfEpochTransactionKind::AuthenticatorStateExpire(expire) => {
900 assert!(protocol_config.enable_jwk_consensus_updates());
901
902 builder = setup_authenticator_state_expire(builder, expire);
905 }
906 EndOfEpochTransactionKind::RandomnessStateCreate => {
907 assert!(protocol_config.random_beacon());
908 builder = setup_randomness_state_create(builder);
909 }
910 EndOfEpochTransactionKind::DenyListStateCreate => {
911 assert!(protocol_config.enable_coin_deny_list_v1());
912 builder = setup_coin_deny_list_state_create(builder);
913 }
914 EndOfEpochTransactionKind::BridgeStateCreate(chain_id) => {
915 assert!(protocol_config.enable_bridge());
916 builder = setup_bridge_create(builder, chain_id)
917 }
918 EndOfEpochTransactionKind::BridgeCommitteeInit(bridge_shared_version) => {
919 assert!(protocol_config.enable_bridge());
920 assert!(protocol_config.should_try_to_finalize_bridge_committee());
921 builder = setup_bridge_committee_update(builder, bridge_shared_version)
922 }
923 EndOfEpochTransactionKind::StoreExecutionTimeObservations(estimates) => {
924 if let PerObjectCongestionControlMode::ExecutionTimeEstimate(params) =
925 protocol_config.per_object_congestion_control_mode()
926 {
927 if let Some(chunk_size) = params.observations_chunk_size {
928 builder = setup_store_execution_time_estimates_v2(
929 builder,
930 estimates,
931 chunk_size as usize,
932 );
933 } else {
934 builder =
935 setup_store_execution_time_estimates(builder, estimates);
936 }
937 }
938 }
939 EndOfEpochTransactionKind::AccumulatorRootCreate => {
940 assert!(protocol_config.create_root_accumulator_object());
941 builder = setup_accumulator_root_create(builder);
942 }
943 EndOfEpochTransactionKind::WriteAccumulatorStorageCost(
944 write_storage_cost,
945 ) => {
946 assert!(protocol_config.enable_accumulators());
947 builder =
948 setup_write_accumulator_storage_cost(builder, &write_storage_cost);
949 }
950 EndOfEpochTransactionKind::CoinRegistryCreate => {
951 assert!(protocol_config.enable_coin_registry());
952 builder = setup_coin_registry_create(builder);
953 }
954 EndOfEpochTransactionKind::DisplayRegistryCreate => {
955 assert!(protocol_config.enable_display_registry());
956 builder = setup_display_registry_create(builder);
957 }
958 EndOfEpochTransactionKind::AddressAliasStateCreate => {
959 assert!(protocol_config.address_aliases());
960 builder = setup_address_alias_state_create(builder);
961 }
962 }
963 }
964 unreachable!(
965 "EndOfEpochTransactionKind::ChangeEpoch should be the last transaction in the list"
966 )
967 }
968 TransactionKind::AuthenticatorStateUpdate(auth_state_update) => {
969 setup_authenticator_state_update::<Mode>(
970 auth_state_update,
971 temporary_store,
972 store,
973 tx_ctx,
974 move_vm,
975 gas_charger,
976 protocol_config,
977 metrics,
978 trace_builder_opt,
979 )
980 .map_err(|e| (e, vec![]))?;
981 Ok((Mode::empty_results(), vec![]))
982 }
983 TransactionKind::RandomnessStateUpdate(randomness_state_update) => {
984 setup_randomness_state_update::<Mode>(
985 randomness_state_update,
986 temporary_store,
987 store,
988 tx_ctx,
989 move_vm,
990 gas_charger,
991 protocol_config,
992 metrics,
993 trace_builder_opt,
994 )
995 .map_err(|e| (e, vec![]))?;
996 Ok((Mode::empty_results(), vec![]))
997 }
998 }?;
999 temporary_store
1000 .check_execution_results_consistency()
1001 .map_err(|e| (e.into(), vec![]))?;
1003 Ok(result)
1004 }
1005
1006 fn mint_epoch_rewards_in_pt(
1007 builder: &mut ProgrammableTransactionBuilder,
1008 params: &AdvanceEpochParams,
1009 ) -> (Argument, Argument) {
1010 let storage_charge_arg = builder
1012 .input(CallArg::Pure(
1013 bcs::to_bytes(¶ms.storage_charge).unwrap(),
1014 ))
1015 .unwrap();
1016 let storage_rewards = builder.programmable_move_call(
1017 SUI_FRAMEWORK_PACKAGE_ID,
1018 BALANCE_MODULE_NAME.to_owned(),
1019 BALANCE_CREATE_REWARDS_FUNCTION_NAME.to_owned(),
1020 vec![GAS::type_tag()],
1021 vec![storage_charge_arg],
1022 );
1023
1024 let computation_charge_arg = builder
1026 .input(CallArg::Pure(
1027 bcs::to_bytes(¶ms.computation_charge).unwrap(),
1028 ))
1029 .unwrap();
1030 let computation_rewards = builder.programmable_move_call(
1031 SUI_FRAMEWORK_PACKAGE_ID,
1032 BALANCE_MODULE_NAME.to_owned(),
1033 BALANCE_CREATE_REWARDS_FUNCTION_NAME.to_owned(),
1034 vec![GAS::type_tag()],
1035 vec![computation_charge_arg],
1036 );
1037 (storage_rewards, computation_rewards)
1038 }
1039
1040 pub fn construct_advance_epoch_pt(
1041 mut builder: ProgrammableTransactionBuilder,
1042 params: &AdvanceEpochParams,
1043 ) -> Result<ProgrammableTransaction, ExecutionError> {
1044 let (storage_rewards, computation_rewards) = mint_epoch_rewards_in_pt(&mut builder, params);
1046
1047 let mut arguments = vec![storage_rewards, computation_rewards];
1049 let call_arg_arguments = vec![
1050 CallArg::SUI_SYSTEM_MUT,
1051 CallArg::Pure(bcs::to_bytes(¶ms.epoch).unwrap()),
1052 CallArg::Pure(bcs::to_bytes(¶ms.next_protocol_version.as_u64()).unwrap()),
1053 CallArg::Pure(bcs::to_bytes(¶ms.storage_rebate).unwrap()),
1054 CallArg::Pure(bcs::to_bytes(¶ms.non_refundable_storage_fee).unwrap()),
1055 CallArg::Pure(bcs::to_bytes(¶ms.storage_fund_reinvest_rate).unwrap()),
1056 CallArg::Pure(bcs::to_bytes(¶ms.reward_slashing_rate).unwrap()),
1057 CallArg::Pure(bcs::to_bytes(¶ms.epoch_start_timestamp_ms).unwrap()),
1058 ]
1059 .into_iter()
1060 .map(|a| builder.input(a))
1061 .collect::<Result<_, _>>();
1062
1063 assert_invariant!(
1064 call_arg_arguments.is_ok(),
1065 "Unable to generate args for advance_epoch transaction!"
1066 );
1067
1068 arguments.append(&mut call_arg_arguments.unwrap());
1069
1070 info!("Call arguments to advance_epoch transaction: {:?}", params);
1071
1072 let storage_rebates = builder.programmable_move_call(
1073 SUI_SYSTEM_PACKAGE_ID,
1074 SUI_SYSTEM_MODULE_NAME.to_owned(),
1075 ADVANCE_EPOCH_FUNCTION_NAME.to_owned(),
1076 vec![],
1077 arguments,
1078 );
1079
1080 builder.programmable_move_call(
1082 SUI_FRAMEWORK_PACKAGE_ID,
1083 BALANCE_MODULE_NAME.to_owned(),
1084 BALANCE_DESTROY_REBATES_FUNCTION_NAME.to_owned(),
1085 vec![GAS::type_tag()],
1086 vec![storage_rebates],
1087 );
1088 Ok(builder.finish())
1089 }
1090
1091 pub fn construct_advance_epoch_safe_mode_pt(
1092 params: &AdvanceEpochParams,
1093 ) -> Result<ProgrammableTransaction, ExecutionError> {
1094 let mut builder = ProgrammableTransactionBuilder::new();
1095 let (storage_rewards, computation_rewards) = mint_epoch_rewards_in_pt(&mut builder, params);
1097
1098 let mut arguments = vec![storage_rewards, computation_rewards];
1100
1101 let mut args = vec![
1102 CallArg::SUI_SYSTEM_MUT,
1103 CallArg::Pure(bcs::to_bytes(¶ms.epoch).unwrap()),
1104 CallArg::Pure(bcs::to_bytes(¶ms.next_protocol_version.as_u64()).unwrap()),
1105 CallArg::Pure(bcs::to_bytes(¶ms.storage_rebate).unwrap()),
1106 CallArg::Pure(bcs::to_bytes(¶ms.non_refundable_storage_fee).unwrap()),
1107 ];
1108
1109 args.push(CallArg::Pure(
1110 bcs::to_bytes(¶ms.epoch_start_timestamp_ms).unwrap(),
1111 ));
1112
1113 let call_arg_arguments = args
1114 .into_iter()
1115 .map(|a| builder.input(a))
1116 .collect::<Result<_, _>>();
1117
1118 assert_invariant!(
1119 call_arg_arguments.is_ok(),
1120 "Unable to generate args for advance_epoch transaction!"
1121 );
1122
1123 arguments.append(&mut call_arg_arguments.unwrap());
1124
1125 info!("Call arguments to advance_epoch transaction: {:?}", params);
1126
1127 builder.programmable_move_call(
1128 SUI_SYSTEM_PACKAGE_ID,
1129 SUI_SYSTEM_MODULE_NAME.to_owned(),
1130 ADVANCE_EPOCH_SAFE_MODE_FUNCTION_NAME.to_owned(),
1131 vec![],
1132 arguments,
1133 );
1134
1135 Ok(builder.finish())
1136 }
1137
1138 fn advance_epoch<Mode: ExecutionMode>(
1139 builder: ProgrammableTransactionBuilder,
1140 change_epoch: ChangeEpoch,
1141 temporary_store: &mut TemporaryStore<'_>,
1142 store: &dyn BackingStore,
1143 tx_ctx: Rc<RefCell<TxContext>>,
1144 move_vm: &Arc<MoveRuntime>,
1145 gas_charger: &mut GasCharger,
1146 protocol_config: &ProtocolConfig,
1147 metrics: Arc<ExecutionMetrics>,
1148 trace_builder_opt: &mut Option<MoveTraceBuilder>,
1149 ) -> Result<(), Mode::Error> {
1150 let params = AdvanceEpochParams {
1151 epoch: change_epoch.epoch,
1152 next_protocol_version: change_epoch.protocol_version,
1153 storage_charge: change_epoch.storage_charge,
1154 computation_charge: change_epoch.computation_charge,
1155 storage_rebate: change_epoch.storage_rebate,
1156 non_refundable_storage_fee: change_epoch.non_refundable_storage_fee,
1157 storage_fund_reinvest_rate: protocol_config.storage_fund_reinvest_rate(),
1158 reward_slashing_rate: protocol_config.reward_slashing_rate(),
1159 epoch_start_timestamp_ms: change_epoch.epoch_start_timestamp_ms,
1160 };
1161 let advance_epoch_pt = construct_advance_epoch_pt(builder, ¶ms)?;
1163 let result = SPT::execute::<execution_mode::System>(
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>(
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)?;
1329 Ok(())
1330 }
1331
1332 fn setup_authenticator_state_create(
1333 mut builder: ProgrammableTransactionBuilder,
1334 ) -> ProgrammableTransactionBuilder {
1335 builder
1336 .move_call(
1337 SUI_FRAMEWORK_ADDRESS.into(),
1338 AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1339 AUTHENTICATOR_STATE_CREATE_FUNCTION_NAME.to_owned(),
1340 vec![],
1341 vec![],
1342 )
1343 .expect("Unable to generate authenticator_state_create transaction!");
1344 builder
1345 }
1346
1347 fn setup_randomness_state_create(
1348 mut builder: ProgrammableTransactionBuilder,
1349 ) -> ProgrammableTransactionBuilder {
1350 builder
1351 .move_call(
1352 SUI_FRAMEWORK_ADDRESS.into(),
1353 RANDOMNESS_MODULE_NAME.to_owned(),
1354 RANDOMNESS_STATE_CREATE_FUNCTION_NAME.to_owned(),
1355 vec![],
1356 vec![],
1357 )
1358 .expect("Unable to generate randomness_state_create transaction!");
1359 builder
1360 }
1361
1362 fn setup_bridge_create(
1363 mut builder: ProgrammableTransactionBuilder,
1364 chain_id: ChainIdentifier,
1365 ) -> ProgrammableTransactionBuilder {
1366 let bridge_uid = builder
1367 .input(CallArg::Pure(UID::new(SUI_BRIDGE_OBJECT_ID).to_bcs_bytes()))
1368 .expect("Unable to create Bridge object UID!");
1369
1370 let bridge_chain_id = if chain_id == get_mainnet_chain_identifier() {
1371 BridgeChainId::SuiMainnet as u8
1372 } else if chain_id == get_testnet_chain_identifier() {
1373 BridgeChainId::SuiTestnet as u8
1374 } else {
1375 BridgeChainId::SuiCustom as u8
1377 };
1378
1379 let bridge_chain_id = builder.pure(bridge_chain_id).unwrap();
1380 builder.programmable_move_call(
1381 BRIDGE_ADDRESS.into(),
1382 BRIDGE_MODULE_NAME.to_owned(),
1383 BRIDGE_CREATE_FUNCTION_NAME.to_owned(),
1384 vec![],
1385 vec![bridge_uid, bridge_chain_id],
1386 );
1387 builder
1388 }
1389
1390 fn setup_bridge_committee_update(
1391 mut builder: ProgrammableTransactionBuilder,
1392 bridge_shared_version: SequenceNumber,
1393 ) -> ProgrammableTransactionBuilder {
1394 let bridge = builder
1395 .obj(ObjectArg::SharedObject {
1396 id: SUI_BRIDGE_OBJECT_ID,
1397 initial_shared_version: bridge_shared_version,
1398 mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1399 })
1400 .expect("Unable to create Bridge object arg!");
1401 let system_state = builder
1402 .obj(ObjectArg::SUI_SYSTEM_MUT)
1403 .expect("Unable to create System State object arg!");
1404
1405 let voting_power = builder.programmable_move_call(
1406 SUI_SYSTEM_PACKAGE_ID,
1407 SUI_SYSTEM_MODULE_NAME.to_owned(),
1408 ident_str!("validator_voting_powers").to_owned(),
1409 vec![],
1410 vec![system_state],
1411 );
1412
1413 let min_stake_participation_percentage = builder
1416 .input(CallArg::Pure(
1417 bcs::to_bytes(&BRIDGE_COMMITTEE_MINIMAL_VOTING_POWER).unwrap(),
1418 ))
1419 .unwrap();
1420
1421 builder.programmable_move_call(
1422 BRIDGE_ADDRESS.into(),
1423 BRIDGE_MODULE_NAME.to_owned(),
1424 BRIDGE_INIT_COMMITTEE_FUNCTION_NAME.to_owned(),
1425 vec![],
1426 vec![bridge, voting_power, min_stake_participation_percentage],
1427 );
1428 builder
1429 }
1430
1431 fn setup_authenticator_state_update<Mode: ExecutionMode>(
1432 update: AuthenticatorStateUpdate,
1433 temporary_store: &mut TemporaryStore<'_>,
1434 store: &dyn BackingStore,
1435 tx_ctx: Rc<RefCell<TxContext>>,
1436 move_vm: &Arc<MoveRuntime>,
1437 gas_charger: &mut GasCharger,
1438 protocol_config: &ProtocolConfig,
1439 metrics: Arc<ExecutionMetrics>,
1440 trace_builder_opt: &mut Option<MoveTraceBuilder>,
1441 ) -> Result<(), Mode::Error> {
1442 let pt = {
1443 let mut builder = ProgrammableTransactionBuilder::new();
1444 let res = builder.move_call(
1445 SUI_FRAMEWORK_ADDRESS.into(),
1446 AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1447 AUTHENTICATOR_STATE_UPDATE_FUNCTION_NAME.to_owned(),
1448 vec![],
1449 vec![
1450 CallArg::Object(ObjectArg::SharedObject {
1451 id: SUI_AUTHENTICATOR_STATE_OBJECT_ID,
1452 initial_shared_version: update.authenticator_obj_initial_shared_version,
1453 mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1454 }),
1455 CallArg::Pure(bcs::to_bytes(&update.new_active_jwks).unwrap()),
1456 ],
1457 );
1458 assert_invariant!(
1459 res.is_ok(),
1460 "Unable to generate authenticator_state_update transaction!"
1461 );
1462 builder.finish()
1463 };
1464 SPT::execute::<execution_mode::System>(
1465 protocol_config,
1466 metrics,
1467 move_vm,
1468 temporary_store,
1469 store.as_backing_package_store(),
1470 tx_ctx,
1471 gas_charger,
1472 None,
1473 pt,
1474 trace_builder_opt,
1475 )
1476 .map_err(|(e, _)| e)?;
1477 Ok(())
1478 }
1479
1480 fn setup_authenticator_state_expire(
1481 mut builder: ProgrammableTransactionBuilder,
1482 expire: AuthenticatorStateExpire,
1483 ) -> ProgrammableTransactionBuilder {
1484 builder
1485 .move_call(
1486 SUI_FRAMEWORK_ADDRESS.into(),
1487 AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1488 AUTHENTICATOR_STATE_EXPIRE_JWKS_FUNCTION_NAME.to_owned(),
1489 vec![],
1490 vec![
1491 CallArg::Object(ObjectArg::SharedObject {
1492 id: SUI_AUTHENTICATOR_STATE_OBJECT_ID,
1493 initial_shared_version: expire.authenticator_obj_initial_shared_version,
1494 mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1495 }),
1496 CallArg::Pure(bcs::to_bytes(&expire.min_epoch).unwrap()),
1497 ],
1498 )
1499 .expect("Unable to generate authenticator_state_expire transaction!");
1500 builder
1501 }
1502
1503 fn setup_randomness_state_update<Mode: ExecutionMode>(
1504 update: RandomnessStateUpdate,
1505 temporary_store: &mut TemporaryStore<'_>,
1506 store: &dyn BackingStore,
1507 tx_ctx: Rc<RefCell<TxContext>>,
1508 move_vm: &Arc<MoveRuntime>,
1509 gas_charger: &mut GasCharger,
1510 protocol_config: &ProtocolConfig,
1511 metrics: Arc<ExecutionMetrics>,
1512 trace_builder_opt: &mut Option<MoveTraceBuilder>,
1513 ) -> Result<(), Mode::Error> {
1514 let pt = {
1515 let mut builder = ProgrammableTransactionBuilder::new();
1516 let res = builder.move_call(
1517 SUI_FRAMEWORK_ADDRESS.into(),
1518 RANDOMNESS_MODULE_NAME.to_owned(),
1519 RANDOMNESS_STATE_UPDATE_FUNCTION_NAME.to_owned(),
1520 vec![],
1521 vec![
1522 CallArg::Object(ObjectArg::SharedObject {
1523 id: SUI_RANDOMNESS_STATE_OBJECT_ID,
1524 initial_shared_version: update.randomness_obj_initial_shared_version,
1525 mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1526 }),
1527 CallArg::Pure(bcs::to_bytes(&update.randomness_round).unwrap()),
1528 CallArg::Pure(bcs::to_bytes(&update.random_bytes).unwrap()),
1529 ],
1530 );
1531 assert_invariant!(
1532 res.is_ok(),
1533 "Unable to generate randomness_state_update transaction!"
1534 );
1535 builder.finish()
1536 };
1537 SPT::execute::<execution_mode::System>(
1538 protocol_config,
1539 metrics,
1540 move_vm,
1541 temporary_store,
1542 store.as_backing_package_store(),
1543 tx_ctx,
1544 gas_charger,
1545 None,
1546 pt,
1547 trace_builder_opt,
1548 )
1549 .map_err(|(e, _)| e)?;
1550 Ok(())
1551 }
1552
1553 fn setup_coin_deny_list_state_create(
1554 mut builder: ProgrammableTransactionBuilder,
1555 ) -> ProgrammableTransactionBuilder {
1556 builder
1557 .move_call(
1558 SUI_FRAMEWORK_ADDRESS.into(),
1559 DENY_LIST_MODULE.to_owned(),
1560 DENY_LIST_CREATE_FUNC.to_owned(),
1561 vec![],
1562 vec![],
1563 )
1564 .expect("Unable to generate coin_deny_list_create transaction!");
1565 builder
1566 }
1567
1568 fn setup_store_execution_time_estimates(
1569 mut builder: ProgrammableTransactionBuilder,
1570 estimates: StoredExecutionTimeObservations,
1571 ) -> ProgrammableTransactionBuilder {
1572 let system_state = builder.obj(ObjectArg::SUI_SYSTEM_MUT).unwrap();
1573 let estimates_bytes = bcs::to_bytes(&estimates).unwrap();
1576 let estimates_arg = builder.pure(estimates_bytes).unwrap();
1577 builder.programmable_move_call(
1578 SUI_SYSTEM_PACKAGE_ID,
1579 SUI_SYSTEM_MODULE_NAME.to_owned(),
1580 ident_str!("store_execution_time_estimates").to_owned(),
1581 vec![],
1582 vec![system_state, estimates_arg],
1583 );
1584 builder
1585 }
1586
1587 fn setup_store_execution_time_estimates_v2(
1588 mut builder: ProgrammableTransactionBuilder,
1589 estimates: StoredExecutionTimeObservations,
1590 chunk_size: usize,
1591 ) -> ProgrammableTransactionBuilder {
1592 let system_state = builder.obj(ObjectArg::SUI_SYSTEM_MUT).unwrap();
1593
1594 let estimate_chunks = estimates.chunk_observations(chunk_size);
1595
1596 let chunk_bytes: Vec<Vec<u8>> = estimate_chunks
1597 .into_iter()
1598 .map(|chunk| bcs::to_bytes(&chunk).unwrap())
1599 .collect();
1600
1601 let chunks_arg = builder.pure(chunk_bytes).unwrap();
1602
1603 builder.programmable_move_call(
1604 SUI_SYSTEM_PACKAGE_ID,
1605 SUI_SYSTEM_MODULE_NAME.to_owned(),
1606 ident_str!("store_execution_time_estimates_v2").to_owned(),
1607 vec![],
1608 vec![system_state, chunks_arg],
1609 );
1610 builder
1611 }
1612
1613 fn setup_accumulator_root_create(
1614 mut builder: ProgrammableTransactionBuilder,
1615 ) -> ProgrammableTransactionBuilder {
1616 builder
1617 .move_call(
1618 SUI_FRAMEWORK_ADDRESS.into(),
1619 ACCUMULATOR_ROOT_MODULE.to_owned(),
1620 ACCUMULATOR_ROOT_CREATE_FUNC.to_owned(),
1621 vec![],
1622 vec![],
1623 )
1624 .expect("Unable to generate accumulator_root_create transaction!");
1625 builder
1626 }
1627
1628 fn setup_write_accumulator_storage_cost(
1629 mut builder: ProgrammableTransactionBuilder,
1630 write_storage_cost: &WriteAccumulatorStorageCost,
1631 ) -> ProgrammableTransactionBuilder {
1632 let system_state = builder.obj(ObjectArg::SUI_SYSTEM_MUT).unwrap();
1633 let storage_cost_arg = builder.pure(write_storage_cost.storage_cost).unwrap();
1634 builder.programmable_move_call(
1635 SUI_SYSTEM_PACKAGE_ID,
1636 SUI_SYSTEM_MODULE_NAME.to_owned(),
1637 ident_str!("write_accumulator_storage_cost").to_owned(),
1638 vec![],
1639 vec![system_state, storage_cost_arg],
1640 );
1641 builder
1642 }
1643
1644 fn setup_coin_registry_create(
1645 mut builder: ProgrammableTransactionBuilder,
1646 ) -> ProgrammableTransactionBuilder {
1647 builder
1648 .move_call(
1649 SUI_FRAMEWORK_ADDRESS.into(),
1650 ident_str!("coin_registry").to_owned(),
1651 ident_str!("create").to_owned(),
1652 vec![],
1653 vec![],
1654 )
1655 .expect("Unable to generate coin_registry_create transaction!");
1656 builder
1657 }
1658
1659 fn setup_display_registry_create(
1660 mut builder: ProgrammableTransactionBuilder,
1661 ) -> ProgrammableTransactionBuilder {
1662 builder
1663 .move_call(
1664 SUI_FRAMEWORK_ADDRESS.into(),
1665 ident_str!("display_registry").to_owned(),
1666 ident_str!("create").to_owned(),
1667 vec![],
1668 vec![],
1669 )
1670 .expect("Unable to generate display_registry_create transaction!");
1671 builder
1672 }
1673
1674 fn setup_address_alias_state_create(
1675 mut builder: ProgrammableTransactionBuilder,
1676 ) -> ProgrammableTransactionBuilder {
1677 builder
1678 .move_call(
1679 SUI_FRAMEWORK_ADDRESS.into(),
1680 ident_str!("address_alias").to_owned(),
1681 ident_str!("create").to_owned(),
1682 vec![],
1683 vec![],
1684 )
1685 .expect("Unable to generate address_alias_state_create transaction!");
1686 builder
1687 }
1688}