Skip to main content

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());
724                            builder = setup_coin_deny_list_state_create(builder);
725                        }
726                        EndOfEpochTransactionKind::BridgeStateCreate(chain_id) => {
727                            assert!(protocol_config.bridge());
728                            builder = setup_bridge_create(builder, chain_id)
729                        }
730                        EndOfEpochTransactionKind::BridgeCommitteeInit(bridge_shared_version) => {
731                            assert!(protocol_config.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                        EndOfEpochTransactionKind::ForwardingAddressRegistryCreate => {
775                            panic!(
776                                "EndOfEpochTransactionKind::ForwardingAddressRegistryCreate should not exist in v3"
777                            );
778                        }
779                    }
780                }
781                unreachable!(
782                    "EndOfEpochTransactionKind::ChangeEpoch should be the last transaction in the list"
783                )
784            }
785            TransactionKind::AuthenticatorStateUpdate(auth_state_update) => {
786                setup_authenticator_state_update(
787                    auth_state_update,
788                    temporary_store,
789                    store,
790                    tx_ctx,
791                    move_vm,
792                    gas_charger,
793                    protocol_config,
794                    metrics,
795                    trace_builder_opt,
796                )
797                .map_err(|e| (e, vec![]))?;
798                Ok((Mode::empty_results(), vec![]))
799            }
800            TransactionKind::RandomnessStateUpdate(randomness_state_update) => {
801                setup_randomness_state_update(
802                    randomness_state_update,
803                    temporary_store,
804                    store,
805                    tx_ctx,
806                    move_vm,
807                    gas_charger,
808                    protocol_config,
809                    metrics,
810                    trace_builder_opt,
811                )
812                .map_err(|e| (e, vec![]))?;
813                Ok((Mode::empty_results(), vec![]))
814            }
815        }?;
816        temporary_store
817            .check_execution_results_consistency()
818            .map_err(|e| (e, vec![]))?;
819        Ok(result)
820    }
821
822    fn mint_epoch_rewards_in_pt(
823        builder: &mut ProgrammableTransactionBuilder,
824        params: &AdvanceEpochParams,
825    ) -> (Argument, Argument) {
826        // Create storage rewards.
827        let storage_charge_arg = builder
828            .input(CallArg::Pure(
829                bcs::to_bytes(&params.storage_charge).unwrap(),
830            ))
831            .unwrap();
832        let storage_rewards = builder.programmable_move_call(
833            SUI_FRAMEWORK_PACKAGE_ID,
834            BALANCE_MODULE_NAME.to_owned(),
835            BALANCE_CREATE_REWARDS_FUNCTION_NAME.to_owned(),
836            vec![GAS::type_tag()],
837            vec![storage_charge_arg],
838        );
839
840        // Create computation rewards.
841        let computation_charge_arg = builder
842            .input(CallArg::Pure(
843                bcs::to_bytes(&params.computation_charge).unwrap(),
844            ))
845            .unwrap();
846        let computation_rewards = builder.programmable_move_call(
847            SUI_FRAMEWORK_PACKAGE_ID,
848            BALANCE_MODULE_NAME.to_owned(),
849            BALANCE_CREATE_REWARDS_FUNCTION_NAME.to_owned(),
850            vec![GAS::type_tag()],
851            vec![computation_charge_arg],
852        );
853        (storage_rewards, computation_rewards)
854    }
855
856    pub fn construct_advance_epoch_pt(
857        mut builder: ProgrammableTransactionBuilder,
858        params: &AdvanceEpochParams,
859    ) -> Result<ProgrammableTransaction, ExecutionError> {
860        // Step 1: Create storage and computation rewards.
861        let (storage_rewards, computation_rewards) = mint_epoch_rewards_in_pt(&mut builder, params);
862
863        // Step 2: Advance the epoch.
864        let mut arguments = vec![storage_rewards, computation_rewards];
865        let call_arg_arguments = vec![
866            CallArg::SUI_SYSTEM_MUT,
867            CallArg::Pure(bcs::to_bytes(&params.epoch).unwrap()),
868            CallArg::Pure(bcs::to_bytes(&params.next_protocol_version.as_u64()).unwrap()),
869            CallArg::Pure(bcs::to_bytes(&params.storage_rebate).unwrap()),
870            CallArg::Pure(bcs::to_bytes(&params.non_refundable_storage_fee).unwrap()),
871            CallArg::Pure(bcs::to_bytes(&params.storage_fund_reinvest_rate).unwrap()),
872            CallArg::Pure(bcs::to_bytes(&params.reward_slashing_rate).unwrap()),
873            CallArg::Pure(bcs::to_bytes(&params.epoch_start_timestamp_ms).unwrap()),
874        ]
875        .into_iter()
876        .map(|a| builder.input(a))
877        .collect::<Result<_, _>>();
878
879        assert_invariant!(
880            call_arg_arguments.is_ok(),
881            "Unable to generate args for advance_epoch transaction!"
882        );
883
884        arguments.append(&mut call_arg_arguments.unwrap());
885
886        info!("Call arguments to advance_epoch transaction: {:?}", params);
887
888        let storage_rebates = builder.programmable_move_call(
889            SUI_SYSTEM_PACKAGE_ID,
890            SUI_SYSTEM_MODULE_NAME.to_owned(),
891            ADVANCE_EPOCH_FUNCTION_NAME.to_owned(),
892            vec![],
893            arguments,
894        );
895
896        // Step 3: Destroy the storage rebates.
897        builder.programmable_move_call(
898            SUI_FRAMEWORK_PACKAGE_ID,
899            BALANCE_MODULE_NAME.to_owned(),
900            BALANCE_DESTROY_REBATES_FUNCTION_NAME.to_owned(),
901            vec![GAS::type_tag()],
902            vec![storage_rebates],
903        );
904        Ok(builder.finish())
905    }
906
907    pub fn construct_advance_epoch_safe_mode_pt(
908        params: &AdvanceEpochParams,
909        protocol_config: &ProtocolConfig,
910    ) -> Result<ProgrammableTransaction, ExecutionError> {
911        let mut builder = ProgrammableTransactionBuilder::new();
912        // Step 1: Create storage and computation rewards.
913        let (storage_rewards, computation_rewards) = mint_epoch_rewards_in_pt(&mut builder, params);
914
915        // Step 2: Advance the epoch.
916        let mut arguments = vec![storage_rewards, computation_rewards];
917
918        let mut args = vec![
919            CallArg::SUI_SYSTEM_MUT,
920            CallArg::Pure(bcs::to_bytes(&params.epoch).unwrap()),
921            CallArg::Pure(bcs::to_bytes(&params.next_protocol_version.as_u64()).unwrap()),
922            CallArg::Pure(bcs::to_bytes(&params.storage_rebate).unwrap()),
923            CallArg::Pure(bcs::to_bytes(&params.non_refundable_storage_fee).unwrap()),
924        ];
925
926        if protocol_config.advance_epoch_start_time_in_safe_mode() {
927            args.push(CallArg::Pure(
928                bcs::to_bytes(&params.epoch_start_timestamp_ms).unwrap(),
929            ));
930        }
931
932        let call_arg_arguments = args
933            .into_iter()
934            .map(|a| builder.input(a))
935            .collect::<Result<_, _>>();
936
937        assert_invariant!(
938            call_arg_arguments.is_ok(),
939            "Unable to generate args for advance_epoch transaction!"
940        );
941
942        arguments.append(&mut call_arg_arguments.unwrap());
943
944        info!("Call arguments to advance_epoch transaction: {:?}", params);
945
946        builder.programmable_move_call(
947            SUI_SYSTEM_PACKAGE_ID,
948            SUI_SYSTEM_MODULE_NAME.to_owned(),
949            ADVANCE_EPOCH_SAFE_MODE_FUNCTION_NAME.to_owned(),
950            vec![],
951            arguments,
952        );
953
954        Ok(builder.finish())
955    }
956
957    fn advance_epoch(
958        builder: ProgrammableTransactionBuilder,
959        change_epoch: ChangeEpoch,
960        temporary_store: &mut TemporaryStore<'_>,
961        store: &dyn BackingStore,
962        tx_ctx: Rc<RefCell<TxContext>>,
963        move_vm: &Arc<MoveVM>,
964        gas_charger: &mut GasCharger,
965        protocol_config: &ProtocolConfig,
966        metrics: Arc<ExecutionMetrics>,
967        trace_builder_opt: &mut Option<MoveTraceBuilder>,
968    ) -> Result<(), ExecutionError> {
969        let params = AdvanceEpochParams {
970            epoch: change_epoch.epoch,
971            next_protocol_version: change_epoch.protocol_version,
972            storage_charge: change_epoch.storage_charge,
973            computation_charge: change_epoch.computation_charge,
974            storage_rebate: change_epoch.storage_rebate,
975            non_refundable_storage_fee: change_epoch.non_refundable_storage_fee,
976            storage_fund_reinvest_rate: protocol_config.storage_fund_reinvest_rate(),
977            reward_slashing_rate: protocol_config.reward_slashing_rate(),
978            epoch_start_timestamp_ms: change_epoch.epoch_start_timestamp_ms,
979        };
980        let advance_epoch_pt = construct_advance_epoch_pt(builder, &params)?;
981        let result = programmable_transactions::execution::execute::<execution_mode::System>(
982            protocol_config,
983            metrics.clone(),
984            move_vm,
985            temporary_store,
986            store.as_backing_package_store(),
987            tx_ctx.clone(),
988            gas_charger,
989            None,
990            advance_epoch_pt,
991            trace_builder_opt,
992        );
993
994        #[cfg(msim)]
995        let result = maybe_modify_result(result, change_epoch.epoch);
996
997        if let Err(err) = &result {
998            tracing::error!(
999                "Failed to execute advance epoch transaction. Switching to safe mode. Error: {:?}. Input objects: {:?}. Tx data: {:?}",
1000                err.0,
1001                temporary_store.objects(),
1002                change_epoch,
1003            );
1004            temporary_store.drop_writes();
1005            // Must reset the storage rebate since we are re-executing.
1006            gas_charger.reset_storage_cost_and_rebate();
1007
1008            if protocol_config.advance_epoch_start_time_in_safe_mode() {
1009                temporary_store.advance_epoch_safe_mode(&params, protocol_config);
1010            } else {
1011                let advance_epoch_safe_mode_pt =
1012                    construct_advance_epoch_safe_mode_pt(&params, protocol_config)?;
1013                programmable_transactions::execution::execute::<execution_mode::System>(
1014                    protocol_config,
1015                    metrics.clone(),
1016                    move_vm,
1017                    temporary_store,
1018                    store.as_backing_package_store(),
1019                    tx_ctx.clone(),
1020                    gas_charger,
1021                    None,
1022                    advance_epoch_safe_mode_pt,
1023                    trace_builder_opt,
1024                )
1025                .map_err(|(e, _)| e)
1026                .expect("Advance epoch with safe mode must succeed");
1027            }
1028        }
1029
1030        if protocol_config.fresh_vm_on_framework_upgrade() {
1031            let new_vm = new_move_vm(
1032                all_natives(/* silent */ true, protocol_config),
1033                protocol_config,
1034            )
1035            .expect("Failed to create new MoveVM");
1036            process_system_packages(
1037                change_epoch,
1038                temporary_store,
1039                store,
1040                tx_ctx,
1041                &new_vm,
1042                gas_charger,
1043                protocol_config,
1044                metrics,
1045                trace_builder_opt,
1046            );
1047        } else {
1048            process_system_packages(
1049                change_epoch,
1050                temporary_store,
1051                store,
1052                tx_ctx,
1053                move_vm,
1054                gas_charger,
1055                protocol_config,
1056                metrics,
1057                trace_builder_opt,
1058            );
1059        }
1060        Ok(())
1061    }
1062
1063    fn process_system_packages(
1064        change_epoch: ChangeEpoch,
1065        temporary_store: &mut TemporaryStore<'_>,
1066        store: &dyn BackingStore,
1067        tx_ctx: Rc<RefCell<TxContext>>,
1068        move_vm: &MoveVM,
1069        gas_charger: &mut GasCharger,
1070        protocol_config: &ProtocolConfig,
1071        metrics: Arc<ExecutionMetrics>,
1072        trace_builder_opt: &mut Option<MoveTraceBuilder>,
1073    ) {
1074        let digest = tx_ctx.borrow().digest();
1075        let binary_config = protocol_config.binary_config(None);
1076        for (version, modules, dependencies) in change_epoch.system_packages.into_iter() {
1077            let deserialized_modules: Vec<_> = modules
1078                .iter()
1079                .map(|m| CompiledModule::deserialize_with_config(m, &binary_config).unwrap())
1080                .collect();
1081
1082            if version == OBJECT_START_VERSION {
1083                let package_id = deserialized_modules.first().unwrap().address();
1084                info!("adding new system package {package_id}");
1085
1086                let publish_pt = {
1087                    let mut b = ProgrammableTransactionBuilder::new();
1088                    b.command(Command::Publish(modules, dependencies));
1089                    b.finish()
1090                };
1091
1092                programmable_transactions::execution::execute::<execution_mode::System>(
1093                    protocol_config,
1094                    metrics.clone(),
1095                    move_vm,
1096                    temporary_store,
1097                    store.as_backing_package_store(),
1098                    tx_ctx.clone(),
1099                    gas_charger,
1100                    None,
1101                    publish_pt,
1102                    trace_builder_opt,
1103                )
1104                .map_err(|(e, _)| e)
1105                .expect("System Package Publish must succeed");
1106            } else {
1107                let mut new_package = Object::new_system_package(
1108                    &deserialized_modules,
1109                    version,
1110                    dependencies,
1111                    digest,
1112                );
1113
1114                info!(
1115                    "upgraded system package {:?}",
1116                    new_package.compute_object_reference()
1117                );
1118
1119                // Decrement the version before writing the package so that the store can record the
1120                // version growing by one in the effects.
1121                new_package
1122                    .data
1123                    .try_as_package_mut()
1124                    .unwrap()
1125                    .decrement_version();
1126
1127                // upgrade of a previously existing framework module
1128                temporary_store.upgrade_system_package(new_package);
1129            }
1130        }
1131    }
1132
1133    /// Perform metadata updates in preparation for the transactions in the upcoming checkpoint:
1134    ///
1135    /// - Set the timestamp for the `Clock` shared object from the timestamp in the header from
1136    ///   consensus.
1137    fn setup_consensus_commit(
1138        consensus_commit_timestamp_ms: CheckpointTimestamp,
1139        temporary_store: &mut TemporaryStore<'_>,
1140        store: &dyn BackingStore,
1141        tx_ctx: Rc<RefCell<TxContext>>,
1142        move_vm: &Arc<MoveVM>,
1143        gas_charger: &mut GasCharger,
1144        protocol_config: &ProtocolConfig,
1145        metrics: Arc<ExecutionMetrics>,
1146        trace_builder_opt: &mut Option<MoveTraceBuilder>,
1147    ) -> Result<(), ExecutionError> {
1148        let pt = {
1149            let mut builder = ProgrammableTransactionBuilder::new();
1150            let res = builder.move_call(
1151                SUI_FRAMEWORK_ADDRESS.into(),
1152                CLOCK_MODULE_NAME.to_owned(),
1153                CONSENSUS_COMMIT_PROLOGUE_FUNCTION_NAME.to_owned(),
1154                vec![],
1155                vec![
1156                    CallArg::CLOCK_MUT,
1157                    CallArg::Pure(bcs::to_bytes(&consensus_commit_timestamp_ms).unwrap()),
1158                ],
1159            );
1160            assert_invariant!(
1161                res.is_ok(),
1162                "Unable to generate consensus_commit_prologue transaction!"
1163            );
1164            builder.finish()
1165        };
1166        programmable_transactions::execution::execute::<execution_mode::System>(
1167            protocol_config,
1168            metrics,
1169            move_vm,
1170            temporary_store,
1171            store.as_backing_package_store(),
1172            tx_ctx,
1173            gas_charger,
1174            None,
1175            pt,
1176            trace_builder_opt,
1177        )
1178        .map_err(|(e, _)| e)?;
1179        Ok(())
1180    }
1181
1182    fn setup_authenticator_state_create(
1183        mut builder: ProgrammableTransactionBuilder,
1184    ) -> ProgrammableTransactionBuilder {
1185        builder
1186            .move_call(
1187                SUI_FRAMEWORK_ADDRESS.into(),
1188                AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1189                AUTHENTICATOR_STATE_CREATE_FUNCTION_NAME.to_owned(),
1190                vec![],
1191                vec![],
1192            )
1193            .expect("Unable to generate authenticator_state_create transaction!");
1194        builder
1195    }
1196
1197    fn setup_randomness_state_create(
1198        mut builder: ProgrammableTransactionBuilder,
1199    ) -> ProgrammableTransactionBuilder {
1200        builder
1201            .move_call(
1202                SUI_FRAMEWORK_ADDRESS.into(),
1203                RANDOMNESS_MODULE_NAME.to_owned(),
1204                RANDOMNESS_STATE_CREATE_FUNCTION_NAME.to_owned(),
1205                vec![],
1206                vec![],
1207            )
1208            .expect("Unable to generate randomness_state_create transaction!");
1209        builder
1210    }
1211
1212    fn setup_bridge_create(
1213        mut builder: ProgrammableTransactionBuilder,
1214        chain_id: ChainIdentifier,
1215    ) -> ProgrammableTransactionBuilder {
1216        let bridge_uid = builder
1217            .input(CallArg::Pure(UID::new(SUI_BRIDGE_OBJECT_ID).to_bcs_bytes()))
1218            .expect("Unable to create Bridge object UID!");
1219
1220        let bridge_chain_id = if chain_id == get_mainnet_chain_identifier() {
1221            BridgeChainId::SuiMainnet as u8
1222        } else if chain_id == get_testnet_chain_identifier() {
1223            BridgeChainId::SuiTestnet as u8
1224        } else {
1225            // How do we distinguish devnet from other test envs?
1226            BridgeChainId::SuiCustom as u8
1227        };
1228
1229        let bridge_chain_id = builder.pure(bridge_chain_id).unwrap();
1230        builder.programmable_move_call(
1231            BRIDGE_ADDRESS.into(),
1232            BRIDGE_MODULE_NAME.to_owned(),
1233            BRIDGE_CREATE_FUNCTION_NAME.to_owned(),
1234            vec![],
1235            vec![bridge_uid, bridge_chain_id],
1236        );
1237        builder
1238    }
1239
1240    fn setup_bridge_committee_update(
1241        mut builder: ProgrammableTransactionBuilder,
1242        bridge_shared_version: SequenceNumber,
1243    ) -> ProgrammableTransactionBuilder {
1244        let bridge = builder
1245            .obj(ObjectArg::SharedObject {
1246                id: SUI_BRIDGE_OBJECT_ID,
1247                initial_shared_version: bridge_shared_version,
1248                mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1249            })
1250            .expect("Unable to create Bridge object arg!");
1251        let system_state = builder
1252            .obj(ObjectArg::SUI_SYSTEM_MUT)
1253            .expect("Unable to create System State object arg!");
1254
1255        let voting_power = builder.programmable_move_call(
1256            SUI_SYSTEM_PACKAGE_ID,
1257            SUI_SYSTEM_MODULE_NAME.to_owned(),
1258            ident_str!("validator_voting_powers").to_owned(),
1259            vec![],
1260            vec![system_state],
1261        );
1262
1263        // Hardcoding min stake participation to 75.00%
1264        // TODO: We need to set a correct value or make this configurable.
1265        let min_stake_participation_percentage = builder
1266            .input(CallArg::Pure(
1267                bcs::to_bytes(&BRIDGE_COMMITTEE_MINIMAL_VOTING_POWER).unwrap(),
1268            ))
1269            .unwrap();
1270
1271        builder.programmable_move_call(
1272            BRIDGE_ADDRESS.into(),
1273            BRIDGE_MODULE_NAME.to_owned(),
1274            BRIDGE_INIT_COMMITTEE_FUNCTION_NAME.to_owned(),
1275            vec![],
1276            vec![bridge, voting_power, min_stake_participation_percentage],
1277        );
1278        builder
1279    }
1280
1281    fn setup_authenticator_state_update(
1282        update: AuthenticatorStateUpdate,
1283        temporary_store: &mut TemporaryStore<'_>,
1284        store: &dyn BackingStore,
1285        tx_ctx: Rc<RefCell<TxContext>>,
1286        move_vm: &Arc<MoveVM>,
1287        gas_charger: &mut GasCharger,
1288        protocol_config: &ProtocolConfig,
1289        metrics: Arc<ExecutionMetrics>,
1290        trace_builder_opt: &mut Option<MoveTraceBuilder>,
1291    ) -> Result<(), ExecutionError> {
1292        let pt = {
1293            let mut builder = ProgrammableTransactionBuilder::new();
1294            let res = builder.move_call(
1295                SUI_FRAMEWORK_ADDRESS.into(),
1296                AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1297                AUTHENTICATOR_STATE_UPDATE_FUNCTION_NAME.to_owned(),
1298                vec![],
1299                vec![
1300                    CallArg::Object(ObjectArg::SharedObject {
1301                        id: SUI_AUTHENTICATOR_STATE_OBJECT_ID,
1302                        initial_shared_version: update.authenticator_obj_initial_shared_version,
1303                        mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1304                    }),
1305                    CallArg::Pure(bcs::to_bytes(&update.new_active_jwks).unwrap()),
1306                ],
1307            );
1308            assert_invariant!(
1309                res.is_ok(),
1310                "Unable to generate authenticator_state_update transaction!"
1311            );
1312            builder.finish()
1313        };
1314        programmable_transactions::execution::execute::<execution_mode::System>(
1315            protocol_config,
1316            metrics,
1317            move_vm,
1318            temporary_store,
1319            store.as_backing_package_store(),
1320            tx_ctx,
1321            gas_charger,
1322            None,
1323            pt,
1324            trace_builder_opt,
1325        )
1326        .map_err(|(e, _)| e)?;
1327        Ok(())
1328    }
1329
1330    fn setup_authenticator_state_expire(
1331        mut builder: ProgrammableTransactionBuilder,
1332        expire: AuthenticatorStateExpire,
1333    ) -> ProgrammableTransactionBuilder {
1334        builder
1335            .move_call(
1336                SUI_FRAMEWORK_ADDRESS.into(),
1337                AUTHENTICATOR_STATE_MODULE_NAME.to_owned(),
1338                AUTHENTICATOR_STATE_EXPIRE_JWKS_FUNCTION_NAME.to_owned(),
1339                vec![],
1340                vec![
1341                    CallArg::Object(ObjectArg::SharedObject {
1342                        id: SUI_AUTHENTICATOR_STATE_OBJECT_ID,
1343                        initial_shared_version: expire.authenticator_obj_initial_shared_version,
1344                        mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1345                    }),
1346                    CallArg::Pure(bcs::to_bytes(&expire.min_epoch).unwrap()),
1347                ],
1348            )
1349            .expect("Unable to generate authenticator_state_expire transaction!");
1350        builder
1351    }
1352
1353    fn setup_randomness_state_update(
1354        update: RandomnessStateUpdate,
1355        temporary_store: &mut TemporaryStore<'_>,
1356        store: &dyn BackingStore,
1357        tx_ctx: Rc<RefCell<TxContext>>,
1358        move_vm: &Arc<MoveVM>,
1359        gas_charger: &mut GasCharger,
1360        protocol_config: &ProtocolConfig,
1361        metrics: Arc<ExecutionMetrics>,
1362        trace_builder_opt: &mut Option<MoveTraceBuilder>,
1363    ) -> Result<(), ExecutionError> {
1364        let pt = {
1365            let mut builder = ProgrammableTransactionBuilder::new();
1366            let res = builder.move_call(
1367                SUI_FRAMEWORK_ADDRESS.into(),
1368                RANDOMNESS_MODULE_NAME.to_owned(),
1369                RANDOMNESS_STATE_UPDATE_FUNCTION_NAME.to_owned(),
1370                vec![],
1371                vec![
1372                    CallArg::Object(ObjectArg::SharedObject {
1373                        id: SUI_RANDOMNESS_STATE_OBJECT_ID,
1374                        initial_shared_version: update.randomness_obj_initial_shared_version,
1375                        mutability: sui_types::transaction::SharedObjectMutability::Mutable,
1376                    }),
1377                    CallArg::Pure(bcs::to_bytes(&update.randomness_round).unwrap()),
1378                    CallArg::Pure(bcs::to_bytes(&update.random_bytes).unwrap()),
1379                ],
1380            );
1381            assert_invariant!(
1382                res.is_ok(),
1383                "Unable to generate randomness_state_update transaction!"
1384            );
1385            builder.finish()
1386        };
1387        programmable_transactions::execution::execute::<execution_mode::System>(
1388            protocol_config,
1389            metrics,
1390            move_vm,
1391            temporary_store,
1392            store.as_backing_package_store(),
1393            tx_ctx,
1394            gas_charger,
1395            None,
1396            pt,
1397            trace_builder_opt,
1398        )
1399        .map_err(|(e, _)| e)?;
1400        Ok(())
1401    }
1402
1403    fn setup_coin_deny_list_state_create(
1404        mut builder: ProgrammableTransactionBuilder,
1405    ) -> ProgrammableTransactionBuilder {
1406        builder
1407            .move_call(
1408                SUI_FRAMEWORK_ADDRESS.into(),
1409                DENY_LIST_MODULE.to_owned(),
1410                DENY_LIST_CREATE_FUNC.to_owned(),
1411                vec![],
1412                vec![],
1413            )
1414            .expect("Unable to generate coin_deny_list_create transaction!");
1415        builder
1416    }
1417
1418    fn setup_store_execution_time_estimates(
1419        mut builder: ProgrammableTransactionBuilder,
1420        estimates: StoredExecutionTimeObservations,
1421    ) -> ProgrammableTransactionBuilder {
1422        let system_state = builder.obj(ObjectArg::SUI_SYSTEM_MUT).unwrap();
1423        // This is stored as a vector<u8> in Move, so we first convert to bytes before again
1424        // serializing inside the call to `pure`.
1425        let estimates_bytes = bcs::to_bytes(&estimates).unwrap();
1426        let estimates_arg = builder.pure(estimates_bytes).unwrap();
1427        builder.programmable_move_call(
1428            SUI_SYSTEM_PACKAGE_ID,
1429            SUI_SYSTEM_MODULE_NAME.to_owned(),
1430            ident_str!("store_execution_time_estimates").to_owned(),
1431            vec![],
1432            vec![system_state, estimates_arg],
1433        );
1434        builder
1435    }
1436
1437    fn setup_store_execution_time_estimates_v2(
1438        mut builder: ProgrammableTransactionBuilder,
1439        estimates: StoredExecutionTimeObservations,
1440        chunk_size: usize,
1441    ) -> ProgrammableTransactionBuilder {
1442        let system_state = builder.obj(ObjectArg::SUI_SYSTEM_MUT).unwrap();
1443
1444        let estimate_chunks = estimates.chunk_observations(chunk_size);
1445
1446        let chunk_bytes: Vec<Vec<u8>> = estimate_chunks
1447            .into_iter()
1448            .map(|chunk| bcs::to_bytes(&chunk).unwrap())
1449            .collect();
1450
1451        let chunks_arg = builder.pure(chunk_bytes).unwrap();
1452
1453        builder.programmable_move_call(
1454            SUI_SYSTEM_PACKAGE_ID,
1455            SUI_SYSTEM_MODULE_NAME.to_owned(),
1456            ident_str!("store_execution_time_estimates_v2").to_owned(),
1457            vec![],
1458            vec![system_state, chunks_arg],
1459        );
1460        builder
1461    }
1462
1463    fn setup_accumulator_root_create(
1464        mut builder: ProgrammableTransactionBuilder,
1465    ) -> ProgrammableTransactionBuilder {
1466        builder
1467            .move_call(
1468                SUI_FRAMEWORK_ADDRESS.into(),
1469                ACCUMULATOR_ROOT_MODULE.to_owned(),
1470                ACCUMULATOR_ROOT_CREATE_FUNC.to_owned(),
1471                vec![],
1472                vec![],
1473            )
1474            .expect("Unable to generate accumulator_root_create transaction!");
1475        builder
1476    }
1477
1478    fn setup_write_accumulator_storage_cost(
1479        mut builder: ProgrammableTransactionBuilder,
1480        write_storage_cost: &WriteAccumulatorStorageCost,
1481    ) -> ProgrammableTransactionBuilder {
1482        let system_state = builder.obj(ObjectArg::SUI_SYSTEM_MUT).unwrap();
1483        let storage_cost_arg = builder.pure(write_storage_cost.storage_cost).unwrap();
1484        builder.programmable_move_call(
1485            SUI_SYSTEM_PACKAGE_ID,
1486            SUI_SYSTEM_MODULE_NAME.to_owned(),
1487            ident_str!("write_accumulator_storage_cost").to_owned(),
1488            vec![],
1489            vec![system_state, storage_cost_arg],
1490        );
1491        builder
1492    }
1493
1494    fn setup_coin_registry_create(
1495        mut builder: ProgrammableTransactionBuilder,
1496    ) -> ProgrammableTransactionBuilder {
1497        builder
1498            .move_call(
1499                SUI_FRAMEWORK_ADDRESS.into(),
1500                ident_str!("coin_registry").to_owned(),
1501                ident_str!("create").to_owned(),
1502                vec![],
1503                vec![],
1504            )
1505            .expect("Unable to generate coin_registry_create transaction!");
1506        builder
1507    }
1508
1509    fn setup_display_registry_create(
1510        mut builder: ProgrammableTransactionBuilder,
1511    ) -> ProgrammableTransactionBuilder {
1512        builder
1513            .move_call(
1514                SUI_FRAMEWORK_ADDRESS.into(),
1515                ident_str!("display_registry").to_owned(),
1516                ident_str!("create").to_owned(),
1517                vec![],
1518                vec![],
1519            )
1520            .expect("Unable to generate display_registry_create transaction!");
1521        builder
1522    }
1523
1524    fn setup_address_alias_state_create(
1525        mut builder: ProgrammableTransactionBuilder,
1526    ) -> ProgrammableTransactionBuilder {
1527        builder
1528            .move_call(
1529                SUI_FRAMEWORK_ADDRESS.into(),
1530                ident_str!("address_alias").to_owned(),
1531                ident_str!("create").to_owned(),
1532                vec![],
1533                vec![],
1534            )
1535            .expect("Unable to generate address_alias_state_create transaction!");
1536        builder
1537    }
1538}