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