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::{PackageStore, cached_package_store::CachedPackageStore},
10    execution_value::ExecutionState,
11    static_programmable_transactions::{
12        execution::context::subst_signature,
13        linkage::{analysis::LinkageAnalyzer, resolved_linkage::ExecutableLinkage},
14        loading::ast::{self as L, Datatype, LoadedFunction, LoadedFunctionInstantiation, Type},
15    },
16};
17use move_binary_format::{
18    errors::VMError,
19    file_format::{Ability, AbilitySet, TypeParameterIndex},
20};
21use move_core_types::{
22    annotated_value,
23    identifier::IdentStr,
24    language_storage::{ModuleId, StructTag},
25    resolver::IntraPackageName,
26    runtime_value::{self, MoveTypeLayout},
27    vm_status::StatusCode,
28};
29use move_vm_runtime::{
30    execution::{self as vm_runtime, vm::MoveVM},
31    runtime::MoveRuntime,
32};
33use std::{cell::OnceCell, rc::Rc};
34use sui_protocol_config::ProtocolConfig;
35use sui_types::{
36    Identifier, SUI_FRAMEWORK_PACKAGE_ID, TypeTag,
37    balance::RESOLVED_BALANCE_STRUCT,
38    base_types::{ObjectID, TxContext},
39    coin::RESOLVED_COIN_STRUCT,
40    error::ExecutionError,
41    execution_status::{ExecutionErrorKind, TypeArgumentError},
42    funds_accumulator::RESOLVED_WITHDRAWAL_STRUCT,
43    gas_coin::GasCoin,
44    move_package::{UpgradeCap, UpgradeReceipt, UpgradeTicket},
45    object::Object,
46    type_input::{StructInput, TypeInput},
47};
48
49pub struct Env<'pc, 'vm, 'state, 'linkage, 'extensions> {
50    pub protocol_config: &'pc ProtocolConfig,
51    pub vm: &'vm MoveRuntime,
52    pub state_view: &'state mut dyn ExecutionState,
53    pub linkable_store: &'linkage CachedPackageStore<'state, 'vm>,
54    pub linkage_analysis: &'linkage LinkageAnalyzer,
55    gas_coin_type: OnceCell<Type>,
56    upgrade_ticket_type: OnceCell<Type>,
57    upgrade_receipt_type: OnceCell<Type>,
58    upgrade_cap_type: OnceCell<Type>,
59    tx_context_type: OnceCell<Type>,
60    // The VM used for type resolution of input types (and types statically present in the PTB)
61    // only. This VM should only be used for resolution of input types, but should not be used for
62    // resolution around function calls, execution, or final serialization of execution values.
63    input_type_resolution_vm: &'linkage MoveVM<'extensions>,
64}
65
66macro_rules! get_or_init_ty {
67    ($env:expr, $ident:ident, $tag:expr) => {{
68        let env = $env;
69        if env.$ident.get().is_none() {
70            let tag = $tag;
71            let ty = env.load_type_from_struct(&tag)?;
72            env.$ident.set(ty.clone()).unwrap();
73        }
74        Ok(env.$ident.get().unwrap().clone())
75    }};
76}
77
78impl<'pc, 'vm, 'state, 'linkage, 'extensions> Env<'pc, 'vm, 'state, 'linkage, 'extensions> {
79    pub fn new(
80        protocol_config: &'pc ProtocolConfig,
81        vm: &'vm MoveRuntime,
82        state_view: &'state mut dyn ExecutionState,
83        linkable_store: &'linkage CachedPackageStore<'state, 'vm>,
84        linkage_analysis: &'linkage LinkageAnalyzer,
85        input_type_resolution_vm: &'linkage MoveVM<'extensions>,
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            input_type_resolution_vm,
99        }
100    }
101
102    pub fn convert_linked_vm_error(
103        &self,
104        e: VMError,
105        linkage: &ExecutableLinkage,
106    ) -> ExecutionError {
107        convert_vm_error(e, self.linkable_store, Some(linkage), self.protocol_config)
108    }
109
110    pub fn convert_vm_error(&self, e: VMError) -> ExecutionError {
111        convert_vm_error(e, self.linkable_store, None, self.protocol_config)
112    }
113
114    pub fn convert_type_argument_error(
115        &self,
116        idx: usize,
117        e: VMError,
118        linkage: &ExecutableLinkage,
119    ) -> ExecutionError {
120        use move_core_types::vm_status::StatusCode;
121        let argument_idx = match checked_as!(idx, TypeParameterIndex) {
122            Err(e) => return e,
123            Ok(v) => v,
124        };
125        match e.major_status() {
126            StatusCode::NUMBER_OF_TYPE_ARGUMENTS_MISMATCH => {
127                ExecutionErrorKind::TypeArityMismatch.into()
128            }
129            StatusCode::EXTERNAL_RESOLUTION_REQUEST_ERROR => {
130                ExecutionErrorKind::TypeArgumentError {
131                    argument_idx,
132                    kind: TypeArgumentError::TypeNotFound,
133                }
134                .into()
135            }
136            StatusCode::CONSTRAINT_NOT_SATISFIED => ExecutionErrorKind::TypeArgumentError {
137                argument_idx,
138                kind: TypeArgumentError::ConstraintNotSatisfied,
139            }
140            .into(),
141            _ => self.convert_linked_vm_error(e, linkage),
142        }
143    }
144
145    pub fn fully_annotated_layout(
146        &self,
147        ty: &Type,
148    ) -> Result<annotated_value::MoveTypeLayout, ExecutionError> {
149        let tag: TypeTag = ty.clone().try_into().map_err(|s| {
150            ExecutionError::new_with_source(ExecutionErrorKind::VMInvariantViolation, s)
151        })?;
152        let objects = tag.all_addresses();
153        let tag_linkage = ExecutableLinkage::type_linkage(
154            self.linkage_analysis.config().clone(),
155            objects.into_iter().map(ObjectID::from),
156            self.linkable_store,
157        )?;
158        self.input_type_resolution_vm
159            .annotated_type_layout(&tag)
160            .map_err(|e| self.convert_linked_vm_error(e, &tag_linkage))
161    }
162
163    pub fn runtime_layout(
164        &self,
165        ty: &Type,
166    ) -> Result<runtime_value::MoveTypeLayout, ExecutionError> {
167        let tag: TypeTag = ty.clone().try_into().map_err(|s| {
168            ExecutionError::new_with_source(ExecutionErrorKind::VMInvariantViolation, s)
169        })?;
170        let objects = tag.all_addresses();
171        let tag_linkage = ExecutableLinkage::type_linkage(
172            self.linkage_analysis.config().clone(),
173            objects.into_iter().map(ObjectID::from),
174            self.linkable_store,
175        )?;
176        self.input_type_resolution_vm
177            .runtime_type_layout(&tag)
178            .map_err(|e| self.convert_linked_vm_error(e, &tag_linkage))
179    }
180
181    pub fn load_framework_function(
182        &self,
183        module: &IdentStr,
184        function: &IdentStr,
185        type_arguments: Vec<Type>,
186    ) -> Result<LoadedFunction, ExecutionError> {
187        self.load_function(
188            SUI_FRAMEWORK_PACKAGE_ID,
189            module.to_string(),
190            function.to_string(),
191            type_arguments,
192        )
193    }
194
195    pub fn load_function(
196        &self,
197        package: ObjectID,
198        module: String,
199        function: String,
200        type_arguments: Vec<Type>,
201    ) -> Result<LoadedFunction, ExecutionError> {
202        let module = to_identifier(module)?;
203        let name = to_identifier(function)?;
204
205        let linkage = self.linkage_analysis.compute_call_linkage(
206            &package,
207            module.as_ident_str(),
208            name.as_ident_str(),
209            &type_arguments,
210            self.linkable_store,
211        )?;
212
213        let Some(original_id) = linkage.0.resolve_to_original_id(&package) else {
214            invariant_violation!(
215                "Package ID {:?} is not found in linkage generated for that package",
216                package
217            );
218        };
219        let version_mid = ModuleId::new(package.into(), module.clone());
220        let original_mid = ModuleId::new(original_id.into(), module);
221        let loaded_type_arguments = type_arguments
222            .iter()
223            .enumerate()
224            .map(|(idx, ty)| self.load_vm_type_argument_from_adapter_type(idx, ty))
225            .collect::<Result<Vec<_>, _>>()?;
226        // NB: We cannot use the resolution VM here because the linkage for that unifies up, and if
227        // this is a private entry function, it may have been removed in future versions of the
228        // package.
229        let vm = self
230            .vm
231            .make_vm(
232                &self.linkable_store.package_store,
233                linkage.linkage_context()?,
234            )
235            .map_err(|e| self.convert_linked_vm_error(e, &linkage))?;
236        let runtime_signature = vm
237            .function_information(&original_mid, name.as_ident_str(), &loaded_type_arguments)
238            .map_err(|e| {
239                if e.major_status() == StatusCode::EXTERNAL_RESOLUTION_REQUEST_ERROR {
240                    ExecutionError::new_with_source(
241                        ExecutionErrorKind::FunctionNotFound,
242                        format!(
243                            "Could not resolve function '{}' in module '{}'",
244                            name, &version_mid,
245                        ),
246                    )
247                } else {
248                    self.convert_linked_vm_error(e, &linkage)
249                }
250            })?;
251        let runtime_signature = subst_signature(runtime_signature, &loaded_type_arguments)
252            .map_err(|e| self.convert_linked_vm_error(e, &linkage))?;
253        let parameters = runtime_signature
254            .parameters
255            .into_iter()
256            .map(|ty| self.adapter_type_from_vm_type(&vm, &ty))
257            .collect::<Result<Vec<_>, _>>()?;
258        let return_ = runtime_signature
259            .return_
260            .into_iter()
261            .map(|ty| self.adapter_type_from_vm_type(&vm, &ty))
262            .collect::<Result<Vec<_>, _>>()?;
263        let signature = LoadedFunctionInstantiation {
264            parameters,
265            return_,
266        };
267        Ok(LoadedFunction {
268            version_mid,
269            original_mid,
270            name,
271            type_arguments,
272            signature,
273            linkage,
274            instruction_length: runtime_signature.instruction_count,
275            definition_index: runtime_signature.index,
276            visibility: runtime_signature.visibility,
277            is_entry: runtime_signature.is_entry,
278            is_native: runtime_signature.is_native,
279        })
280    }
281
282    pub fn load_type_input(&self, idx: usize, ty: TypeInput) -> Result<Type, ExecutionError> {
283        let vm_type = self.load_vm_type_from_type_input(idx, ty)?;
284        self.adapter_type_from_vm_type(self.input_type_resolution_vm, &vm_type)
285    }
286
287    pub fn load_type_tag(&self, idx: usize, ty: &TypeTag) -> Result<Type, ExecutionError> {
288        let vm_type = self.load_vm_type_from_type_tag(Some(idx), ty)?;
289        self.adapter_type_from_vm_type(self.input_type_resolution_vm, &vm_type)
290    }
291
292    /// We verify that all types in the `StructTag` are defining ID-based types.
293    pub fn load_type_from_struct(&self, tag: &StructTag) -> Result<Type, ExecutionError> {
294        let vm_type =
295            self.load_vm_type_from_type_tag(None, &TypeTag::Struct(Box::new(tag.clone())))?;
296        self.adapter_type_from_vm_type(self.input_type_resolution_vm, &vm_type)
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, 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, 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, ExecutionError> {
413        fn execution_error(
414            env: &Env,
415            type_arg_idx: Option<usize>,
416            e: VMError,
417            linkage: &ExecutableLinkage,
418        ) -> ExecutionError {
419            if let Some(idx) = type_arg_idx {
420                env.convert_type_argument_error(idx, e, linkage)
421            } else {
422                env.convert_linked_vm_error(e, linkage)
423            }
424        }
425
426        let objects = tag.all_addresses();
427
428        let tag_linkage = ExecutableLinkage::type_linkage(
429            self.linkage_analysis.config().clone(),
430            objects.iter().map(|a| ObjectID::from(*a)),
431            self.linkable_store,
432        )?;
433        let ty = self
434            .input_type_resolution_vm
435            .load_type(tag)
436            .map_err(|e| execution_error(self, type_arg_idx, e, &tag_linkage))?;
437        Ok(ty)
438    }
439
440    /// Converts a VM runtime Type to an adapter Type.
441    pub(crate) fn adapter_type_from_vm_type(
442        &self,
443        vm: &MoveVM,
444        vm_type: &vm_runtime::Type,
445    ) -> Result<Type, ExecutionError> {
446        use vm_runtime as VRT;
447
448        Ok(match vm_type {
449            VRT::Type::Bool => Type::Bool,
450            VRT::Type::U8 => Type::U8,
451            VRT::Type::U16 => Type::U16,
452            VRT::Type::U32 => Type::U32,
453            VRT::Type::U64 => Type::U64,
454            VRT::Type::U128 => Type::U128,
455            VRT::Type::U256 => Type::U256,
456            VRT::Type::Address => Type::Address,
457            VRT::Type::Signer => Type::Signer,
458
459            VRT::Type::Reference(ref_ty) => {
460                let inner_ty = self.adapter_type_from_vm_type(vm, ref_ty)?;
461                Type::Reference(false, Rc::new(inner_ty))
462            }
463            VRT::Type::MutableReference(ref_ty) => {
464                let inner_ty = self.adapter_type_from_vm_type(vm, ref_ty)?;
465                Type::Reference(true, Rc::new(inner_ty))
466            }
467
468            VRT::Type::Vector(inner) => {
469                let element_type = self.adapter_type_from_vm_type(vm, inner)?;
470                self.vector_type(element_type)?
471            }
472            VRT::Type::Datatype(_) => {
473                let type_information = vm
474                    .type_information(vm_type)
475                    .map_err(|e| self.convert_vm_error(e))?;
476                let Some(data_type_info) = type_information.datatype_info else {
477                    invariant_violation!("Expected datatype info for datatype type {:?}", vm_type);
478                };
479                let datatype = Datatype {
480                    abilities: type_information.abilities,
481                    module: ModuleId::new(data_type_info.defining_id, data_type_info.module_name),
482                    name: data_type_info.type_name,
483                    type_arguments: vec![],
484                };
485                Type::Datatype(Rc::new(datatype))
486            }
487            ty @ VRT::Type::DatatypeInstantiation(inst) => {
488                let (_, type_arguments) = &**inst;
489                let type_information = vm
490                    .type_information(ty)
491                    .map_err(|e| self.convert_vm_error(e))?;
492                let Some(data_type_info) = type_information.datatype_info else {
493                    invariant_violation!("Expected datatype info for datatype type {:?}", vm_type);
494                };
495
496                let abilities = type_information.abilities;
497                let module = ModuleId::new(data_type_info.defining_id, data_type_info.module_name);
498                let name = data_type_info.type_name;
499                let type_arguments = type_arguments
500                    .iter()
501                    .map(|t| self.adapter_type_from_vm_type(vm, t))
502                    .collect::<Result<Vec<_>, _>>()?;
503
504                Type::Datatype(Rc::new(Datatype {
505                    abilities,
506                    module,
507                    name,
508                    type_arguments,
509                }))
510            }
511
512            VRT::Type::TyParam(_) => {
513                invariant_violation!(
514                    "Unexpected type parameter in VM type: {:?}. This should not happen as we should \
515                     have resolved all type parameters before this point.",
516                    vm_type
517                );
518            }
519        })
520    }
521
522    /// Load a `TypeInput` into a VM runtime `Type` and its `Linkage`. Loading into the VM ensures
523    /// that any adapter type or type tag that results from this is properly output with defining
524    /// IDs.
525    fn load_vm_type_from_type_input(
526        &self,
527        type_arg_idx: usize,
528        ty: TypeInput,
529    ) -> Result<vm_runtime::Type, ExecutionError> {
530        fn to_type_tag_internal(
531            env: &Env,
532            type_arg_idx: usize,
533            ty: TypeInput,
534        ) -> Result<TypeTag, ExecutionError> {
535            Ok(match ty {
536                TypeInput::Bool => TypeTag::Bool,
537                TypeInput::U8 => TypeTag::U8,
538                TypeInput::U16 => TypeTag::U16,
539                TypeInput::U32 => TypeTag::U32,
540                TypeInput::U64 => TypeTag::U64,
541                TypeInput::U128 => TypeTag::U128,
542                TypeInput::U256 => TypeTag::U256,
543                TypeInput::Address => TypeTag::Address,
544                TypeInput::Signer => TypeTag::Signer,
545                TypeInput::Vector(type_input) => {
546                    let inner = to_type_tag_internal(env, type_arg_idx, *type_input)?;
547                    TypeTag::Vector(Box::new(inner))
548                }
549                TypeInput::Struct(struct_input) => {
550                    let StructInput {
551                        address,
552                        module,
553                        name,
554                        type_params,
555                    } = *struct_input;
556
557                    let pkg = env
558                        .linkable_store
559                        .get_package(&address.into())
560                        .ok()
561                        .flatten()
562                        .ok_or_else(|| {
563                            let argument_idx = match checked_as!(type_arg_idx, u16) {
564                                Err(e) => return e,
565                                Ok(v) => v,
566                            };
567                            ExecutionError::from_kind(ExecutionErrorKind::TypeArgumentError {
568                                argument_idx,
569                                kind: TypeArgumentError::TypeNotFound,
570                            })
571                        })?;
572                    let module = to_identifier(module)?;
573                    let name = to_identifier(name)?;
574                    let tid = IntraPackageName {
575                        module_name: module,
576                        type_name: name,
577                    };
578                    let Some(resolved_address) = pkg.type_origin_table().get(&tid).cloned() else {
579                        return Err(ExecutionError::from_kind(
580                            ExecutionErrorKind::TypeArgumentError {
581                                argument_idx: checked_as!(type_arg_idx, u16)?,
582                                kind: TypeArgumentError::TypeNotFound,
583                            },
584                        ));
585                    };
586
587                    let tys = type_params
588                        .into_iter()
589                        .map(|tp| to_type_tag_internal(env, type_arg_idx, tp))
590                        .collect::<Result<Vec<_>, _>>()?;
591                    TypeTag::Struct(Box::new(StructTag {
592                        address: resolved_address,
593                        module: tid.module_name,
594                        name: tid.type_name,
595                        type_params: tys,
596                    }))
597                }
598            })
599        }
600        let tag = to_type_tag_internal(self, type_arg_idx, ty)?;
601        self.load_vm_type_from_type_tag(Some(type_arg_idx), &tag)
602    }
603}
604
605fn to_identifier(name: String) -> Result<Identifier, ExecutionError> {
606    Identifier::new(name).map_err(|e| {
607        ExecutionError::new_with_source(ExecutionErrorKind::VMInvariantViolation, e.to_string())
608    })
609}
610
611fn convert_vm_error(
612    error: VMError,
613    store: &dyn PackageStore,
614    linkage: Option<&ExecutableLinkage>,
615    _protocol_config: &ProtocolConfig,
616) -> ExecutionError {
617    use crate::error::convert_vm_error_impl;
618    convert_vm_error_impl(
619        error,
620        &|id| {
621            debug_assert!(
622                linkage.is_some(),
623                "Linkage should be set anywhere where runtime errors may occur in order to resolve abort locations to package IDs"
624            );
625            linkage
626                .and_then(|linkage| {
627                    linkage
628                        .0
629                        .linkage
630                        .get(&(*id.address()).into())
631                        .map(|new_id| ModuleId::new((*new_id).into(), id.name().to_owned()))
632                })
633                .unwrap_or_else(|| id.clone())
634        },
635        // NB: the `id` here is the original ID (and hence _not_ relocated).
636        &|id, function| {
637            debug_assert!(
638                linkage.is_some(),
639                "Linkage should be set anywhere where runtime errors may occur in order to resolve abort locations to package IDs"
640            );
641            linkage.and_then(|linkage| {
642                let version_id = linkage
643                    .0
644                    .linkage
645                    .get(&(*id.address()).into())
646                    .cloned()
647                    .unwrap_or_else(|| ObjectID::from_address(*id.address()));
648                store.get_package(&version_id).ok().flatten().and_then(|p| {
649                    p.modules().get(id).map(|module| {
650                        let module = module.compiled_module();
651                        let fdef = module.function_def_at(function);
652                        let fhandle = module.function_handle_at(fdef.function);
653                        module.identifier_at(fhandle.name).to_string()
654                    })
655                })
656            })
657        },
658    )
659}