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