Skip to main content

sui_adapter_latest/static_programmable_transactions/
env.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4//! This module defines the shared environment, `Env`, used for the compilation/translation and
5//! execution of programmable transactions. While the "context" for each pass might be different,
6//! the `Env` provides consistent access to shared components such as the VM or the protocol config.
7
8use crate::{
9    data_store::{VerifiedPackageStore, cached_package_store::CachedPackageStore},
10    execution_mode::ExecutionMode,
11    execution_value::ExecutionState,
12    static_programmable_transactions::{
13        execution::context::subst_signature,
14        linkage::{analysis::LinkageAnalyzer, resolved_linkage::ExecutableLinkage},
15        loading::ast::{
16            self as L, Datatype, DeserializedPackage, LoadedFunction, LoadedFunctionInstantiation,
17            Type,
18        },
19    },
20};
21use move_binary_format::{
22    CompiledModule,
23    errors::{Location, VMError, VMResult},
24    file_format::{Ability, AbilitySet, TypeParameterIndex},
25};
26use move_core_types::{
27    annotated_value,
28    identifier::IdentStr,
29    language_storage::{ModuleId, StructTag},
30    resolver::IntraPackageName,
31    runtime_value::{self, MoveTypeLayout},
32    vm_status::StatusCode,
33};
34use move_vm_runtime::{
35    execution::{self as vm_runtime, vm::MoveVM},
36    runtime::MoveRuntime,
37};
38use std::{cell::OnceCell, marker::PhantomData, rc::Rc};
39use sui_protocol_config::ProtocolConfig;
40use sui_types::{
41    Identifier, SUI_FRAMEWORK_PACKAGE_ID, TypeTag,
42    allowance::RESOLVED_ALLOWANCE_WITHDRAWAL_STRUCT,
43    balance::RESOLVED_BALANCE_STRUCT,
44    base_types::{ObjectID, TxContext},
45    coin::RESOLVED_COIN_STRUCT,
46    error::ExecutionErrorTrait,
47    execution_status::{ExecutionErrorKind, TypeArgumentError},
48    funds_accumulator::RESOLVED_WITHDRAWAL_STRUCT,
49    gas_coin::GasCoin,
50    move_package::{MovePackage, UpgradeCap, UpgradeReceipt, UpgradeTicket},
51    object::Object,
52    type_input::{StructInput, TypeInput},
53};
54
55pub struct Env<'pc, 'vm, 'state, 'linkage, 'extensions, Mode>
56where
57    Mode: ExecutionMode,
58{
59    pub protocol_config: &'pc ProtocolConfig,
60    pub vm: &'vm MoveRuntime,
61    pub state_view: &'state mut dyn ExecutionState,
62    pub linkable_store: &'linkage CachedPackageStore<'state, 'vm>,
63    pub linkage_analysis: &'linkage LinkageAnalyzer,
64    gas_coin_type: OnceCell<Type>,
65    upgrade_ticket_type: OnceCell<Type>,
66    upgrade_receipt_type: OnceCell<Type>,
67    upgrade_cap_type: OnceCell<Type>,
68    tx_context_type: OnceCell<Type>,
69    // The VM used for type resolution of input types (and types statically present in the PTB)
70    // only. This VM should only be used for resolution of input types, but should not be used for
71    // resolution around function calls, execution, or final serialization of execution values.
72    input_type_resolution_vm: &'linkage MoveVM<'extensions>,
73    _mode: PhantomData<fn() -> Mode>,
74}
75
76macro_rules! get_or_init_ty {
77    ($env:expr, $ident:ident, $tag:expr) => {{
78        let env = $env;
79        if env.$ident.get().is_none() {
80            let tag = $tag;
81            let ty = env.load_type_from_struct(&tag)?;
82            env.$ident.set(ty.clone()).unwrap();
83        }
84        Ok(env.$ident.get().unwrap().clone())
85    }};
86}
87
88impl<'pc, 'vm, 'state, 'linkage, 'extensions, Mode>
89    Env<'pc, 'vm, 'state, 'linkage, 'extensions, Mode>
90where
91    Mode: ExecutionMode,
92{
93    pub fn new(
94        protocol_config: &'pc ProtocolConfig,
95        vm: &'vm MoveRuntime,
96        state_view: &'state mut dyn ExecutionState,
97        linkable_store: &'linkage CachedPackageStore<'state, 'vm>,
98        linkage_analysis: &'linkage LinkageAnalyzer,
99        input_type_resolution_vm: &'linkage MoveVM<'extensions>,
100    ) -> Self {
101        Self {
102            protocol_config,
103            vm,
104            state_view,
105            linkable_store,
106            linkage_analysis,
107            gas_coin_type: OnceCell::new(),
108            upgrade_ticket_type: OnceCell::new(),
109            upgrade_receipt_type: OnceCell::new(),
110            upgrade_cap_type: OnceCell::new(),
111            tx_context_type: OnceCell::new(),
112            input_type_resolution_vm,
113            _mode: PhantomData,
114        }
115    }
116
117    pub fn convert_linked_vm_error(&self, e: VMError, linkage: &ExecutableLinkage) -> Mode::Error {
118        convert_vm_error(e, self.linkable_store, Some(linkage), self.protocol_config)
119    }
120
121    pub fn convert_vm_error(&self, e: VMError) -> Mode::Error {
122        convert_vm_error(e, self.linkable_store, None, self.protocol_config)
123    }
124
125    pub fn convert_type_argument_error(
126        &self,
127        idx: usize,
128        e: VMError,
129        linkage: &ExecutableLinkage,
130    ) -> Mode::Error {
131        use move_core_types::vm_status::StatusCode;
132        let argument_idx = match checked_as!(idx, TypeParameterIndex) {
133            Err(e) => return e.into(),
134            Ok(v) => v,
135        };
136        match e.major_status() {
137            StatusCode::NUMBER_OF_TYPE_ARGUMENTS_MISMATCH => {
138                Mode::Error::from_kind(ExecutionErrorKind::TypeArityMismatch)
139            }
140            StatusCode::EXTERNAL_RESOLUTION_REQUEST_ERROR => {
141                Mode::Error::from_kind(ExecutionErrorKind::TypeArgumentError {
142                    argument_idx,
143                    kind: TypeArgumentError::TypeNotFound,
144                })
145            }
146            StatusCode::CONSTRAINT_NOT_SATISFIED => {
147                Mode::Error::from_kind(ExecutionErrorKind::TypeArgumentError {
148                    argument_idx,
149                    kind: TypeArgumentError::ConstraintNotSatisfied,
150                })
151            }
152            _ => self.convert_linked_vm_error(e, linkage),
153        }
154    }
155
156    pub fn fully_annotated_layout(
157        &self,
158        ty: &Type,
159    ) -> Result<annotated_value::MoveTypeLayout, Mode::Error> {
160        let tag: TypeTag = ty.clone().try_into().map_err(|s| {
161            Mode::Error::new_with_source(ExecutionErrorKind::VMInvariantViolation, s)
162        })?;
163        let objects = tag.all_addresses();
164        let tag_linkage = ExecutableLinkage::type_linkage::<_, Mode::Error>(
165            self.linkage_analysis.config().clone(),
166            objects.into_iter().map(ObjectID::from),
167            self.linkable_store,
168        )?;
169        self.input_type_resolution_vm
170            .annotated_type_layout(&tag)
171            .map_err(|e| self.convert_linked_vm_error(e, &tag_linkage))
172    }
173
174    pub fn runtime_layout(&self, ty: &Type) -> Result<runtime_value::MoveTypeLayout, Mode::Error> {
175        let tag: TypeTag = ty.clone().try_into().map_err(|s| {
176            Mode::Error::new_with_source(ExecutionErrorKind::VMInvariantViolation, s)
177        })?;
178        let objects = tag.all_addresses();
179        let tag_linkage = ExecutableLinkage::type_linkage::<_, Mode::Error>(
180            self.linkage_analysis.config().clone(),
181            objects.into_iter().map(ObjectID::from),
182            self.linkable_store,
183        )?;
184        self.input_type_resolution_vm
185            .runtime_type_layout(&tag)
186            .map_err(|e| self.convert_linked_vm_error(e, &tag_linkage))
187    }
188
189    pub fn load_framework_function(
190        &self,
191        module: &IdentStr,
192        function: &IdentStr,
193        type_arguments: Vec<Type>,
194        unified_linkage: Option<&ExecutableLinkage>,
195    ) -> Result<LoadedFunction, Mode::Error> {
196        let mut loaded = self.load_function(
197            SUI_FRAMEWORK_PACKAGE_ID,
198            module.to_string(),
199            function.to_string(),
200            type_arguments,
201        )?;
202        if self.protocol_config.harden_linkage_consistency() {
203            let Some(unified_linkage) = unified_linkage else {
204                invariant_violation!(
205                    "Unified linkage is required when hardened linkage consistency is enabled"
206                )
207            };
208            assert_invariant!(
209                loaded
210                    .linkage
211                    .0
212                    .linkage
213                    .keys()
214                    .all(|original_id| unified_linkage.0.linkage.contains_key(original_id)),
215                "transaction linkage drops a package resolved by a framework MoveCall"
216            );
217            loaded.linkage = unified_linkage.clone();
218        }
219        Ok(loaded)
220    }
221
222    pub fn load_function(
223        &self,
224        package: ObjectID,
225        module: String,
226        function: String,
227        type_arguments: Vec<Type>,
228    ) -> Result<LoadedFunction, Mode::Error> {
229        let module = to_identifier(module)?;
230        let name = to_identifier(function)?;
231
232        let linkage = self.linkage_analysis.compute_call_linkage::<Mode::Error>(
233            &package,
234            module.as_ident_str(),
235            name.as_ident_str(),
236            &type_arguments,
237            self.linkable_store,
238        )?;
239
240        let Some(original_id) = linkage.0.resolve_to_original_id(&package) else {
241            invariant_violation!(
242                "Package ID {:?} is not found in linkage generated for that package",
243                package
244            );
245        };
246        let version_mid = ModuleId::new(package.into(), module.clone());
247        let original_mid = ModuleId::new(original_id.into(), module);
248        let loaded_type_arguments = type_arguments
249            .iter()
250            .enumerate()
251            .map(|(idx, ty)| self.load_vm_type_argument_from_adapter_type(idx, ty))
252            .collect::<Result<Vec<_>, _>>()?;
253        // NB: We cannot use the resolution VM here because the linkage for that unifies up, and if
254        // this is a private entry function, it may have been removed in future versions of the
255        // package.
256        let vm = self
257            .vm
258            .make_vm(
259                &self.linkable_store.package_store,
260                linkage.linkage_context::<Mode::Error>()?,
261            )
262            .map_err(|e| self.convert_linked_vm_error(e, &linkage))?;
263        let runtime_signature = vm
264            .function_information(&original_mid, name.as_ident_str(), &loaded_type_arguments)
265            .map_err(|e| {
266                if e.major_status() == StatusCode::EXTERNAL_RESOLUTION_REQUEST_ERROR {
267                    Mode::Error::new_with_source(
268                        ExecutionErrorKind::FunctionNotFound,
269                        format!(
270                            "Could not resolve function '{}' in module '{}'",
271                            name, &version_mid,
272                        ),
273                    )
274                } else {
275                    self.convert_linked_vm_error(e, &linkage)
276                }
277            })?;
278        let runtime_signature = subst_signature(runtime_signature, &loaded_type_arguments)
279            .map_err(|e| self.convert_linked_vm_error(e, &linkage))?;
280        let parameters = runtime_signature
281            .parameters
282            .into_iter()
283            .map(|ty| self.adapter_type_from_vm_type(&vm, &ty))
284            .collect::<Result<Vec<_>, _>>()?;
285        let return_ = runtime_signature
286            .return_
287            .into_iter()
288            .map(|ty| self.adapter_type_from_vm_type(&vm, &ty))
289            .collect::<Result<Vec<_>, _>>()?;
290        let signature = LoadedFunctionInstantiation {
291            parameters,
292            return_,
293        };
294        Ok(LoadedFunction {
295            version_mid,
296            original_mid,
297            name,
298            type_arguments,
299            signature,
300            linkage,
301            instruction_length: runtime_signature.instruction_count,
302            definition_index: runtime_signature.index,
303            visibility: runtime_signature.visibility,
304            is_entry: runtime_signature.is_entry,
305            is_native: runtime_signature.is_native,
306        })
307    }
308
309    pub fn load_type_input(&self, idx: usize, ty: TypeInput) -> Result<Type, Mode::Error> {
310        let vm_type = self.load_vm_type_from_type_input(idx, ty)?;
311        self.adapter_type_from_vm_type(self.input_type_resolution_vm, &vm_type)
312    }
313
314    pub fn load_type_tag(&self, idx: usize, ty: &TypeTag) -> Result<Type, Mode::Error> {
315        let vm_type = self.load_vm_type_from_type_tag(Some(idx), ty)?;
316        self.adapter_type_from_vm_type(self.input_type_resolution_vm, &vm_type)
317    }
318
319    /// We verify that all types in the `StructTag` are defining ID-based types.
320    pub fn load_type_from_struct(&self, tag: &StructTag) -> Result<Type, Mode::Error> {
321        let vm_type =
322            self.load_vm_type_from_type_tag(None, &TypeTag::Struct(Box::new(tag.clone())))?;
323        self.adapter_type_from_vm_type(self.input_type_resolution_vm, &vm_type)
324    }
325
326    pub fn type_layout_for_struct(&self, tag: &StructTag) -> Result<MoveTypeLayout, Mode::Error> {
327        let ty: Type = self.load_type_from_struct(tag)?;
328        self.runtime_layout(&ty)
329    }
330
331    pub fn gas_coin_type(&self) -> Result<Type, Mode::Error> {
332        get_or_init_ty!(self, gas_coin_type, GasCoin::type_())
333    }
334
335    pub fn upgrade_ticket_type(&self) -> Result<Type, Mode::Error> {
336        get_or_init_ty!(self, upgrade_ticket_type, UpgradeTicket::type_())
337    }
338
339    pub fn upgrade_receipt_type(&self) -> Result<Type, Mode::Error> {
340        get_or_init_ty!(self, upgrade_receipt_type, UpgradeReceipt::type_())
341    }
342
343    pub fn upgrade_cap_type(&self) -> Result<Type, Mode::Error> {
344        get_or_init_ty!(self, upgrade_cap_type, UpgradeCap::type_())
345    }
346
347    pub fn tx_context_type(&self) -> Result<Type, Mode::Error> {
348        get_or_init_ty!(self, tx_context_type, TxContext::type_())
349    }
350
351    pub fn coin_type(&self, inner_type: Type) -> Result<Type, Mode::Error> {
352        const COIN_ABILITIES: AbilitySet =
353            AbilitySet::singleton(Ability::Key).union(AbilitySet::singleton(Ability::Store));
354        let (a, m, n) = RESOLVED_COIN_STRUCT;
355        let module = ModuleId::new(*a, m.to_owned());
356        Ok(Type::Datatype(Rc::new(Datatype {
357            abilities: COIN_ABILITIES,
358            module,
359            name: n.to_owned(),
360            type_arguments: vec![inner_type],
361        })))
362    }
363
364    pub fn balance_type(&self, inner_type: Type) -> Result<Type, Mode::Error> {
365        const BALANCE_ABILITIES: AbilitySet = AbilitySet::singleton(Ability::Store);
366        let (a, m, n) = RESOLVED_BALANCE_STRUCT;
367        let module = ModuleId::new(*a, m.to_owned());
368        Ok(Type::Datatype(Rc::new(Datatype {
369            abilities: BALANCE_ABILITIES,
370            module,
371            name: n.to_owned(),
372            type_arguments: vec![inner_type],
373        })))
374    }
375
376    pub fn withdrawal_type(&self, inner_type: Type) -> Result<Type, Mode::Error> {
377        const WITHDRAWAL_ABILITIES: AbilitySet = AbilitySet::singleton(Ability::Drop);
378        let (a, m, n) = RESOLVED_WITHDRAWAL_STRUCT;
379        let module = ModuleId::new(*a, m.to_owned());
380        Ok(Type::Datatype(Rc::new(Datatype {
381            abilities: WITHDRAWAL_ABILITIES,
382            module,
383            name: n.to_owned(),
384            type_arguments: vec![inner_type],
385        })))
386    }
387
388    pub fn allowance_withdrawal_type(&self, inner_type: Type) -> Result<Type, Mode::Error> {
389        const ALLOWANCE_WITHDRAWAL_ABILITIES: AbilitySet = AbilitySet::singleton(Ability::Drop);
390        let (a, m, n) = RESOLVED_ALLOWANCE_WITHDRAWAL_STRUCT;
391        let module = ModuleId::new(*a, m.to_owned());
392        Ok(Type::Datatype(Rc::new(Datatype {
393            abilities: ALLOWANCE_WITHDRAWAL_ABILITIES,
394            module,
395            name: n.to_owned(),
396            type_arguments: vec![inner_type],
397        })))
398    }
399
400    /// Either `Withdrawal` or `AllowanceWithdrawal` depending on the source
401    pub fn withdrawal_type_for_source(
402        &self,
403        source: &L::WithdrawalSource,
404        funds_type: Type,
405    ) -> Result<Type, Mode::Error> {
406        match source {
407            L::WithdrawalSource::Direct { .. } => self.withdrawal_type(funds_type),
408            L::WithdrawalSource::Allowance { .. } => self.allowance_withdrawal_type(funds_type),
409        }
410    }
411
412    pub fn vector_type(&self, element_type: Type) -> Result<Type, Mode::Error> {
413        let abilities = AbilitySet::polymorphic_abilities(
414            AbilitySet::VECTOR,
415            [false],
416            [element_type.abilities()],
417        )
418        .map_err(|e| {
419            Mode::Error::new_with_source(ExecutionErrorKind::VMInvariantViolation, e.to_string())
420        })?;
421        Ok(Type::Vector(Rc::new(L::Vector {
422            abilities,
423            element_type,
424        })))
425    }
426
427    pub fn read_object(&self, id: &ObjectID) -> Result<&Object, Mode::Error> {
428        let Some(obj) = self.state_view.read_object(id) else {
429            // protected by transaction input checker
430            invariant_violation!("Object {:?} does not exist", id);
431        };
432        Ok(obj)
433    }
434
435    /// Takes an adapter Type and returns a VM runtime Type and the linkage for it.
436    pub fn load_vm_type_argument_from_adapter_type(
437        &self,
438        idx: usize,
439        ty: &Type,
440    ) -> Result<vm_runtime::Type, Mode::Error> {
441        self.load_vm_type_from_adapter_type(Some(idx), ty)
442    }
443
444    fn load_vm_type_from_adapter_type(
445        &self,
446        type_arg_idx: Option<usize>,
447        ty: &Type,
448    ) -> Result<vm_runtime::Type, Mode::Error> {
449        let tag: TypeTag = ty.clone().try_into().map_err(|s| {
450            Mode::Error::new_with_source(ExecutionErrorKind::VMInvariantViolation, s)
451        })?;
452        self.load_vm_type_from_type_tag(type_arg_idx, &tag)
453    }
454
455    /// Take a type tag and returns a VM runtime Type and the linkage for it.
456    fn load_vm_type_from_type_tag(
457        &self,
458        type_arg_idx: Option<usize>,
459        tag: &TypeTag,
460    ) -> Result<vm_runtime::Type, Mode::Error> {
461        fn execution_error<Mode: ExecutionMode>(
462            env: &Env<Mode>,
463            type_arg_idx: Option<usize>,
464            e: VMError,
465            linkage: &ExecutableLinkage,
466        ) -> Mode::Error {
467            if let Some(idx) = type_arg_idx {
468                env.convert_type_argument_error(idx, e, linkage)
469            } else {
470                env.convert_linked_vm_error(e, linkage)
471            }
472        }
473
474        let objects = tag.all_addresses();
475
476        let tag_linkage = ExecutableLinkage::type_linkage::<_, Mode::Error>(
477            self.linkage_analysis.config().clone(),
478            objects.iter().map(|a| ObjectID::from(*a)),
479            self.linkable_store,
480        )?;
481        let ty = self
482            .input_type_resolution_vm
483            .load_type(tag)
484            .map_err(|e| execution_error(self, type_arg_idx, e, &tag_linkage))?;
485        Ok(ty)
486    }
487
488    /// Converts a VM runtime Type to an adapter Type.
489    pub(crate) fn adapter_type_from_vm_type(
490        &self,
491        vm: &MoveVM,
492        vm_type: &vm_runtime::Type,
493    ) -> Result<Type, Mode::Error> {
494        use vm_runtime as VRT;
495
496        Ok(match vm_type {
497            VRT::Type::Bool => Type::Bool,
498            VRT::Type::U8 => Type::U8,
499            VRT::Type::U16 => Type::U16,
500            VRT::Type::U32 => Type::U32,
501            VRT::Type::U64 => Type::U64,
502            VRT::Type::U128 => Type::U128,
503            VRT::Type::U256 => Type::U256,
504            VRT::Type::Address => Type::Address,
505            VRT::Type::Signer => Type::Signer,
506
507            VRT::Type::Reference(ref_ty) => {
508                let inner_ty = self.adapter_type_from_vm_type(vm, ref_ty)?;
509                Type::Reference(false, Rc::new(inner_ty))
510            }
511            VRT::Type::MutableReference(ref_ty) => {
512                let inner_ty = self.adapter_type_from_vm_type(vm, ref_ty)?;
513                Type::Reference(true, Rc::new(inner_ty))
514            }
515
516            VRT::Type::Vector(inner) => {
517                let element_type = self.adapter_type_from_vm_type(vm, inner)?;
518                self.vector_type(element_type)?
519            }
520            VRT::Type::Datatype(_) => {
521                let type_information = vm
522                    .type_information(vm_type)
523                    .map_err(|e| self.convert_vm_error(e))?;
524                let Some(data_type_info) = type_information.datatype_info else {
525                    invariant_violation!("Expected datatype info for datatype type {:?}", vm_type);
526                };
527                let datatype = Datatype {
528                    abilities: type_information.abilities,
529                    module: ModuleId::new(data_type_info.defining_id, data_type_info.module_name),
530                    name: data_type_info.type_name,
531                    type_arguments: vec![],
532                };
533                Type::Datatype(Rc::new(datatype))
534            }
535            ty @ VRT::Type::DatatypeInstantiation(inst) => {
536                let (_, type_arguments) = &**inst;
537                let type_information = vm
538                    .type_information(ty)
539                    .map_err(|e| self.convert_vm_error(e))?;
540                let Some(data_type_info) = type_information.datatype_info else {
541                    invariant_violation!("Expected datatype info for datatype type {:?}", vm_type);
542                };
543
544                let abilities = type_information.abilities;
545                let module = ModuleId::new(data_type_info.defining_id, data_type_info.module_name);
546                let name = data_type_info.type_name;
547                let type_arguments = type_arguments
548                    .iter()
549                    .map(|t| self.adapter_type_from_vm_type(vm, t))
550                    .collect::<Result<Vec<_>, _>>()?;
551
552                Type::Datatype(Rc::new(Datatype {
553                    abilities,
554                    module,
555                    name,
556                    type_arguments,
557                }))
558            }
559
560            VRT::Type::TyParam(_) => {
561                invariant_violation!(
562                    "Unexpected type parameter in VM type: {:?}. This should not happen as we should \
563                     have resolved all type parameters before this point.",
564                    vm_type
565                );
566            }
567        })
568    }
569
570    /// Load a `TypeInput` into a VM runtime `Type` and its `Linkage`. Loading into the VM ensures
571    /// that any adapter type or type tag that results from this is properly output with defining
572    /// IDs.
573    fn load_vm_type_from_type_input(
574        &self,
575        type_arg_idx: usize,
576        ty: TypeInput,
577    ) -> Result<vm_runtime::Type, Mode::Error> {
578        fn to_type_tag_internal<Mode: ExecutionMode>(
579            env: &Env<Mode>,
580            type_arg_idx: usize,
581            ty: TypeInput,
582        ) -> Result<TypeTag, Mode::Error> {
583            Ok(match ty {
584                TypeInput::Bool => TypeTag::Bool,
585                TypeInput::U8 => TypeTag::U8,
586                TypeInput::U16 => TypeTag::U16,
587                TypeInput::U32 => TypeTag::U32,
588                TypeInput::U64 => TypeTag::U64,
589                TypeInput::U128 => TypeTag::U128,
590                TypeInput::U256 => TypeTag::U256,
591                TypeInput::Address => TypeTag::Address,
592                TypeInput::Signer => TypeTag::Signer,
593                TypeInput::Vector(type_input) => {
594                    let inner = to_type_tag_internal(env, type_arg_idx, *type_input)?;
595                    TypeTag::Vector(Box::new(inner))
596                }
597                TypeInput::Struct(struct_input) => {
598                    let StructInput {
599                        address,
600                        module,
601                        name,
602                        type_params,
603                    } = *struct_input;
604
605                    let pkg = env
606                        .linkable_store
607                        .get_package(&address.into())
608                        .ok()
609                        .flatten()
610                        .ok_or_else(|| {
611                            let argument_idx = match checked_as!(type_arg_idx, u16) {
612                                Err(e) => return e.into(),
613                                Ok(v) => v,
614                            };
615                            Mode::Error::from_kind(ExecutionErrorKind::TypeArgumentError {
616                                argument_idx,
617                                kind: TypeArgumentError::TypeNotFound,
618                            })
619                        })?;
620                    let module = to_identifier(module)?;
621                    let name = to_identifier(name)?;
622                    let tid = IntraPackageName {
623                        module_name: module,
624                        type_name: name,
625                    };
626                    let Some(resolved_address) = pkg.type_origin_table().get(&tid).cloned() else {
627                        return Err(Mode::Error::from_kind(
628                            ExecutionErrorKind::TypeArgumentError {
629                                argument_idx: checked_as!(type_arg_idx, u16)?,
630                                kind: TypeArgumentError::TypeNotFound,
631                            },
632                        ));
633                    };
634
635                    let tys = type_params
636                        .into_iter()
637                        .map(|tp| to_type_tag_internal(env, type_arg_idx, tp))
638                        .collect::<Result<Vec<_>, _>>()?;
639                    TypeTag::Struct(Box::new(StructTag {
640                        address: resolved_address,
641                        module: tid.module_name,
642                        name: tid.type_name,
643                        type_params: tys,
644                    }))
645                }
646            })
647        }
648        let tag = to_type_tag_internal(self, type_arg_idx, ty)?;
649        self.load_vm_type_from_type_tag(Some(type_arg_idx), &tag)
650    }
651
652    pub fn deserialize_package(
653        &self,
654        module_bytes: &[Vec<u8>],
655        dep_ids: &[ObjectID],
656    ) -> Result<DeserializedPackage, Mode::Error> {
657        assert_invariant!(
658            !module_bytes.is_empty(),
659            "empty package is checked in transaction input checker"
660        );
661
662        let total_bytes = module_bytes.iter().map(|v| v.len()).sum();
663
664        let binary_config = self.protocol_config.binary_config(None);
665        let deserialized_modules = module_bytes
666            .iter()
667            .map(|b| {
668                CompiledModule::deserialize_with_config(b, &binary_config)
669                    .map_err(|e| e.finish(Location::Undefined))
670            })
671            .collect::<VMResult<Vec<CompiledModule>>>()
672            .map_err(|e| self.convert_vm_error(e))?;
673        let computed_digest = MovePackage::compute_digest_for_modules_and_deps(
674            module_bytes,
675            dep_ids,
676            /* hash_modules */ true,
677        );
678        Ok(DeserializedPackage::new(
679            deserialized_modules,
680            total_bytes,
681            computed_digest,
682        ))
683    }
684}
685
686fn to_identifier<E: ExecutionErrorTrait>(name: String) -> Result<Identifier, E> {
687    Identifier::new(name)
688        .map_err(|e| E::new_with_source(ExecutionErrorKind::VMInvariantViolation, e.to_string()))
689}
690
691fn convert_vm_error<E: ExecutionErrorTrait>(
692    error: VMError,
693    store: &VerifiedPackageStore<'_>,
694    linkage: Option<&ExecutableLinkage>,
695    _protocol_config: &ProtocolConfig,
696) -> E {
697    use crate::error::convert_vm_error_impl;
698    convert_vm_error_impl(
699        error,
700        &|id| {
701            debug_assert!(
702                linkage.is_some(),
703                "Linkage should be set anywhere where runtime errors may occur in order to resolve abort locations to package IDs"
704            );
705            linkage
706                .and_then(|linkage| {
707                    linkage
708                        .0
709                        .linkage
710                        .get(&(*id.address()).into())
711                        .map(|new_id| ModuleId::new((*new_id).into(), id.name().to_owned()))
712                })
713                .unwrap_or_else(|| id.clone())
714        },
715        // NB: the `id` here is the original ID (and hence _not_ relocated).
716        &|id, function| {
717            debug_assert!(
718                linkage.is_some(),
719                "Linkage should be set anywhere where runtime errors may occur in order to resolve abort locations to package IDs"
720            );
721            linkage.and_then(|linkage| {
722                let version_id = linkage
723                    .0
724                    .linkage
725                    .get(&(*id.address()).into())
726                    .cloned()
727                    .unwrap_or_else(|| ObjectID::from_address(*id.address()));
728                store.get_package(&version_id).ok().flatten().and_then(|p| {
729                    p.modules().get(id).map(|module| {
730                        let module = module.compiled_module();
731                        let fdef = module.function_def_at(function);
732                        let fhandle = module.function_handle_at(fdef.function);
733                        module.identifier_at(fhandle.name).to_string()
734                    })
735                })
736            })
737        },
738    )
739    .into()
740}