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