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.into_early_errors() {
315                        Some(early_execution_errors) => Err((
316                            ExecutionError::new(early_execution_errors.head, None),
317                            vec![],
318                        )),
319                        None => execution_loop::<Mode>(
320                            store,
321                            temporary_store,
322                            transaction_kind,
323                            tx_ctx,
324                            move_vm,
325                            gas_charger,
326                            protocol_config,
327                            metrics.clone(),
328                            trace_builder_opt,
329                        ),
330                    };
331
332                    let meter_check = check_meter_limit(
333                        temporary_store,
334                        gas_charger,
335                        protocol_config,
336                        metrics.clone(),
337                    );
338                    if let Err(e) = meter_check {
339                        execution_result = Err((e, vec![]));
340                    }
341
342                    if execution_result.is_ok() {
343                        let gas_check = check_written_objects_limit(
344                            temporary_store,
345                            gas_charger,
346                            protocol_config,
347                            metrics,
348                        );
349                        if let Err(e) = gas_check {
350                            execution_result = Err((e, vec![]));
351                        }
352                    }
353
354                    execution_result
355                },
356            );
357
358        let (mut result, timings) = match result {
359            Ok((r, t)) => (Ok(r), t),
360            Err((e, t)) => (Err(e), t),
361        };
362
363        let cost_summary = gas_charger.charge_gas(temporary_store, &mut result);
364        // For advance epoch transaction, we need to provide epoch rewards and rebates as extra
365        // information provided to check_sui_conserved, because we mint rewards, and burn
366        // the rebates. We also need to pass in the unmetered_storage_rebate because storage
367        // rebate is not reflected in the storage_rebate of gas summary. This is a bit confusing.
368        // We could probably clean up the code a bit.
369        // Put all the storage rebate accumulated in the system transaction
370        // to the 0x5 object so that it's not lost.
371        temporary_store.conserve_unmetered_storage_rebate(gas_charger.unmetered_storage_rebate());
372
373        if let Err(e) = run_conservation_checks::<Mode>(
374            temporary_store,
375            gas_charger,
376            digest,
377            move_vm,
378            protocol_config.simple_conservation_checks(),
379            enable_expensive_checks,
380            &cost_summary,
381            is_genesis_tx,
382            advance_epoch_gas_summary,
383        ) {
384            // FIXME: we cannot fail the transaction if this is an epoch change transaction.
385            result = Err(e);
386        }
387
388        (cost_summary, result, timings)
389    }
390
391    #[instrument(name = "run_conservation_checks", level = "debug", skip_all)]
392    fn run_conservation_checks<Mode: ExecutionMode>(
393        temporary_store: &mut TemporaryStore<'_>,
394        gas_charger: &mut GasCharger,
395        tx_digest: TransactionDigest,
396        move_vm: &Arc<MoveVM>,
397        simple_conservation_checks: bool,
398        enable_expensive_checks: bool,
399        cost_summary: &GasCostSummary,
400        is_genesis_tx: bool,
401        advance_epoch_gas_summary: Option<(u64, u64)>,
402    ) -> Result<(), ExecutionError> {
403        let mut result: std::result::Result<(), sui_types::error::ExecutionError> = Ok(());
404        if !is_genesis_tx && !Mode::skip_conservation_checks() {
405            // ensure that this transaction did not create or destroy SUI, try to recover if the check fails
406            let conservation_result = {
407                temporary_store
408                    .check_sui_conserved(simple_conservation_checks, cost_summary)
409                    .and_then(|()| {
410                        if enable_expensive_checks {
411                            // ensure that this transaction did not create or destroy SUI, try to recover if the check fails
412                            let mut layout_resolver =
413                                TypeLayoutResolver::new(move_vm, Box::new(&*temporary_store));
414                            temporary_store.check_sui_conserved_expensive(
415                                cost_summary,
416                                advance_epoch_gas_summary,
417                                &mut layout_resolver,
418                            )
419                        } else {
420                            Ok(())
421                        }
422                    })
423            };
424            if let Err(conservation_err) = conservation_result {
425                // conservation violated. try to avoid panic by dumping all writes, charging for gas, re-checking
426                // conservation, and surfacing an aborted transaction with an invariant violation if all of that works
427                result = Err(conservation_err);
428                gas_charger.reset(temporary_store);
429                gas_charger.charge_gas(temporary_store, &mut result);
430                // check conservation once more
431                if let Err(recovery_err) = {
432                    temporary_store
433                        .check_sui_conserved(simple_conservation_checks, cost_summary)
434                        .and_then(|()| {
435                            if enable_expensive_checks {
436                                // ensure that this transaction did not create or destroy SUI, try to recover if the check fails
437                                let mut layout_resolver =
438                                    TypeLayoutResolver::new(move_vm, Box::new(&*temporary_store));
439                                temporary_store.check_sui_conserved_expensive(
440                                    cost_summary,
441                                    advance_epoch_gas_summary,
442                                    &mut layout_resolver,
443                                )
444                            } else {
445                                Ok(())
446                            }
447                        })
448                } {
449                    // if we still fail, it's a problem with gas
450                    // charging that happens even in the "aborted" case--no other option but panic.
451                    // we will create or destroy SUI otherwise
452                    panic!(
453                        "SUI conservation fail in tx block {}: {}\nGas status is {}\nTx was ",
454                        tx_digest,
455                        recovery_err,
456                        gas_charger.summary()
457                    )
458                }
459            }
460        } // else, we're in the genesis transaction which mints the SUI supply, and hence does not satisfy SUI conservation, or
461        // we're in the non-production dev inspect mode which allows us to violate conservation
462        result
463    }
464
465    #[instrument(name = "check_meter_limit", level = "debug", skip_all)]
466    fn check_meter_limit(
467        temporary_store: &mut TemporaryStore<'_>,
468        gas_charger: &mut GasCharger,
469        protocol_config: &ProtocolConfig,
470        metrics: Arc<ExecutionMetrics>,
471    ) -> Result<(), ExecutionError> {
472        let effects_estimated_size = temporary_store.estimate_effects_size_upperbound();
473
474        // Check if a limit threshold was crossed.
475        // For metered transactions, there is not soft limit.
476        // For system transactions, we allow a soft limit with alerting, and a hard limit where we terminate
477        match check_limit_by_meter!(
478            !gas_charger.is_unmetered(),
479            effects_estimated_size,
480            protocol_config.max_serialized_tx_effects_size_bytes(),
481            protocol_config.max_serialized_tx_effects_size_bytes_system_tx(),
482            metrics.limits_metrics.excessive_estimated_effects_size
483        ) {
484            LimitThresholdCrossed::None => Ok(()),
485            LimitThresholdCrossed::Soft(_, limit) => {
486                warn!(
487                    effects_estimated_size = effects_estimated_size,
488                    soft_limit = limit,
489                    "Estimated transaction effects size crossed soft limit",
490                );
491                Ok(())
492            }
493            LimitThresholdCrossed::Hard(_, lim) => Err(ExecutionError::new_with_source(
494                ExecutionErrorKind::EffectsTooLarge {
495                    current_size: effects_estimated_size as u64,
496                    max_size: lim as u64,
497                },
498                "Transaction effects are too large",
499            )),
500        }
501    }
502
503    #[instrument(name = "check_written_objects_limit", level = "debug", skip_all)]
504    fn check_written_objects_limit(
505        temporary_store: &mut TemporaryStore<'_>,
506        gas_charger: &mut GasCharger,
507        protocol_config: &ProtocolConfig,
508        metrics: Arc<ExecutionMetrics>,
509    ) -> Result<(), ExecutionError> {
510        if let (Some(normal_lim), Some(system_lim)) = (
511            protocol_config.max_size_written_objects_as_option(),
512            protocol_config.max_size_written_objects_system_tx_as_option(),
513        ) {
514            let written_objects_size = temporary_store.written_objects_size();
515
516            match check_limit_by_meter!(
517                !gas_charger.is_unmetered(),
518                written_objects_size,
519                normal_lim,
520                system_lim,
521                metrics.limits_metrics.excessive_written_objects_size
522            ) {
523                LimitThresholdCrossed::None => (),
524                LimitThresholdCrossed::Soft(_, limit) => {
525                    warn!(
526                        written_objects_size = written_objects_size,
527                        soft_limit = limit,
528                        "Written objects size crossed soft limit",
529                    )
530                }
531                LimitThresholdCrossed::Hard(_, lim) => {
532                    return Err(ExecutionError::new_with_source(
533                        ExecutionErrorKind::WrittenObjectsTooLarge {
534                            current_size: written_objects_size as u64,
535                            max_size: lim as u64,
536                        },
537                        "Written objects size crossed hard limit",
538                    ));
539                }
540            };
541        }
542
543        Ok(())
544    }
545
546    #[instrument(level = "debug", skip_all)]
547    fn execution_loop<Mode: ExecutionMode>(
548        store: &dyn BackingStore,
549        temporary_store: &mut TemporaryStore<'_>,
550        transaction_kind: TransactionKind,
551        tx_ctx: Rc<RefCell<TxContext>>,
552        move_vm: &Arc<MoveVM>,
553        gas_charger: &mut GasCharger,
554        protocol_config: &ProtocolConfig,
555        metrics: Arc<ExecutionMetrics>,
556        trace_builder_opt: &mut Option<MoveTraceBuilder>,
557    ) -> ResultWithTimings<Mode::ExecutionResults, ExecutionError> {
558        let result = match transaction_kind {
559            TransactionKind::ChangeEpoch(change_epoch) => {
560                let builder = ProgrammableTransactionBuilder::new();
561                advance_epoch(
562                    builder,
563                    change_epoch,
564                    temporary_store,
565                    store,
566                    tx_ctx,
567                    move_vm,
568                    gas_charger,
569                    protocol_config,
570                    metrics,
571                    trace_builder_opt,
572                )
573                .map_err(|e| (e, vec![]))?;
574                Ok((Mode::empty_results(), vec![]))
575            }
576            TransactionKind::Genesis(GenesisTransaction { objects }) => {
577                if tx_ctx.borrow().epoch() != 0 {
578                    panic!("BUG: Genesis Transactions can only be executed in epoch 0");
579                }
580
581                for genesis_object in objects {
582                    match genesis_object {
583                        sui_types::transaction::GenesisObject::RawObject { data, owner } => {
584                            let object = ObjectInner {
585                                data,
586                                owner,
587                                previous_transaction: tx_ctx.borrow().digest(),
588                                storage_rebate: 0,
589                            };
590                            temporary_store.create_object(object.into());
591                        }
592                    }
593                }
594                Ok((Mode::empty_results(), vec![]))
595            }
596            TransactionKind::ConsensusCommitPrologue(prologue) => {
597                setup_consensus_commit(
598                    prologue.commit_timestamp_ms,
599                    temporary_store,
600                    store,
601                    tx_ctx,
602                    move_vm,
603                    gas_charger,
604                    protocol_config,
605                    metrics,
606                    trace_builder_opt,
607                )
608                .expect("ConsensusCommitPrologue cannot fail");
609                Ok((Mode::empty_results(), vec![]))
610            }
611            TransactionKind::ConsensusCommitPrologueV2(prologue) => {
612                setup_consensus_commit(
613                    prologue.commit_timestamp_ms,
614                    temporary_store,
615                    store,
616                    tx_ctx,
617                    move_vm,
618                    gas_charger,
619                    protocol_config,
620                    metrics,
621                    trace_builder_opt,
622                )
623                .expect("ConsensusCommitPrologueV2 cannot fail");
624                Ok((Mode::empty_results(), vec![]))
625            }
626            TransactionKind::ConsensusCommitPrologueV3(prologue) => {
627                setup_consensus_commit(
628                    prologue.commit_timestamp_ms,
629                    temporary_store,
630                    store,
631                    tx_ctx,
632                    move_vm,
633                    gas_charger,
634                    protocol_config,
635                    metrics,
636                    trace_builder_opt,
637                )
638                .expect("ConsensusCommitPrologueV3 cannot fail");
639                Ok((Mode::empty_results(), vec![]))
640            }
641            TransactionKind::ConsensusCommitPrologueV4(prologue) => {
642                setup_consensus_commit(
643                    prologue.commit_timestamp_ms,
644                    temporary_store,
645                    store,
646                    tx_ctx,
647                    move_vm,
648                    gas_charger,
649                    protocol_config,
650                    metrics,
651                    trace_builder_opt,
652                )
653                .expect("ConsensusCommitPrologue cannot fail");
654                Ok((Mode::empty_results(), vec![]))
655            }
656            TransactionKind::ProgrammableTransaction(pt) => {
657                programmable_transactions::execution::execute::<Mode>(
658                    protocol_config,
659                    metrics,
660                    move_vm,
661                    temporary_store,
662                    store.as_backing_package_store(),
663                    tx_ctx,
664                    gas_charger,
665                    None,
666                    pt,
667                    trace_builder_opt,
668                )
669            }
670            TransactionKind::ProgrammableSystemTransaction(pt) => {
671                programmable_transactions::execution::execute::<execution_mode::System>(
672                    protocol_config,
673                    metrics,
674                    move_vm,
675                    temporary_store,
676                    store.as_backing_package_store(),
677                    tx_ctx,
678                    gas_charger,
679                    None,
680                    pt,
681                    trace_builder_opt,
682                )?;
683                Ok((Mode::empty_results(), vec![]))
684            }
685            TransactionKind::EndOfEpochTransaction(txns) => {
686                let mut builder = ProgrammableTransactionBuilder::new();
687                let len = txns.len();
688                for (i, tx) in txns.into_iter().enumerate() {
689                    match tx {
690                        EndOfEpochTransactionKind::ChangeEpoch(change_epoch) => {
691                            assert_eq!(i, len - 1);
692                            advance_epoch(
693                                builder,
694                                change_epoch,
695                                temporary_store,
696                                store,
697                                tx_ctx,
698                                move_vm,
699                                gas_charger,
700                                protocol_config,
701                                metrics,
702                                trace_builder_opt,
703                            )
704                            .map_err(|e| (e, vec![]))?;
705                            return Ok((Mode::empty_results(), vec![]));
706                        }
707                        EndOfEpochTransactionKind::AuthenticatorStateCreate => {
708                            assert!(protocol_config.enable_jwk_consensus_updates());
709                            builder = setup_authenticator_state_create(builder);
710                        }
711                        EndOfEpochTransactionKind::AuthenticatorStateExpire(expire) => {
712                            assert!(protocol_config.enable_jwk_consensus_updates());
713
714                            // TODO: it would be nice if a failure of this function didn't cause
715                            // safe mode.
716                            builder = setup_authenticator_state_expire(builder, expire);
717                        }
718                        EndOfEpochTransactionKind::RandomnessStateCreate => {
719                            assert!(protocol_config.random_beacon());
720                            builder = setup_randomness_state_create(builder);
721                        }
722                        EndOfEpochTransactionKind::DenyListStateCreate => {
723                            assert!(protocol_config.enable_coin_deny_list_v1());
724                            builder = setup_coin_deny_list_state_create(builder);
725                        }
726                        EndOfEpochTransactionKind::BridgeStateCreate(chain_id) => {
727                            assert!(protocol_config.enable_bridge());
728                            builder = setup_bridge_create(builder, chain_id)
729                        }
730                        EndOfEpochTransactionKind::BridgeCommitteeInit(bridge_shared_version) => {
731                            assert!(protocol_config.enable_bridge());
732                            assert!(protocol_config.should_try_to_finalize_bridge_committee());
733                            builder = setup_bridge_committee_update(builder, bridge_shared_version)
734                        }
735                        EndOfEpochTransactionKind::StoreExecutionTimeObservations(estimates) => {
736                            if let PerObjectCongestionControlMode::ExecutionTimeEstimate(params) =
737                                protocol_config.per_object_congestion_control_mode()
738                            {
739                                if let Some(chunk_size) = params.observations_chunk_size {
740                                    builder = setup_store_execution_time_estimates_v2(
741                                        builder,
742                                        estimates,
743                                        chunk_size as usize,
744                                    );
745                                } else {
746                                    builder =
747                                        setup_store_execution_time_estimates(builder, estimates);
748                                }
749                            }
750                        }
751                        EndOfEpochTransactionKind::AccumulatorRootCreate => {
752                            assert!(protocol_config.create_root_accumulator_object());
753                            builder = setup_accumulator_root_create(builder);
754                        }
755                        EndOfEpochTransactionKind::WriteAccumulatorStorageCost(
756                            write_storage_cost,
757                        ) => {
758                            assert!(protocol_config.enable_accumulators());
759                            builder =
760                                setup_write_accumulator_storage_cost(builder, &write_storage_cost);
761                        }
762                        EndOfEpochTransactionKind::CoinRegistryCreate => {
763                            assert!(protocol_config.enable_coin_registry());
764                            builder = setup_coin_registry_create(builder);
765                        }
766                        EndOfEpochTransactionKind::DisplayRegistryCreate => {
767                            assert!(protocol_config.enable_display_registry());
768                            builder = setup_display_registry_create(builder);
769                        }
770                        EndOfEpochTransactionKind::AddressAliasStateCreate => {
771                            assert!(protocol_config.address_aliases());
772                            builder = setup_address_alias_state_create(builder);
773                        }
774                    }
775                }
776                unreachable!(
777                    "EndOfEpochTransactionKind::ChangeEpoch should be the last transaction in the list"
778                )
779            }
780            TransactionKind::AuthenticatorStateUpdate(auth_state_update) => {
781                setup_authenticator_state_update(
782                    auth_state_update,
783                    temporary_store,
784                    store,
785                    tx_ctx,
786                    move_vm,
787                    gas_charger,
788                    protocol_config,
789                    metrics,
790                    trace_builder_opt,
791                )
792                .map_err(|e| (e, vec![]))?;
793                Ok((Mode::empty_results(), vec![]))
794            }
795            TransactionKind::RandomnessStateUpdate(randomness_state_update) => {
796                setup_randomness_state_update(
797                    randomness_state_update,
798                    temporary_store,
799                    store,
800                    tx_ctx,
801                    move_vm,
802                    gas_charger,
803                    protocol_config,
804                    metrics,
805                    trace_builder_opt,
806                )
807                .map_err(|e| (e, vec![]))?;
808                Ok((Mode::empty_results(), vec![]))
809            }
810        }?;
811        temporary_store
812            .check_execution_results_consistency()
813            .map_err(|e| (e, vec![]))?;
814        Ok(result)
815    }
816
817    fn mint_epoch_rewards_in_pt(
818        builder: &mut ProgrammableTransactionBuilder,
819        params: &AdvanceEpochParams,
820    ) -> (Argument, Argument) {
821        // Create storage rewards.
822        let storage_charge_arg = builder
823            .input(CallArg::Pure(
824                bcs::to_bytes(&params.storage_charge).unwrap(),
825            ))
826            .unwrap();
827        let storage_rewards = builder.programmable_move_call(
828            SUI_FRAMEWORK_PACKAGE_ID,
829            BALANCE_MODULE_NAME.to_owned(),
830            BALANCE_CREATE_REWARDS_FUNCTION_NAME.to_owned(),
831            vec![GAS::type_tag()],
832            vec![storage_charge_arg],
833        );
834
835        // Create computation rewards.
836        let computation_charge_arg = builder
837            .input(CallArg::Pure(
838                bcs::to_bytes(&params.computation_charge).unwrap(),
839            ))
840            .unwrap();
841        let computation_rewards = builder.programmable_move_call(
842            SUI_FRAMEWORK_PACKAGE_ID,
843            BALANCE_MODULE_NAME.to_owned(),
844            BALANCE_CREATE_REWARDS_FUNCTION_NAME.to_owned(),
845            vec![GAS::type_tag()],
846            vec![computation_charge_arg],
847        );
848        (storage_rewards, computation_rewards)
849    }
850
851    pub fn construct_advance_epoch_pt(
852        mut builder: ProgrammableTransactionBuilder,
853        params: &AdvanceEpochParams,
854    ) -> Result<ProgrammableTransaction, ExecutionError> {
855        // Step 1: Create storage and computation rewards.
856        let (storage_rewards, computation_rewards) = mint_epoch_rewards_in_pt(&mut builder, params);
857
858        // Step 2: Advance the epoch.
859        let mut arguments = vec![storage_rewards, computation_rewards];
860        let call_arg_arguments = vec![
861            CallArg::SUI_SYSTEM_MUT,
862            CallArg::Pure(bcs::to_bytes(&params.epoch).unwrap()),
863            CallArg::Pure(bcs::to_bytes(&params.next_protocol_version.as_u64()).unwrap()),
864            CallArg::Pure(bcs::to_bytes(&params.storage_rebate).unwrap()),
865            CallArg::Pure(bcs::to_bytes(&params.non_refundable_storage_fee).unwrap()),
866            CallArg::Pure(bcs::to_bytes(&params.storage_fund_reinvest_rate).unwrap()),
867            CallArg::Pure(bcs::to_bytes(&params.reward_slashing_rate).unwrap()),
868            CallArg::Pure(bcs::to_bytes(&params.epoch_start_timestamp_ms).unwrap()),
869        ]
870        .into_iter()
871        .map(|a| builder.input(a))
872        .collect::<Result<_, _>>();
873
874        assert_invariant!(
875            call_arg_arguments.is_ok(),
876            "Unable to generate args for advance_epoch transaction!"
877        );
878
879        arguments.append(&mut call_arg_arguments.unwrap());
880
881        info!("Call arguments to advance_epoch transaction: {:?}", params);
882
883        let storage_rebates = builder.programmable_move_call(
884            SUI_SYSTEM_PACKAGE_ID,
885            SUI_SYSTEM_MODULE_NAME.to_owned(),
886            ADVANCE_EPOCH_FUNCTION_NAME.to_owned(),
887            vec![],
888            arguments,
889        );
890
891        // Step 3: Destroy the storage rebates.
892        builder.programmable_move_call(
893            SUI_FRAMEWORK_PACKAGE_ID,
894            BALANCE_MODULE_NAME.to_owned(),
895            BALANCE_DESTROY_REBATES_FUNCTION_NAME.to_owned(),
896            vec![GAS::type_tag()],
897            vec![storage_rebates],
898        );
899        Ok(builder.finish())
900    }
901
902    pub fn construct_advance_epoch_safe_mode_pt(
903        params: &AdvanceEpochParams,
904        protocol_config: &ProtocolConfig,
905    ) -> Result<ProgrammableTransaction, ExecutionError> {
906        let mut builder = ProgrammableTransactionBuilder::new();
907        // Step 1: Create storage and computation rewards.
908        let (storage_rewards, computation_rewards) = mint_epoch_rewards_in_pt(&mut builder, params);
909
910        // Step 2: Advance the epoch.
911        let mut arguments = vec![storage_rewards, computation_rewards];
912
913        let mut args = vec![
914            CallArg::SUI_SYSTEM_MUT,
915            CallArg::Pure(bcs::to_bytes(&params.epoch).unwrap()),
916            CallArg::Pure(bcs::to_bytes(&params.next_protocol_version.as_u64()).unwrap()),
917            CallArg::Pure(bcs::to_bytes(&params.storage_rebate).unwrap()),
918            CallArg::Pure(bcs::to_bytes(&params.non_refundable_storage_fee).unwrap()),
919        ];
920
921        if protocol_config.get_advance_epoch_start_time_in_safe_mode() {
922            args.push(CallArg::Pure(
923                bcs::to_bytes(&params.epoch_start_timestamp_ms).unwrap(),
924            ));
925        }
926
927        let call_arg_arguments = args
928            .into_iter()
929            .map(|a| builder.input(a))
930            .collect::<Result<_, _>>();
931
932        assert_invariant!(
933            call_arg_arguments.is_ok(),
934            "Unable to generate args for advance_epoch transaction!"
935        );
936
937        arguments.append(&mut call_arg_arguments.unwrap());
938
939        info!("Call arguments to advance_epoch transaction: {:?}", params);
940
941        builder.programmable_move_call(
942            SUI_SYSTEM_PACKAGE_ID,
943            SUI_SYSTEM_MODULE_NAME.to_owned(),
944            ADVANCE_EPOCH_SAFE_MODE_FUNCTION_NAME.to_owned(),
945            vec![],
946            arguments,
947        );
948
949        Ok(builder.finish())
950    }
951
952    fn advance_epoch(
953        builder: ProgrammableTransactionBuilder,
954        change_epoch: ChangeEpoch,
955        temporary_store: &mut TemporaryStore<'_>,
956        store: &dyn BackingStore,
957        tx_ctx: Rc<RefCell<TxContext>>,
958        move_vm: &Arc<MoveVM>,
959        gas_charger: &mut GasCharger,
960        protocol_config: &ProtocolConfig,
961        metrics: Arc<ExecutionMetrics>,
962        trace_builder_opt: &mut Option<MoveTraceBuilder>,
963    ) -> Result<(), ExecutionError> {
964        let params = AdvanceEpochParams {
965            epoch: change_epoch.epoch,
966            next_protocol_version: change_epoch.protocol_version,
967            storage_charge: change_epoch.storage_charge,
968            computation_charge: change_epoch.computation_charge,
969            storage_rebate: change_epoch.storage_rebate,
970            non_refundable_storage_fee: change_epoch.non_refundable_storage_fee,
971            storage_fund_reinvest_rate: protocol_config.storage_fund_reinvest_rate(),
972            reward_slashing_rate: protocol_config.reward_slashing_rate(),
973            epoch_start_timestamp_ms: change_epoch.epoch_start_timestamp_ms,
974        };
975        let advance_epoch_pt = construct_advance_epoch_pt(builder, &params)?;
976        let result = programmable_transactions::execution::execute::<execution_mode::System>(
977            protocol_config,
978            metrics.clone(),
979            move_vm,
980            temporary_store,
981            store.as_backing_package_store(),
982            tx_ctx.clone(),
983            gas_charger,
984            None,
985            advance_epoch_pt,
986            trace_builder_opt,
987        );
988
989        #[cfg(msim)]
990        let result = maybe_modify_result(result, change_epoch.epoch);
991
992        if let Err(err) = &result {
993            tracing::error!(
994                "Failed to execute advance epoch transaction. Switching to safe mode. Error: {:?}. Input objects: {:?}. Tx data: {:?}",
995                err.0,
996                temporary_store.objects(),
997                change_epoch,
998            );
999            temporary_store.drop_writes();
1000            // Must reset the storage rebate since we are re-executing.
1001            gas_charger.reset_storage_cost_and_rebate();
1002
1003            if protocol_config.get_advance_epoch_start_time_in_safe_mode() {
1004                temporary_store.advance_epoch_safe_mode(&params, protocol_config);
1005            } else {
1006                let advance_epoch_safe_mode_pt =
1007                    construct_advance_epoch_safe_mode_pt(&params, protocol_config)?;
1008                programmable_transactions::execution::execute::<execution_mode::System>(
1009                    protocol_config,
1010                    metrics.clone(),
1011                    move_vm,
1012                    temporary_store,
1013                    store.as_backing_package_store(),
1014                    tx_ctx.clone(),
1015                    gas_charger,
1016                    None,
1017                    advance_epoch_safe_mode_pt,
1018                    trace_builder_opt,
1019                )
1020                .map_err(|(e, _)| e)
1021                .expect("Advance epoch with safe mode must succeed");
1022            }
1023        }
1024
1025        if protocol_config.fresh_vm_on_framework_upgrade() {
1026            let new_vm = new_move_vm(
1027                all_natives(/* silent */ true, protocol_config),
1028                protocol_config,
1029            )
1030            .expect("Failed to create new MoveVM");
1031            process_system_packages(
1032                change_epoch,
1033                temporary_store,
1034                store,
1035                tx_ctx,
1036                &new_vm,
1037                gas_charger,
1038                protocol_config,
1039                metrics,
1040                trace_builder_opt,
1041            );
1042        } else {
1043            process_system_packages(
1044                change_epoch,
1045                temporary_store,
1046                store,
1047                tx_ctx,
1048                move_vm,
1049                gas_charger,
1050                protocol_config,
1051                metrics,
1052                trace_builder_opt,
1053            );
1054        }
1055        Ok(())
1056    }
1057
1058    fn process_system_packages(
1059        change_epoch: ChangeEpoch,
1060        temporary_store: &mut TemporaryStore<'_>,
1061        store: &dyn BackingStore,
1062        tx_ctx: Rc<RefCell<TxContext>>,
1063        move_vm: &MoveVM,
1064        gas_charger: &mut GasCharger,
1065        protocol_config: &ProtocolConfig,
1066        metrics: Arc<ExecutionMetrics>,
1067        trace_builder_opt: &mut Option<MoveTraceBuilder>,
1068    ) {
1069        let digest = tx_ctx.borrow().digest();
1070        let binary_config = protocol_config.binary_config(None);
1071        for (version, modules, dependencies) in change_epoch.system_packages.into_iter() {
1072            let deserialized_modules: Vec<_> = modules
1073                .iter()
1074                .map(|m| CompiledModule::deserialize_with_config(m, &binary_config).unwrap())
1075                .collect();
1076
1077            if version == OBJECT_START_VERSION {
1078                let package_id = deserialized_modules.first().unwrap().address();
1079                info!("adding new system package {package_id}");
1080
1081                let publish_pt = {
1082                    let mut b = ProgrammableTransactionBuilder::new();
1083                    b.command(Command::Publish(modules, dependencies));
1084                    b.finish()
1085                };
1086
1087                programmable_transactions::execution::execute::<execution_mode::System>(
1088                    protocol_config,
1089                    metrics.clone(),
1090                    move_vm,
1091                    temporary_store,
1092                    store.as_backing_package_store(),
1093                    tx_ctx.clone(),
1094                    gas_charger,
1095                    None,
1096                    publish_pt,
1097                    trace_builder_opt,
1098                )
1099                .map_err(|(e, _)| e)
1100                .expect("System Package Publish must succeed");
1101            } else {
1102                let mut new_package = Object::new_system_package(
1103                    &deserialized_modules,
1104                    version,
1105                    dependencies,
1106                    digest,
1107                );
1108
1109                info!(
1110                    "upgraded system package {:?}",
1111                    new_package.compute_object_reference()
1112                );
1113
1114                // Decrement the version before writing the package so that the store can record the
1115                // version growing by one in the effects.
1116                new_package
1117                    .data
1118                    .try_as_package_mut()
1119                    .unwrap()
1120                    .decrement_version();
1121
1122                // upgrade of a previously existing framework module
1123                temporary_store.upgrade_system_package(new_package);
1124            }
1125        }
1126    }
1127
1128    /// Perform metadata updates in preparation for the transactions in the upcoming checkpoint:
1129    ///
1130    /// - Set the timestamp for the `Clock` shared object from the timestamp in the header from
1131    ///   consensus.
1132    fn setup_consensus_commit(
1133        consensus_commit_timestamp_ms: CheckpointTimestamp,
1134        temporary_store: &mut TemporaryStore<'_>,
1135        store: &dyn BackingStore,
1136        tx_ctx: Rc<RefCell<TxContext>>,
1137        move_vm: &Arc<MoveVM>,
1138        gas_charger: &mut GasCharger,
1139        protocol_config: &ProtocolConfig,
1140        metrics: Arc<ExecutionMetrics>,
1141        trace_builder_opt: &mut Option<MoveTraceBuilder>,
1142    ) -> Result<(), ExecutionError> {
1143        let pt = {
1144            let mut builder = ProgrammableTransactionBuilder::new();
1145            let res = builder.move_call(
1146                SUI_FRAMEWORK_ADDRESS.into(),
1147                CLOCK_MODULE_NAME.to_owned(),
1148                CONSENSUS_COMMIT_PROLOGUE_FUNCTION_NAME.to_owned(),
1149                vec![],
1150                vec![
1151                    CallArg::CLOCK_MUT,
1152                    CallArg::Pure(bcs::to_bytes(&consensus_commit_timestamp_ms).unwrap()),
1153                ],
1154            );
1155            assert_invariant!(
1156                res.is_ok(),
1157                "Unable to generate consensus_commit_prologue transaction!"
1158            );
1159            builder.finish()
1160        };
1161        programmable_transactions::execution::execute::<execution_mode::System>(
1162            protocol_config,
1163            metrics,
1164            move_vm,
1165            temporary_store,
1166            store.as_backing_package_store(),
1167            tx_ctx,
1168            gas_charger,
1169            None,
1170            pt,
1171            trace_builder_opt,
1172        )
1173        .map_err(|(e, _)| e)?;
1174        Ok(())
1175    }
1176
1177    fn setup_authenticator_state_create(
1178        mut builder: ProgrammableTransactionBuilder,
1179    ) -> ProgrammableTransactionBuilder {
1180        builder
1181            .move_call(
1182                SUI_FRAMEWORK_ADDRESS.into(),
1183                AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1184                AUTHENTICATOR_STATE_CREATE_FUNCTION_NAME.to_owned(),
1185                vec![],
1186                vec![],
1187            )
1188            .expect("Unable to generate authenticator_state_create transaction!");
1189        builder
1190    }
1191
1192    fn setup_randomness_state_create(
1193        mut builder: ProgrammableTransactionBuilder,
1194    ) -> ProgrammableTransactionBuilder {
1195        builder
1196            .move_call(
1197                SUI_FRAMEWORK_ADDRESS.into(),
1198                RANDOMNESS_MODULE_NAME.to_owned(),
1199                RANDOMNESS_STATE_CREATE_FUNCTION_NAME.to_owned(),
1200                vec![],
1201                vec![],
1202            )
1203            .expect("Unable to generate randomness_state_create transaction!");
1204        builder
1205    }
1206
1207    fn setup_bridge_create(
1208        mut builder: ProgrammableTransactionBuilder,
1209        chain_id: ChainIdentifier,
1210    ) -> ProgrammableTransactionBuilder {
1211        let bridge_uid = builder
1212            .input(CallArg::Pure(UID::new(SUI_BRIDGE_OBJECT_ID).to_bcs_bytes()))
1213            .expect("Unable to create Bridge object UID!");
1214
1215        let bridge_chain_id = if chain_id == get_mainnet_chain_identifier() {
1216            BridgeChainId::SuiMainnet as u8
1217        } else if chain_id == get_testnet_chain_identifier() {
1218            BridgeChainId::SuiTestnet as u8
1219        } else {
1220            // How do we distinguish devnet from other test envs?
1221            BridgeChainId::SuiCustom as u8
1222        };
1223
1224        let bridge_chain_id = builder.pure(bridge_chain_id).unwrap();
1225        builder.programmable_move_call(
1226            BRIDGE_ADDRESS.into(),
1227            BRIDGE_MODULE_NAME.to_owned(),
1228            BRIDGE_CREATE_FUNCTION_NAME.to_owned(),
1229            vec![],
1230            vec![bridge_uid, bridge_chain_id],
1231        );
1232        builder
1233    }
1234
1235    fn setup_bridge_committee_update(
1236        mut builder: ProgrammableTransactionBuilder,
1237        bridge_shared_version: SequenceNumber,
1238    ) -> ProgrammableTransactionBuilder {
1239        let bridge = builder
1240            .obj(ObjectArg::SharedObject {
1241                id: SUI_BRIDGE_OBJECT_ID,
1242                initial_shared_version: bridge_shared_version,
1243                mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1244            })
1245            .expect("Unable to create Bridge object arg!");
1246        let system_state = builder
1247            .obj(ObjectArg::SUI_SYSTEM_MUT)
1248            .expect("Unable to create System State object arg!");
1249
1250        let voting_power = builder.programmable_move_call(
1251            SUI_SYSTEM_PACKAGE_ID,
1252            SUI_SYSTEM_MODULE_NAME.to_owned(),
1253            ident_str!("validator_voting_powers").to_owned(),
1254            vec![],
1255            vec![system_state],
1256        );
1257
1258        // Hardcoding min stake participation to 75.00%
1259        // TODO: We need to set a correct value or make this configurable.
1260        let min_stake_participation_percentage = builder
1261            .input(CallArg::Pure(
1262                bcs::to_bytes(&BRIDGE_COMMITTEE_MINIMAL_VOTING_POWER).unwrap(),
1263            ))
1264            .unwrap();
1265
1266        builder.programmable_move_call(
1267            BRIDGE_ADDRESS.into(),
1268            BRIDGE_MODULE_NAME.to_owned(),
1269            BRIDGE_INIT_COMMITTEE_FUNCTION_NAME.to_owned(),
1270            vec![],
1271            vec![bridge, voting_power, min_stake_participation_percentage],
1272        );
1273        builder
1274    }
1275
1276    fn setup_authenticator_state_update(
1277        update: AuthenticatorStateUpdate,
1278        temporary_store: &mut TemporaryStore<'_>,
1279        store: &dyn BackingStore,
1280        tx_ctx: Rc<RefCell<TxContext>>,
1281        move_vm: &Arc<MoveVM>,
1282        gas_charger: &mut GasCharger,
1283        protocol_config: &ProtocolConfig,
1284        metrics: Arc<ExecutionMetrics>,
1285        trace_builder_opt: &mut Option<MoveTraceBuilder>,
1286    ) -> Result<(), ExecutionError> {
1287        let pt = {
1288            let mut builder = ProgrammableTransactionBuilder::new();
1289            let res = builder.move_call(
1290                SUI_FRAMEWORK_ADDRESS.into(),
1291                AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1292                AUTHENTICATOR_STATE_UPDATE_FUNCTION_NAME.to_owned(),
1293                vec![],
1294                vec![
1295                    CallArg::Object(ObjectArg::SharedObject {
1296                        id: SUI_AUTHENTICATOR_STATE_OBJECT_ID,
1297                        initial_shared_version: update.authenticator_obj_initial_shared_version,
1298                        mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1299                    }),
1300                    CallArg::Pure(bcs::to_bytes(&update.new_active_jwks).unwrap()),
1301                ],
1302            );
1303            assert_invariant!(
1304                res.is_ok(),
1305                "Unable to generate authenticator_state_update transaction!"
1306            );
1307            builder.finish()
1308        };
1309        programmable_transactions::execution::execute::<execution_mode::System>(
1310            protocol_config,
1311            metrics,
1312            move_vm,
1313            temporary_store,
1314            store.as_backing_package_store(),
1315            tx_ctx,
1316            gas_charger,
1317            None,
1318            pt,
1319            trace_builder_opt,
1320        )
1321        .map_err(|(e, _)| e)?;
1322        Ok(())
1323    }
1324
1325    fn setup_authenticator_state_expire(
1326        mut builder: ProgrammableTransactionBuilder,
1327        expire: AuthenticatorStateExpire,
1328    ) -> ProgrammableTransactionBuilder {
1329        builder
1330            .move_call(
1331                SUI_FRAMEWORK_ADDRESS.into(),
1332                AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1333                AUTHENTICATOR_STATE_EXPIRE_JWKS_FUNCTION_NAME.to_owned(),
1334                vec![],
1335                vec![
1336                    CallArg::Object(ObjectArg::SharedObject {
1337                        id: SUI_AUTHENTICATOR_STATE_OBJECT_ID,
1338                        initial_shared_version: expire.authenticator_obj_initial_shared_version,
1339                        mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1340                    }),
1341                    CallArg::Pure(bcs::to_bytes(&expire.min_epoch).unwrap()),
1342                ],
1343            )
1344            .expect("Unable to generate authenticator_state_expire transaction!");
1345        builder
1346    }
1347
1348    fn setup_randomness_state_update(
1349        update: RandomnessStateUpdate,
1350        temporary_store: &mut TemporaryStore<'_>,
1351        store: &dyn BackingStore,
1352        tx_ctx: Rc<RefCell<TxContext>>,
1353        move_vm: &Arc<MoveVM>,
1354        gas_charger: &mut GasCharger,
1355        protocol_config: &ProtocolConfig,
1356        metrics: Arc<ExecutionMetrics>,
1357        trace_builder_opt: &mut Option<MoveTraceBuilder>,
1358    ) -> Result<(), ExecutionError> {
1359        let pt = {
1360            let mut builder = ProgrammableTransactionBuilder::new();
1361            let res = builder.move_call(
1362                SUI_FRAMEWORK_ADDRESS.into(),
1363                RANDOMNESS_MODULE_NAME.to_owned(),
1364                RANDOMNESS_STATE_UPDATE_FUNCTION_NAME.to_owned(),
1365                vec![],
1366                vec![
1367                    CallArg::Object(ObjectArg::SharedObject {
1368                        id: SUI_RANDOMNESS_STATE_OBJECT_ID,
1369                        initial_shared_version: update.randomness_obj_initial_shared_version,
1370                        mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1371                    }),
1372                    CallArg::Pure(bcs::to_bytes(&update.randomness_round).unwrap()),
1373                    CallArg::Pure(bcs::to_bytes(&update.random_bytes).unwrap()),
1374                ],
1375            );
1376            assert_invariant!(
1377                res.is_ok(),
1378                "Unable to generate randomness_state_update transaction!"
1379            );
1380            builder.finish()
1381        };
1382        programmable_transactions::execution::execute::<execution_mode::System>(
1383            protocol_config,
1384            metrics,
1385            move_vm,
1386            temporary_store,
1387            store.as_backing_package_store(),
1388            tx_ctx,
1389            gas_charger,
1390            None,
1391            pt,
1392            trace_builder_opt,
1393        )
1394        .map_err(|(e, _)| e)?;
1395        Ok(())
1396    }
1397
1398    fn setup_coin_deny_list_state_create(
1399        mut builder: ProgrammableTransactionBuilder,
1400    ) -> ProgrammableTransactionBuilder {
1401        builder
1402            .move_call(
1403                SUI_FRAMEWORK_ADDRESS.into(),
1404                DENY_LIST_MODULE.to_owned(),
1405                DENY_LIST_CREATE_FUNC.to_owned(),
1406                vec![],
1407                vec![],
1408            )
1409            .expect("Unable to generate coin_deny_list_create transaction!");
1410        builder
1411    }
1412
1413    fn setup_store_execution_time_estimates(
1414        mut builder: ProgrammableTransactionBuilder,
1415        estimates: StoredExecutionTimeObservations,
1416    ) -> ProgrammableTransactionBuilder {
1417        let system_state = builder.obj(ObjectArg::SUI_SYSTEM_MUT).unwrap();
1418        // This is stored as a vector<u8> in Move, so we first convert to bytes before again
1419        // serializing inside the call to `pure`.
1420        let estimates_bytes = bcs::to_bytes(&estimates).unwrap();
1421        let estimates_arg = builder.pure(estimates_bytes).unwrap();
1422        builder.programmable_move_call(
1423            SUI_SYSTEM_PACKAGE_ID,
1424            SUI_SYSTEM_MODULE_NAME.to_owned(),
1425            ident_str!("store_execution_time_estimates").to_owned(),
1426            vec![],
1427            vec![system_state, estimates_arg],
1428        );
1429        builder
1430    }
1431
1432    fn setup_store_execution_time_estimates_v2(
1433        mut builder: ProgrammableTransactionBuilder,
1434        estimates: StoredExecutionTimeObservations,
1435        chunk_size: usize,
1436    ) -> ProgrammableTransactionBuilder {
1437        let system_state = builder.obj(ObjectArg::SUI_SYSTEM_MUT).unwrap();
1438
1439        let estimate_chunks = estimates.chunk_observations(chunk_size);
1440
1441        let chunk_bytes: Vec<Vec<u8>> = estimate_chunks
1442            .into_iter()
1443            .map(|chunk| bcs::to_bytes(&chunk).unwrap())
1444            .collect();
1445
1446        let chunks_arg = builder.pure(chunk_bytes).unwrap();
1447
1448        builder.programmable_move_call(
1449            SUI_SYSTEM_PACKAGE_ID,
1450            SUI_SYSTEM_MODULE_NAME.to_owned(),
1451            ident_str!("store_execution_time_estimates_v2").to_owned(),
1452            vec![],
1453            vec![system_state, chunks_arg],
1454        );
1455        builder
1456    }
1457
1458    fn setup_accumulator_root_create(
1459        mut builder: ProgrammableTransactionBuilder,
1460    ) -> ProgrammableTransactionBuilder {
1461        builder
1462            .move_call(
1463                SUI_FRAMEWORK_ADDRESS.into(),
1464                ACCUMULATOR_ROOT_MODULE.to_owned(),
1465                ACCUMULATOR_ROOT_CREATE_FUNC.to_owned(),
1466                vec![],
1467                vec![],
1468            )
1469            .expect("Unable to generate accumulator_root_create transaction!");
1470        builder
1471    }
1472
1473    fn setup_write_accumulator_storage_cost(
1474        mut builder: ProgrammableTransactionBuilder,
1475        write_storage_cost: &WriteAccumulatorStorageCost,
1476    ) -> ProgrammableTransactionBuilder {
1477        let system_state = builder.obj(ObjectArg::SUI_SYSTEM_MUT).unwrap();
1478        let storage_cost_arg = builder.pure(write_storage_cost.storage_cost).unwrap();
1479        builder.programmable_move_call(
1480            SUI_SYSTEM_PACKAGE_ID,
1481            SUI_SYSTEM_MODULE_NAME.to_owned(),
1482            ident_str!("write_accumulator_storage_cost").to_owned(),
1483            vec![],
1484            vec![system_state, storage_cost_arg],
1485        );
1486        builder
1487    }
1488
1489    fn setup_coin_registry_create(
1490        mut builder: ProgrammableTransactionBuilder,
1491    ) -> ProgrammableTransactionBuilder {
1492        builder
1493            .move_call(
1494                SUI_FRAMEWORK_ADDRESS.into(),
1495                ident_str!("coin_registry").to_owned(),
1496                ident_str!("create").to_owned(),
1497                vec![],
1498                vec![],
1499            )
1500            .expect("Unable to generate coin_registry_create transaction!");
1501        builder
1502    }
1503
1504    fn setup_display_registry_create(
1505        mut builder: ProgrammableTransactionBuilder,
1506    ) -> ProgrammableTransactionBuilder {
1507        builder
1508            .move_call(
1509                SUI_FRAMEWORK_ADDRESS.into(),
1510                ident_str!("display_registry").to_owned(),
1511                ident_str!("create").to_owned(),
1512                vec![],
1513                vec![],
1514            )
1515            .expect("Unable to generate display_registry_create transaction!");
1516        builder
1517    }
1518
1519    fn setup_address_alias_state_create(
1520        mut builder: ProgrammableTransactionBuilder,
1521    ) -> ProgrammableTransactionBuilder {
1522        builder
1523            .move_call(
1524                SUI_FRAMEWORK_ADDRESS.into(),
1525                ident_str!("address_alias").to_owned(),
1526                ident_str!("create").to_owned(),
1527                vec![],
1528                vec![],
1529            )
1530            .expect("Unable to generate address_alias_state_create transaction!");
1531        builder
1532    }
1533}