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