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            objects.into_iter().map(ObjectID::from),
155            self.linkable_store,
156        )?;
157        self.input_type_resolution_vm
158            .annotated_type_layout(&tag)
159            .map_err(|e| self.convert_linked_vm_error(e, &tag_linkage))
160    }
161
162    pub fn runtime_layout(
163        &self,
164        ty: &Type,
165    ) -> Result<runtime_value::MoveTypeLayout, ExecutionError> {
166        let tag: TypeTag = ty.clone().try_into().map_err(|s| {
167            ExecutionError::new_with_source(ExecutionErrorKind::VMInvariantViolation, s)
168        })?;
169        let objects = tag.all_addresses();
170        let tag_linkage = ExecutableLinkage::type_linkage(
171            objects.into_iter().map(ObjectID::from),
172            self.linkable_store,
173        )?;
174        self.input_type_resolution_vm
175            .runtime_type_layout(&tag)
176            .map_err(|e| self.convert_linked_vm_error(e, &tag_linkage))
177    }
178
179    pub fn load_framework_function(
180        &self,
181        module: &IdentStr,
182        function: &IdentStr,
183        type_arguments: Vec<Type>,
184    ) -> Result<LoadedFunction, ExecutionError> {
185        self.load_function(
186            SUI_FRAMEWORK_PACKAGE_ID,
187            module.to_string(),
188            function.to_string(),
189            type_arguments,
190        )
191    }
192
193    pub fn load_function(
194        &self,
195        package: ObjectID,
196        module: String,
197        function: String,
198        type_arguments: Vec<Type>,
199    ) -> Result<LoadedFunction, ExecutionError> {
200        let module = to_identifier(module)?;
201        let name = to_identifier(function)?;
202
203        let linkage = self.linkage_analysis.compute_call_linkage(
204            &package,
205            module.as_ident_str(),
206            name.as_ident_str(),
207            &type_arguments,
208            self.linkable_store,
209        )?;
210
211        let Some(original_id) = linkage.0.resolve_to_original_id(&package) else {
212            invariant_violation!(
213                "Package ID {:?} is not found in linkage generated for that package",
214                package
215            );
216        };
217        let version_mid = ModuleId::new(package.into(), module.clone());
218        let original_mid = ModuleId::new(original_id.into(), module);
219        let loaded_type_arguments = type_arguments
220            .iter()
221            .enumerate()
222            .map(|(idx, ty)| self.load_vm_type_argument_from_adapter_type(idx, ty))
223            .collect::<Result<Vec<_>, _>>()?;
224        // NB: We cannot use the resolution VM here because the linkage for that unifies up, and if
225        // this is a private entry function, it may have been removed in future versions of the
226        // package.
227        let vm = self
228            .vm
229            .make_vm(
230                &self.linkable_store.package_store,
231                linkage.linkage_context()?,
232            )
233            .map_err(|e| self.convert_linked_vm_error(e, &linkage))?;
234        let runtime_signature = vm
235            .function_information(&original_mid, name.as_ident_str(), &loaded_type_arguments)
236            .map_err(|e| {
237                if e.major_status() == StatusCode::EXTERNAL_RESOLUTION_REQUEST_ERROR {
238                    ExecutionError::new_with_source(
239                        ExecutionErrorKind::FunctionNotFound,
240                        format!(
241                            "Could not resolve function '{}' in module '{}'",
242                            name, &version_mid,
243                        ),
244                    )
245                } else {
246                    self.convert_linked_vm_error(e, &linkage)
247                }
248            })?;
249        let runtime_signature = subst_signature(runtime_signature, &loaded_type_arguments)
250            .map_err(|e| self.convert_linked_vm_error(e, &linkage))?;
251        let parameters = runtime_signature
252            .parameters
253            .into_iter()
254            .map(|ty| self.adapter_type_from_vm_type(&vm, &ty))
255            .collect::<Result<Vec<_>, _>>()?;
256        let return_ = runtime_signature
257            .return_
258            .into_iter()
259            .map(|ty| self.adapter_type_from_vm_type(&vm, &ty))
260            .collect::<Result<Vec<_>, _>>()?;
261        let signature = LoadedFunctionInstantiation {
262            parameters,
263            return_,
264        };
265        Ok(LoadedFunction {
266            version_mid,
267            original_mid,
268            name,
269            type_arguments,
270            signature,
271            linkage,
272            instruction_length: runtime_signature.instruction_count,
273            definition_index: runtime_signature.index,
274            visibility: runtime_signature.visibility,
275            is_entry: runtime_signature.is_entry,
276            is_native: runtime_signature.is_native,
277        })
278    }
279
280    pub fn load_type_input(&self, idx: usize, ty: TypeInput) -> Result<Type, ExecutionError> {
281        let vm_type = self.load_vm_type_from_type_input(idx, ty)?;
282        self.adapter_type_from_vm_type(self.input_type_resolution_vm, &vm_type)
283    }
284
285    pub fn load_type_tag(&self, idx: usize, ty: &TypeTag) -> Result<Type, ExecutionError> {
286        let vm_type = self.load_vm_type_from_type_tag(Some(idx), ty)?;
287        self.adapter_type_from_vm_type(self.input_type_resolution_vm, &vm_type)
288    }
289
290    /// We verify that all types in the `StructTag` are defining ID-based types.
291    pub fn load_type_from_struct(&self, tag: &StructTag) -> Result<Type, ExecutionError> {
292        let vm_type =
293            self.load_vm_type_from_type_tag(None, &TypeTag::Struct(Box::new(tag.clone())))?;
294        self.adapter_type_from_vm_type(self.input_type_resolution_vm, &vm_type)
295    }
296
297    pub fn type_layout_for_struct(
298        &self,
299        tag: &StructTag,
300    ) -> Result<MoveTypeLayout, ExecutionError> {
301        let ty: Type = self.load_type_from_struct(tag)?;
302        self.runtime_layout(&ty)
303    }
304
305    pub fn gas_coin_type(&self) -> Result<Type, ExecutionError> {
306        get_or_init_ty!(self, gas_coin_type, GasCoin::type_())
307    }
308
309    pub fn upgrade_ticket_type(&self) -> Result<Type, ExecutionError> {
310        get_or_init_ty!(self, upgrade_ticket_type, UpgradeTicket::type_())
311    }
312
313    pub fn upgrade_receipt_type(&self) -> Result<Type, ExecutionError> {
314        get_or_init_ty!(self, upgrade_receipt_type, UpgradeReceipt::type_())
315    }
316
317    pub fn upgrade_cap_type(&self) -> Result<Type, ExecutionError> {
318        get_or_init_ty!(self, upgrade_cap_type, UpgradeCap::type_())
319    }
320
321    pub fn tx_context_type(&self) -> Result<Type, ExecutionError> {
322        get_or_init_ty!(self, tx_context_type, TxContext::type_())
323    }
324
325    pub fn coin_type(&self, inner_type: Type) -> Result<Type, ExecutionError> {
326        const COIN_ABILITIES: AbilitySet =
327            AbilitySet::singleton(Ability::Key).union(AbilitySet::singleton(Ability::Store));
328        let (a, m, n) = RESOLVED_COIN_STRUCT;
329        let module = ModuleId::new(*a, m.to_owned());
330        Ok(Type::Datatype(Rc::new(Datatype {
331            abilities: COIN_ABILITIES,
332            module,
333            name: n.to_owned(),
334            type_arguments: vec![inner_type],
335        })))
336    }
337
338    pub fn balance_type(&self, inner_type: Type) -> Result<Type, ExecutionError> {
339        const BALANCE_ABILITIES: AbilitySet = AbilitySet::singleton(Ability::Store);
340        let (a, m, n) = RESOLVED_BALANCE_STRUCT;
341        let module = ModuleId::new(*a, m.to_owned());
342        Ok(Type::Datatype(Rc::new(Datatype {
343            abilities: BALANCE_ABILITIES,
344            module,
345            name: n.to_owned(),
346            type_arguments: vec![inner_type],
347        })))
348    }
349
350    pub fn withdrawal_type(&self, inner_type: Type) -> Result<Type, ExecutionError> {
351        const WITHDRAWAL_ABILITIES: AbilitySet = AbilitySet::singleton(Ability::Drop);
352        let (a, m, n) = RESOLVED_WITHDRAWAL_STRUCT;
353        let module = ModuleId::new(*a, m.to_owned());
354        Ok(Type::Datatype(Rc::new(Datatype {
355            abilities: WITHDRAWAL_ABILITIES,
356            module,
357            name: n.to_owned(),
358            type_arguments: vec![inner_type],
359        })))
360    }
361
362    pub fn vector_type(&self, element_type: Type) -> Result<Type, ExecutionError> {
363        let abilities = AbilitySet::polymorphic_abilities(
364            AbilitySet::VECTOR,
365            [false],
366            [element_type.abilities()],
367        )
368        .map_err(|e| {
369            ExecutionError::new_with_source(ExecutionErrorKind::VMInvariantViolation, e.to_string())
370        })?;
371        Ok(Type::Vector(Rc::new(L::Vector {
372            abilities,
373            element_type,
374        })))
375    }
376
377    pub fn read_object(&self, id: &ObjectID) -> Result<&Object, ExecutionError> {
378        let Some(obj) = self.state_view.read_object(id) else {
379            // protected by transaction input checker
380            invariant_violation!("Object {:?} does not exist", id);
381        };
382        Ok(obj)
383    }
384
385    /// Takes an adapter Type and returns a VM runtime Type and the linkage for it.
386    pub fn load_vm_type_argument_from_adapter_type(
387        &self,
388        idx: usize,
389        ty: &Type,
390    ) -> Result<vm_runtime::Type, ExecutionError> {
391        self.load_vm_type_from_adapter_type(Some(idx), ty)
392    }
393
394    fn load_vm_type_from_adapter_type(
395        &self,
396        type_arg_idx: Option<usize>,
397        ty: &Type,
398    ) -> Result<vm_runtime::Type, ExecutionError> {
399        let tag: TypeTag = ty.clone().try_into().map_err(|s| {
400            ExecutionError::new_with_source(ExecutionErrorKind::VMInvariantViolation, s)
401        })?;
402        self.load_vm_type_from_type_tag(type_arg_idx, &tag)
403    }
404
405    /// Take a type tag and returns a VM runtime Type and the linkage for it.
406    fn load_vm_type_from_type_tag(
407        &self,
408        type_arg_idx: Option<usize>,
409        tag: &TypeTag,
410    ) -> Result<vm_runtime::Type, ExecutionError> {
411        fn execution_error(
412            env: &Env,
413            type_arg_idx: Option<usize>,
414            e: VMError,
415            linkage: &ExecutableLinkage,
416        ) -> ExecutionError {
417            if let Some(idx) = type_arg_idx {
418                env.convert_type_argument_error(idx, e, linkage)
419            } else {
420                env.convert_linked_vm_error(e, linkage)
421            }
422        }
423
424        let objects = tag.all_addresses();
425
426        let tag_linkage = ExecutableLinkage::type_linkage(
427            objects.iter().map(|a| ObjectID::from(*a)),
428            self.linkable_store,
429        )?;
430        let ty = self
431            .input_type_resolution_vm
432            .load_type(tag)
433            .map_err(|e| execution_error(self, type_arg_idx, e, &tag_linkage))?;
434        Ok(ty)
435    }
436
437    /// Converts a VM runtime Type to an adapter Type.
438    pub(crate) fn adapter_type_from_vm_type(
439        &self,
440        vm: &MoveVM,
441        vm_type: &vm_runtime::Type,
442    ) -> Result<Type, ExecutionError> {
443        use vm_runtime as VRT;
444
445        Ok(match vm_type {
446            VRT::Type::Bool => Type::Bool,
447            VRT::Type::U8 => Type::U8,
448            VRT::Type::U16 => Type::U16,
449            VRT::Type::U32 => Type::U32,
450            VRT::Type::U64 => Type::U64,
451            VRT::Type::U128 => Type::U128,
452            VRT::Type::U256 => Type::U256,
453            VRT::Type::Address => Type::Address,
454            VRT::Type::Signer => Type::Signer,
455
456            VRT::Type::Reference(ref_ty) => {
457                let inner_ty = self.adapter_type_from_vm_type(vm, ref_ty)?;
458                Type::Reference(false, Rc::new(inner_ty))
459            }
460            VRT::Type::MutableReference(ref_ty) => {
461                let inner_ty = self.adapter_type_from_vm_type(vm, ref_ty)?;
462                Type::Reference(true, Rc::new(inner_ty))
463            }
464
465            VRT::Type::Vector(inner) => {
466                let element_type = self.adapter_type_from_vm_type(vm, inner)?;
467                self.vector_type(element_type)?
468            }
469            VRT::Type::Datatype(_) => {
470                let type_information = vm
471                    .type_information(vm_type)
472                    .map_err(|e| self.convert_vm_error(e))?;
473                let Some(data_type_info) = type_information.datatype_info else {
474                    invariant_violation!("Expected datatype info for datatype type {:?}", vm_type);
475                };
476                let datatype = Datatype {
477                    abilities: type_information.abilities,
478                    module: ModuleId::new(data_type_info.defining_id, data_type_info.module_name),
479                    name: data_type_info.type_name,
480                    type_arguments: vec![],
481                };
482                Type::Datatype(Rc::new(datatype))
483            }
484            ty @ VRT::Type::DatatypeInstantiation(inst) => {
485                let (_, type_arguments) = &**inst;
486                let type_information = vm
487                    .type_information(ty)
488                    .map_err(|e| self.convert_vm_error(e))?;
489                let Some(data_type_info) = type_information.datatype_info else {
490                    invariant_violation!("Expected datatype info for datatype type {:?}", vm_type);
491                };
492
493                let abilities = type_information.abilities;
494                let module = ModuleId::new(data_type_info.defining_id, data_type_info.module_name);
495                let name = data_type_info.type_name;
496                let type_arguments = type_arguments
497                    .iter()
498                    .map(|t| self.adapter_type_from_vm_type(vm, t))
499                    .collect::<Result<Vec<_>, _>>()?;
500
501                Type::Datatype(Rc::new(Datatype {
502                    abilities,
503                    module,
504                    name,
505                    type_arguments,
506                }))
507            }
508
509            VRT::Type::TyParam(_) => {
510                invariant_violation!(
511                    "Unexpected type parameter in VM type: {:?}. This should not happen as we should \
512                     have resolved all type parameters before this point.",
513                    vm_type
514                );
515            }
516        })
517    }
518
519    /// Load a `TypeInput` into a VM runtime `Type` and its `Linkage`. Loading into the VM ensures
520    /// that any adapter type or type tag that results from this is properly output with defining
521    /// IDs.
522    fn load_vm_type_from_type_input(
523        &self,
524        type_arg_idx: usize,
525        ty: TypeInput,
526    ) -> Result<vm_runtime::Type, ExecutionError> {
527        fn to_type_tag_internal(
528            env: &Env,
529            type_arg_idx: usize,
530            ty: TypeInput,
531        ) -> Result<TypeTag, ExecutionError> {
532            Ok(match ty {
533                TypeInput::Bool => TypeTag::Bool,
534                TypeInput::U8 => TypeTag::U8,
535                TypeInput::U16 => TypeTag::U16,
536                TypeInput::U32 => TypeTag::U32,
537                TypeInput::U64 => TypeTag::U64,
538                TypeInput::U128 => TypeTag::U128,
539                TypeInput::U256 => TypeTag::U256,
540                TypeInput::Address => TypeTag::Address,
541                TypeInput::Signer => TypeTag::Signer,
542                TypeInput::Vector(type_input) => {
543                    let inner = to_type_tag_internal(env, type_arg_idx, *type_input)?;
544                    TypeTag::Vector(Box::new(inner))
545                }
546                TypeInput::Struct(struct_input) => {
547                    let StructInput {
548                        address,
549                        module,
550                        name,
551                        type_params,
552                    } = *struct_input;
553
554                    let pkg = env
555                        .linkable_store
556                        .get_package(&address.into())
557                        .ok()
558                        .flatten()
559                        .ok_or_else(|| {
560                            let argument_idx = match checked_as!(type_arg_idx, u16) {
561                                Err(e) => return e,
562                                Ok(v) => v,
563                            };
564                            ExecutionError::from_kind(ExecutionErrorKind::TypeArgumentError {
565                                argument_idx,
566                                kind: TypeArgumentError::TypeNotFound,
567                            })
568                        })?;
569                    let module = to_identifier(module)?;
570                    let name = to_identifier(name)?;
571                    let tid = IntraPackageName {
572                        module_name: module,
573                        type_name: name,
574                    };
575                    let Some(resolved_address) = pkg.type_origin_table().get(&tid).cloned() else {
576                        return Err(ExecutionError::from_kind(
577                            ExecutionErrorKind::TypeArgumentError {
578                                argument_idx: checked_as!(type_arg_idx, u16)?,
579                                kind: TypeArgumentError::TypeNotFound,
580                            },
581                        ));
582                    };
583
584                    let tys = type_params
585                        .into_iter()
586                        .map(|tp| to_type_tag_internal(env, type_arg_idx, tp))
587                        .collect::<Result<Vec<_>, _>>()?;
588                    TypeTag::Struct(Box::new(StructTag {
589                        address: resolved_address,
590                        module: tid.module_name,
591                        name: tid.type_name,
592                        type_params: tys,
593                    }))
594                }
595            })
596        }
597        let tag = to_type_tag_internal(self, type_arg_idx, ty)?;
598        self.load_vm_type_from_type_tag(Some(type_arg_idx), &tag)
599    }
600}
601
602fn to_identifier(name: String) -> Result<Identifier, ExecutionError> {
603    Identifier::new(name).map_err(|e| {
604        ExecutionError::new_with_source(ExecutionErrorKind::VMInvariantViolation, e.to_string())
605    })
606}
607
608fn convert_vm_error(
609    error: VMError,
610    store: &dyn PackageStore,
611    linkage: Option<&ExecutableLinkage>,
612    _protocol_config: &ProtocolConfig,
613) -> ExecutionError {
614    use crate::error::convert_vm_error_impl;
615    convert_vm_error_impl(
616        error,
617        &|id| {
618            debug_assert!(
619                linkage.is_some(),
620                "Linkage should be set anywhere where runtime errors may occur in order to resolve abort locations to package IDs"
621            );
622            linkage
623                .and_then(|linkage| {
624                    linkage
625                        .0
626                        .linkage
627                        .get(&(*id.address()).into())
628                        .map(|new_id| ModuleId::new((*new_id).into(), id.name().to_owned()))
629                })
630                .unwrap_or_else(|| id.clone())
631        },
632        // NB: the `id` here is the original ID (and hence _not_ relocated).
633        &|id, function| {
634            debug_assert!(
635                linkage.is_some(),
636                "Linkage should be set anywhere where runtime errors may occur in order to resolve abort locations to package IDs"
637            );
638            linkage.and_then(|linkage| {
639                let version_id = linkage
640                    .0
641                    .linkage
642                    .get(&(*id.address()).into())
643                    .cloned()
644                    .unwrap_or_else(|| ObjectID::from_address(*id.address()));
645                store.get_package(&version_id).ok().flatten().and_then(|p| {
646                    p.modules().get(id).map(|module| {
647                        let module = module.compiled_module();
648                        let fdef = module.function_def_at(function);
649                        let fhandle = module.function_handle_at(fdef.function);
650                        module.identifier_at(fhandle.name).to_string()
651                    })
652                })
653            })
654        },
655    )
656}