sui_adapter_v3/
execution_engine.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4pub use checked::*;
5
6#[sui_macros::with_checked_arithmetic]
7mod checked {
8
9    use crate::execution_mode::{self, ExecutionMode};
10    use crate::execution_value::SuiResolver;
11    use crate::gas_charger::PaymentMethod;
12    use move_binary_format::CompiledModule;
13    use move_trace_format::format::MoveTraceBuilder;
14    use move_vm_runtime::move_vm::MoveVM;
15    use std::collections::BTreeMap;
16    use std::{cell::RefCell, collections::HashSet, rc::Rc, sync::Arc};
17    use sui_types::accumulator_root::{ACCUMULATOR_ROOT_CREATE_FUNC, ACCUMULATOR_ROOT_MODULE};
18    use sui_types::balance::{
19        BALANCE_CREATE_REWARDS_FUNCTION_NAME, BALANCE_DESTROY_REBATES_FUNCTION_NAME,
20        BALANCE_MODULE_NAME,
21    };
22    use sui_types::execution_params::ExecutionOrEarlyError;
23    use sui_types::gas_coin::GAS;
24    use sui_types::messages_checkpoint::CheckpointTimestamp;
25    use sui_types::metrics::ExecutionMetrics;
26    use sui_types::object::OBJECT_START_VERSION;
27    use sui_types::programmable_transaction_builder::ProgrammableTransactionBuilder;
28    use sui_types::randomness_state::{
29        RANDOMNESS_MODULE_NAME, RANDOMNESS_STATE_CREATE_FUNCTION_NAME,
30        RANDOMNESS_STATE_UPDATE_FUNCTION_NAME,
31    };
32    use sui_types::{BRIDGE_ADDRESS, SUI_BRIDGE_OBJECT_ID, SUI_RANDOMNESS_STATE_OBJECT_ID};
33    use tracing::{info, instrument, trace, warn};
34
35    use crate::adapter::new_move_vm;
36    use crate::programmable_transactions;
37    use crate::sui_types::gas::SuiGasStatusAPI;
38    use crate::type_layout_resolver::TypeLayoutResolver;
39    use crate::{gas_charger::GasCharger, temporary_store::TemporaryStore};
40    use move_core_types::ident_str;
41    use sui_move_natives::all_natives;
42    use sui_protocol_config::{
43        LimitThresholdCrossed, PerObjectCongestionControlMode, ProtocolConfig, check_limit_by_meter,
44    };
45    use sui_types::authenticator_state::{
46        AUTHENTICATOR_STATE_CREATE_FUNCTION_NAME, AUTHENTICATOR_STATE_EXPIRE_JWKS_FUNCTION_NAME,
47        AUTHENTICATOR_STATE_MODULE_NAME, AUTHENTICATOR_STATE_UPDATE_FUNCTION_NAME,
48    };
49    use sui_types::base_types::SequenceNumber;
50    use sui_types::bridge::BRIDGE_COMMITTEE_MINIMAL_VOTING_POWER;
51    use sui_types::bridge::{
52        BRIDGE_CREATE_FUNCTION_NAME, BRIDGE_INIT_COMMITTEE_FUNCTION_NAME, BRIDGE_MODULE_NAME,
53        BridgeChainId,
54    };
55    use sui_types::clock::{CLOCK_MODULE_NAME, CONSENSUS_COMMIT_PROLOGUE_FUNCTION_NAME};
56    use sui_types::committee::EpochId;
57    use sui_types::deny_list_v1::{DENY_LIST_CREATE_FUNC, DENY_LIST_MODULE};
58    use sui_types::digests::{
59        ChainIdentifier, get_mainnet_chain_identifier, get_testnet_chain_identifier,
60    };
61    use sui_types::effects::TransactionEffects;
62    use sui_types::error::{ExecutionError, ExecutionErrorTrait};
63    use sui_types::execution::{ExecutionTiming, ResultWithTimings};
64    use sui_types::execution_status::{ExecutionErrorKind, ExecutionStatus};
65    use sui_types::gas::GasCostSummary;
66    use sui_types::gas::SuiGasStatus;
67    use sui_types::id::UID;
68    use sui_types::inner_temporary_store::InnerTemporaryStore;
69    use sui_types::storage::BackingStore;
70    #[cfg(msim)]
71    use sui_types::sui_system_state::advance_epoch_result_injection::maybe_modify_result;
72    use sui_types::sui_system_state::{ADVANCE_EPOCH_SAFE_MODE_FUNCTION_NAME, AdvanceEpochParams};
73    use sui_types::transaction::{
74        Argument, AuthenticatorStateExpire, AuthenticatorStateUpdate, CallArg, ChangeEpoch,
75        Command, EndOfEpochTransactionKind, GasData, GenesisTransaction, ObjectArg,
76        ProgrammableTransaction, StoredExecutionTimeObservations, TransactionKind,
77        WriteAccumulatorStorageCost, is_gas_paid_from_address_balance,
78    };
79    use sui_types::transaction::{CheckedInputObjects, RandomnessStateUpdate};
80    use sui_types::{
81        SUI_AUTHENTICATOR_STATE_OBJECT_ID, SUI_FRAMEWORK_ADDRESS, SUI_FRAMEWORK_PACKAGE_ID,
82        SUI_SYSTEM_PACKAGE_ID,
83        base_types::{SuiAddress, TransactionDigest, TxContext},
84        object::{Object, ObjectInner},
85        sui_system_state::{ADVANCE_EPOCH_FUNCTION_NAME, SUI_SYSTEM_MODULE_NAME},
86    };
87
88    #[instrument(name = "tx_execute_to_effects", level = "debug", skip_all)]
89    pub fn execute_transaction_to_effects<Mode: ExecutionMode>(
90        store: &dyn BackingStore,
91        input_objects: CheckedInputObjects,
92        gas_data: GasData,
93        gas_status: SuiGasStatus,
94        transaction_kind: TransactionKind,
95        transaction_signer: SuiAddress,
96        transaction_digest: TransactionDigest,
97        move_vm: &Arc<MoveVM>,
98        epoch_id: &EpochId,
99        epoch_timestamp_ms: u64,
100        protocol_config: &ProtocolConfig,
101        metrics: Arc<ExecutionMetrics>,
102        enable_expensive_checks: bool,
103        execution_params: ExecutionOrEarlyError,
104        trace_builder_opt: &mut Option<MoveTraceBuilder>,
105    ) -> (
106        InnerTemporaryStore,
107        SuiGasStatus,
108        TransactionEffects,
109        Vec<ExecutionTiming>,
110        Result<Mode::ExecutionResults, ExecutionError>,
111    ) {
112        let input_objects = input_objects.into_inner();
113        let mutable_inputs = if enable_expensive_checks {
114            input_objects.all_mutable_inputs().keys().copied().collect()
115        } else {
116            HashSet::new()
117        };
118        let shared_object_refs = input_objects.filter_shared_objects();
119        let receiving_objects = transaction_kind.receiving_objects();
120        let mut transaction_dependencies = input_objects.transaction_dependencies();
121
122        let mut temporary_store = TemporaryStore::new(
123            store,
124            input_objects,
125            receiving_objects,
126            transaction_digest,
127            protocol_config,
128            *epoch_id,
129        );
130
131        let sponsor = {
132            let gas_owner = gas_data.owner;
133            if gas_owner == transaction_signer {
134                None
135            } else {
136                Some(gas_owner)
137            }
138        };
139        let gas_price = gas_status.gas_price();
140        let rgp = gas_status.reference_gas_price();
141
142        let payment_method = if gas_data.is_unmetered() || transaction_kind.is_system_tx() {
143            PaymentMethod::Unmetered
144        } else if is_gas_paid_from_address_balance(&gas_data, &transaction_kind) {
145            PaymentMethod::AddressBalance(gas_data.owner)
146        } else {
147            PaymentMethod::Coins(gas_data.payment)
148        };
149
150        let mut gas_charger = GasCharger::new(
151            transaction_digest,
152            payment_method,
153            gas_status,
154            protocol_config,
155        );
156
157        let tx_ctx = TxContext::new_from_components(
158            &transaction_signer,
159            &transaction_digest,
160            epoch_id,
161            epoch_timestamp_ms,
162            rgp,
163            gas_price,
164            gas_data.budget,
165            sponsor,
166            protocol_config,
167        );
168        let tx_ctx = Rc::new(RefCell::new(tx_ctx));
169
170        let is_epoch_change = transaction_kind.is_end_of_epoch_tx();
171
172        let (gas_cost_summary, execution_result, timings) = execute_transaction::<Mode>(
173            store,
174            &mut temporary_store,
175            transaction_kind,
176            &mut gas_charger,
177            tx_ctx,
178            move_vm,
179            protocol_config,
180            metrics,
181            enable_expensive_checks,
182            execution_params,
183            trace_builder_opt,
184        );
185
186        let status = if let Err(error) = &execution_result {
187            ExecutionStatus::new_failure(error.to_execution_failure())
188        } else {
189            ExecutionStatus::Success
190        };
191
192        #[skip_checked_arithmetic]
193        trace!(
194            tx_digest = ?transaction_digest,
195            computation_gas_cost = gas_cost_summary.computation_cost,
196            storage_gas_cost = gas_cost_summary.storage_cost,
197            storage_gas_rebate = gas_cost_summary.storage_rebate,
198            "Finished execution of transaction with status {:?}",
199            status
200        );
201
202        // Genesis writes a special digest to indicate that an object was created during
203        // genesis and not written by any normal transaction - remove that from the
204        // dependencies
205        transaction_dependencies.remove(&TransactionDigest::genesis_marker());
206
207        if enable_expensive_checks && !Mode::allow_arbitrary_function_calls() {
208            temporary_store
209                .check_ownership_invariants(
210                    &transaction_signer,
211                    &sponsor,
212                    &mut gas_charger,
213                    &mutable_inputs,
214                    is_epoch_change,
215                )
216                .unwrap()
217        } // else, in dev inspect mode and anything goes--don't check
218
219        let (inner, effects) = temporary_store.into_effects(
220            shared_object_refs,
221            &transaction_digest,
222            transaction_dependencies,
223            gas_cost_summary,
224            status,
225            &mut gas_charger,
226            *epoch_id,
227        );
228
229        (
230            inner,
231            gas_charger.into_gas_status(),
232            effects,
233            timings,
234            execution_result,
235        )
236    }
237
238    pub fn execute_genesis_state_update(
239        store: &dyn BackingStore,
240        protocol_config: &ProtocolConfig,
241        metrics: Arc<ExecutionMetrics>,
242        move_vm: &Arc<MoveVM>,
243        tx_context: Rc<RefCell<TxContext>>,
244        input_objects: CheckedInputObjects,
245        pt: ProgrammableTransaction,
246    ) -> Result<InnerTemporaryStore, ExecutionError> {
247        let input_objects = input_objects.into_inner();
248        let mut temporary_store = TemporaryStore::new(
249            store,
250            input_objects,
251            vec![],
252            tx_context.borrow().digest(),
253            protocol_config,
254            0,
255        );
256        let mut gas_charger = GasCharger::new_unmetered(tx_context.borrow().digest());
257        programmable_transactions::execution::execute::<execution_mode::Genesis>(
258            protocol_config,
259            metrics,
260            move_vm,
261            &mut temporary_store,
262            store.as_backing_package_store(),
263            tx_context,
264            &mut gas_charger,
265            None,
266            pt,
267            &mut None,
268        )
269        .map_err(|(e, _)| e)?;
270        temporary_store.update_object_version_and_prev_tx();
271        Ok(temporary_store.into_inner(BTreeMap::new()))
272    }
273
274    #[instrument(name = "tx_execute", level = "debug", skip_all)]
275    fn execute_transaction<Mode: ExecutionMode>(
276        store: &dyn BackingStore,
277        temporary_store: &mut TemporaryStore<'_>,
278        transaction_kind: TransactionKind,
279        gas_charger: &mut GasCharger,
280        tx_ctx: Rc<RefCell<TxContext>>,
281        move_vm: &Arc<MoveVM>,
282        protocol_config: &ProtocolConfig,
283        metrics: Arc<ExecutionMetrics>,
284        enable_expensive_checks: bool,
285        execution_params: ExecutionOrEarlyError,
286        trace_builder_opt: &mut Option<MoveTraceBuilder>,
287    ) -> (
288        GasCostSummary,
289        Result<Mode::ExecutionResults, ExecutionError>,
290        Vec<ExecutionTiming>,
291    ) {
292        gas_charger.smash_gas(temporary_store);
293
294        // At this point no charges have been applied yet
295        debug_assert!(
296            gas_charger.no_charges(),
297            "No gas charges must be applied yet"
298        );
299
300        let is_genesis_tx = matches!(transaction_kind, TransactionKind::Genesis(_));
301        let advance_epoch_gas_summary = transaction_kind.get_advance_epoch_tx_gas_summary();
302        let digest = tx_ctx.borrow().digest();
303
304        // We must charge object read here during transaction execution, because if this fails
305        // we must still ensure an effect is committed and all objects versions incremented
306        let result = gas_charger.charge_input_objects(temporary_store);
307
308        let result: ResultWithTimings<Mode::ExecutionResults, ExecutionError> =
309            result.map_err(|e| (e, vec![])).and_then(
310                |()| -> ResultWithTimings<Mode::ExecutionResults, ExecutionError> {
311                    let mut execution_result: ResultWithTimings<
312                        Mode::ExecutionResults,
313                        ExecutionError,
314                    > = match execution_params {
315                        ExecutionOrEarlyError::Err(early_execution_error) => {
316                            Err((ExecutionError::new(early_execution_error, None), vec![]))
317                        }
318                        ExecutionOrEarlyError::Ok(()) => execution_loop::<Mode>(
319                            store,
320                            temporary_store,
321                            transaction_kind,
322                            tx_ctx,
323                            move_vm,
324                            gas_charger,
325                            protocol_config,
326                            metrics.clone(),
327                            trace_builder_opt,
328                        ),
329                    };
330
331                    let meter_check = check_meter_limit(
332                        temporary_store,
333                        gas_charger,
334                        protocol_config,
335                        metrics.clone(),
336                    );
337                    if let Err(e) = meter_check {
338                        execution_result = Err((e, vec![]));
339                    }
340
341                    if execution_result.is_ok() {
342                        let gas_check = check_written_objects_limit(
343                            temporary_store,
344                            gas_charger,
345                            protocol_config,
346                            metrics,
347                        );
348                        if let Err(e) = gas_check {
349                            execution_result = Err((e, vec![]));
350                        }
351                    }
352
353                    execution_result
354                },
355            );
356
357        let (mut result, timings) = match result {
358            Ok((r, t)) => (Ok(r), t),
359            Err((e, t)) => (Err(e), t),
360        };
361
362        let cost_summary = gas_charger.charge_gas(temporary_store, &mut result);
363        // For advance epoch transaction, we need to provide epoch rewards and rebates as extra
364        // information provided to check_sui_conserved, because we mint rewards, and burn
365        // the rebates. We also need to pass in the unmetered_storage_rebate because storage
366        // rebate is not reflected in the storage_rebate of gas summary. This is a bit confusing.
367        // We could probably clean up the code a bit.
368        // Put all the storage rebate accumulated in the system transaction
369        // to the 0x5 object so that it's not lost.
370        temporary_store.conserve_unmetered_storage_rebate(gas_charger.unmetered_storage_rebate());
371
372        if let Err(e) = run_conservation_checks::<Mode>(
373            temporary_store,
374            gas_charger,
375            digest,
376            move_vm,
377            protocol_config.simple_conservation_checks(),
378            enable_expensive_checks,
379            &cost_summary,
380            is_genesis_tx,
381            advance_epoch_gas_summary,
382        ) {
383            // FIXME: we cannot fail the transaction if this is an epoch change transaction.
384            result = Err(e);
385        }
386
387        (cost_summary, result, timings)
388    }
389
390    #[instrument(name = "run_conservation_checks", level = "debug", skip_all)]
391    fn run_conservation_checks<Mode: ExecutionMode>(
392        temporary_store: &mut TemporaryStore<'_>,
393        gas_charger: &mut GasCharger,
394        tx_digest: TransactionDigest,
395        move_vm: &Arc<MoveVM>,
396        simple_conservation_checks: bool,
397        enable_expensive_checks: bool,
398        cost_summary: &GasCostSummary,
399        is_genesis_tx: bool,
400        advance_epoch_gas_summary: Option<(u64, u64)>,
401    ) -> Result<(), ExecutionError> {
402        let mut result: std::result::Result<(), sui_types::error::ExecutionError> = Ok(());
403        if !is_genesis_tx && !Mode::skip_conservation_checks() {
404            // ensure that this transaction did not create or destroy SUI, try to recover if the check fails
405            let conservation_result = {
406                temporary_store
407                    .check_sui_conserved(simple_conservation_checks, cost_summary)
408                    .and_then(|()| {
409                        if enable_expensive_checks {
410                            // ensure that this transaction did not create or destroy SUI, try to recover if the check fails
411                            let mut layout_resolver =
412                                TypeLayoutResolver::new(move_vm, Box::new(&*temporary_store));
413                            temporary_store.check_sui_conserved_expensive(
414                                cost_summary,
415                                advance_epoch_gas_summary,
416                                &mut layout_resolver,
417                            )
418                        } else {
419                            Ok(())
420                        }
421                    })
422            };
423            if let Err(conservation_err) = conservation_result {
424                // conservation violated. try to avoid panic by dumping all writes, charging for gas, re-checking
425                // conservation, and surfacing an aborted transaction with an invariant violation if all of that works
426                result = Err(conservation_err);
427                gas_charger.reset(temporary_store);
428                gas_charger.charge_gas(temporary_store, &mut result);
429                // check conservation once more
430                if let Err(recovery_err) = {
431                    temporary_store
432                        .check_sui_conserved(simple_conservation_checks, cost_summary)
433                        .and_then(|()| {
434                            if enable_expensive_checks {
435                                // ensure that this transaction did not create or destroy SUI, try to recover if the check fails
436                                let mut layout_resolver =
437                                    TypeLayoutResolver::new(move_vm, Box::new(&*temporary_store));
438                                temporary_store.check_sui_conserved_expensive(
439                                    cost_summary,
440                                    advance_epoch_gas_summary,
441                                    &mut layout_resolver,
442                                )
443                            } else {
444                                Ok(())
445                            }
446                        })
447                } {
448                    // if we still fail, it's a problem with gas
449                    // charging that happens even in the "aborted" case--no other option but panic.
450                    // we will create or destroy SUI otherwise
451                    panic!(
452                        "SUI conservation fail in tx block {}: {}\nGas status is {}\nTx was ",
453                        tx_digest,
454                        recovery_err,
455                        gas_charger.summary()
456                    )
457                }
458            }
459        } // else, we're in the genesis transaction which mints the SUI supply, and hence does not satisfy SUI conservation, or
460        // we're in the non-production dev inspect mode which allows us to violate conservation
461        result
462    }
463
464    #[instrument(name = "check_meter_limit", level = "debug", skip_all)]
465    fn check_meter_limit(
466        temporary_store: &mut TemporaryStore<'_>,
467        gas_charger: &mut GasCharger,
468        protocol_config: &ProtocolConfig,
469        metrics: Arc<ExecutionMetrics>,
470    ) -> Result<(), ExecutionError> {
471        let effects_estimated_size = temporary_store.estimate_effects_size_upperbound();
472
473        // Check if a limit threshold was crossed.
474        // For metered transactions, there is not soft limit.
475        // For system transactions, we allow a soft limit with alerting, and a hard limit where we terminate
476        match check_limit_by_meter!(
477            !gas_charger.is_unmetered(),
478            effects_estimated_size,
479            protocol_config.max_serialized_tx_effects_size_bytes(),
480            protocol_config.max_serialized_tx_effects_size_bytes_system_tx(),
481            metrics.limits_metrics.excessive_estimated_effects_size
482        ) {
483            LimitThresholdCrossed::None => Ok(()),
484            LimitThresholdCrossed::Soft(_, limit) => {
485                warn!(
486                    effects_estimated_size = effects_estimated_size,
487                    soft_limit = limit,
488                    "Estimated transaction effects size crossed soft limit",
489                );
490                Ok(())
491            }
492            LimitThresholdCrossed::Hard(_, lim) => Err(ExecutionError::new_with_source(
493                ExecutionErrorKind::EffectsTooLarge {
494                    current_size: effects_estimated_size as u64,
495                    max_size: lim as u64,
496                },
497                "Transaction effects are too large",
498            )),
499        }
500    }
501
502    #[instrument(name = "check_written_objects_limit", level = "debug", skip_all)]
503    fn check_written_objects_limit(
504        temporary_store: &mut TemporaryStore<'_>,
505        gas_charger: &mut GasCharger,
506        protocol_config: &ProtocolConfig,
507        metrics: Arc<ExecutionMetrics>,
508    ) -> Result<(), ExecutionError> {
509        if let (Some(normal_lim), Some(system_lim)) = (
510            protocol_config.max_size_written_objects_as_option(),
511            protocol_config.max_size_written_objects_system_tx_as_option(),
512        ) {
513            let written_objects_size = temporary_store.written_objects_size();
514
515            match check_limit_by_meter!(
516                !gas_charger.is_unmetered(),
517                written_objects_size,
518                normal_lim,
519                system_lim,
520                metrics.limits_metrics.excessive_written_objects_size
521            ) {
522                LimitThresholdCrossed::None => (),
523                LimitThresholdCrossed::Soft(_, limit) => {
524                    warn!(
525                        written_objects_size = written_objects_size,
526                        soft_limit = limit,
527                        "Written objects size crossed soft limit",
528                    )
529                }
530                LimitThresholdCrossed::Hard(_, lim) => {
531                    return Err(ExecutionError::new_with_source(
532                        ExecutionErrorKind::WrittenObjectsTooLarge {
533                            current_size: written_objects_size as u64,
534                            max_size: lim as u64,
535                        },
536                        "Written objects size crossed hard limit",
537                    ));
538                }
539            };
540        }
541
542        Ok(())
543    }
544
545    #[instrument(level = "debug", skip_all)]
546    fn execution_loop<Mode: ExecutionMode>(
547        store: &dyn BackingStore,
548        temporary_store: &mut TemporaryStore<'_>,
549        transaction_kind: TransactionKind,
550        tx_ctx: Rc<RefCell<TxContext>>,
551        move_vm: &Arc<MoveVM>,
552        gas_charger: &mut GasCharger,
553        protocol_config: &ProtocolConfig,
554        metrics: Arc<ExecutionMetrics>,
555        trace_builder_opt: &mut Option<MoveTraceBuilder>,
556    ) -> ResultWithTimings<Mode::ExecutionResults, ExecutionError> {
557        let result = match transaction_kind {
558            TransactionKind::ChangeEpoch(change_epoch) => {
559                let builder = ProgrammableTransactionBuilder::new();
560                advance_epoch(
561                    builder,
562                    change_epoch,
563                    temporary_store,
564                    store,
565                    tx_ctx,
566                    move_vm,
567                    gas_charger,
568                    protocol_config,
569                    metrics,
570                    trace_builder_opt,
571                )
572                .map_err(|e| (e, vec![]))?;
573                Ok((Mode::empty_results(), vec![]))
574            }
575            TransactionKind::Genesis(GenesisTransaction { objects }) => {
576                if tx_ctx.borrow().epoch() != 0 {
577                    panic!("BUG: Genesis Transactions can only be executed in epoch 0");
578                }
579
580                for genesis_object in objects {
581                    match genesis_object {
582                        sui_types::transaction::GenesisObject::RawObject { data, owner } => {
583                            let object = ObjectInner {
584                                data,
585                                owner,
586                                previous_transaction: tx_ctx.borrow().digest(),
587                                storage_rebate: 0,
588                            };
589                            temporary_store.create_object(object.into());
590                        }
591                    }
592                }
593                Ok((Mode::empty_results(), vec![]))
594            }
595            TransactionKind::ConsensusCommitPrologue(prologue) => {
596                setup_consensus_commit(
597                    prologue.commit_timestamp_ms,
598                    temporary_store,
599                    store,
600                    tx_ctx,
601                    move_vm,
602                    gas_charger,
603                    protocol_config,
604                    metrics,
605                    trace_builder_opt,
606                )
607                .expect("ConsensusCommitPrologue cannot fail");
608                Ok((Mode::empty_results(), vec![]))
609            }
610            TransactionKind::ConsensusCommitPrologueV2(prologue) => {
611                setup_consensus_commit(
612                    prologue.commit_timestamp_ms,
613                    temporary_store,
614                    store,
615                    tx_ctx,
616                    move_vm,
617                    gas_charger,
618                    protocol_config,
619                    metrics,
620                    trace_builder_opt,
621                )
622                .expect("ConsensusCommitPrologueV2 cannot fail");
623                Ok((Mode::empty_results(), vec![]))
624            }
625            TransactionKind::ConsensusCommitPrologueV3(prologue) => {
626                setup_consensus_commit(
627                    prologue.commit_timestamp_ms,
628                    temporary_store,
629                    store,
630                    tx_ctx,
631                    move_vm,
632                    gas_charger,
633                    protocol_config,
634                    metrics,
635                    trace_builder_opt,
636                )
637                .expect("ConsensusCommitPrologueV3 cannot fail");
638                Ok((Mode::empty_results(), vec![]))
639            }
640            TransactionKind::ConsensusCommitPrologueV4(prologue) => {
641                setup_consensus_commit(
642                    prologue.commit_timestamp_ms,
643                    temporary_store,
644                    store,
645                    tx_ctx,
646                    move_vm,
647                    gas_charger,
648                    protocol_config,
649                    metrics,
650                    trace_builder_opt,
651                )
652                .expect("ConsensusCommitPrologue cannot fail");
653                Ok((Mode::empty_results(), vec![]))
654            }
655            TransactionKind::ProgrammableTransaction(pt) => {
656                programmable_transactions::execution::execute::<Mode>(
657                    protocol_config,
658                    metrics,
659                    move_vm,
660                    temporary_store,
661                    store.as_backing_package_store(),
662                    tx_ctx,
663                    gas_charger,
664                    None,
665                    pt,
666                    trace_builder_opt,
667                )
668            }
669            TransactionKind::ProgrammableSystemTransaction(pt) => {
670                programmable_transactions::execution::execute::<execution_mode::System>(
671                    protocol_config,
672                    metrics,
673                    move_vm,
674                    temporary_store,
675                    store.as_backing_package_store(),
676                    tx_ctx,
677                    gas_charger,
678                    None,
679                    pt,
680                    trace_builder_opt,
681                )?;
682                Ok((Mode::empty_results(), vec![]))
683            }
684            TransactionKind::EndOfEpochTransaction(txns) => {
685                let mut builder = ProgrammableTransactionBuilder::new();
686                let len = txns.len();
687                for (i, tx) in txns.into_iter().enumerate() {
688                    match tx {
689                        EndOfEpochTransactionKind::ChangeEpoch(change_epoch) => {
690                            assert_eq!(i, len - 1);
691                            advance_epoch(
692                                builder,
693                                change_epoch,
694                                temporary_store,
695                                store,
696                                tx_ctx,
697                                move_vm,
698                                gas_charger,
699                                protocol_config,
700                                metrics,
701                                trace_builder_opt,
702                            )
703                            .map_err(|e| (e, vec![]))?;
704                            return Ok((Mode::empty_results(), vec![]));
705                        }
706                        EndOfEpochTransactionKind::AuthenticatorStateCreate => {
707                            assert!(protocol_config.enable_jwk_consensus_updates());
708                            builder = setup_authenticator_state_create(builder);
709                        }
710                        EndOfEpochTransactionKind::AuthenticatorStateExpire(expire) => {
711                            assert!(protocol_config.enable_jwk_consensus_updates());
712
713                            // TODO: it would be nice if a failure of this function didn't cause
714                            // safe mode.
715                            builder = setup_authenticator_state_expire(builder, expire);
716                        }
717                        EndOfEpochTransactionKind::RandomnessStateCreate => {
718                            assert!(protocol_config.random_beacon());
719                            builder = setup_randomness_state_create(builder);
720                        }
721                        EndOfEpochTransactionKind::DenyListStateCreate => {
722                            assert!(protocol_config.enable_coin_deny_list_v1());
723                            builder = setup_coin_deny_list_state_create(builder);
724                        }
725                        EndOfEpochTransactionKind::BridgeStateCreate(chain_id) => {
726                            assert!(protocol_config.enable_bridge());
727                            builder = setup_bridge_create(builder, chain_id)
728                        }
729                        EndOfEpochTransactionKind::BridgeCommitteeInit(bridge_shared_version) => {
730                            assert!(protocol_config.enable_bridge());
731                            assert!(protocol_config.should_try_to_finalize_bridge_committee());
732                            builder = setup_bridge_committee_update(builder, bridge_shared_version)
733                        }
734                        EndOfEpochTransactionKind::StoreExecutionTimeObservations(estimates) => {
735                            if let PerObjectCongestionControlMode::ExecutionTimeEstimate(params) =
736                                protocol_config.per_object_congestion_control_mode()
737                            {
738                                if let Some(chunk_size) = params.observations_chunk_size {
739                                    builder = setup_store_execution_time_estimates_v2(
740                                        builder,
741                                        estimates,
742                                        chunk_size as usize,
743                                    );
744                                } else {
745                                    builder =
746                                        setup_store_execution_time_estimates(builder, estimates);
747                                }
748                            }
749                        }
750                        EndOfEpochTransactionKind::AccumulatorRootCreate => {
751                            assert!(protocol_config.create_root_accumulator_object());
752                            builder = setup_accumulator_root_create(builder);
753                        }
754                        EndOfEpochTransactionKind::WriteAccumulatorStorageCost(
755                            write_storage_cost,
756                        ) => {
757                            assert!(protocol_config.enable_accumulators());
758                            builder =
759                                setup_write_accumulator_storage_cost(builder, &write_storage_cost);
760                        }
761                        EndOfEpochTransactionKind::CoinRegistryCreate => {
762                            assert!(protocol_config.enable_coin_registry());
763                            builder = setup_coin_registry_create(builder);
764                        }
765                        EndOfEpochTransactionKind::DisplayRegistryCreate => {
766                            assert!(protocol_config.enable_display_registry());
767                            builder = setup_display_registry_create(builder);
768                        }
769                        EndOfEpochTransactionKind::AddressAliasStateCreate => {
770                            assert!(protocol_config.address_aliases());
771                            builder = setup_address_alias_state_create(builder);
772                        }
773                    }
774                }
775                unreachable!(
776                    "EndOfEpochTransactionKind::ChangeEpoch should be the last transaction in the list"
777                )
778            }
779            TransactionKind::AuthenticatorStateUpdate(auth_state_update) => {
780                setup_authenticator_state_update(
781                    auth_state_update,
782                    temporary_store,
783                    store,
784                    tx_ctx,
785                    move_vm,
786                    gas_charger,
787                    protocol_config,
788                    metrics,
789                    trace_builder_opt,
790                )
791                .map_err(|e| (e, vec![]))?;
792                Ok((Mode::empty_results(), vec![]))
793            }
794            TransactionKind::RandomnessStateUpdate(randomness_state_update) => {
795                setup_randomness_state_update(
796                    randomness_state_update,
797                    temporary_store,
798                    store,
799                    tx_ctx,
800                    move_vm,
801                    gas_charger,
802                    protocol_config,
803                    metrics,
804                    trace_builder_opt,
805                )
806                .map_err(|e| (e, vec![]))?;
807                Ok((Mode::empty_results(), vec![]))
808            }
809        }?;
810        temporary_store
811            .check_execution_results_consistency()
812            .map_err(|e| (e, vec![]))?;
813        Ok(result)
814    }
815
816    fn mint_epoch_rewards_in_pt(
817        builder: &mut ProgrammableTransactionBuilder,
818        params: &AdvanceEpochParams,
819    ) -> (Argument, Argument) {
820        // Create storage rewards.
821        let storage_charge_arg = builder
822            .input(CallArg::Pure(
823                bcs::to_bytes(&params.storage_charge).unwrap(),
824            ))
825            .unwrap();
826        let storage_rewards = builder.programmable_move_call(
827            SUI_FRAMEWORK_PACKAGE_ID,
828            BALANCE_MODULE_NAME.to_owned(),
829            BALANCE_CREATE_REWARDS_FUNCTION_NAME.to_owned(),
830            vec![GAS::type_tag()],
831            vec![storage_charge_arg],
832        );
833
834        // Create computation rewards.
835        let computation_charge_arg = builder
836            .input(CallArg::Pure(
837                bcs::to_bytes(&params.computation_charge).unwrap(),
838            ))
839            .unwrap();
840        let computation_rewards = builder.programmable_move_call(
841            SUI_FRAMEWORK_PACKAGE_ID,
842            BALANCE_MODULE_NAME.to_owned(),
843            BALANCE_CREATE_REWARDS_FUNCTION_NAME.to_owned(),
844            vec![GAS::type_tag()],
845            vec![computation_charge_arg],
846        );
847        (storage_rewards, computation_rewards)
848    }
849
850    pub fn construct_advance_epoch_pt(
851        mut builder: ProgrammableTransactionBuilder,
852        params: &AdvanceEpochParams,
853    ) -> Result<ProgrammableTransaction, ExecutionError> {
854        // Step 1: Create storage and computation rewards.
855        let (storage_rewards, computation_rewards) = mint_epoch_rewards_in_pt(&mut builder, params);
856
857        // Step 2: Advance the epoch.
858        let mut arguments = vec![storage_rewards, computation_rewards];
859        let call_arg_arguments = vec![
860            CallArg::SUI_SYSTEM_MUT,
861            CallArg::Pure(bcs::to_bytes(&params.epoch).unwrap()),
862            CallArg::Pure(bcs::to_bytes(&params.next_protocol_version.as_u64()).unwrap()),
863            CallArg::Pure(bcs::to_bytes(&params.storage_rebate).unwrap()),
864            CallArg::Pure(bcs::to_bytes(&params.non_refundable_storage_fee).unwrap()),
865            CallArg::Pure(bcs::to_bytes(&params.storage_fund_reinvest_rate).unwrap()),
866            CallArg::Pure(bcs::to_bytes(&params.reward_slashing_rate).unwrap()),
867            CallArg::Pure(bcs::to_bytes(&params.epoch_start_timestamp_ms).unwrap()),
868        ]
869        .into_iter()
870        .map(|a| builder.input(a))
871        .collect::<Result<_, _>>();
872
873        assert_invariant!(
874            call_arg_arguments.is_ok(),
875            "Unable to generate args for advance_epoch transaction!"
876        );
877
878        arguments.append(&mut call_arg_arguments.unwrap());
879
880        info!("Call arguments to advance_epoch transaction: {:?}", params);
881
882        let storage_rebates = builder.programmable_move_call(
883            SUI_SYSTEM_PACKAGE_ID,
884            SUI_SYSTEM_MODULE_NAME.to_owned(),
885            ADVANCE_EPOCH_FUNCTION_NAME.to_owned(),
886            vec![],
887            arguments,
888        );
889
890        // Step 3: Destroy the storage rebates.
891        builder.programmable_move_call(
892            SUI_FRAMEWORK_PACKAGE_ID,
893            BALANCE_MODULE_NAME.to_owned(),
894            BALANCE_DESTROY_REBATES_FUNCTION_NAME.to_owned(),
895            vec![GAS::type_tag()],
896            vec![storage_rebates],
897        );
898        Ok(builder.finish())
899    }
900
901    pub fn construct_advance_epoch_safe_mode_pt(
902        params: &AdvanceEpochParams,
903        protocol_config: &ProtocolConfig,
904    ) -> Result<ProgrammableTransaction, ExecutionError> {
905        let mut builder = ProgrammableTransactionBuilder::new();
906        // Step 1: Create storage and computation rewards.
907        let (storage_rewards, computation_rewards) = mint_epoch_rewards_in_pt(&mut builder, params);
908
909        // Step 2: Advance the epoch.
910        let mut arguments = vec![storage_rewards, computation_rewards];
911
912        let mut args = vec![
913            CallArg::SUI_SYSTEM_MUT,
914            CallArg::Pure(bcs::to_bytes(&params.epoch).unwrap()),
915            CallArg::Pure(bcs::to_bytes(&params.next_protocol_version.as_u64()).unwrap()),
916            CallArg::Pure(bcs::to_bytes(&params.storage_rebate).unwrap()),
917            CallArg::Pure(bcs::to_bytes(&params.non_refundable_storage_fee).unwrap()),
918        ];
919
920        if protocol_config.get_advance_epoch_start_time_in_safe_mode() {
921            args.push(CallArg::Pure(
922                bcs::to_bytes(&params.epoch_start_timestamp_ms).unwrap(),
923            ));
924        }
925
926        let call_arg_arguments = args
927            .into_iter()
928            .map(|a| builder.input(a))
929            .collect::<Result<_, _>>();
930
931        assert_invariant!(
932            call_arg_arguments.is_ok(),
933            "Unable to generate args for advance_epoch transaction!"
934        );
935
936        arguments.append(&mut call_arg_arguments.unwrap());
937
938        info!("Call arguments to advance_epoch transaction: {:?}", params);
939
940        builder.programmable_move_call(
941            SUI_SYSTEM_PACKAGE_ID,
942            SUI_SYSTEM_MODULE_NAME.to_owned(),
943            ADVANCE_EPOCH_SAFE_MODE_FUNCTION_NAME.to_owned(),
944            vec![],
945            arguments,
946        );
947
948        Ok(builder.finish())
949    }
950
951    fn advance_epoch(
952        builder: ProgrammableTransactionBuilder,
953        change_epoch: ChangeEpoch,
954        temporary_store: &mut TemporaryStore<'_>,
955        store: &dyn BackingStore,
956        tx_ctx: Rc<RefCell<TxContext>>,
957        move_vm: &Arc<MoveVM>,
958        gas_charger: &mut GasCharger,
959        protocol_config: &ProtocolConfig,
960        metrics: Arc<ExecutionMetrics>,
961        trace_builder_opt: &mut Option<MoveTraceBuilder>,
962    ) -> Result<(), ExecutionError> {
963        let params = AdvanceEpochParams {
964            epoch: change_epoch.epoch,
965            next_protocol_version: change_epoch.protocol_version,
966            storage_charge: change_epoch.storage_charge,
967            computation_charge: change_epoch.computation_charge,
968            storage_rebate: change_epoch.storage_rebate,
969            non_refundable_storage_fee: change_epoch.non_refundable_storage_fee,
970            storage_fund_reinvest_rate: protocol_config.storage_fund_reinvest_rate(),
971            reward_slashing_rate: protocol_config.reward_slashing_rate(),
972            epoch_start_timestamp_ms: change_epoch.epoch_start_timestamp_ms,
973        };
974        let advance_epoch_pt = construct_advance_epoch_pt(builder, &params)?;
975        let result = programmable_transactions::execution::execute::<execution_mode::System>(
976            protocol_config,
977            metrics.clone(),
978            move_vm,
979            temporary_store,
980            store.as_backing_package_store(),
981            tx_ctx.clone(),
982            gas_charger,
983            None,
984            advance_epoch_pt,
985            trace_builder_opt,
986        );
987
988        #[cfg(msim)]
989        let result = maybe_modify_result(result, change_epoch.epoch);
990
991        if let Err(err) = &result {
992            tracing::error!(
993                "Failed to execute advance epoch transaction. Switching to safe mode. Error: {:?}. Input objects: {:?}. Tx data: {:?}",
994                err.0,
995                temporary_store.objects(),
996                change_epoch,
997            );
998            temporary_store.drop_writes();
999            // Must reset the storage rebate since we are re-executing.
1000            gas_charger.reset_storage_cost_and_rebate();
1001
1002            if protocol_config.get_advance_epoch_start_time_in_safe_mode() {
1003                temporary_store.advance_epoch_safe_mode(&params, protocol_config);
1004            } else {
1005                let advance_epoch_safe_mode_pt =
1006                    construct_advance_epoch_safe_mode_pt(&params, protocol_config)?;
1007                programmable_transactions::execution::execute::<execution_mode::System>(
1008                    protocol_config,
1009                    metrics.clone(),
1010                    move_vm,
1011                    temporary_store,
1012                    store.as_backing_package_store(),
1013                    tx_ctx.clone(),
1014                    gas_charger,
1015                    None,
1016                    advance_epoch_safe_mode_pt,
1017                    trace_builder_opt,
1018                )
1019                .map_err(|(e, _)| e)
1020                .expect("Advance epoch with safe mode must succeed");
1021            }
1022        }
1023
1024        if protocol_config.fresh_vm_on_framework_upgrade() {
1025            let new_vm = new_move_vm(
1026                all_natives(/* silent */ true, protocol_config),
1027                protocol_config,
1028            )
1029            .expect("Failed to create new MoveVM");
1030            process_system_packages(
1031                change_epoch,
1032                temporary_store,
1033                store,
1034                tx_ctx,
1035                &new_vm,
1036                gas_charger,
1037                protocol_config,
1038                metrics,
1039                trace_builder_opt,
1040            );
1041        } else {
1042            process_system_packages(
1043                change_epoch,
1044                temporary_store,
1045                store,
1046                tx_ctx,
1047                move_vm,
1048                gas_charger,
1049                protocol_config,
1050                metrics,
1051                trace_builder_opt,
1052            );
1053        }
1054        Ok(())
1055    }
1056
1057    fn process_system_packages(
1058        change_epoch: ChangeEpoch,
1059        temporary_store: &mut TemporaryStore<'_>,
1060        store: &dyn BackingStore,
1061        tx_ctx: Rc<RefCell<TxContext>>,
1062        move_vm: &MoveVM,
1063        gas_charger: &mut GasCharger,
1064        protocol_config: &ProtocolConfig,
1065        metrics: Arc<ExecutionMetrics>,
1066        trace_builder_opt: &mut Option<MoveTraceBuilder>,
1067    ) {
1068        let digest = tx_ctx.borrow().digest();
1069        let binary_config = protocol_config.binary_config(None);
1070        for (version, modules, dependencies) in change_epoch.system_packages.into_iter() {
1071            let deserialized_modules: Vec<_> = modules
1072                .iter()
1073                .map(|m| CompiledModule::deserialize_with_config(m, &binary_config).unwrap())
1074                .collect();
1075
1076            if version == OBJECT_START_VERSION {
1077                let package_id = deserialized_modules.first().unwrap().address();
1078                info!("adding new system package {package_id}");
1079
1080                let publish_pt = {
1081                    let mut b = ProgrammableTransactionBuilder::new();
1082                    b.command(Command::Publish(modules, dependencies));
1083                    b.finish()
1084                };
1085
1086                programmable_transactions::execution::execute::<execution_mode::System>(
1087                    protocol_config,
1088                    metrics.clone(),
1089                    move_vm,
1090                    temporary_store,
1091                    store.as_backing_package_store(),
1092                    tx_ctx.clone(),
1093                    gas_charger,
1094                    None,
1095                    publish_pt,
1096                    trace_builder_opt,
1097                )
1098                .map_err(|(e, _)| e)
1099                .expect("System Package Publish must succeed");
1100            } else {
1101                let mut new_package = Object::new_system_package(
1102                    &deserialized_modules,
1103                    version,
1104                    dependencies,
1105                    digest,
1106                );
1107
1108                info!(
1109                    "upgraded system package {:?}",
1110                    new_package.compute_object_reference()
1111                );
1112
1113                // Decrement the version before writing the package so that the store can record the
1114                // version growing by one in the effects.
1115                new_package
1116                    .data
1117                    .try_as_package_mut()
1118                    .unwrap()
1119                    .decrement_version();
1120
1121                // upgrade of a previously existing framework module
1122                temporary_store.upgrade_system_package(new_package);
1123            }
1124        }
1125    }
1126
1127    /// Perform metadata updates in preparation for the transactions in the upcoming checkpoint:
1128    ///
1129    /// - Set the timestamp for the `Clock` shared object from the timestamp in the header from
1130    ///   consensus.
1131    fn setup_consensus_commit(
1132        consensus_commit_timestamp_ms: CheckpointTimestamp,
1133        temporary_store: &mut TemporaryStore<'_>,
1134        store: &dyn BackingStore,
1135        tx_ctx: Rc<RefCell<TxContext>>,
1136        move_vm: &Arc<MoveVM>,
1137        gas_charger: &mut GasCharger,
1138        protocol_config: &ProtocolConfig,
1139        metrics: Arc<ExecutionMetrics>,
1140        trace_builder_opt: &mut Option<MoveTraceBuilder>,
1141    ) -> Result<(), ExecutionError> {
1142        let pt = {
1143            let mut builder = ProgrammableTransactionBuilder::new();
1144            let res = builder.move_call(
1145                SUI_FRAMEWORK_ADDRESS.into(),
1146                CLOCK_MODULE_NAME.to_owned(),
1147                CONSENSUS_COMMIT_PROLOGUE_FUNCTION_NAME.to_owned(),
1148                vec![],
1149                vec![
1150                    CallArg::CLOCK_MUT,
1151                    CallArg::Pure(bcs::to_bytes(&consensus_commit_timestamp_ms).unwrap()),
1152                ],
1153            );
1154            assert_invariant!(
1155                res.is_ok(),
1156                "Unable to generate consensus_commit_prologue transaction!"
1157            );
1158            builder.finish()
1159        };
1160        programmable_transactions::execution::execute::<execution_mode::System>(
1161            protocol_config,
1162            metrics,
1163            move_vm,
1164            temporary_store,
1165            store.as_backing_package_store(),
1166            tx_ctx,
1167            gas_charger,
1168            None,
1169            pt,
1170            trace_builder_opt,
1171        )
1172        .map_err(|(e, _)| e)?;
1173        Ok(())
1174    }
1175
1176    fn setup_authenticator_state_create(
1177        mut builder: ProgrammableTransactionBuilder,
1178    ) -> ProgrammableTransactionBuilder {
1179        builder
1180            .move_call(
1181                SUI_FRAMEWORK_ADDRESS.into(),
1182                AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1183                AUTHENTICATOR_STATE_CREATE_FUNCTION_NAME.to_owned(),
1184                vec![],
1185                vec![],
1186            )
1187            .expect("Unable to generate authenticator_state_create transaction!");
1188        builder
1189    }
1190
1191    fn setup_randomness_state_create(
1192        mut builder: ProgrammableTransactionBuilder,
1193    ) -> ProgrammableTransactionBuilder {
1194        builder
1195            .move_call(
1196                SUI_FRAMEWORK_ADDRESS.into(),
1197                RANDOMNESS_MODULE_NAME.to_owned(),
1198                RANDOMNESS_STATE_CREATE_FUNCTION_NAME.to_owned(),
1199                vec![],
1200                vec![],
1201            )
1202            .expect("Unable to generate randomness_state_create transaction!");
1203        builder
1204    }
1205
1206    fn setup_bridge_create(
1207        mut builder: ProgrammableTransactionBuilder,
1208        chain_id: ChainIdentifier,
1209    ) -> ProgrammableTransactionBuilder {
1210        let bridge_uid = builder
1211            .input(CallArg::Pure(UID::new(SUI_BRIDGE_OBJECT_ID).to_bcs_bytes()))
1212            .expect("Unable to create Bridge object UID!");
1213
1214        let bridge_chain_id = if chain_id == get_mainnet_chain_identifier() {
1215            BridgeChainId::SuiMainnet as u8
1216        } else if chain_id == get_testnet_chain_identifier() {
1217            BridgeChainId::SuiTestnet as u8
1218        } else {
1219            // How do we distinguish devnet from other test envs?
1220            BridgeChainId::SuiCustom as u8
1221        };
1222
1223        let bridge_chain_id = builder.pure(bridge_chain_id).unwrap();
1224        builder.programmable_move_call(
1225            BRIDGE_ADDRESS.into(),
1226            BRIDGE_MODULE_NAME.to_owned(),
1227            BRIDGE_CREATE_FUNCTION_NAME.to_owned(),
1228            vec![],
1229            vec![bridge_uid, bridge_chain_id],
1230        );
1231        builder
1232    }
1233
1234    fn setup_bridge_committee_update(
1235        mut builder: ProgrammableTransactionBuilder,
1236        bridge_shared_version: SequenceNumber,
1237    ) -> ProgrammableTransactionBuilder {
1238        let bridge = builder
1239            .obj(ObjectArg::SharedObject {
1240                id: SUI_BRIDGE_OBJECT_ID,
1241                initial_shared_version: bridge_shared_version,
1242                mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1243            })
1244            .expect("Unable to create Bridge object arg!");
1245        let system_state = builder
1246            .obj(ObjectArg::SUI_SYSTEM_MUT)
1247            .expect("Unable to create System State object arg!");
1248
1249        let voting_power = builder.programmable_move_call(
1250            SUI_SYSTEM_PACKAGE_ID,
1251            SUI_SYSTEM_MODULE_NAME.to_owned(),
1252            ident_str!("validator_voting_powers").to_owned(),
1253            vec![],
1254            vec![system_state],
1255        );
1256
1257        // Hardcoding min stake participation to 75.00%
1258        // TODO: We need to set a correct value or make this configurable.
1259        let min_stake_participation_percentage = builder
1260            .input(CallArg::Pure(
1261                bcs::to_bytes(&BRIDGE_COMMITTEE_MINIMAL_VOTING_POWER).unwrap(),
1262            ))
1263            .unwrap();
1264
1265        builder.programmable_move_call(
1266            BRIDGE_ADDRESS.into(),
1267            BRIDGE_MODULE_NAME.to_owned(),
1268            BRIDGE_INIT_COMMITTEE_FUNCTION_NAME.to_owned(),
1269            vec![],
1270            vec![bridge, voting_power, min_stake_participation_percentage],
1271        );
1272        builder
1273    }
1274
1275    fn setup_authenticator_state_update(
1276        update: AuthenticatorStateUpdate,
1277        temporary_store: &mut TemporaryStore<'_>,
1278        store: &dyn BackingStore,
1279        tx_ctx: Rc<RefCell<TxContext>>,
1280        move_vm: &Arc<MoveVM>,
1281        gas_charger: &mut GasCharger,
1282        protocol_config: &ProtocolConfig,
1283        metrics: Arc<ExecutionMetrics>,
1284        trace_builder_opt: &mut Option<MoveTraceBuilder>,
1285    ) -> Result<(), ExecutionError> {
1286        let pt = {
1287            let mut builder = ProgrammableTransactionBuilder::new();
1288            let res = builder.move_call(
1289                SUI_FRAMEWORK_ADDRESS.into(),
1290                AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1291                AUTHENTICATOR_STATE_UPDATE_FUNCTION_NAME.to_owned(),
1292                vec![],
1293                vec![
1294                    CallArg::Object(ObjectArg::SharedObject {
1295                        id: SUI_AUTHENTICATOR_STATE_OBJECT_ID,
1296                        initial_shared_version: update.authenticator_obj_initial_shared_version,
1297                        mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1298                    }),
1299                    CallArg::Pure(bcs::to_bytes(&update.new_active_jwks).unwrap()),
1300                ],
1301            );
1302            assert_invariant!(
1303                res.is_ok(),
1304                "Unable to generate authenticator_state_update transaction!"
1305            );
1306            builder.finish()
1307        };
1308        programmable_transactions::execution::execute::<execution_mode::System>(
1309            protocol_config,
1310            metrics,
1311            move_vm,
1312            temporary_store,
1313            store.as_backing_package_store(),
1314            tx_ctx,
1315            gas_charger,
1316            None,
1317            pt,
1318            trace_builder_opt,
1319        )
1320        .map_err(|(e, _)| e)?;
1321        Ok(())
1322    }
1323
1324    fn setup_authenticator_state_expire(
1325        mut builder: ProgrammableTransactionBuilder,
1326        expire: AuthenticatorStateExpire,
1327    ) -> ProgrammableTransactionBuilder {
1328        builder
1329            .move_call(
1330                SUI_FRAMEWORK_ADDRESS.into(),
1331                AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1332                AUTHENTICATOR_STATE_EXPIRE_JWKS_FUNCTION_NAME.to_owned(),
1333                vec![],
1334                vec![
1335                    CallArg::Object(ObjectArg::SharedObject {
1336                        id: SUI_AUTHENTICATOR_STATE_OBJECT_ID,
1337                        initial_shared_version: expire.authenticator_obj_initial_shared_version,
1338                        mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1339                    }),
1340                    CallArg::Pure(bcs::to_bytes(&expire.min_epoch).unwrap()),
1341                ],
1342            )
1343            .expect("Unable to generate authenticator_state_expire transaction!");
1344        builder
1345    }
1346
1347    fn setup_randomness_state_update(
1348        update: RandomnessStateUpdate,
1349        temporary_store: &mut TemporaryStore<'_>,
1350        store: &dyn BackingStore,
1351        tx_ctx: Rc<RefCell<TxContext>>,
1352        move_vm: &Arc<MoveVM>,
1353        gas_charger: &mut GasCharger,
1354        protocol_config: &ProtocolConfig,
1355        metrics: Arc<ExecutionMetrics>,
1356        trace_builder_opt: &mut Option<MoveTraceBuilder>,
1357    ) -> Result<(), ExecutionError> {
1358        let pt = {
1359            let mut builder = ProgrammableTransactionBuilder::new();
1360            let res = builder.move_call(
1361                SUI_FRAMEWORK_ADDRESS.into(),
1362                RANDOMNESS_MODULE_NAME.to_owned(),
1363                RANDOMNESS_STATE_UPDATE_FUNCTION_NAME.to_owned(),
1364                vec![],
1365                vec![
1366                    CallArg::Object(ObjectArg::SharedObject {
1367                        id: SUI_RANDOMNESS_STATE_OBJECT_ID,
1368                        initial_shared_version: update.randomness_obj_initial_shared_version,
1369                        mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1370                    }),
1371                    CallArg::Pure(bcs::to_bytes(&update.randomness_round).unwrap()),
1372                    CallArg::Pure(bcs::to_bytes(&update.random_bytes).unwrap()),
1373                ],
1374            );
1375            assert_invariant!(
1376                res.is_ok(),
1377                "Unable to generate randomness_state_update transaction!"
1378            );
1379            builder.finish()
1380        };
1381        programmable_transactions::execution::execute::<execution_mode::System>(
1382            protocol_config,
1383            metrics,
1384            move_vm,
1385            temporary_store,
1386            store.as_backing_package_store(),
1387            tx_ctx,
1388            gas_charger,
1389            None,
1390            pt,
1391            trace_builder_opt,
1392        )
1393        .map_err(|(e, _)| e)?;
1394        Ok(())
1395    }
1396
1397    fn setup_coin_deny_list_state_create(
1398        mut builder: ProgrammableTransactionBuilder,
1399    ) -> ProgrammableTransactionBuilder {
1400        builder
1401            .move_call(
1402                SUI_FRAMEWORK_ADDRESS.into(),
1403                DENY_LIST_MODULE.to_owned(),
1404                DENY_LIST_CREATE_FUNC.to_owned(),
1405                vec![],
1406                vec![],
1407            )
1408            .expect("Unable to generate coin_deny_list_create transaction!");
1409        builder
1410    }
1411
1412    fn setup_store_execution_time_estimates(
1413        mut builder: ProgrammableTransactionBuilder,
1414        estimates: StoredExecutionTimeObservations,
1415    ) -> ProgrammableTransactionBuilder {
1416        let system_state = builder.obj(ObjectArg::SUI_SYSTEM_MUT).unwrap();
1417        // This is stored as a vector<u8> in Move, so we first convert to bytes before again
1418        // serializing inside the call to `pure`.
1419        let estimates_bytes = bcs::to_bytes(&estimates).unwrap();
1420        let estimates_arg = builder.pure(estimates_bytes).unwrap();
1421        builder.programmable_move_call(
1422            SUI_SYSTEM_PACKAGE_ID,
1423            SUI_SYSTEM_MODULE_NAME.to_owned(),
1424            ident_str!("store_execution_time_estimates").to_owned(),
1425            vec![],
1426            vec![system_state, estimates_arg],
1427        );
1428        builder
1429    }
1430
1431    fn setup_store_execution_time_estimates_v2(
1432        mut builder: ProgrammableTransactionBuilder,
1433        estimates: StoredExecutionTimeObservations,
1434        chunk_size: usize,
1435    ) -> ProgrammableTransactionBuilder {
1436        let system_state = builder.obj(ObjectArg::SUI_SYSTEM_MUT).unwrap();
1437
1438        let estimate_chunks = estimates.chunk_observations(chunk_size);
1439
1440        let chunk_bytes: Vec<Vec<u8>> = estimate_chunks
1441            .into_iter()
1442            .map(|chunk| bcs::to_bytes(&chunk).unwrap())
1443            .collect();
1444
1445        let chunks_arg = builder.pure(chunk_bytes).unwrap();
1446
1447        builder.programmable_move_call(
1448            SUI_SYSTEM_PACKAGE_ID,
1449            SUI_SYSTEM_MODULE_NAME.to_owned(),
1450            ident_str!("store_execution_time_estimates_v2").to_owned(),
1451            vec![],
1452            vec![system_state, chunks_arg],
1453        );
1454        builder
1455    }
1456
1457    fn setup_accumulator_root_create(
1458        mut builder: ProgrammableTransactionBuilder,
1459    ) -> ProgrammableTransactionBuilder {
1460        builder
1461            .move_call(
1462                SUI_FRAMEWORK_ADDRESS.into(),
1463                ACCUMULATOR_ROOT_MODULE.to_owned(),
1464                ACCUMULATOR_ROOT_CREATE_FUNC.to_owned(),
1465                vec![],
1466                vec![],
1467            )
1468            .expect("Unable to generate accumulator_root_create transaction!");
1469        builder
1470    }
1471
1472    fn setup_write_accumulator_storage_cost(
1473        mut builder: ProgrammableTransactionBuilder,
1474        write_storage_cost: &WriteAccumulatorStorageCost,
1475    ) -> ProgrammableTransactionBuilder {
1476        let system_state = builder.obj(ObjectArg::SUI_SYSTEM_MUT).unwrap();
1477        let storage_cost_arg = builder.pure(write_storage_cost.storage_cost).unwrap();
1478        builder.programmable_move_call(
1479            SUI_SYSTEM_PACKAGE_ID,
1480            SUI_SYSTEM_MODULE_NAME.to_owned(),
1481            ident_str!("write_accumulator_storage_cost").to_owned(),
1482            vec![],
1483            vec![system_state, storage_cost_arg],
1484        );
1485        builder
1486    }
1487
1488    fn setup_coin_registry_create(
1489        mut builder: ProgrammableTransactionBuilder,
1490    ) -> ProgrammableTransactionBuilder {
1491        builder
1492            .move_call(
1493                SUI_FRAMEWORK_ADDRESS.into(),
1494                ident_str!("coin_registry").to_owned(),
1495                ident_str!("create").to_owned(),
1496                vec![],
1497                vec![],
1498            )
1499            .expect("Unable to generate coin_registry_create transaction!");
1500        builder
1501    }
1502
1503    fn setup_display_registry_create(
1504        mut builder: ProgrammableTransactionBuilder,
1505    ) -> ProgrammableTransactionBuilder {
1506        builder
1507            .move_call(
1508                SUI_FRAMEWORK_ADDRESS.into(),
1509                ident_str!("display_registry").to_owned(),
1510                ident_str!("create").to_owned(),
1511                vec![],
1512                vec![],
1513            )
1514            .expect("Unable to generate display_registry_create transaction!");
1515        builder
1516    }
1517
1518    fn setup_address_alias_state_create(
1519        mut builder: ProgrammableTransactionBuilder,
1520    ) -> ProgrammableTransactionBuilder {
1521        builder
1522            .move_call(
1523                SUI_FRAMEWORK_ADDRESS.into(),
1524                ident_str!("address_alias").to_owned(),
1525                ident_str!("create").to_owned(),
1526                vec![],
1527                vec![],
1528            )
1529            .expect("Unable to generate address_alias_state_create transaction!");
1530        builder
1531    }
1532}