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::{
10        PackageStore, cached_package_store::CachedPackageStore, linked_data_store::LinkedDataStore,
11    },
12    execution_value::ExecutionState,
13    programmable_transactions::execution::subst_signature,
14    static_programmable_transactions::{
15        linkage::{
16            analysis::LinkageAnalyzer,
17            resolved_linkage::{ResolvedLinkage, RootedLinkage},
18        },
19        loading::ast::{
20            self as L, Datatype, LoadedFunction, LoadedFunctionInstantiation, Type, Vector,
21        },
22    },
23};
24use move_binary_format::{
25    CompiledModule,
26    errors::{Location, PartialVMError, VMError},
27    file_format::{Ability, AbilitySet, TypeParameterIndex},
28};
29use move_core_types::{
30    annotated_value,
31    language_storage::{ModuleId, StructTag},
32    runtime_value::{self, MoveTypeLayout},
33    vm_status::StatusCode,
34};
35use move_vm_runtime::move_vm::MoveVM;
36use move_vm_types::{data_store::DataStore, loaded_data::runtime_types as vm_runtime_type};
37use std::{cell::OnceCell, rc::Rc, sync::Arc};
38use sui_protocol_config::ProtocolConfig;
39use sui_types::{
40    Identifier, TypeTag,
41    balance::RESOLVED_BALANCE_STRUCT,
42    base_types::{ObjectID, TxContext},
43    error::{ExecutionError, ExecutionErrorKind},
44    execution_status::TypeArgumentError,
45    funds_accumulator::RESOLVED_WITHDRAWAL_STRUCT,
46    gas_coin::GasCoin,
47    move_package::{UpgradeCap, UpgradeReceipt, UpgradeTicket},
48    object::Object,
49    type_input::{StructInput, TypeInput},
50};
51
52pub struct Env<'pc, 'vm, 'state, 'linkage> {
53    pub protocol_config: &'pc ProtocolConfig,
54    pub vm: &'vm MoveVM,
55    pub state_view: &'state mut dyn ExecutionState,
56    pub linkable_store: &'linkage CachedPackageStore<'state>,
57    pub linkage_analysis: &'linkage LinkageAnalyzer,
58    gas_coin_type: OnceCell<Type>,
59    upgrade_ticket_type: OnceCell<Type>,
60    upgrade_receipt_type: OnceCell<Type>,
61    upgrade_cap_type: OnceCell<Type>,
62    tx_context_type: OnceCell<Type>,
63}
64
65macro_rules! get_or_init_ty {
66    ($env:expr, $ident:ident, $tag:expr) => {{
67        let env = $env;
68        if env.$ident.get().is_none() {
69            let tag = $tag;
70            let ty = env.load_type_from_struct(&tag)?;
71            env.$ident.set(ty.clone()).unwrap();
72        }
73        Ok(env.$ident.get().unwrap().clone())
74    }};
75}
76
77impl<'pc, 'vm, 'state, 'linkage> Env<'pc, 'vm, 'state, 'linkage> {
78    pub fn new(
79        protocol_config: &'pc ProtocolConfig,
80        vm: &'vm MoveVM,
81        state_view: &'state mut dyn ExecutionState,
82        linkable_store: &'linkage CachedPackageStore<'state>,
83        linkage_analysis: &'linkage LinkageAnalyzer,
84    ) -> Self {
85        Self {
86            protocol_config,
87            vm,
88            state_view,
89            linkable_store,
90            linkage_analysis,
91            gas_coin_type: OnceCell::new(),
92            upgrade_ticket_type: OnceCell::new(),
93            upgrade_receipt_type: OnceCell::new(),
94            upgrade_cap_type: OnceCell::new(),
95            tx_context_type: OnceCell::new(),
96        }
97    }
98
99    pub fn convert_linked_vm_error(&self, e: VMError, linkage: &RootedLinkage) -> ExecutionError {
100        convert_vm_error(e, self.vm, self.linkable_store, Some(linkage))
101    }
102
103    pub fn convert_vm_error(&self, e: VMError) -> ExecutionError {
104        convert_vm_error(e, self.vm, self.linkable_store, None)
105    }
106
107    pub fn convert_type_argument_error(
108        &self,
109        idx: usize,
110        e: VMError,
111        linkage: &RootedLinkage,
112    ) -> ExecutionError {
113        use move_core_types::vm_status::StatusCode;
114        match e.major_status() {
115            StatusCode::NUMBER_OF_TYPE_ARGUMENTS_MISMATCH => {
116                ExecutionErrorKind::TypeArityMismatch.into()
117            }
118            StatusCode::TYPE_RESOLUTION_FAILURE => ExecutionErrorKind::TypeArgumentError {
119                argument_idx: idx as TypeParameterIndex,
120                kind: TypeArgumentError::TypeNotFound,
121            }
122            .into(),
123            StatusCode::CONSTRAINT_NOT_SATISFIED => ExecutionErrorKind::TypeArgumentError {
124                argument_idx: idx as TypeParameterIndex,
125                kind: TypeArgumentError::ConstraintNotSatisfied,
126            }
127            .into(),
128            _ => self.convert_linked_vm_error(e, linkage),
129        }
130    }
131
132    pub fn module_definition(
133        &self,
134        module_id: &ModuleId,
135        linkage: &RootedLinkage,
136    ) -> Result<Arc<CompiledModule>, ExecutionError> {
137        let linked_data_store = LinkedDataStore::new(linkage, self.linkable_store);
138        self.vm
139            .get_runtime()
140            .load_module(module_id, &linked_data_store)
141            .map_err(|e| self.convert_linked_vm_error(e, linkage))
142    }
143
144    pub fn fully_annotated_layout(
145        &self,
146        ty: &Type,
147    ) -> Result<annotated_value::MoveTypeLayout, ExecutionError> {
148        let ty = self.load_vm_type_from_adapter_type(None, ty)?;
149        self.vm
150            .get_runtime()
151            .type_to_fully_annotated_layout(&ty)
152            .map_err(|e| self.convert_vm_error(e))
153    }
154
155    pub fn runtime_layout(
156        &self,
157        ty: &Type,
158    ) -> Result<runtime_value::MoveTypeLayout, ExecutionError> {
159        let ty = self.load_vm_type_from_adapter_type(None, ty)?;
160        self.vm
161            .get_runtime()
162            .type_to_type_layout(&ty)
163            .map_err(|e| self.convert_vm_error(e))
164    }
165
166    pub fn load_function(
167        &self,
168        package: ObjectID,
169        module: String,
170        function: String,
171        type_arguments: Vec<Type>,
172        linkage: RootedLinkage,
173    ) -> Result<LoadedFunction, ExecutionError> {
174        let Some(original_id) = linkage.resolved_linkage.resolve_to_original_id(&package) else {
175            invariant_violation!(
176                "Package ID {:?} is not found in linkage generated for that package",
177                package
178            );
179        };
180        let module = to_identifier(module)?;
181        let name = to_identifier(function)?;
182        let storage_id = ModuleId::new(package.into(), module.clone());
183        let runtime_id = ModuleId::new(original_id.into(), module);
184        let mut data_store = LinkedDataStore::new(&linkage, self.linkable_store);
185        let loaded_type_arguments = type_arguments
186            .iter()
187            .enumerate()
188            .map(|(idx, ty)| self.load_vm_type_argument_from_adapter_type(idx, ty))
189            .collect::<Result<Vec<_>, _>>()?;
190        let runtime_signature = self
191            .vm
192            .get_runtime()
193            .load_function(
194                &runtime_id,
195                name.as_ident_str(),
196                &loaded_type_arguments,
197                &mut data_store,
198            )
199            .map_err(|e| {
200                if e.major_status() == StatusCode::FUNCTION_RESOLUTION_FAILURE {
201                    ExecutionError::new_with_source(
202                        ExecutionErrorKind::FunctionNotFound,
203                        format!(
204                            "Could not resolve function '{}' in module {}",
205                            name, &storage_id,
206                        ),
207                    )
208                } else {
209                    self.convert_linked_vm_error(e, &linkage)
210                }
211            })?;
212        let runtime_signature = subst_signature(runtime_signature, &loaded_type_arguments)
213            .map_err(|e| self.convert_linked_vm_error(e, &linkage))?;
214        let parameters = runtime_signature
215            .parameters
216            .into_iter()
217            .map(|ty| self.adapter_type_from_vm_type(&ty))
218            .collect::<Result<Vec<_>, _>>()?;
219        let return_ = runtime_signature
220            .return_
221            .into_iter()
222            .map(|ty| self.adapter_type_from_vm_type(&ty))
223            .collect::<Result<Vec<_>, _>>()?;
224        let signature = LoadedFunctionInstantiation {
225            parameters,
226            return_,
227        };
228        Ok(LoadedFunction {
229            storage_id,
230            runtime_id,
231            name,
232            type_arguments,
233            signature,
234            linkage,
235            instruction_length: runtime_signature.instruction_length,
236            definition_index: runtime_signature.definition_index,
237        })
238    }
239
240    pub fn load_type_input(&self, idx: usize, ty: TypeInput) -> Result<Type, ExecutionError> {
241        let runtime_type = self.load_vm_type_from_type_input(idx, ty)?;
242        self.adapter_type_from_vm_type(&runtime_type)
243    }
244
245    /// We verify that all types in the `StructTag` are defining ID-based types.
246    pub fn load_type_from_struct(&self, tag: &StructTag) -> Result<Type, ExecutionError> {
247        let vm_type =
248            self.load_vm_type_from_type_tag(None, &TypeTag::Struct(Box::new(tag.clone())))?;
249        self.adapter_type_from_vm_type(&vm_type)
250    }
251
252    /// Load the type and layout for a struct tag.
253    /// This is an optimization to avoid loading the VM type twice when both adapter type and type
254    /// layout are needed.
255    pub fn load_type_and_layout_from_struct(
256        &self,
257        tag: &StructTag,
258    ) -> Result<(Type, MoveTypeLayout), ExecutionError> {
259        let vm_type =
260            self.load_vm_type_from_type_tag(None, &TypeTag::Struct(Box::new(tag.clone())))?;
261        let type_layout = self
262            .vm
263            .get_runtime()
264            .type_to_type_layout(&vm_type)
265            .map_err(|e| self.convert_vm_error(e))?;
266        self.adapter_type_from_vm_type(&vm_type)
267            .map(|ty| (ty, type_layout))
268    }
269
270    pub fn type_layout_for_struct(
271        &self,
272        tag: &StructTag,
273    ) -> Result<MoveTypeLayout, ExecutionError> {
274        let ty: Type = self.load_type_from_struct(tag)?;
275        self.runtime_layout(&ty)
276    }
277
278    pub fn gas_coin_type(&self) -> Result<Type, ExecutionError> {
279        get_or_init_ty!(self, gas_coin_type, GasCoin::type_())
280    }
281
282    pub fn upgrade_ticket_type(&self) -> Result<Type, ExecutionError> {
283        get_or_init_ty!(self, upgrade_ticket_type, UpgradeTicket::type_())
284    }
285
286    pub fn upgrade_receipt_type(&self) -> Result<Type, ExecutionError> {
287        get_or_init_ty!(self, upgrade_receipt_type, UpgradeReceipt::type_())
288    }
289
290    pub fn upgrade_cap_type(&self) -> Result<Type, ExecutionError> {
291        get_or_init_ty!(self, upgrade_cap_type, UpgradeCap::type_())
292    }
293
294    pub fn tx_context_type(&self) -> Result<Type, ExecutionError> {
295        get_or_init_ty!(self, tx_context_type, TxContext::type_())
296    }
297
298    pub fn balance_type(&self, inner_type: Type) -> Result<Type, ExecutionError> {
299        let Some(abilities) = AbilitySet::from_u8(Ability::Store as u8) else {
300            invariant_violation!("Unable to create balance abilities");
301        };
302        let (a, m, n) = RESOLVED_BALANCE_STRUCT;
303        let module = ModuleId::new(*a, m.to_owned());
304        Ok(Type::Datatype(Rc::new(Datatype {
305            abilities,
306            module,
307            name: n.to_owned(),
308            type_arguments: vec![inner_type],
309        })))
310    }
311
312    pub fn withdrawal_type(&self, inner_type: Type) -> Result<Type, ExecutionError> {
313        let Some(abilities) = AbilitySet::from_u8(Ability::Drop as u8) else {
314            invariant_violation!("Unable to create withdrawal abilities");
315        };
316        let (a, m, n) = RESOLVED_WITHDRAWAL_STRUCT;
317        let module = ModuleId::new(*a, m.to_owned());
318        Ok(Type::Datatype(Rc::new(Datatype {
319            abilities,
320            module,
321            name: n.to_owned(),
322            type_arguments: vec![inner_type],
323        })))
324    }
325
326    pub fn vector_type(&self, element_type: Type) -> Result<Type, ExecutionError> {
327        let abilities = AbilitySet::polymorphic_abilities(
328            AbilitySet::VECTOR,
329            [false],
330            [element_type.abilities()],
331        )
332        .map_err(|e| {
333            ExecutionError::new_with_source(ExecutionErrorKind::VMInvariantViolation, e.to_string())
334        })?;
335        Ok(Type::Vector(Rc::new(L::Vector {
336            abilities,
337            element_type,
338        })))
339    }
340
341    pub fn read_object(&self, id: &ObjectID) -> Result<&Object, ExecutionError> {
342        let Some(obj) = self.state_view.read_object(id) else {
343            // protected by transaction input checker
344            invariant_violation!("Object {:?} does not exist", id);
345        };
346        Ok(obj)
347    }
348
349    /// Takes an adapter Type and returns a VM runtime Type and the linkage for it.
350    pub fn load_vm_type_argument_from_adapter_type(
351        &self,
352        idx: usize,
353        ty: &Type,
354    ) -> Result<vm_runtime_type::Type, ExecutionError> {
355        self.load_vm_type_from_adapter_type(Some(idx), ty)
356    }
357
358    fn load_vm_type_from_adapter_type(
359        &self,
360        type_arg_idx: Option<usize>,
361        ty: &Type,
362    ) -> Result<vm_runtime_type::Type, ExecutionError> {
363        let tag: TypeTag = ty.clone().try_into().map_err(|s| {
364            ExecutionError::new_with_source(ExecutionErrorKind::VMInvariantViolation, s)
365        })?;
366        self.load_vm_type_from_type_tag(type_arg_idx, &tag)
367    }
368
369    /// Take a type tag and returns a VM runtime Type and the linkage for it.
370    fn load_vm_type_from_type_tag(
371        &self,
372        type_arg_idx: Option<usize>,
373        tag: &TypeTag,
374    ) -> Result<vm_runtime_type::Type, ExecutionError> {
375        use vm_runtime_type as VMR;
376
377        fn load_type_tag(
378            env: &Env,
379            type_arg_idx: Option<usize>,
380            tag: &TypeTag,
381        ) -> Result<VMR::Type, ExecutionError> {
382            Ok(match tag {
383                TypeTag::Bool => VMR::Type::Bool,
384                TypeTag::U8 => VMR::Type::U8,
385                TypeTag::U16 => VMR::Type::U16,
386                TypeTag::U32 => VMR::Type::U32,
387                TypeTag::U64 => VMR::Type::U64,
388                TypeTag::U128 => VMR::Type::U128,
389                TypeTag::U256 => VMR::Type::U256,
390                TypeTag::Address => VMR::Type::Address,
391                TypeTag::Signer => VMR::Type::Signer,
392
393                TypeTag::Vector(inner) => {
394                    VMR::Type::Vector(Box::new(load_type_tag(env, type_arg_idx, inner)?))
395                }
396                TypeTag::Struct(tag) => load_struct_tag(env, type_arg_idx, tag)?,
397            })
398        }
399
400        fn load_struct_tag(
401            env: &Env,
402            type_arg_idx: Option<usize>,
403            struct_tag: &StructTag,
404        ) -> Result<vm_runtime_type::Type, ExecutionError> {
405            fn execution_error(
406                env: &Env,
407                type_arg_idx: Option<usize>,
408                e: VMError,
409                linkage: &RootedLinkage,
410            ) -> ExecutionError {
411                if let Some(idx) = type_arg_idx {
412                    env.convert_type_argument_error(idx, e, linkage)
413                } else {
414                    env.convert_linked_vm_error(e, linkage)
415                }
416            }
417
418            fn verification_error(code: StatusCode) -> VMError {
419                PartialVMError::new(code).finish(Location::Undefined)
420            }
421
422            let StructTag {
423                address,
424                module,
425                name,
426                type_params,
427            } = struct_tag;
428
429            let tag_linkage =
430                ResolvedLinkage::type_linkage(&[(*address).into()], env.linkable_store)?;
431            let linkage = RootedLinkage::new(*address, tag_linkage);
432            let linked_store = LinkedDataStore::new(&linkage, env.linkable_store);
433
434            let original_id = linkage
435                .resolved_linkage
436                .resolve_to_original_id(&(*address).into())
437                .ok_or_else(|| {
438                    make_invariant_violation!(
439                        "StructTag {:?} is not found in linkage generated for that struct tag -- this shouldn't happen.",
440                        struct_tag
441                    )
442                })?;
443            let runtime_id = ModuleId::new(*original_id, module.clone());
444
445            let (idx, struct_type) = env
446                .vm
447                .get_runtime()
448                .load_type(&runtime_id, name, &linked_store)
449                .map_err(|e| execution_error(env, type_arg_idx, e, &linkage))?;
450
451            let type_param_constraints = struct_type.type_param_constraints();
452            if type_param_constraints.len() != type_params.len() {
453                return Err(execution_error(
454                    env,
455                    type_arg_idx,
456                    verification_error(StatusCode::NUMBER_OF_TYPE_ARGUMENTS_MISMATCH),
457                    &linkage,
458                ));
459            }
460
461            if type_params.is_empty() {
462                Ok(VMR::Type::Datatype(idx))
463            } else {
464                let loaded_type_params = type_params
465                    .iter()
466                    .map(|type_param| load_type_tag(env, type_arg_idx, type_param))
467                    .collect::<Result<Vec<_>, _>>()?;
468
469                // Verify that the type parameter constraints on the struct are met
470                for (constraint, param) in type_param_constraints.zip(&loaded_type_params) {
471                    let abilities = env
472                        .vm
473                        .get_runtime()
474                        .get_type_abilities(param)
475                        .map_err(|e| execution_error(env, type_arg_idx, e, &linkage))?;
476                    if !constraint.is_subset(abilities) {
477                        return Err(execution_error(
478                            env,
479                            type_arg_idx,
480                            verification_error(StatusCode::CONSTRAINT_NOT_SATISFIED),
481                            &linkage,
482                        ));
483                    }
484                }
485
486                Ok(VMR::Type::DatatypeInstantiation(Box::new((
487                    idx,
488                    loaded_type_params,
489                ))))
490            }
491        }
492
493        load_type_tag(self, type_arg_idx, tag)
494    }
495
496    /// Converts a VM runtime Type to an adapter Type.
497    fn adapter_type_from_vm_type(
498        &self,
499        vm_type: &vm_runtime_type::Type,
500    ) -> Result<Type, ExecutionError> {
501        use vm_runtime_type as VRT;
502
503        Ok(match vm_type {
504            VRT::Type::Bool => Type::Bool,
505            VRT::Type::U8 => Type::U8,
506            VRT::Type::U16 => Type::U16,
507            VRT::Type::U32 => Type::U32,
508            VRT::Type::U64 => Type::U64,
509            VRT::Type::U128 => Type::U128,
510            VRT::Type::U256 => Type::U256,
511            VRT::Type::Address => Type::Address,
512            VRT::Type::Signer => Type::Signer,
513
514            VRT::Type::Reference(ref_ty) => {
515                let inner_ty = self.adapter_type_from_vm_type(ref_ty)?;
516                Type::Reference(false, Rc::new(inner_ty))
517            }
518            VRT::Type::MutableReference(ref_ty) => {
519                let inner_ty = self.adapter_type_from_vm_type(ref_ty)?;
520                Type::Reference(true, Rc::new(inner_ty))
521            }
522
523            VRT::Type::Vector(inner) => {
524                let element_type = self.adapter_type_from_vm_type(inner)?;
525                let abilities = self
526                    .vm
527                    .get_runtime()
528                    .get_type_abilities(vm_type)
529                    .map_err(|e| self.convert_vm_error(e))?;
530                let vector_ty = Vector {
531                    abilities,
532                    element_type,
533                };
534                Type::Vector(Rc::new(vector_ty))
535            }
536            VRT::Type::Datatype(cached_type_index) => {
537                let runtime = self.vm.get_runtime();
538                let Some(cached_info) = runtime.get_type(*cached_type_index) else {
539                    invariant_violation!(
540                        "Unable to find cached type info for {:?}. This should not happen as we have \
541                         a loaded VM type in-hand.",
542                        vm_type
543                    )
544                };
545                let datatype = Datatype {
546                    abilities: cached_info.abilities,
547                    module: cached_info.defining_id.clone(),
548                    name: cached_info.name.clone(),
549                    type_arguments: vec![],
550                };
551                Type::Datatype(Rc::new(datatype))
552            }
553            ty @ VRT::Type::DatatypeInstantiation(inst) => {
554                let (cached_type_index, type_arguments) = &**inst;
555                let runtime = self.vm.get_runtime();
556                let Some(cached_info) = runtime.get_type(*cached_type_index) else {
557                    invariant_violation!(
558                        "Unable to find cached type info for {:?}. This should not happen as we have \
559                         a loaded VM type in-hand.",
560                        vm_type
561                    )
562                };
563
564                let abilities = runtime
565                    .get_type_abilities(ty)
566                    .map_err(|e| self.convert_vm_error(e))?;
567                let module = cached_info.defining_id.clone();
568                let name = cached_info.name.clone();
569                let type_arguments = type_arguments
570                    .iter()
571                    .map(|t| self.adapter_type_from_vm_type(t))
572                    .collect::<Result<Vec<_>, _>>()?;
573
574                Type::Datatype(Rc::new(Datatype {
575                    abilities,
576                    module,
577                    name,
578                    type_arguments,
579                }))
580            }
581
582            VRT::Type::TyParam(_) => {
583                invariant_violation!(
584                    "Unexpected type parameter in VM type: {:?}. This should not happen as we should \
585                     have resolved all type parameters before this point.",
586                    vm_type
587                );
588            }
589        })
590    }
591
592    /// Load a `TypeInput` into a VM runtime `Type` and its `Linkage`. Loading into the VM ensures
593    /// that any adapter type or type tag that results from this is properly output with defining
594    /// IDs.
595    fn load_vm_type_from_type_input(
596        &self,
597        type_arg_idx: usize,
598        ty: TypeInput,
599    ) -> Result<vm_runtime_type::Type, ExecutionError> {
600        fn to_type_tag_internal(
601            env: &Env,
602            type_arg_idx: usize,
603            ty: TypeInput,
604        ) -> Result<TypeTag, ExecutionError> {
605            Ok(match ty {
606                TypeInput::Bool => TypeTag::Bool,
607                TypeInput::U8 => TypeTag::U8,
608                TypeInput::U16 => TypeTag::U16,
609                TypeInput::U32 => TypeTag::U32,
610                TypeInput::U64 => TypeTag::U64,
611                TypeInput::U128 => TypeTag::U128,
612                TypeInput::U256 => TypeTag::U256,
613                TypeInput::Address => TypeTag::Address,
614                TypeInput::Signer => TypeTag::Signer,
615                TypeInput::Vector(type_input) => {
616                    let inner = to_type_tag_internal(env, type_arg_idx, *type_input)?;
617                    TypeTag::Vector(Box::new(inner))
618                }
619                TypeInput::Struct(struct_input) => {
620                    let StructInput {
621                        address,
622                        module,
623                        name,
624                        type_params,
625                    } = *struct_input;
626
627                    let pkg = env
628                        .linkable_store
629                        .get_package(&address.into())
630                        .ok()
631                        .flatten()
632                        .ok_or_else(|| {
633                            ExecutionError::from_kind(ExecutionErrorKind::TypeArgumentError {
634                                argument_idx: type_arg_idx as u16,
635                                kind: TypeArgumentError::TypeNotFound,
636                            })
637                        })?;
638                    let Some(resolved_address) = pkg
639                        .type_origin_map()
640                        .get(&(module.clone(), name.clone()))
641                        .cloned()
642                    else {
643                        return Err(ExecutionError::from_kind(
644                            ExecutionErrorKind::TypeArgumentError {
645                                argument_idx: type_arg_idx as u16,
646                                kind: TypeArgumentError::TypeNotFound,
647                            },
648                        ));
649                    };
650
651                    let module = to_identifier(module)?;
652                    let name = to_identifier(name)?;
653                    let tys = type_params
654                        .into_iter()
655                        .map(|tp| to_type_tag_internal(env, type_arg_idx, tp))
656                        .collect::<Result<Vec<_>, _>>()?;
657                    TypeTag::Struct(Box::new(StructTag {
658                        address: *resolved_address,
659                        module,
660                        name,
661                        type_params: tys,
662                    }))
663                }
664            })
665        }
666        let tag = to_type_tag_internal(self, type_arg_idx, ty)?;
667        self.load_vm_type_from_type_tag(Some(type_arg_idx), &tag)
668    }
669}
670
671fn to_identifier(name: String) -> Result<Identifier, ExecutionError> {
672    Identifier::new(name).map_err(|e| {
673        ExecutionError::new_with_source(ExecutionErrorKind::VMInvariantViolation, e.to_string())
674    })
675}
676
677fn convert_vm_error(
678    error: VMError,
679    vm: &MoveVM,
680    store: &dyn PackageStore,
681    linkage: Option<&RootedLinkage>,
682) -> ExecutionError {
683    use crate::error::convert_vm_error_impl;
684    convert_vm_error_impl(
685        error,
686        &|id| {
687            debug_assert!(
688                linkage.is_some(),
689                "Linkage should be set anywhere where runtime errors may occur in order to resolve abort locations to package IDs"
690            );
691            linkage
692                .and_then(|linkage| LinkedDataStore::new(linkage, store).relocate(id).ok())
693                .unwrap_or_else(|| id.clone())
694        },
695        // NB: the `id` here is the original ID (and hence _not_ relocated).
696        &|id, function| {
697            debug_assert!(
698                linkage.is_some(),
699                "Linkage should be set anywhere where runtime errors may occur in order to resolve abort locations to package IDs"
700            );
701            linkage.and_then(|linkage| {
702                let state_view = LinkedDataStore::new(linkage, store);
703                vm.load_module(id, state_view).ok().map(|module| {
704                    let fdef = module.function_def_at(function);
705                    let fhandle = module.function_handle_at(fdef.function);
706                    module.identifier_at(fhandle.name).to_string()
707                })
708            })
709        },
710    )
711}