Skip to main content

iota_package_resolver/
lib.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use std::{
6    borrow::Cow,
7    collections::{BTreeMap, BTreeSet},
8    num::NonZeroUsize,
9    sync::{Arc, Mutex},
10};
11
12use async_trait::async_trait;
13use iota_sdk_types::{
14    Address, Argument, Command, Identifier, MakeMoveVector, ProgrammableTransaction, StructTag,
15    TypeTag, Version,
16    move_package::{MovePackage, TypeOrigin},
17};
18use iota_types::{
19    base_types::is_primitive_type_tag,
20    iota_sdk_types_conversions::{struct_tag_sdk_to_core, type_tag_core_to_sdk},
21    object::Object,
22    transaction::CallArg,
23};
24use lru::LruCache;
25use move_binary_format::{
26    CompiledModule,
27    errors::Location,
28    file_format::{
29        AbilitySet, DatatypeHandleIndex, DatatypeTyParameter, EnumDefinitionIndex,
30        FunctionDefinitionIndex, Signature as MoveSignature, SignatureIndex, SignatureToken,
31        StructDefinitionIndex, StructFieldInformation, TableIndex, Visibility,
32    },
33};
34use move_command_line_common::{
35    display::{RenderResult, try_render_constant},
36    error_bitset::ErrorBitset,
37};
38use move_core_types::{
39    account_address::AccountAddress,
40    annotated_value::{MoveEnumLayout, MoveFieldLayout, MoveStructLayout, MoveTypeLayout},
41    language_storage::ModuleId,
42};
43
44use crate::error::Error;
45
46pub mod error;
47
48// TODO Move to ServiceConfig
49
50const PACKAGE_CACHE_SIZE: NonZeroUsize = NonZeroUsize::new(1024).unwrap();
51
52pub type Result<T> = std::result::Result<T, Error>;
53
54/// The Resolver is responsible for providing information about types. It relies
55/// on its internal `package_store` to load packages and then type definitions
56/// from those packages.
57#[derive(Debug)]
58pub struct Resolver<S> {
59    package_store: S,
60    limits: Option<Limits>,
61}
62
63/// Optional configuration that imposes limits on the work that the resolver can
64/// do for each request.
65#[derive(Debug)]
66pub struct Limits {
67    /// Maximum recursion depth through type parameters.
68    pub max_type_argument_depth: usize,
69    /// Maximum number of type arguments in a single type instantiation.
70    pub max_type_argument_width: usize,
71    /// Maximum size for the resolution context.
72    pub max_type_nodes: usize,
73    /// Maximum recursion depth through struct fields.
74    pub max_move_value_depth: usize,
75}
76
77/// Store which fetches package for the given address from the backend db and
78/// caches it locally in an lru cache. On every call to `fetch` it checks
79/// backend db and if package version is stale locally, it updates the local
80/// state before returning to the user
81pub struct PackageStoreWithLruCache<T> {
82    pub(crate) packages: Mutex<LruCache<Address, Arc<Package>>>,
83    pub(crate) inner: T,
84}
85
86#[derive(Clone, Debug)]
87pub struct Package {
88    /// The ID this package was loaded from on-chain.
89    storage_id: Address,
90
91    /// The ID that this package is associated with at runtime.  Bytecode in
92    /// other packages refers to types and functions from this package using
93    /// this ID.
94    runtime_id: Address,
95
96    /// The package's transitive dependencies as a mapping from the package's
97    /// runtime ID (the ID it is referred to by in other packages) to its
98    /// storage ID (the ID it is loaded from on chain).
99    linkage: Linkage,
100
101    /// The version this package was loaded at -- necessary for handling race
102    /// conditions when loading system packages.
103    version: Version,
104
105    modules: BTreeMap<String, Module>,
106}
107
108type Linkage = BTreeMap<Address, Address>;
109
110/// A `CleverError` is a special kind of abort code that is used to encode more
111/// information than a normal abort code. These clever errors are used to encode
112/// the line number, error constant name, and error constant value as pool
113/// indices packed into a format satisfying the `ErrorBitset` format. This
114/// struct is the "inflated" view of that data, providing the module ID, line
115/// number, and error constant name and value (if available).
116#[derive(Clone, Debug)]
117pub struct CleverError {
118    /// The (storage) module ID of the module that the assertion failed in.
119    pub module_id: ModuleId,
120    /// Inner error information. This is either a complete error, just a line
121    /// number, or bytes that should be treated opaquely.
122    pub error_info: ErrorConstants,
123    /// The line number in the source file where the error occurred.
124    pub source_line_number: u16,
125}
126
127/// The `ErrorConstants` enum is used to represent the different kinds of error
128/// information that can be returned from a clever error when looking at the
129/// constant values for the clever error. These values are either:
130/// * `None` - No constant information is available, only a line number.
131/// * `Rendered` - The error is a complete error, with an error identifier and
132///   constant that can be rendered in a human-readable format (see in-line doc
133///   comments for exact types of values supported).
134/// * `Raw` - If there is an error constant value, but it is not a renderable
135///   type (e.g., a `vector<address>`), then it is treated as opaque and the
136///   bytes are returned.
137#[derive(Clone, Debug)]
138pub enum ErrorConstants {
139    /// No constant information is available, only a line number.
140    None,
141    /// The error is a complete error, with an error identifier and constant
142    /// that can be rendered. The rendered string representation of the
143    /// constant is returned only when the constant value is one of the
144    /// following types:
145    /// * A vector of bytes convertible to a valid UTF-8 string; or
146    /// * A numeric value (u8, u16, u32, u64, u128, u256); or
147    /// * A boolean value; or
148    /// * An address value
149    ///
150    /// Otherwise, the `Raw` bytes of the error constant are returned.
151    Rendered {
152        /// The name of the error constant.
153        identifier: String,
154        /// The value of the error constant.
155        constant: String,
156    },
157    /// If there is an error constant value, but ii is not one of the above
158    /// types, then it is treated as opaque and the bytes are returned. The
159    /// caller is responsible for determining how best to display the error
160    /// constant in this case.
161    Raw {
162        /// The name of the error constant.
163        identifier: String,
164        /// The raw (BCS) bytes of the error constant.
165        bytes: Vec<u8>,
166    },
167}
168
169#[derive(Clone, Debug)]
170pub struct Module {
171    bytecode: CompiledModule,
172
173    /// Index mapping struct names to their defining ID, and the index for their
174    /// definition in the bytecode, to speed up definition lookups.
175    struct_index: BTreeMap<String, (Address, StructDefinitionIndex)>,
176
177    /// Index mapping enum names to their defining ID and the index of their
178    /// definition in the bytecode. This speeds up definition lookups.
179    enum_index: BTreeMap<String, (Address, EnumDefinitionIndex)>,
180    /// Index mapping function names to the index for their definition in the
181    /// bytecode, to speed up definition lookups.
182    function_index: BTreeMap<String, FunctionDefinitionIndex>,
183}
184
185/// Deserialized representation of a struct definition.
186#[derive(Debug)]
187pub struct DataDef {
188    /// The storage ID of the package that first introduced this type.
189    pub defining_id: Address,
190
191    /// This type's abilities.
192    pub abilities: AbilitySet,
193
194    /// Ability constraints and phantom status for type parameters
195    pub type_params: Vec<DatatypeTyParameter>,
196
197    /// The internal data of the datatype. This can either be a sequence of
198    /// fields, or a sequence of variants.
199    pub data: MoveData,
200}
201
202#[derive(Debug)]
203pub enum MoveData {
204    /// Serialized representation of fields (names and deserialized signatures).
205    /// Signatures refer to packages at their runtime IDs (not their storage
206    /// ID or defining ID).
207    Struct(Vec<(String, OpenSignatureBody)>),
208
209    /// Serialized representation of variants (names and deserialized
210    /// signatures).
211    Enum(Vec<VariantDef>),
212}
213
214/// Deserialized representation of an enum definition. These are always held
215/// inside an `EnumDef`.
216#[derive(Debug)]
217pub struct VariantDef {
218    /// The name of the enum variant
219    pub name: String,
220
221    /// The serialized representation of the variant's signature. Signatures
222    /// refer to packages at their runtime IDs (not their storage ID or
223    /// defining ID).
224    pub signatures: Vec<(String, OpenSignatureBody)>,
225}
226
227/// Deserialized representation of a function definition
228#[derive(Debug)]
229pub struct FunctionDef {
230    /// Whether the function is `public`, `private` or `public(friend)`.
231    pub visibility: Visibility,
232
233    /// Whether the function is marked `entry` or not.
234    pub is_entry: bool,
235
236    /// Ability constraints for type parameters
237    pub type_params: Vec<AbilitySet>,
238
239    /// Formal parameter types.
240    pub parameters: Vec<OpenSignature>,
241
242    /// Return types.
243    pub return_: Vec<OpenSignature>,
244}
245
246/// Fully qualified struct identifier.  Uses copy-on-write strings so that when
247/// it is used as a key to a map, an instance can be created to query the map
248/// without having to allocate strings on the heap.
249#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Hash)]
250pub struct DatatypeRef<'m, 'n> {
251    pub package: Address,
252    pub module: Cow<'m, str>,
253    pub name: Cow<'n, str>,
254}
255
256/// A `StructRef` that owns its strings.
257pub type DatatypeKey = DatatypeRef<'static, 'static>;
258
259#[derive(Copy, Clone, Debug)]
260pub enum Reference {
261    Immutable,
262    Mutable,
263}
264
265/// A function parameter or return signature, with its type parameters
266/// instantiated.
267#[derive(Clone, Debug)]
268pub struct Signature {
269    pub ref_: Option<Reference>,
270    pub body: TypeTag,
271}
272
273/// Deserialized representation of a type signature that could appear as a
274/// function parameter or return.
275#[derive(Clone, Debug)]
276pub struct OpenSignature {
277    pub ref_: Option<Reference>,
278    pub body: OpenSignatureBody,
279}
280
281/// Deserialized representation of a type signature that could appear as a field
282/// type for a struct.
283#[derive(Clone, Debug)]
284pub enum OpenSignatureBody {
285    Address,
286    Bool,
287    U8,
288    U16,
289    U32,
290    U64,
291    U128,
292    U256,
293    Vector(Box<OpenSignatureBody>),
294    Datatype(DatatypeKey, Vec<OpenSignatureBody>),
295    TypeParameter(u16),
296}
297
298/// Information necessary to convert a type tag into a type layout.
299#[derive(Debug, Default)]
300struct ResolutionContext<'l> {
301    /// Definitions (field information) for structs referred to by types added
302    /// to this context.
303    datatypes: BTreeMap<DatatypeKey, DataDef>,
304
305    /// Limits configuration from the calling resolver.
306    limits: Option<&'l Limits>,
307}
308
309/// Interface to abstract over access to a store of live packages.  Used to
310/// override the default store during testing.
311#[async_trait]
312pub trait PackageStore: Send + Sync + 'static {
313    /// Read package contents. Fails if `id` is not an object, not a package, or
314    /// is malformed in some way.
315    async fn fetch(&self, id: Address) -> Result<Arc<Package>>;
316}
317
318macro_rules! as_ref_impl {
319    ($type:ty) => {
320        #[async_trait]
321        impl PackageStore for $type {
322            async fn fetch(&self, id: Address) -> Result<Arc<Package>> {
323                self.as_ref().fetch(id).await
324            }
325        }
326    };
327}
328
329as_ref_impl!(Arc<dyn PackageStore>);
330as_ref_impl!(Box<dyn PackageStore>);
331
332/// Check $value does not exceed $limit in config, if the limit config exists,
333/// returning an error containing the max value and actual value otherwise.
334macro_rules! check_max_limit {
335    ($err:ident, $config:expr; $limit:ident $op:tt $value:expr) => {
336        if let Some(l) = $config {
337            let max = l.$limit;
338            let val = $value;
339            if !(max $op val) {
340                return Err(Error::$err(max, val));
341            }
342        }
343    };
344}
345
346impl<S> Resolver<S> {
347    pub fn new(package_store: S) -> Self {
348        Self {
349            package_store,
350            limits: None,
351        }
352    }
353
354    pub fn new_with_limits(package_store: S, limits: Limits) -> Self {
355        Self {
356            package_store,
357            limits: Some(limits),
358        }
359    }
360
361    pub fn package_store(&self) -> &S {
362        &self.package_store
363    }
364
365    pub fn package_store_mut(&mut self) -> &mut S {
366        &mut self.package_store
367    }
368}
369
370impl<S: PackageStore> Resolver<S> {
371    /// The canonical form of a type refers to each type in terms of its
372    /// defining package ID. ThisAdd commentMore actions function takes a
373    /// non-canonical type and updates all its package IDs to the appropriate
374    /// defining ID.
375    ///
376    /// For every `package::module::datatype` in the input `tag`, `package` must
377    /// be an object on-chain, containing a move package that includes
378    /// `module`, and that module must define the `datatype`. In practice
379    /// this means the input type `tag` can refer to types at or after their
380    /// defining IDs.
381    pub async fn canonical_type(&self, mut tag: TypeTag) -> Result<TypeTag> {
382        let mut context = ResolutionContext::new(self.limits.as_ref());
383
384        // (1). Fetch all the information from this store that is necessary to relocate
385        // package IDs in the type.
386        context
387            .add_type_tag(
388                &mut tag,
389                &self.package_store,
390                // visit_fields
391                false,
392                // visit_phantoms
393                true,
394            )
395            .await?;
396
397        // (2). Use that information to relocate package IDs in the type.
398        context.canonicalize_type(&mut tag)?;
399        Ok(tag)
400    }
401
402    /// Return the type layout corresponding to the given type tag.  The layout
403    /// always refers to structs in terms of their defining ID (i.e. their
404    /// package ID always points to the first package that introduced them).
405    pub async fn type_layout(&self, mut tag: TypeTag) -> Result<MoveTypeLayout> {
406        let mut context = ResolutionContext::new(self.limits.as_ref());
407
408        // (1). Fetch all the information from this store that is necessary to resolve
409        // types referenced by this tag.
410        context
411            .add_type_tag(
412                &mut tag,
413                &self.package_store,
414                // visit_fields
415                true,
416                // visit_phantoms
417                true,
418            )
419            .await?;
420
421        // (2). Use that information to resolve the tag into a layout.
422        let max_depth = self
423            .limits
424            .as_ref()
425            .map_or(usize::MAX, |l| l.max_move_value_depth);
426
427        Ok(context.resolve_type_layout(&tag, max_depth)?.0)
428    }
429
430    /// Return the abilities of a concrete type, based on the abilities in its
431    /// type definition, and the abilities of its concrete type parameters:
432    /// An instance of a generic type has `store`, `copy, or `drop` if its
433    /// definition has the ability, and all its non-phantom type parameters
434    /// have the ability as well. Similar rules apply for `key` except that it
435    /// requires its type parameters to have `store`.
436    pub async fn abilities(&self, mut tag: TypeTag) -> Result<AbilitySet> {
437        let mut context = ResolutionContext::new(self.limits.as_ref());
438
439        // (1). Fetch all the information from this store that is necessary to resolve
440        // types referenced by this tag.
441        context
442            .add_type_tag(
443                &mut tag,
444                &self.package_store,
445                // visit_fields
446                false,
447                // visit_phantoms
448                false,
449            )
450            .await?;
451
452        // (2). Use that information to calculate the type's abilities.
453        context.resolve_abilities(&tag)
454    }
455
456    /// Returns the signatures of parameters to function `pkg::module::function`
457    /// in the package store, assuming the function exists.
458    pub async fn function_signature(
459        &self,
460        pkg: Address,
461        module: &str,
462        function: &str,
463    ) -> Result<FunctionDef> {
464        let mut context = ResolutionContext::new(self.limits.as_ref());
465
466        let package = self.package_store.fetch(pkg).await?;
467        let Some(mut def) = package.module(module)?.function_def(function)? else {
468            return Err(Error::FunctionNotFound(
469                pkg,
470                module.to_string(),
471                function.to_string(),
472            ));
473        };
474
475        // (1). Fetch all the information from this store that is necessary to resolve
476        // types referenced by this tag.
477        for sig in def.parameters.iter().chain(def.return_.iter()) {
478            context
479                .add_signature(
480                    sig.body.clone(),
481                    &self.package_store,
482                    package.as_ref(),
483                    // visit_fields
484                    false,
485                )
486                .await?;
487        }
488
489        // (2). Use that information to relocate package IDs in the signature.
490        for sig in def.parameters.iter_mut().chain(def.return_.iter_mut()) {
491            context.relocate_signature(&mut sig.body)?;
492        }
493
494        Ok(def)
495    }
496
497    /// Attempts to infer the type layouts for pure inputs to the programmable
498    /// transaction.
499    ///
500    /// The returned vector contains an element for each input to `tx`. Elements
501    /// corresponding to pure inputs that are used as arguments to
502    /// transaction commands will contain `Some(layout)`. Elements for other
503    /// inputs (non-pure inputs, and unused pure inputs) will be `None`.
504    ///
505    /// Layout resolution can fail if a type/module/package doesn't exist, if
506    /// layout resolution hits a limit, or if a pure input is somehow used
507    /// in multiple conflicting occasions (with different types).
508    pub async fn pure_input_layouts(
509        &self,
510        tx: &ProgrammableTransaction,
511    ) -> Result<Vec<Option<MoveTypeLayout>>> {
512        let mut tags = vec![None; tx.inputs.len()];
513        let mut register_type = |arg: &Argument, tag: &TypeTag| {
514            let &Argument::Input(ix) = arg else {
515                return Ok(());
516            };
517
518            if !matches!(tx.inputs.get(ix as usize), Some(CallArg::Pure(_))) {
519                return Ok(());
520            }
521
522            let Some(type_) = tags.get_mut(ix as usize) else {
523                return Ok(());
524            };
525
526            match type_ {
527                None => *type_ = Some(tag.clone()),
528                Some(prev) => {
529                    if prev != tag {
530                        return Err(Error::InputTypeConflict(ix, prev.clone(), tag.clone()));
531                    }
532                }
533            }
534
535            Ok(())
536        };
537
538        // (1). Infer type tags for pure inputs from their uses.
539        for cmd in &tx.commands {
540            match cmd {
541                Command::MoveCall(cmd) => {
542                    let Ok(signature) = self
543                        .function_signature(
544                            cmd.package.into(),
545                            cmd.module.as_str(),
546                            cmd.function.as_str(),
547                        )
548                        .await
549                    else {
550                        continue;
551                    };
552
553                    for (open_sig, arg) in signature.parameters.iter().zip(cmd.arguments.iter()) {
554                        let sig = open_sig.instantiate(&cmd.type_arguments)?;
555                        register_type(arg, &sig.body)?;
556                    }
557                }
558                Command::TransferObjects(cmd) => register_type(&cmd.address, &TypeTag::Address)?,
559                Command::SplitCoins(cmd) => {
560                    for amount in &cmd.amounts {
561                        register_type(amount, &TypeTag::U64)?;
562                    }
563                }
564                Command::MakeMoveVector(MakeMoveVector {
565                    type_: Some(tag),
566                    elements,
567                }) if is_primitive_type_tag(tag) => {
568                    for elem in elements {
569                        register_type(elem, tag)?;
570                    }
571                }
572                _ => { /* nop */ }
573            }
574        }
575
576        // (2). Gather all the unique type tags to convert into layouts. There are
577        // relatively few primitive types so this is worth doing to avoid
578        // redundant work.
579        let unique_tags: BTreeSet<_> = tags.iter().filter_map(|t| t.clone()).collect();
580
581        // (3). Convert the type tags into layouts.
582        let mut layouts = BTreeMap::new();
583        for tag in unique_tags {
584            let layout = self.type_layout(tag.clone()).await?;
585            layouts.insert(tag, layout);
586        }
587
588        // (4) Prepare the result vector.
589        Ok(tags
590            .iter()
591            .map(|t| t.as_ref().and_then(|t| layouts.get(t).cloned()))
592            .collect())
593    }
594
595    /// Resolves a runtime address in a `ModuleId` to a storage `ModuleId`
596    /// according to the linkage table in the `context` which must refer to
597    /// a package.
598    /// * Will fail if the wrong context is provided, i.e., is not a package, or
599    ///   does not exist.
600    /// * Will fail if an invalid `context` is provided for the `location`,
601    ///   i.e., the package at `context` does not contain the module that
602    ///   `location` refers to.
603    pub async fn resolve_module_id(
604        &self,
605        module_id: ModuleId,
606        context: Address,
607    ) -> Result<ModuleId> {
608        let package = self.package_store.fetch(context).await?;
609        let storage_id = package.relocate(Address::new(module_id.address().into_bytes()))?;
610        Ok(ModuleId::new(
611            AccountAddress::new(storage_id.into_bytes()),
612            module_id.name().to_owned(),
613        ))
614    }
615
616    /// Resolves an abort code following the clever error format to a
617    /// `CleverError` enum. The `module_id` must be the storage ID of the
618    /// module (which can e.g., be gotten from the `resolve_module_id`
619    /// function) and not the runtime ID.
620    ///
621    /// If the `abort_code` is not a clever error (i.e., does not follow the
622    /// tagging and layout as defined in `ErrorBitset`), this function will
623    /// return `None`.
624    ///
625    /// In the case where it is a clever error but only a line number is present
626    /// (i.e., the error is the result of an `assert!(<cond>)` source
627    /// expression) a `CleverError::LineNumberOnly` is returned. Otherwise a
628    /// `CleverError::CompleteError` is returned.
629    ///
630    /// If for any reason we are unable to resolve the abort code to a
631    /// `CleverError`, this function will return `None`.
632    pub async fn resolve_clever_error(
633        &self,
634        module_id: ModuleId,
635        abort_code: u64,
636    ) -> Option<CleverError> {
637        let bitset = ErrorBitset::from_u64(abort_code)?;
638        let package = self
639            .package_store
640            .fetch(Address::new(module_id.address().into_bytes()))
641            .await
642            .ok()?;
643        let module = package.module(module_id.name().as_str()).ok()?.bytecode();
644        let source_line_number = bitset.line_number()?;
645
646        // We only have a line number in our clever error, so return early.
647        if bitset.identifier_index().is_none() && bitset.constant_index().is_none() {
648            return Some(CleverError {
649                module_id,
650                error_info: ErrorConstants::None,
651                source_line_number,
652            });
653        } else if bitset.identifier_index().is_none() || bitset.constant_index().is_none() {
654            return None;
655        }
656
657        let error_identifier_constant = module
658            .constant_pool()
659            .get(bitset.identifier_index()? as usize)?;
660        let error_value_constant = module
661            .constant_pool()
662            .get(bitset.constant_index()? as usize)?;
663
664        if !matches!(&error_identifier_constant.type_, SignatureToken::Vector(x) if x.as_ref() == &SignatureToken::U8)
665        {
666            return None;
667        };
668
669        let error_identifier = bcs::from_bytes::<Vec<u8>>(&error_identifier_constant.data)
670            .ok()
671            .and_then(|x| String::from_utf8(x).ok())?;
672        let bytes = error_value_constant.data.clone();
673
674        let rendered = try_render_constant(error_value_constant);
675
676        let error_info = match rendered {
677            RenderResult::NotRendered => ErrorConstants::Raw {
678                identifier: error_identifier,
679                bytes,
680            },
681            RenderResult::AsString(s) | RenderResult::AsValue(s) => ErrorConstants::Rendered {
682                identifier: error_identifier,
683                constant: s,
684            },
685        };
686
687        Some(CleverError {
688            module_id,
689            error_info,
690            source_line_number,
691        })
692    }
693}
694
695impl<T> PackageStoreWithLruCache<T> {
696    pub fn new(inner: T) -> Self {
697        let packages = Mutex::new(LruCache::new(PACKAGE_CACHE_SIZE));
698        Self { packages, inner }
699    }
700
701    /// Removes all packages with ids in `ids` from the cache, if they exist.
702    /// Does nothing for ids that are not in the cache. Accepts `self`
703    /// immutably as it operates under the lock.
704    pub fn evict(&self, ids: impl IntoIterator<Item = Address>) {
705        let mut packages = self.packages.lock().unwrap();
706        for id in ids {
707            packages.pop(&id);
708        }
709    }
710}
711
712#[async_trait]
713impl<T: PackageStore> PackageStore for PackageStoreWithLruCache<T> {
714    async fn fetch(&self, id: Address) -> Result<Arc<Package>> {
715        if let Some(package) = {
716            // Release the lock after getting the package
717            let mut packages = self.packages.lock().unwrap();
718            packages.get(&id).cloned()
719        } {
720            return Ok(package);
721        };
722
723        let package = self.inner.fetch(id).await?;
724
725        // Try and insert the package into the cache, accounting for races.  In most
726        // cases the racing fetches will produce the same package, but for
727        // system packages, they may not, so favour the package that has the
728        // newer version, or if they are the same, the package that is already
729        // in the cache.
730
731        let mut packages = self.packages.lock().unwrap();
732        Ok(match packages.peek(&id) {
733            Some(prev) if package.version <= prev.version => {
734                let package = prev.clone();
735                packages.promote(&id);
736                package
737            }
738
739            Some(_) | None => {
740                packages.push(id, package.clone());
741                package
742            }
743        })
744    }
745}
746
747impl Package {
748    pub fn read_from_object(object: &Object) -> Result<Self> {
749        let Some(package) = object.data.as_opt_package() else {
750            return Err(Error::NotAPackage(object.id().into()));
751        };
752
753        Self::read_from_package(package)
754    }
755
756    pub fn read_from_package(package: &MovePackage) -> Result<Self> {
757        let mut type_origins: BTreeMap<String, BTreeMap<String, Address>> = BTreeMap::new();
758        for TypeOrigin {
759            module_name,
760            datatype_name,
761            package,
762        } in package.type_origin_table()
763        {
764            type_origins
765                .entry(module_name.to_string())
766                .or_default()
767                .insert(datatype_name.to_string(), (*package).into());
768        }
769
770        let mut runtime_id = None;
771        let mut modules = BTreeMap::new();
772        for (name, bytes) in package.serialized_module_map() {
773            let origins = type_origins.remove(&name.to_string()).unwrap_or_default();
774            let bytecode = CompiledModule::deserialize_with_defaults(bytes)
775                .map_err(|e| Error::Deserialize(e.finish(Location::Undefined)))?;
776
777            runtime_id = Some(Address::new(bytecode.address().into_bytes()));
778
779            let name = name.clone();
780            match Module::read(bytecode, origins) {
781                Ok(module) => modules.insert(name.to_string(), module),
782                Err(struct_) => {
783                    return Err(Error::NoTypeOrigin(
784                        package.id().into(),
785                        name.to_string(),
786                        struct_,
787                    ));
788                }
789            };
790        }
791
792        let Some(runtime_id) = runtime_id else {
793            return Err(Error::EmptyPackage(package.id().into()));
794        };
795
796        let linkage = package
797            .linkage_table()
798            .iter()
799            .map(|(&dep, linkage)| (dep.into(), linkage.upgraded_id.into()))
800            .collect();
801
802        Ok(Package {
803            storage_id: package.id().into(),
804            runtime_id,
805            version: package.version(),
806            modules,
807            linkage,
808        })
809    }
810
811    pub fn module(&self, module: &str) -> Result<&Module> {
812        self.modules
813            .get(module)
814            .ok_or_else(|| Error::ModuleNotFound(self.storage_id, module.to_string()))
815    }
816
817    pub fn modules(&self) -> &BTreeMap<String, Module> {
818        &self.modules
819    }
820
821    fn data_def(&self, module_name: &str, datatype_name: &str) -> Result<DataDef> {
822        let module = self.module(module_name)?;
823        let Some(data_def) = module.data_def(datatype_name)? else {
824            return Err(Error::DatatypeNotFound(
825                self.storage_id,
826                module_name.to_string(),
827                datatype_name.to_string(),
828            ));
829        };
830        Ok(data_def)
831    }
832
833    /// Translate the `runtime_id` of a package to a specific storage ID using
834    /// this package's linkage table.  Returns an error if the package in
835    /// question is not present in the linkage table.
836    fn relocate(&self, runtime_id: Address) -> Result<Address> {
837        // Special case the current package, because it doesn't get an entry in the
838        // linkage table.
839        if runtime_id == self.runtime_id {
840            return Ok(self.storage_id);
841        }
842
843        self.linkage
844            .get(&runtime_id)
845            .ok_or_else(|| Error::LinkageNotFound(runtime_id))
846            .copied()
847    }
848}
849
850impl Module {
851    /// Deserialize a module from its bytecode, and a table containing the
852    /// origins of its structs. Fails if the origin table is missing an
853    /// entry for one of its types, returning the name of the type in that
854    /// case.
855    fn read(
856        bytecode: CompiledModule,
857        mut origins: BTreeMap<String, Address>,
858    ) -> std::result::Result<Self, String> {
859        let mut struct_index = BTreeMap::new();
860        for (index, def) in bytecode.struct_defs.iter().enumerate() {
861            let sh = bytecode.datatype_handle_at(def.struct_handle);
862            let struct_ = bytecode.identifier_at(sh.name).to_string();
863            let index = StructDefinitionIndex::new(index as TableIndex);
864
865            let Some(defining_id) = origins.remove(&struct_) else {
866                return Err(struct_);
867            };
868
869            struct_index.insert(struct_, (defining_id, index));
870        }
871
872        let mut enum_index = BTreeMap::new();
873        for (index, def) in bytecode.enum_defs.iter().enumerate() {
874            let eh = bytecode.datatype_handle_at(def.enum_handle);
875            let enum_ = bytecode.identifier_at(eh.name).to_string();
876            let index = EnumDefinitionIndex::new(index as TableIndex);
877
878            let Some(defining_id) = origins.remove(&enum_) else {
879                return Err(enum_);
880            };
881
882            enum_index.insert(enum_, (defining_id, index));
883        }
884
885        let mut function_index = BTreeMap::new();
886        for (index, def) in bytecode.function_defs.iter().enumerate() {
887            let fh = bytecode.function_handle_at(def.function);
888            let function = bytecode.identifier_at(fh.name).to_string();
889            let index = FunctionDefinitionIndex::new(index as TableIndex);
890
891            function_index.insert(function, index);
892        }
893
894        Ok(Module {
895            bytecode,
896            struct_index,
897            enum_index,
898            function_index,
899        })
900    }
901
902    pub fn bytecode(&self) -> &CompiledModule {
903        &self.bytecode
904    }
905
906    /// The module's name
907    pub fn name(&self) -> &str {
908        self.bytecode
909            .identifier_at(self.bytecode.self_handle().name)
910            .as_str()
911    }
912
913    /// Iterate over the structs with names strictly after `after` (or from the
914    /// beginning), and strictly before `before` (or to the end).
915    pub fn structs(
916        &self,
917        after: Option<&str>,
918        before: Option<&str>,
919    ) -> impl DoubleEndedIterator<Item = &str> + Clone {
920        use std::ops::Bound as B;
921        self.struct_index
922            .range::<str, _>((
923                after.map_or(B::Unbounded, B::Excluded),
924                before.map_or(B::Unbounded, B::Excluded),
925            ))
926            .map(|(name, _)| name.as_str())
927    }
928
929    /// Iterate over the enums with names strictly after `after` (or from the
930    /// beginning), and strictly before `before` (or to the end).
931    pub fn enums(
932        &self,
933        after: Option<&str>,
934        before: Option<&str>,
935    ) -> impl DoubleEndedIterator<Item = &str> + Clone {
936        use std::ops::Bound as B;
937        self.enum_index
938            .range::<str, _>((
939                after.map_or(B::Unbounded, B::Excluded),
940                before.map_or(B::Unbounded, B::Excluded),
941            ))
942            .map(|(name, _)| name.as_str())
943    }
944
945    /// Iterate over the datatypes with names strictly after `after` (or from
946    /// the beginning), and strictly before `before` (or to the end). Enums
947    /// and structs will be interleaved, and will be sorted by their names.
948    pub fn datatypes(
949        &self,
950        after: Option<&str>,
951        before: Option<&str>,
952    ) -> impl DoubleEndedIterator<Item = &str> + Clone {
953        let mut names = self
954            .structs(after, before)
955            .chain(self.enums(after, before))
956            .collect::<Vec<_>>();
957        names.sort();
958        names.into_iter()
959    }
960
961    /// Get the struct definition corresponding to the struct with name `name`
962    /// in this module. Returns `Ok(None)` if the struct cannot be found in
963    /// this module, `Err(...)` if there was an error deserializing it, and
964    /// `Ok(Some(def))` on success.
965    pub fn struct_def(&self, name: &str) -> Result<Option<DataDef>> {
966        let Some(&(defining_id, index)) = self.struct_index.get(name) else {
967            return Ok(None);
968        };
969
970        let struct_def = self.bytecode.struct_def_at(index);
971        let struct_handle = self.bytecode.datatype_handle_at(struct_def.struct_handle);
972        let abilities = struct_handle.abilities;
973        let type_params = struct_handle.type_parameters.clone();
974
975        let fields = match &struct_def.field_information {
976            StructFieldInformation::Native => vec![],
977            StructFieldInformation::Declared(fields) => fields
978                .iter()
979                .map(|f| {
980                    Ok((
981                        self.bytecode.identifier_at(f.name).to_string(),
982                        OpenSignatureBody::read(&f.signature.0, &self.bytecode)?,
983                    ))
984                })
985                .collect::<Result<_>>()?,
986        };
987
988        Ok(Some(DataDef {
989            defining_id,
990            abilities,
991            type_params,
992            data: MoveData::Struct(fields),
993        }))
994    }
995
996    /// Get the enum definition corresponding to the enum with name `name` in
997    /// this module. Returns `Ok(None)` if the enum cannot be found in this
998    /// module, `Err(...)` if there was an error deserializing it, and
999    /// `Ok(Some(def))` on success.
1000    pub fn enum_def(&self, name: &str) -> Result<Option<DataDef>> {
1001        let Some(&(defining_id, index)) = self.enum_index.get(name) else {
1002            return Ok(None);
1003        };
1004
1005        let enum_def = self.bytecode.enum_def_at(index);
1006        let enum_handle = self.bytecode.datatype_handle_at(enum_def.enum_handle);
1007        let abilities = enum_handle.abilities;
1008        let type_params = enum_handle.type_parameters.clone();
1009
1010        let variants = enum_def
1011            .variants
1012            .iter()
1013            .map(|variant| {
1014                let name = self
1015                    .bytecode
1016                    .identifier_at(variant.variant_name)
1017                    .to_string();
1018                let signatures = variant
1019                    .fields
1020                    .iter()
1021                    .map(|f| {
1022                        Ok((
1023                            self.bytecode.identifier_at(f.name).to_string(),
1024                            OpenSignatureBody::read(&f.signature.0, &self.bytecode)?,
1025                        ))
1026                    })
1027                    .collect::<Result<_>>()?;
1028
1029                Ok(VariantDef { name, signatures })
1030            })
1031            .collect::<Result<_>>()?;
1032
1033        Ok(Some(DataDef {
1034            defining_id,
1035            abilities,
1036            type_params,
1037            data: MoveData::Enum(variants),
1038        }))
1039    }
1040
1041    /// Get the data definition corresponding to the data type with name `name`
1042    /// in this module. Returns `Ok(None)` if the datatype cannot be found
1043    /// in this module, `Err(...)` if there was an error deserializing it,
1044    /// and `Ok(Some(def))` on success.
1045    pub fn data_def(&self, name: &str) -> Result<Option<DataDef>> {
1046        self.struct_def(name)
1047            .transpose()
1048            .or_else(|| self.enum_def(name).transpose())
1049            .transpose()
1050    }
1051
1052    /// Iterate over the functions with names strictly after `after` (or from
1053    /// the beginning), and strictly before `before` (or to the end).
1054    pub fn functions(
1055        &self,
1056        after: Option<&str>,
1057        before: Option<&str>,
1058    ) -> impl DoubleEndedIterator<Item = &str> + Clone {
1059        use std::ops::Bound as B;
1060        self.function_index
1061            .range::<str, _>((
1062                after.map_or(B::Unbounded, B::Excluded),
1063                before.map_or(B::Unbounded, B::Excluded),
1064            ))
1065            .map(|(name, _)| name.as_str())
1066    }
1067
1068    /// Get the function definition corresponding to the function with name
1069    /// `name` in this module. Returns `Ok(None)` if the function cannot be
1070    /// found in this module, `Err(...)` if there was an error deserializing
1071    /// it, and `Ok(Some(def))` on success.
1072    pub fn function_def(&self, name: &str) -> Result<Option<FunctionDef>> {
1073        let Some(&index) = self.function_index.get(name) else {
1074            return Ok(None);
1075        };
1076
1077        let function_def = self.bytecode.function_def_at(index);
1078        let function_handle = self.bytecode.function_handle_at(function_def.function);
1079
1080        Ok(Some(FunctionDef {
1081            visibility: function_def.visibility,
1082            is_entry: function_def.is_entry,
1083            type_params: function_handle.type_parameters.clone(),
1084            parameters: read_signature(function_handle.parameters, &self.bytecode)?,
1085            return_: read_signature(function_handle.return_, &self.bytecode)?,
1086        }))
1087    }
1088}
1089
1090impl OpenSignature {
1091    fn read(sig: &SignatureToken, bytecode: &CompiledModule) -> Result<Self> {
1092        use SignatureToken as S;
1093        Ok(match sig {
1094            S::Reference(sig) => OpenSignature {
1095                ref_: Some(Reference::Immutable),
1096                body: OpenSignatureBody::read(sig, bytecode)?,
1097            },
1098
1099            S::MutableReference(sig) => OpenSignature {
1100                ref_: Some(Reference::Mutable),
1101                body: OpenSignatureBody::read(sig, bytecode)?,
1102            },
1103
1104            sig => OpenSignature {
1105                ref_: None,
1106                body: OpenSignatureBody::read(sig, bytecode)?,
1107            },
1108        })
1109    }
1110
1111    /// Return a specific instantiation of this signature, with `type_params` as
1112    /// the actual type parameters. This function does not check that the
1113    /// supplied type parameters are valid (meet the ability constraints of
1114    /// the struct or function this signature is part of), but will
1115    /// produce an error if the signature references a type parameter that is
1116    /// out of bounds.
1117    pub fn instantiate(&self, type_params: &[TypeTag]) -> Result<Signature> {
1118        Ok(Signature {
1119            ref_: self.ref_,
1120            body: self.body.instantiate(type_params)?,
1121        })
1122    }
1123}
1124
1125impl OpenSignatureBody {
1126    fn read(sig: &SignatureToken, bytecode: &CompiledModule) -> Result<Self> {
1127        use OpenSignatureBody as O;
1128        use SignatureToken as S;
1129
1130        Ok(match sig {
1131            S::Signer => return Err(Error::UnexpectedSigner),
1132            S::Reference(_) | S::MutableReference(_) => return Err(Error::UnexpectedReference),
1133
1134            S::Address => O::Address,
1135            S::Bool => O::Bool,
1136            S::U8 => O::U8,
1137            S::U16 => O::U16,
1138            S::U32 => O::U32,
1139            S::U64 => O::U64,
1140            S::U128 => O::U128,
1141            S::U256 => O::U256,
1142            S::TypeParameter(ix) => O::TypeParameter(*ix),
1143
1144            S::Vector(sig) => O::Vector(Box::new(OpenSignatureBody::read(sig, bytecode)?)),
1145
1146            S::Datatype(ix) => O::Datatype(DatatypeKey::read(*ix, bytecode), vec![]),
1147            S::DatatypeInstantiation(inst) => {
1148                let (ix, params) = &**inst;
1149                O::Datatype(
1150                    DatatypeKey::read(*ix, bytecode),
1151                    params
1152                        .iter()
1153                        .map(|sig| OpenSignatureBody::read(sig, bytecode))
1154                        .collect::<Result<_>>()?,
1155                )
1156            }
1157        })
1158    }
1159
1160    fn instantiate(&self, type_params: &[TypeTag]) -> Result<TypeTag> {
1161        use OpenSignatureBody as O;
1162        use TypeTag as T;
1163
1164        Ok(match self {
1165            O::Address => T::Address,
1166            O::Bool => T::Bool,
1167            O::U8 => T::U8,
1168            O::U16 => T::U16,
1169            O::U32 => T::U32,
1170            O::U64 => T::U64,
1171            O::U128 => T::U128,
1172            O::U256 => T::U256,
1173            O::Vector(s) => T::Vector(Box::new(s.instantiate(type_params)?)),
1174
1175            O::Datatype(key, dty_params) => T::Struct(Box::new(StructTag::new(
1176                key.package,
1177                ident(&key.module)?,
1178                ident(&key.name)?,
1179                dty_params
1180                    .iter()
1181                    .map(|p| p.instantiate(type_params))
1182                    .collect::<Result<_>>()?,
1183            ))),
1184
1185            O::TypeParameter(ix) => type_params
1186                .get(*ix as usize)
1187                .ok_or_else(|| Error::TypeParamOOB(*ix, type_params.len()))?
1188                .clone(),
1189        })
1190    }
1191}
1192
1193impl DatatypeRef<'_, '_> {
1194    pub fn as_key(&self) -> DatatypeKey {
1195        DatatypeKey {
1196            package: self.package,
1197            module: self.module.to_string().into(),
1198            name: self.name.to_string().into(),
1199        }
1200    }
1201}
1202
1203impl DatatypeKey {
1204    fn read(ix: DatatypeHandleIndex, bytecode: &CompiledModule) -> Self {
1205        let sh = bytecode.datatype_handle_at(ix);
1206        let mh = bytecode.module_handle_at(sh.module);
1207
1208        let package = Address::new(bytecode.address_identifier_at(mh.address).into_bytes());
1209        let module = bytecode.identifier_at(mh.name).to_string().into();
1210        let name = bytecode.identifier_at(sh.name).to_string().into();
1211
1212        DatatypeKey {
1213            package,
1214            module,
1215            name,
1216        }
1217    }
1218}
1219
1220impl<'l> ResolutionContext<'l> {
1221    fn new(limits: Option<&'l Limits>) -> Self {
1222        ResolutionContext {
1223            datatypes: BTreeMap::new(),
1224            limits,
1225        }
1226    }
1227
1228    /// Gather definitions for types that contribute to the definition of `tag`
1229    /// into this resolution context, fetching data from the `store` as
1230    /// necessary. Also updates package addresses in `tag` to point to
1231    /// runtime IDs instead of storage IDs to ensure queries made using these
1232    /// addresses during the subsequent resolution phase find the relevant type
1233    /// information in the context.
1234    ///
1235    /// The `visit_fields` flag controls whether the traversal looks inside
1236    /// types at their fields (which is necessary for layout resolution) or
1237    /// not (only explores the outer type and any type parameters).
1238    ///
1239    /// The `visit_phantoms` flag controls whether the traversal recurses
1240    /// through phantom type parameters (which is also necessary for type
1241    /// resolution) or not.
1242    async fn add_type_tag<S: PackageStore + ?Sized>(
1243        &mut self,
1244        tag: &mut TypeTag,
1245        store: &S,
1246        visit_fields: bool,
1247        visit_phantoms: bool,
1248    ) -> Result<()> {
1249        use TypeTag as T;
1250
1251        struct ToVisit<'t> {
1252            tag: &'t mut TypeTag,
1253            depth: usize,
1254        }
1255
1256        let mut frontier = vec![ToVisit { tag, depth: 0 }];
1257        while let Some(ToVisit { tag, depth }) = frontier.pop() {
1258            macro_rules! push_ty_param {
1259                ($tag:expr) => {{
1260                    check_max_limit!(
1261                        TypeParamNesting, self.limits;
1262                        max_type_argument_depth > depth
1263                    );
1264
1265                    frontier.push(ToVisit { tag: $tag, depth: depth + 1 })
1266                }}
1267            }
1268
1269            match tag {
1270                T::Address
1271                | T::Bool
1272                | T::U8
1273                | T::U16
1274                | T::U32
1275                | T::U64
1276                | T::U128
1277                | T::U256
1278                | T::Signer => {
1279                    // Nothing further to add to context
1280                }
1281
1282                T::Vector(tag) => push_ty_param!(tag),
1283
1284                T::Struct(s) => {
1285                    let context = store.fetch(s.address()).await?;
1286                    let def = context
1287                        .clone()
1288                        .data_def(s.module().as_str(), s.name().as_str())?;
1289
1290                    // Normalize `address` (the ID of a package that contains the definition of this
1291                    // struct) to be a runtime ID, because that's what the resolution context uses
1292                    // for keys.  Take care to do this before generating the key that is used to
1293                    // query and/or write into `self.structs.
1294                    *s.as_mut() = StructTag::new(
1295                        context.runtime_id,
1296                        s.module().clone(),
1297                        s.name().clone(),
1298                        s.type_params().to_vec(),
1299                    );
1300                    let key = DatatypeRef::from(s.as_ref()).as_key();
1301
1302                    if def.type_params.len() != s.type_params().len() {
1303                        return Err(Error::TypeArityMismatch(
1304                            def.type_params.len(),
1305                            s.type_params().len(),
1306                        ));
1307                    }
1308
1309                    check_max_limit!(
1310                        TooManyTypeParams, self.limits;
1311                        max_type_argument_width >= s.type_params().len()
1312                    );
1313
1314                    for (param, def) in s.type_params_mut().iter_mut().zip(def.type_params.iter()) {
1315                        if !def.is_phantom || visit_phantoms {
1316                            push_ty_param!(param);
1317                        }
1318                    }
1319
1320                    if self.datatypes.contains_key(&key) {
1321                        continue;
1322                    }
1323
1324                    if visit_fields {
1325                        match &def.data {
1326                            MoveData::Struct(fields) => {
1327                                for (_, sig) in fields {
1328                                    self.add_signature(sig.clone(), store, &context, visit_fields)
1329                                        .await?;
1330                                }
1331                            }
1332                            MoveData::Enum(variants) => {
1333                                for variant in variants {
1334                                    for (_, sig) in &variant.signatures {
1335                                        self.add_signature(
1336                                            sig.clone(),
1337                                            store,
1338                                            &context,
1339                                            visit_fields,
1340                                        )
1341                                        .await?;
1342                                    }
1343                                }
1344                            }
1345                        };
1346                    }
1347
1348                    check_max_limit!(
1349                        TooManyTypeNodes, self.limits;
1350                        max_type_nodes > self.datatypes.len()
1351                    );
1352
1353                    self.datatypes.insert(key, def);
1354                }
1355            }
1356        }
1357
1358        Ok(())
1359    }
1360
1361    // Like `add_type_tag` but for type signatures.  Needs a linkage table to
1362    // translate runtime IDs into storage IDs.
1363    async fn add_signature<T: PackageStore + ?Sized>(
1364        &mut self,
1365        sig: OpenSignatureBody,
1366        store: &T,
1367        context: &Package,
1368        visit_fields: bool,
1369    ) -> Result<()> {
1370        use OpenSignatureBody as O;
1371
1372        let mut frontier = vec![sig];
1373        while let Some(sig) = frontier.pop() {
1374            match sig {
1375                O::Address
1376                | O::Bool
1377                | O::U8
1378                | O::U16
1379                | O::U32
1380                | O::U64
1381                | O::U128
1382                | O::U256
1383                | O::TypeParameter(_) => {
1384                    // Nothing further to add to context
1385                }
1386
1387                O::Vector(sig) => frontier.push(*sig),
1388
1389                O::Datatype(key, params) => {
1390                    check_max_limit!(
1391                        TooManyTypeParams, self.limits;
1392                        max_type_argument_width >= params.len()
1393                    );
1394
1395                    let params_count = params.len();
1396                    let data_count = self.datatypes.len();
1397                    frontier.extend(params);
1398
1399                    let type_params = if let Some(def) = self.datatypes.get(&key) {
1400                        &def.type_params
1401                    } else {
1402                        check_max_limit!(
1403                            TooManyTypeNodes, self.limits;
1404                            max_type_nodes > data_count
1405                        );
1406
1407                        // Need to resolve the datatype, so fetch the package that contains it.
1408                        let storage_id = context.relocate(key.package)?;
1409                        let package = store.fetch(storage_id).await?;
1410
1411                        let def = package.data_def(&key.module, &key.name)?;
1412                        if visit_fields {
1413                            match &def.data {
1414                                MoveData::Struct(fields) => {
1415                                    frontier.extend(fields.iter().map(|f| &f.1).cloned());
1416                                }
1417                                MoveData::Enum(variants) => {
1418                                    frontier.extend(
1419                                        variants
1420                                            .iter()
1421                                            .flat_map(|v| v.signatures.iter().map(|(_, s)| s))
1422                                            .cloned(),
1423                                    );
1424                                }
1425                            };
1426                        }
1427
1428                        &self.datatypes.entry(key).or_insert(def).type_params
1429                    };
1430
1431                    if type_params.len() != params_count {
1432                        return Err(Error::TypeArityMismatch(type_params.len(), params_count));
1433                    }
1434                }
1435            }
1436        }
1437
1438        Ok(())
1439    }
1440
1441    /// Translate runtime IDs in a type `tag` into defining IDs using only the
1442    /// informationAdd commentMore actions contained in this context.
1443    /// Requires that the necessary information was added to the context
1444    /// through calls to `add_type_tag`.
1445    fn canonicalize_type(&self, tag: &mut TypeTag) -> Result<()> {
1446        use TypeTag as T;
1447
1448        match tag {
1449            T::Signer => return Err(Error::UnexpectedSigner),
1450            T::Address | T::Bool | T::U8 | T::U16 | T::U32 | T::U64 | T::U128 | T::U256 => {
1451                // nop
1452            }
1453
1454            T::Vector(tag) => self.canonicalize_type(tag.as_mut())?,
1455
1456            T::Struct(s) => {
1457                let mut type_params = s.type_params().to_vec();
1458                for tag in &mut type_params {
1459                    self.canonicalize_type(tag)?;
1460                }
1461
1462                // SAFETY: `add_type_tag` ensures `datatyps` has an element with this key.
1463                let key = DatatypeRef::from(s.as_ref());
1464                let def = &self.datatypes[&key];
1465
1466                *s.as_mut() = StructTag::new(
1467                    def.defining_id,
1468                    s.module().clone(),
1469                    s.name().clone(),
1470                    type_params,
1471                );
1472            }
1473        }
1474
1475        Ok(())
1476    }
1477
1478    /// Translate a type `tag` into its layout using only the information
1479    /// contained in this context. Requires that the necessary information
1480    /// was added to the context through calls to `add_type_tag` and
1481    /// `add_signature` before being called.
1482    ///
1483    /// `max_depth` controls how deep the layout is allowed to grow to. The
1484    /// actual depth reached is returned alongside the layout (assuming it
1485    /// does not exceed `max_depth`).
1486    fn resolve_type_layout(
1487        &self,
1488        tag: &TypeTag,
1489        max_depth: usize,
1490    ) -> Result<(MoveTypeLayout, usize)> {
1491        use MoveTypeLayout as L;
1492        use TypeTag as T;
1493
1494        if max_depth == 0 {
1495            return Err(Error::ValueNesting(
1496                self.limits.map_or(0, |l| l.max_move_value_depth),
1497            ));
1498        }
1499
1500        Ok(match tag {
1501            T::Signer => return Err(Error::UnexpectedSigner),
1502
1503            T::Address => (L::Address, 1),
1504            T::Bool => (L::Bool, 1),
1505            T::U8 => (L::U8, 1),
1506            T::U16 => (L::U16, 1),
1507            T::U32 => (L::U32, 1),
1508            T::U64 => (L::U64, 1),
1509            T::U128 => (L::U128, 1),
1510            T::U256 => (L::U256, 1),
1511
1512            T::Vector(tag) => {
1513                let (layout, depth) = self.resolve_type_layout(tag, max_depth - 1)?;
1514                (L::Vector(Box::new(layout)), depth + 1)
1515            }
1516
1517            T::Struct(s) => {
1518                // TODO (optimization): Could introduce a layout cache to further speed up
1519                // resolution.  Relevant entries in that cache would need to be gathered in the
1520                // ResolutionContext as it is built, and then used here to avoid the recursive
1521                // exploration.  This optimisation is complicated by the fact that in the cache,
1522                // these layouts are naturally keyed based on defining ID, but during
1523                // resolution, they are keyed by runtime IDs.
1524
1525                // TODO (optimization): This could be made more efficient by only generating
1526                // layouts for non-phantom types.  This efficiency could be
1527                // extended to the exploration phase (i.e. only explore layouts
1528                // of non-phantom types). But this optimisation is complicated
1529                // by the fact that we still need to create a correct type tag for a
1530                // phantom parameter, which is currently done by converting a type layout into a
1531                // tag.
1532                let param_layouts = s
1533                    .type_params()
1534                    .iter()
1535                    // Reduce the max depth because we know these type parameters will be nested
1536                    // within this struct.
1537                    .map(|tag| self.resolve_type_layout(tag, max_depth - 1))
1538                    .collect::<Result<Vec<_>>>()?;
1539
1540                // SAFETY: `param_layouts` contains `MoveTypeLayout`-s that are generated by
1541                // this `ResolutionContext`, which guarantees that struct
1542                // layouts come with types, which is necessary to avoid errors
1543                // when converting layouts into type tags.
1544                let type_params = param_layouts
1545                    .iter()
1546                    .map(|l| move_core_types::language_storage::TypeTag::from(&l.0))
1547                    .map(|tt| type_tag_core_to_sdk(&tt))
1548                    .collect();
1549
1550                // SAFETY: `add_type_tag` ensures `datatyps` has an element with this key.
1551                let key = DatatypeRef::from(s.as_ref());
1552                let def = &self.datatypes[&key];
1553
1554                let type_ = StructTag::new(
1555                    def.defining_id,
1556                    s.module().clone(),
1557                    s.name().clone(),
1558                    type_params,
1559                );
1560
1561                self.resolve_datatype_signature(def, type_, param_layouts, max_depth)?
1562            }
1563        })
1564    }
1565
1566    /// Translates a datatype definition into a type layout.  Needs to be
1567    /// provided the layouts of type parameters which are substituted when a
1568    /// type parameter is encountered.
1569    ///
1570    /// `max_depth` controls how deep the layout is allowed to grow to. The
1571    /// actual depth reached is returned alongside the layout (assuming it
1572    /// does not exceed `max_depth`).
1573    fn resolve_datatype_signature(
1574        &self,
1575        data_def: &DataDef,
1576        type_: StructTag,
1577        param_layouts: Vec<(MoveTypeLayout, usize)>,
1578        max_depth: usize,
1579    ) -> Result<(MoveTypeLayout, usize)> {
1580        Ok(match &data_def.data {
1581            MoveData::Struct(fields) => {
1582                let mut resolved_fields = Vec::with_capacity(fields.len());
1583                let mut field_depth = 0;
1584
1585                for (name, sig) in fields {
1586                    let (layout, depth) =
1587                        self.resolve_signature_layout(sig, &param_layouts, max_depth - 1)?;
1588
1589                    field_depth = field_depth.max(depth);
1590                    resolved_fields.push(MoveFieldLayout {
1591                        name: move_core_types::identifier::Identifier::new(name.as_str())
1592                            .map_err(|_| Error::NotAnIdentifier(name.to_string()))?,
1593                        layout,
1594                    })
1595                }
1596
1597                (
1598                    MoveTypeLayout::Struct(Box::new(MoveStructLayout {
1599                        type_: struct_tag_sdk_to_core(&type_),
1600                        fields: resolved_fields,
1601                    })),
1602                    field_depth + 1,
1603                )
1604            }
1605            MoveData::Enum(variants) => {
1606                let mut field_depth = 0;
1607                let mut resolved_variants = BTreeMap::new();
1608
1609                for (tag, variant) in variants.iter().enumerate() {
1610                    let mut fields = Vec::with_capacity(variant.signatures.len());
1611                    for (name, sig) in &variant.signatures {
1612                        // Note: We decrement the depth here because we're already under the variant
1613                        let (layout, depth) =
1614                            self.resolve_signature_layout(sig, &param_layouts, max_depth - 1)?;
1615
1616                        field_depth = field_depth.max(depth);
1617                        fields.push(MoveFieldLayout {
1618                            name: move_core_types::identifier::Identifier::new(name.as_str())
1619                                .map_err(|_| Error::NotAnIdentifier(name.to_string()))?,
1620                            layout,
1621                        })
1622                    }
1623                    resolved_variants.insert(
1624                        (
1625                            move_core_types::identifier::Identifier::new(variant.name.as_str())
1626                                .map_err(|_| Error::NotAnIdentifier(variant.name.to_string()))?,
1627                            tag as u16,
1628                        ),
1629                        fields,
1630                    );
1631                }
1632
1633                (
1634                    MoveTypeLayout::Enum(Box::new(MoveEnumLayout {
1635                        type_: struct_tag_sdk_to_core(&type_),
1636                        variants: resolved_variants,
1637                    })),
1638                    field_depth + 1,
1639                )
1640            }
1641        })
1642    }
1643
1644    /// Like `resolve_type_tag` but for signatures.  Needs to be provided the
1645    /// layouts of type parameters which are substituted when a type
1646    /// parameter is encountered.
1647    ///
1648    /// `max_depth` controls how deep the layout is allowed to grow to. The
1649    /// actual depth reached is returned alongside the layout (assuming it
1650    /// does not exceed `max_depth`).
1651    fn resolve_signature_layout(
1652        &self,
1653        sig: &OpenSignatureBody,
1654        param_layouts: &[(MoveTypeLayout, usize)],
1655        max_depth: usize,
1656    ) -> Result<(MoveTypeLayout, usize)> {
1657        use MoveTypeLayout as L;
1658        use OpenSignatureBody as O;
1659
1660        if max_depth == 0 {
1661            return Err(Error::ValueNesting(
1662                self.limits.map_or(0, |l| l.max_move_value_depth),
1663            ));
1664        }
1665
1666        Ok(match sig {
1667            O::Address => (L::Address, 1),
1668            O::Bool => (L::Bool, 1),
1669            O::U8 => (L::U8, 1),
1670            O::U16 => (L::U16, 1),
1671            O::U32 => (L::U32, 1),
1672            O::U64 => (L::U64, 1),
1673            O::U128 => (L::U128, 1),
1674            O::U256 => (L::U256, 1),
1675
1676            O::TypeParameter(ix) => {
1677                let (layout, depth) = param_layouts
1678                    .get(*ix as usize)
1679                    .ok_or_else(|| Error::TypeParamOOB(*ix, param_layouts.len()))
1680                    .cloned()?;
1681
1682                // We need to re-check the type parameter before we use it because it might have
1683                // been fine when it was created, but result in too deep a layout when we use it
1684                // at this position.
1685                if depth > max_depth {
1686                    return Err(Error::ValueNesting(
1687                        self.limits.map_or(0, |l| l.max_move_value_depth),
1688                    ));
1689                }
1690
1691                (layout, depth)
1692            }
1693
1694            O::Vector(sig) => {
1695                let (layout, depth) =
1696                    self.resolve_signature_layout(sig.as_ref(), param_layouts, max_depth - 1)?;
1697
1698                (L::Vector(Box::new(layout)), depth + 1)
1699            }
1700
1701            O::Datatype(key, params) => {
1702                // SAFETY: `add_signature` ensures `datatypes` has an element with this key.
1703                let def = &self.datatypes[key];
1704
1705                let param_layouts = params
1706                    .iter()
1707                    .map(|sig| self.resolve_signature_layout(sig, param_layouts, max_depth - 1))
1708                    .collect::<Result<Vec<_>>>()?;
1709
1710                // SAFETY: `param_layouts` contains `MoveTypeLayout`-s that are generated by
1711                // this `ResolutionContext`, which guarantees that struct
1712                // layouts come with types, which is necessary to avoid errors
1713                // when converting layouts into type tags.
1714                let type_params: Vec<TypeTag> = param_layouts
1715                    .iter()
1716                    .map(|l| move_core_types::language_storage::TypeTag::from(&l.0))
1717                    .map(|tt| type_tag_core_to_sdk(&tt))
1718                    .collect();
1719
1720                let type_ = StructTag::new(
1721                    def.defining_id,
1722                    ident(&key.module)?,
1723                    ident(&key.name)?,
1724                    type_params,
1725                );
1726
1727                self.resolve_datatype_signature(def, type_, param_layouts, max_depth)?
1728            }
1729        })
1730    }
1731
1732    /// Calculate the abilities for a concrete type `tag`. Requires that the
1733    /// necessary information was added to the context through calls to
1734    /// `add_type_tag` before being called.
1735    fn resolve_abilities(&self, tag: &TypeTag) -> Result<AbilitySet> {
1736        use TypeTag as T;
1737        Ok(match tag {
1738            T::Signer => return Err(Error::UnexpectedSigner),
1739
1740            T::Bool | T::U8 | T::U16 | T::U32 | T::U64 | T::U128 | T::U256 | T::Address => {
1741                AbilitySet::PRIMITIVES
1742            }
1743
1744            T::Vector(tag) => self.resolve_abilities(tag)?.intersect(AbilitySet::VECTOR),
1745
1746            T::Struct(s) => {
1747                // SAFETY: `add_type_tag` ensures `datatypes` has an element with this key.
1748                let key = DatatypeRef::from(s.as_ref());
1749                let def = &self.datatypes[&key];
1750
1751                if def.type_params.len() != s.type_params().len() {
1752                    return Err(Error::TypeArityMismatch(
1753                        def.type_params.len(),
1754                        s.type_params().len(),
1755                    ));
1756                }
1757
1758                let param_abilities: Result<Vec<AbilitySet>> = s
1759                    .type_params()
1760                    .iter()
1761                    .zip(def.type_params.iter())
1762                    .map(|(p, d)| {
1763                        if d.is_phantom {
1764                            Ok(AbilitySet::EMPTY)
1765                        } else {
1766                            self.resolve_abilities(p)
1767                        }
1768                    })
1769                    .collect();
1770
1771                AbilitySet::polymorphic_abilities(
1772                    def.abilities,
1773                    def.type_params.iter().map(|p| p.is_phantom),
1774                    param_abilities?,
1775                )
1776                // This error is unexpected because the only reason it would fail is because of a
1777                // type parameter arity mismatch, which we check for above.
1778                .map_err(|e| Error::Unexpected(Arc::new(e)))?
1779            }
1780        })
1781    }
1782
1783    /// Translate the (runtime) package IDs in `sig` to defining IDs using only
1784    /// the information contained in this context. Requires that the
1785    /// necessary information was added to the context through calls to
1786    /// `add_signature` before being called.
1787    fn relocate_signature(&self, sig: &mut OpenSignatureBody) -> Result<()> {
1788        use OpenSignatureBody as O;
1789
1790        match sig {
1791            O::Address | O::Bool | O::U8 | O::U16 | O::U32 | O::U64 | O::U128 | O::U256 => {
1792                // nop
1793            }
1794
1795            O::TypeParameter(_) => { /* nop */ }
1796
1797            O::Vector(sig) => self.relocate_signature(sig.as_mut())?,
1798
1799            O::Datatype(key, params) => {
1800                // SAFETY: `add_signature` ensures `datatypes` has an element with this key.
1801                let defining_id = &self.datatypes[key].defining_id;
1802                for param in params {
1803                    self.relocate_signature(param)?;
1804                }
1805
1806                key.package = *defining_id;
1807            }
1808        }
1809
1810        Ok(())
1811    }
1812}
1813
1814impl<'s> From<&'s StructTag> for DatatypeRef<'s, 's> {
1815    fn from(tag: &'s StructTag) -> Self {
1816        DatatypeRef {
1817            package: tag.address(),
1818            module: tag.module().as_str().into(),
1819            name: tag.name().as_str().into(),
1820        }
1821    }
1822}
1823
1824/// Translate a string into an `Identifier`, but translating errors into this
1825/// module's error type.
1826fn ident(s: &str) -> Result<Identifier> {
1827    Identifier::new(s).map_err(|_| Error::NotAnIdentifier(s.to_string()))
1828}
1829
1830/// Read and deserialize a signature index (from function parameter or return
1831/// types) into a vector of signatures.
1832fn read_signature(idx: SignatureIndex, bytecode: &CompiledModule) -> Result<Vec<OpenSignature>> {
1833    let MoveSignature(tokens) = bytecode.signature_at(idx);
1834    let mut sigs = Vec::with_capacity(tokens.len());
1835
1836    for token in tokens {
1837        sigs.push(OpenSignature::read(token, bytecode)?);
1838    }
1839
1840    Ok(sigs)
1841}
1842
1843#[cfg(test)]
1844mod tests {
1845    use std::{
1846        path::PathBuf,
1847        str::FromStr,
1848        sync::{Arc, RwLock},
1849    };
1850
1851    use async_trait::async_trait;
1852    use iota_move_build::{BuildConfig, CompiledPackage};
1853    use iota_sdk_types::{Identifier, ObjectId, StructTag, TypeTag};
1854    use iota_types::{base_types::random_object_ref, error::IotaResult};
1855    use move_binary_format::file_format::Ability;
1856    use move_compiler::compiled_unit::NamedCompiledModule;
1857
1858    use super::*;
1859
1860    fn fmt(struct_layout: MoveTypeLayout, enum_layout: MoveTypeLayout) -> String {
1861        format!("struct:\n{struct_layout:#}\n\nenum:\n{enum_layout:#}",)
1862    }
1863
1864    #[tokio::test]
1865    async fn test_simple_canonical_type() {
1866        let (_, cache) = package_cache([(1, build_package("a0").unwrap(), a0_types())]);
1867        let package_resolver = Resolver::new(cache);
1868
1869        let input = type_("0xa0::m::T0");
1870        let expect = input.clone();
1871        let actual = package_resolver.canonical_type(input).await.unwrap();
1872        assert_eq!(expect, actual);
1873    }
1874
1875    #[tokio::test]
1876    async fn test_upgraded_canonical_type() {
1877        let (_, cache) = package_cache([
1878            (1, build_package("a0").unwrap(), a0_types()),
1879            (2, build_package("a1").unwrap(), a1_types()),
1880        ]);
1881
1882        let package_resolver = Resolver::new(cache);
1883
1884        let input = type_("0xa1::m::T3");
1885        let expect = input.clone();
1886        let actual = package_resolver.canonical_type(input).await.unwrap();
1887        assert_eq!(expect, actual);
1888    }
1889
1890    #[tokio::test]
1891    async fn test_latest_canonical_type() {
1892        let (_, cache) = package_cache([
1893            (1, build_package("a0").unwrap(), a0_types()),
1894            (2, build_package("a1").unwrap(), a1_types()),
1895        ]);
1896
1897        let package_resolver = Resolver::new(cache);
1898
1899        let input = type_("0xa1::m::T0");
1900        let expect = type_("0xa0::m::T0");
1901        let actual = package_resolver.canonical_type(input).await.unwrap();
1902        assert_eq!(expect, actual);
1903    }
1904
1905    #[tokio::test]
1906    async fn test_type_param_canonical_type() {
1907        let (_, cache) = package_cache([
1908            (1, build_package("a0").unwrap(), a0_types()),
1909            (2, build_package("a1").unwrap(), a1_types()),
1910        ]);
1911
1912        let package_resolver = Resolver::new(cache);
1913
1914        let input = type_("0xa1::m::T1<0xa1::m::T0, 0xa1::m::T3>");
1915        let expect = type_("0xa0::m::T1<0xa0::m::T0, 0xa1::m::T3>");
1916        let actual = package_resolver.canonical_type(input).await.unwrap();
1917        assert_eq!(expect, actual);
1918    }
1919
1920    #[tokio::test]
1921    async fn test_canonical_err_package_too_old() {
1922        let (_, cache) = package_cache([
1923            (1, build_package("a0").unwrap(), a0_types()),
1924            (2, build_package("a1").unwrap(), a1_types()),
1925        ]);
1926
1927        let package_resolver = Resolver::new(cache);
1928
1929        let input = type_("0xa0::m::T3");
1930        let err = package_resolver.canonical_type(input).await.unwrap_err();
1931        assert!(matches!(err, Error::DatatypeNotFound(_, _, _)));
1932    }
1933
1934    #[tokio::test]
1935    async fn test_canonical_err_signer() {
1936        let (_, cache) = package_cache([(1, build_package("a0").unwrap(), a0_types())]);
1937
1938        let package_resolver = Resolver::new(cache);
1939
1940        let input = type_("0xa0::m::T1<0xa0::m::T0, signer>");
1941        let err = package_resolver.canonical_type(input).await.unwrap_err();
1942        assert!(matches!(err, Error::UnexpectedSigner));
1943    }
1944
1945    /// Layout for a type that only refers to base types or other types in the
1946    /// same module.
1947    #[tokio::test]
1948    async fn test_simple_type_layout() {
1949        let (_, cache) = package_cache([(1, build_package("a0").unwrap(), a0_types())]);
1950        let package_resolver = Resolver::new(cache);
1951        let struct_layout = package_resolver
1952            .type_layout(type_("0xa0::m::T0"))
1953            .await
1954            .unwrap();
1955        let enum_layout = package_resolver
1956            .type_layout(type_("0xa0::m::E0"))
1957            .await
1958            .unwrap();
1959        insta::assert_snapshot!(fmt(struct_layout, enum_layout));
1960    }
1961
1962    /// A type that refers to types from other modules in the same package.
1963    #[tokio::test]
1964    async fn test_cross_module_layout() {
1965        let (_, cache) = package_cache([(1, build_package("a0").unwrap(), a0_types())]);
1966        let resolver = Resolver::new(cache);
1967        let struct_layout = resolver.type_layout(type_("0xa0::n::T0")).await.unwrap();
1968        let enum_layout = resolver.type_layout(type_("0xa0::n::E0")).await.unwrap();
1969        insta::assert_snapshot!(fmt(struct_layout, enum_layout));
1970    }
1971
1972    /// A type that refers to types a different package.
1973    #[tokio::test]
1974    async fn test_cross_package_layout() {
1975        let (_, cache) = package_cache([
1976            (1, build_package("a0").unwrap(), a0_types()),
1977            (1, build_package("b0").unwrap(), b0_types()),
1978        ]);
1979        let resolver = Resolver::new(cache);
1980
1981        let struct_layout = resolver.type_layout(type_("0xb0::m::T0")).await.unwrap();
1982        let enum_layout = resolver.type_layout(type_("0xb0::m::E0")).await.unwrap();
1983        insta::assert_snapshot!(fmt(struct_layout, enum_layout));
1984    }
1985
1986    /// A type from an upgraded package, mixing structs defined in the original
1987    /// package and the upgraded package.
1988    #[tokio::test]
1989    async fn test_upgraded_package_layout() {
1990        let (_, cache) = package_cache([
1991            (1, build_package("a0").unwrap(), a0_types()),
1992            (2, build_package("a1").unwrap(), a1_types()),
1993        ]);
1994        let resolver = Resolver::new(cache);
1995
1996        let struct_layout = resolver.type_layout(type_("0xa1::n::T1")).await.unwrap();
1997        let enum_layout = resolver.type_layout(type_("0xa1::n::E1")).await.unwrap();
1998        insta::assert_snapshot!(fmt(struct_layout, enum_layout));
1999    }
2000
2001    /// A generic type instantiation where the type parameters are resolved
2002    /// relative to linkage contexts from different versions of the same
2003    /// package.
2004    #[tokio::test]
2005    async fn test_multiple_linkage_contexts_layout() {
2006        let (_, cache) = package_cache([
2007            (1, build_package("a0").unwrap(), a0_types()),
2008            (2, build_package("a1").unwrap(), a1_types()),
2009        ]);
2010        let resolver = Resolver::new(cache);
2011
2012        let struct_layout = resolver
2013            .type_layout(type_("0xa0::m::T1<0xa0::m::T0, 0xa1::m::T3>"))
2014            .await
2015            .unwrap();
2016        let enum_layout = resolver
2017            .type_layout(type_("0xa0::m::E1<0xa0::m::E0, 0xa1::m::E3>"))
2018            .await
2019            .unwrap();
2020        insta::assert_snapshot!(fmt(struct_layout, enum_layout));
2021    }
2022
2023    /// Refer to a type, not by its defining ID, but by the ID of some later
2024    /// version of that package.  This doesn't currently work during
2025    /// execution but it simplifies making queries: A type can be referred
2026    /// to using the ID of any package that declares it, rather than only the
2027    /// package that first declared it (whose ID is its defining ID).
2028    #[tokio::test]
2029    async fn test_upgraded_package_non_defining_id_layout() {
2030        let (_, cache) = package_cache([
2031            (1, build_package("a0").unwrap(), a0_types()),
2032            (2, build_package("a1").unwrap(), a1_types()),
2033        ]);
2034        let resolver = Resolver::new(cache);
2035
2036        let struct_layout = resolver
2037            .type_layout(type_("0xa1::m::T1<0xa1::m::T3, 0xa1::m::T0>"))
2038            .await
2039            .unwrap();
2040        let enum_layout = resolver
2041            .type_layout(type_("0xa1::m::E1<0xa1::m::E3, 0xa1::m::E0>"))
2042            .await
2043            .unwrap();
2044        insta::assert_snapshot!(fmt(struct_layout, enum_layout));
2045    }
2046
2047    /// A type that refers to a types in a relinked package.  C depends on B and
2048    /// overrides its dependency on A from v1 to v2.  The type in C refers
2049    /// to types that were defined in both B, A v1, and A v2.
2050    #[tokio::test]
2051    async fn test_relinking_layout() {
2052        let (_, cache) = package_cache([
2053            (1, build_package("a0").unwrap(), a0_types()),
2054            (2, build_package("a1").unwrap(), a1_types()),
2055            (1, build_package("b0").unwrap(), b0_types()),
2056            (1, build_package("c0").unwrap(), c0_types()),
2057        ]);
2058        let resolver = Resolver::new(cache);
2059
2060        let struct_layout = resolver.type_layout(type_("0xc0::m::T0")).await.unwrap();
2061        let enum_layout = resolver.type_layout(type_("0xc0::m::E0")).await.unwrap();
2062        insta::assert_snapshot!(fmt(struct_layout, enum_layout));
2063    }
2064
2065    #[tokio::test]
2066    async fn test_value_nesting_boundary_layout() {
2067        let (_, cache) = package_cache([(1, build_package("a0").unwrap(), a0_types())]);
2068
2069        let resolver = Resolver::new_with_limits(
2070            cache,
2071            Limits {
2072                max_type_argument_width: 100,
2073                max_type_argument_depth: 100,
2074                max_type_nodes: 100,
2075                max_move_value_depth: 3,
2076            },
2077        );
2078
2079        // The layout of this type is fine, because it is *just* at the correct depth.
2080        let struct_layout = resolver
2081            .type_layout(type_("0xa0::m::T1<u8, u8>"))
2082            .await
2083            .unwrap();
2084        let enum_layout = resolver
2085            .type_layout(type_("0xa0::m::E1<u8, u8>"))
2086            .await
2087            .unwrap();
2088        insta::assert_snapshot!(fmt(struct_layout, enum_layout));
2089    }
2090
2091    #[tokio::test]
2092    async fn test_err_value_nesting_simple_layout() {
2093        let (_, cache) = package_cache([(1, build_package("a0").unwrap(), a0_types())]);
2094
2095        let resolver = Resolver::new_with_limits(
2096            cache,
2097            Limits {
2098                max_type_argument_width: 100,
2099                max_type_argument_depth: 100,
2100                max_type_nodes: 100,
2101                max_move_value_depth: 2,
2102            },
2103        );
2104
2105        // The depth limit is now too low, so this will fail.
2106        let struct_err = resolver
2107            .type_layout(type_("0xa0::m::T1<u8, u8>"))
2108            .await
2109            .unwrap_err();
2110        let enum_err = resolver
2111            .type_layout(type_("0xa0::m::E1<u8, u8>"))
2112            .await
2113            .unwrap_err();
2114        assert!(matches!(struct_err, Error::ValueNesting(2)));
2115        assert!(matches!(enum_err, Error::ValueNesting(2)));
2116    }
2117
2118    #[tokio::test]
2119    async fn test_err_value_nesting_big_type_param_layout() {
2120        let (_, cache) = package_cache([(1, build_package("a0").unwrap(), a0_types())]);
2121
2122        let resolver = Resolver::new_with_limits(
2123            cache,
2124            Limits {
2125                max_type_argument_width: 100,
2126                max_type_argument_depth: 100,
2127                max_type_nodes: 100,
2128                max_move_value_depth: 3,
2129            },
2130        );
2131
2132        // This layout calculation will fail early because we know that the type
2133        // parameter we're calculating will eventually contribute to a layout
2134        // that exceeds the max depth.
2135        let struct_err = resolver
2136            .type_layout(type_("0xa0::m::T1<vector<vector<u8>>, u8>"))
2137            .await
2138            .unwrap_err();
2139        let enum_err = resolver
2140            .type_layout(type_("0xa0::m::E1<vector<vector<u8>>, u8>"))
2141            .await
2142            .unwrap_err();
2143        assert!(matches!(struct_err, Error::ValueNesting(3)));
2144        assert!(matches!(enum_err, Error::ValueNesting(3)));
2145    }
2146
2147    #[tokio::test]
2148    async fn test_err_value_nesting_big_phantom_type_param_layout() {
2149        let (_, cache) = package_cache([
2150            (1, build_package("iota").unwrap(), iota_types()),
2151            (1, build_package("d0").unwrap(), d0_types()),
2152        ]);
2153
2154        let resolver = Resolver::new_with_limits(
2155            cache,
2156            Limits {
2157                max_type_argument_width: 100,
2158                max_type_argument_depth: 100,
2159                max_type_nodes: 100,
2160                max_move_value_depth: 3,
2161            },
2162        );
2163
2164        // Check that this layout request would succeed.
2165        let _ = resolver
2166            .type_layout(type_("0xd0::m::O<u8, u8>"))
2167            .await
2168            .unwrap();
2169        let _ = resolver
2170            .type_layout(type_("0xd0::m::EO<u8, u8>"))
2171            .await
2172            .unwrap();
2173
2174        // But this one fails, even though the big layout is for a phantom type
2175        // parameter. This may change in future if we optimise the way we handle
2176        // phantom type parameters to not calculate their full layout, just
2177        // their type tag.
2178        let struct_err = resolver
2179            .type_layout(type_("0xd0::m::O<u8, vector<vector<u8>>>"))
2180            .await
2181            .unwrap_err();
2182        let enum_err = resolver
2183            .type_layout(type_("0xd0::m::EO<u8, vector<vector<u8>>>"))
2184            .await
2185            .unwrap_err();
2186        assert!(matches!(struct_err, Error::ValueNesting(3)));
2187        assert!(matches!(enum_err, Error::ValueNesting(3)));
2188    }
2189
2190    #[tokio::test]
2191    async fn test_err_value_nesting_type_param_application_layout() {
2192        let (_, cache) = package_cache([
2193            (1, build_package("iota").unwrap(), iota_types()),
2194            (1, build_package("d0").unwrap(), d0_types()),
2195        ]);
2196
2197        let resolver = Resolver::new_with_limits(
2198            cache,
2199            Limits {
2200                max_type_argument_width: 100,
2201                max_type_argument_depth: 100,
2202                max_type_nodes: 100,
2203                max_move_value_depth: 3,
2204            },
2205        );
2206
2207        // Make sure that even if all type parameters individually meet the depth
2208        // requirements, that we correctly fail if they extend the layout's
2209        // depth on application.
2210        let struct_err = resolver
2211            .type_layout(type_("0xd0::m::O<vector<u8>, u8>"))
2212            .await
2213            .unwrap_err();
2214        let enum_err = resolver
2215            .type_layout(type_("0xd0::m::EO<vector<u8>, u8>"))
2216            .await
2217            .unwrap_err();
2218
2219        assert!(matches!(struct_err, Error::ValueNesting(3)));
2220        assert!(matches!(enum_err, Error::ValueNesting(3)));
2221    }
2222
2223    #[tokio::test]
2224    async fn test_system_package_invalidation() {
2225        let (inner, cache) = package_cache([(1, build_package("s0").unwrap(), s0_types())]);
2226        let resolver = Resolver::new(cache);
2227
2228        let struct_not_found = resolver.type_layout(type_("0x1::m::T1")).await.unwrap_err();
2229        let enum_not_found = resolver.type_layout(type_("0x1::m::E1")).await.unwrap_err();
2230        assert!(matches!(struct_not_found, Error::DatatypeNotFound(_, _, _)));
2231        assert!(matches!(enum_not_found, Error::DatatypeNotFound(_, _, _)));
2232
2233        // Add a new version of the system package into the store underlying the cache.
2234        inner.write().unwrap().replace(
2235            addr("0x1"),
2236            cached_package(
2237                2,
2238                BTreeMap::new(),
2239                &build_package("s1").unwrap(),
2240                &s1_types(),
2241            ),
2242        );
2243
2244        // Evict the package from the cache
2245        resolver.package_store().evict([addr("0x1")]);
2246
2247        let struct_layout = resolver.type_layout(type_("0x1::m::T1")).await.unwrap();
2248        let enum_layout = resolver.type_layout(type_("0x1::m::E1")).await.unwrap();
2249        insta::assert_snapshot!(fmt(struct_layout, enum_layout));
2250    }
2251
2252    #[tokio::test]
2253    async fn test_caching() {
2254        let (inner, cache) = package_cache([
2255            (1, build_package("a0").unwrap(), a0_types()),
2256            (1, build_package("s0").unwrap(), s0_types()),
2257        ]);
2258        let resolver = Resolver::new(cache);
2259
2260        assert_eq!(inner.read().unwrap().fetches, 0);
2261        let l0 = resolver.type_layout(type_("0xa0::m::T0")).await.unwrap();
2262
2263        // Load A0.
2264        assert_eq!(inner.read().unwrap().fetches, 1);
2265
2266        // Layouts are the same, no need to reload the package.
2267        let l1 = resolver.type_layout(type_("0xa0::m::T0")).await.unwrap();
2268        assert_eq!(format!("{l0}"), format!("{l1}"));
2269        assert_eq!(inner.read().unwrap().fetches, 1);
2270
2271        // Different type, but same package, so no extra fetch.
2272        let l2 = resolver.type_layout(type_("0xa0::m::T2")).await.unwrap();
2273        assert_ne!(format!("{l0}"), format!("{l2}"));
2274        assert_eq!(inner.read().unwrap().fetches, 1);
2275
2276        // Enum types won't trigger a fetch either.
2277        resolver.type_layout(type_("0xa0::m::E0")).await.unwrap();
2278        assert_eq!(inner.read().unwrap().fetches, 1);
2279
2280        // New package to load.
2281        let l3 = resolver.type_layout(type_("0x1::m::T0")).await.unwrap();
2282        assert_eq!(inner.read().unwrap().fetches, 2);
2283
2284        // Reload the same system package type, it gets fetched from cache
2285        let l4 = resolver.type_layout(type_("0x1::m::T0")).await.unwrap();
2286        assert_eq!(format!("{l3}"), format!("{l4}"));
2287        assert_eq!(inner.read().unwrap().fetches, 2);
2288
2289        // Reload a same system package type (enum), which will cause a version check.
2290        let el4 = resolver.type_layout(type_("0x1::m::E0")).await.unwrap();
2291        assert_ne!(format!("{el4}"), format!("{l4}"));
2292        assert_eq!(inner.read().unwrap().fetches, 2);
2293
2294        // Upgrade the system package
2295        inner.write().unwrap().replace(
2296            addr("0x1"),
2297            cached_package(
2298                2,
2299                BTreeMap::new(),
2300                &build_package("s1").unwrap(),
2301                &s1_types(),
2302            ),
2303        );
2304
2305        // Evict the package from the cache
2306        resolver.package_store().evict([addr("0x1")]);
2307
2308        // Reload the system system type again. It will be refetched (even though the
2309        // type is the same as before). This usage pattern (layouts for system
2310        // types) is why a layout cache would be particularly helpful (future
2311        // optimisation).
2312        let l5 = resolver.type_layout(type_("0x1::m::T0")).await.unwrap();
2313        assert_eq!(format!("{l4}"), format!("{l5}"));
2314        assert_eq!(inner.read().unwrap().fetches, 3);
2315    }
2316
2317    #[tokio::test]
2318    async fn test_layout_err_not_a_package() {
2319        let (_, cache) = package_cache([(1, build_package("a0").unwrap(), a0_types())]);
2320        let resolver = Resolver::new(cache);
2321        let err = resolver
2322            .type_layout(type_("0x42::m::T0"))
2323            .await
2324            .unwrap_err();
2325        assert!(matches!(err, Error::PackageNotFound(_)));
2326    }
2327
2328    #[tokio::test]
2329    async fn test_layout_err_no_module() {
2330        let (_, cache) = package_cache([(1, build_package("a0").unwrap(), a0_types())]);
2331        let resolver = Resolver::new(cache);
2332        let err = resolver
2333            .type_layout(type_("0xa0::l::T0"))
2334            .await
2335            .unwrap_err();
2336        assert!(matches!(err, Error::ModuleNotFound(_, _)));
2337    }
2338
2339    #[tokio::test]
2340    async fn test_layout_err_no_struct() {
2341        let (_, cache) = package_cache([(1, build_package("a0").unwrap(), a0_types())]);
2342        let resolver = Resolver::new(cache);
2343
2344        let err = resolver
2345            .type_layout(type_("0xa0::m::T9"))
2346            .await
2347            .unwrap_err();
2348        assert!(matches!(err, Error::DatatypeNotFound(_, _, _)));
2349    }
2350
2351    #[tokio::test]
2352    async fn test_layout_err_type_arity() {
2353        let (_, cache) = package_cache([(1, build_package("a0").unwrap(), a0_types())]);
2354        let resolver = Resolver::new(cache);
2355
2356        // Too few
2357        let err = resolver
2358            .type_layout(type_("0xa0::m::T1<u8>"))
2359            .await
2360            .unwrap_err();
2361        assert!(matches!(err, Error::TypeArityMismatch(2, 1)));
2362
2363        // Too many
2364        let err = resolver
2365            .type_layout(type_("0xa0::m::T1<u8, u16, u32>"))
2366            .await
2367            .unwrap_err();
2368        assert!(matches!(err, Error::TypeArityMismatch(2, 3)));
2369    }
2370
2371    #[tokio::test]
2372    async fn test_structs() {
2373        let (_, cache) = package_cache([(1, build_package("a0").unwrap(), a0_types())]);
2374        let a0 = cache.fetch(addr("0xa0")).await.unwrap();
2375        let m = a0.module("m").unwrap();
2376
2377        assert_eq!(
2378            m.structs(None, None).collect::<Vec<_>>(),
2379            vec!["T0", "T1", "T2"],
2380        );
2381
2382        assert_eq!(m.structs(None, Some("T1")).collect::<Vec<_>>(), vec!["T0"],);
2383
2384        assert_eq!(
2385            m.structs(Some("T0"), Some("T2")).collect::<Vec<_>>(),
2386            vec!["T1"],
2387        );
2388
2389        assert_eq!(m.structs(Some("T1"), None).collect::<Vec<_>>(), vec!["T2"],);
2390
2391        let t0 = m.struct_def("T0").unwrap().unwrap();
2392        let t1 = m.struct_def("T1").unwrap().unwrap();
2393        let t2 = m.struct_def("T2").unwrap().unwrap();
2394
2395        insta::assert_snapshot!(format!(
2396            "a0::m::T0: {t0:#?}\n\
2397             a0::m::T1: {t1:#?}\n\
2398             a0::m::T2: {t2:#?}",
2399        ));
2400    }
2401
2402    #[tokio::test]
2403    async fn test_enums() {
2404        let (_, cache) = package_cache([(1, build_package("a0").unwrap(), a0_types())]);
2405        let a0 = cache
2406            .fetch(Address::from_str("0xa0").unwrap())
2407            .await
2408            .unwrap();
2409        let m = a0.module("m").unwrap();
2410
2411        assert_eq!(
2412            m.enums(None, None).collect::<Vec<_>>(),
2413            vec!["E0", "E1", "E2"],
2414        );
2415
2416        assert_eq!(m.enums(None, Some("E1")).collect::<Vec<_>>(), vec!["E0"],);
2417
2418        assert_eq!(
2419            m.enums(Some("E0"), Some("E2")).collect::<Vec<_>>(),
2420            vec!["E1"],
2421        );
2422
2423        assert_eq!(m.enums(Some("E1"), None).collect::<Vec<_>>(), vec!["E2"],);
2424
2425        let e0 = m.enum_def("E0").unwrap().unwrap();
2426        let e1 = m.enum_def("E1").unwrap().unwrap();
2427        let e2 = m.enum_def("E2").unwrap().unwrap();
2428
2429        insta::assert_snapshot!(format!(
2430            "a0::m::E0: {e0:#?}\n\
2431             a0::m::E1: {e1:#?}\n\
2432             a0::m::E2: {e2:#?}",
2433        ));
2434    }
2435
2436    #[tokio::test]
2437    async fn test_functions() {
2438        let (_, cache) = package_cache([
2439            (1, build_package("a0").unwrap(), a0_types()),
2440            (2, build_package("a1").unwrap(), a1_types()),
2441            (1, build_package("b0").unwrap(), b0_types()),
2442            (1, build_package("c0").unwrap(), c0_types()),
2443        ]);
2444
2445        let c0 = cache.fetch(addr("0xc0")).await.unwrap();
2446        let m = c0.module("m").unwrap();
2447
2448        assert_eq!(
2449            m.functions(None, None).collect::<Vec<_>>(),
2450            vec!["bar", "baz", "foo"],
2451        );
2452
2453        assert_eq!(
2454            m.functions(None, Some("baz")).collect::<Vec<_>>(),
2455            vec!["bar"],
2456        );
2457
2458        assert_eq!(
2459            m.functions(Some("bar"), Some("foo")).collect::<Vec<_>>(),
2460            vec!["baz"],
2461        );
2462
2463        assert_eq!(
2464            m.functions(Some("baz"), None).collect::<Vec<_>>(),
2465            vec!["foo"],
2466        );
2467
2468        let foo = m.function_def("foo").unwrap().unwrap();
2469        let bar = m.function_def("bar").unwrap().unwrap();
2470        let baz = m.function_def("baz").unwrap().unwrap();
2471
2472        insta::assert_snapshot!(format!(
2473            "c0::m::foo: {foo:#?}\n\
2474             c0::m::bar: {bar:#?}\n\
2475             c0::m::baz: {baz:#?}"
2476        ));
2477    }
2478
2479    #[tokio::test]
2480    async fn test_function_parameters() {
2481        let (_, cache) = package_cache([
2482            (1, build_package("a0").unwrap(), a0_types()),
2483            (2, build_package("a1").unwrap(), a1_types()),
2484            (1, build_package("b0").unwrap(), b0_types()),
2485            (1, build_package("c0").unwrap(), c0_types()),
2486        ]);
2487
2488        let resolver = Resolver::new(cache);
2489        let c0 = addr("0xc0");
2490
2491        let foo = resolver.function_signature(c0, "m", "foo").await.unwrap();
2492        let bar = resolver.function_signature(c0, "m", "bar").await.unwrap();
2493        let baz = resolver.function_signature(c0, "m", "baz").await.unwrap();
2494
2495        insta::assert_snapshot!(format!(
2496            "c0::m::foo: {foo:#?}\n\
2497             c0::m::bar: {bar:#?}\n\
2498             c0::m::baz: {baz:#?}"
2499        ));
2500    }
2501
2502    #[tokio::test]
2503    async fn test_signature_instantiation() {
2504        use OpenSignatureBody as O;
2505        use TypeTag as T;
2506
2507        let sig = O::Datatype(
2508            key("0x2::table::Table"),
2509            vec![
2510                O::TypeParameter(1),
2511                O::Vector(Box::new(O::Datatype(
2512                    key("0x1::option::Option"),
2513                    vec![O::TypeParameter(0)],
2514                ))),
2515            ],
2516        );
2517
2518        insta::assert_debug_snapshot!(sig.instantiate(&[T::U64, T::Bool]).unwrap());
2519    }
2520
2521    #[tokio::test]
2522    async fn test_signature_instantiation_error() {
2523        use OpenSignatureBody as O;
2524        use TypeTag as T;
2525
2526        let sig = O::Datatype(
2527            key("0x2::table::Table"),
2528            vec![
2529                O::TypeParameter(1),
2530                O::Vector(Box::new(O::Datatype(
2531                    key("0x1::option::Option"),
2532                    vec![O::TypeParameter(99)],
2533                ))),
2534            ],
2535        );
2536
2537        insta::assert_snapshot!(
2538            sig.instantiate(&[T::U64, T::Bool]).unwrap_err(),
2539            @"Type Parameter 99 out of bounds (2)"
2540        );
2541    }
2542
2543    /// Primitive types should have the expected primitive abilities
2544    #[tokio::test]
2545    async fn test_primitive_abilities() {
2546        use Ability as A;
2547        use AbilitySet as S;
2548
2549        let (_, cache) = package_cache([]);
2550        let resolver = Resolver::new(cache);
2551
2552        for prim in ["address", "bool", "u8", "u16", "u32", "u64", "u128", "u256"] {
2553            assert_eq!(
2554                resolver.abilities(type_(prim)).await.unwrap(),
2555                S::EMPTY | A::Copy | A::Drop | A::Store,
2556                "Unexpected primitive abilities for: {prim}",
2557            );
2558        }
2559    }
2560
2561    /// Generic type abilities depend on the abilities of their type parameters.
2562    #[tokio::test]
2563    async fn test_simple_generic_abilities() {
2564        use Ability as A;
2565        use AbilitySet as S;
2566
2567        let (_, cache) = package_cache([
2568            (1, build_package("iota").unwrap(), iota_types()),
2569            (1, build_package("d0").unwrap(), d0_types()),
2570        ]);
2571        let resolver = Resolver::new(cache);
2572
2573        let a1 = resolver
2574            .abilities(type_("0xd0::m::T<u32, u64>"))
2575            .await
2576            .unwrap();
2577        assert_eq!(a1, S::EMPTY | A::Copy | A::Drop | A::Store);
2578
2579        let a2 = resolver
2580            .abilities(type_("0xd0::m::T<0xd0::m::S, u64>"))
2581            .await
2582            .unwrap();
2583        assert_eq!(a2, S::EMPTY | A::Drop | A::Store);
2584
2585        let a3 = resolver
2586            .abilities(type_("0xd0::m::T<0xd0::m::R, 0xd0::m::S>"))
2587            .await
2588            .unwrap();
2589        assert_eq!(a3, S::EMPTY | A::Drop);
2590
2591        let a4 = resolver
2592            .abilities(type_("0xd0::m::T<0xd0::m::Q, 0xd0::m::R>"))
2593            .await
2594            .unwrap();
2595        assert_eq!(a4, S::EMPTY);
2596    }
2597
2598    /// Generic abilities also need to handle nested type parameters
2599    #[tokio::test]
2600    async fn test_nested_generic_abilities() {
2601        use Ability as A;
2602        use AbilitySet as S;
2603
2604        let (_, cache) = package_cache([
2605            (1, build_package("iota").unwrap(), iota_types()),
2606            (1, build_package("d0").unwrap(), d0_types()),
2607        ]);
2608        let resolver = Resolver::new(cache);
2609
2610        let a1 = resolver
2611            .abilities(type_("0xd0::m::T<0xd0::m::T<0xd0::m::R, u32>, u64>"))
2612            .await
2613            .unwrap();
2614        assert_eq!(a1, S::EMPTY | A::Copy | A::Drop);
2615    }
2616
2617    /// Key is different from other abilities in that it requires fields to have
2618    /// `store`, rather than itself.
2619    #[tokio::test]
2620    async fn test_key_abilities() {
2621        use Ability as A;
2622        use AbilitySet as S;
2623
2624        let (_, cache) = package_cache([
2625            (1, build_package("iota").unwrap(), iota_types()),
2626            (1, build_package("d0").unwrap(), d0_types()),
2627        ]);
2628        let resolver = Resolver::new(cache);
2629
2630        let a1 = resolver
2631            .abilities(type_("0xd0::m::O<u32, u64>"))
2632            .await
2633            .unwrap();
2634        assert_eq!(a1, S::EMPTY | A::Key | A::Store);
2635
2636        let a2 = resolver
2637            .abilities(type_("0xd0::m::O<0xd0::m::S, u64>"))
2638            .await
2639            .unwrap();
2640        assert_eq!(a2, S::EMPTY | A::Key | A::Store);
2641
2642        // We would not be able to get an instance of this type, but in case the
2643        // question is asked, its abilities would be empty.
2644        let a3 = resolver
2645            .abilities(type_("0xd0::m::O<0xd0::m::R, u64>"))
2646            .await
2647            .unwrap();
2648        assert_eq!(a3, S::EMPTY);
2649
2650        // Key does not propagate up by itself, so this type is also uninhabitable.
2651        let a4 = resolver
2652            .abilities(type_("0xd0::m::O<0xd0::m::P, u32>"))
2653            .await
2654            .unwrap();
2655        assert_eq!(a4, S::EMPTY);
2656    }
2657
2658    /// Phantom types don't impact abilities
2659    #[tokio::test]
2660    async fn test_phantom_abilities() {
2661        use Ability as A;
2662        use AbilitySet as S;
2663
2664        let (_, cache) = package_cache([
2665            (1, build_package("iota").unwrap(), iota_types()),
2666            (1, build_package("d0").unwrap(), d0_types()),
2667        ]);
2668        let resolver = Resolver::new(cache);
2669
2670        let a1 = resolver
2671            .abilities(type_("0xd0::m::O<u32, 0xd0::m::R>"))
2672            .await
2673            .unwrap();
2674        assert_eq!(a1, S::EMPTY | A::Key | A::Store);
2675    }
2676
2677    #[tokio::test]
2678    async fn test_err_ability_arity() {
2679        let (_, cache) = package_cache([
2680            (1, build_package("iota").unwrap(), iota_types()),
2681            (1, build_package("d0").unwrap(), d0_types()),
2682        ]);
2683        let resolver = Resolver::new(cache);
2684
2685        // Too few
2686        let err = resolver
2687            .abilities(type_("0xd0::m::T<u8>"))
2688            .await
2689            .unwrap_err();
2690        assert!(matches!(err, Error::TypeArityMismatch(2, 1)));
2691
2692        // Too many
2693        let err = resolver
2694            .abilities(type_("0xd0::m::T<u8, u16, u32>"))
2695            .await
2696            .unwrap_err();
2697        assert!(matches!(err, Error::TypeArityMismatch(2, 3)));
2698    }
2699
2700    #[tokio::test]
2701    async fn test_err_ability_signer() {
2702        let (_, cache) = package_cache([]);
2703        let resolver = Resolver::new(cache);
2704
2705        let err = resolver.abilities(type_("signer")).await.unwrap_err();
2706        assert!(matches!(err, Error::UnexpectedSigner));
2707    }
2708
2709    #[tokio::test]
2710    async fn test_err_too_many_type_params() {
2711        let (_, cache) = package_cache([
2712            (1, build_package("iota").unwrap(), iota_types()),
2713            (1, build_package("d0").unwrap(), d0_types()),
2714        ]);
2715
2716        let resolver = Resolver::new_with_limits(
2717            cache,
2718            Limits {
2719                max_type_argument_width: 1,
2720                max_type_argument_depth: 100,
2721                max_type_nodes: 100,
2722                max_move_value_depth: 100,
2723            },
2724        );
2725
2726        let err = resolver
2727            .abilities(type_("0xd0::m::O<u32, u64>"))
2728            .await
2729            .unwrap_err();
2730        assert!(matches!(err, Error::TooManyTypeParams(1, 2)));
2731    }
2732
2733    #[tokio::test]
2734    async fn test_err_too_many_type_nodes() {
2735        use Ability as A;
2736        use AbilitySet as S;
2737
2738        let (_, cache) = package_cache([
2739            (1, build_package("iota").unwrap(), iota_types()),
2740            (1, build_package("d0").unwrap(), d0_types()),
2741        ]);
2742
2743        let resolver = Resolver::new_with_limits(
2744            cache,
2745            Limits {
2746                max_type_argument_width: 100,
2747                max_type_argument_depth: 100,
2748                max_type_nodes: 2,
2749                max_move_value_depth: 100,
2750            },
2751        );
2752
2753        // This request is OK, because one of O's type parameters is phantom, so we can
2754        // avoid loading its definition.
2755        let a1 = resolver
2756            .abilities(type_("0xd0::m::O<0xd0::m::S, 0xd0::m::Q>"))
2757            .await
2758            .unwrap();
2759        assert_eq!(a1, S::EMPTY | A::Key | A::Store);
2760
2761        // But this request will hit the limit
2762        let err = resolver
2763            .abilities(type_("0xd0::m::T<0xd0::m::P, 0xd0::m::Q>"))
2764            .await
2765            .unwrap_err();
2766        assert!(matches!(err, Error::TooManyTypeNodes(2, _)));
2767    }
2768
2769    #[tokio::test]
2770    async fn test_err_type_param_nesting() {
2771        use Ability as A;
2772        use AbilitySet as S;
2773
2774        let (_, cache) = package_cache([
2775            (1, build_package("iota").unwrap(), iota_types()),
2776            (1, build_package("d0").unwrap(), d0_types()),
2777        ]);
2778
2779        let resolver = Resolver::new_with_limits(
2780            cache,
2781            Limits {
2782                max_type_argument_width: 100,
2783                max_type_argument_depth: 2,
2784                max_type_nodes: 100,
2785                max_move_value_depth: 100,
2786            },
2787        );
2788
2789        // This request is OK, because one of O's type parameters is phantom, so we can
2790        // avoid loading its definition.
2791        let a1 = resolver
2792            .abilities(type_(
2793                "0xd0::m::O<0xd0::m::S, 0xd0::m::T<vector<u32>, vector<u64>>>",
2794            ))
2795            .await
2796            .unwrap();
2797        assert_eq!(a1, S::EMPTY | A::Key | A::Store);
2798
2799        // But this request will hit the limit
2800        let err = resolver
2801            .abilities(type_("vector<0xd0::m::T<0xd0::m::O<u64, u32>, u16>>"))
2802            .await
2803            .unwrap_err();
2804        assert!(matches!(err, Error::TypeParamNesting(2, _)));
2805    }
2806
2807    #[tokio::test]
2808    async fn test_pure_input_layouts() {
2809        use CallArg as I;
2810        use TypeTag as T;
2811
2812        let (_, cache) = package_cache([
2813            (1, build_package("std").unwrap(), std_types()),
2814            (1, build_package("iota").unwrap(), iota_types()),
2815            (1, build_package("e0").unwrap(), e0_types()),
2816        ]);
2817
2818        let resolver = Resolver::new(cache);
2819
2820        // Helper function to generate a PTB calling 0xe0::m::foo.
2821        fn ptb(t: TypeTag, y: CallArg) -> ProgrammableTransaction {
2822            ProgrammableTransaction {
2823                inputs: vec![
2824                    I::ImmutableOrOwned(random_object_ref()),
2825                    I::Pure(bcs::to_bytes(&42u64).unwrap()),
2826                    I::ImmutableOrOwned(random_object_ref()),
2827                    y,
2828                    I::ImmutableOrOwned(random_object_ref()),
2829                    I::Pure(bcs::to_bytes("hello").unwrap()),
2830                    I::Pure(bcs::to_bytes("world").unwrap()),
2831                ],
2832                commands: vec![Command::new_move_call(
2833                    obj_id("0xe0"),
2834                    Identifier::from_static("m"),
2835                    Identifier::from_static("foo"),
2836                    vec![t],
2837                    (0..=6).map(Argument::Input).collect(),
2838                )],
2839            }
2840        }
2841
2842        let ptb_u64 = ptb(T::U64, I::Pure(bcs::to_bytes(&1u64).unwrap()));
2843
2844        let ptb_opt = ptb(
2845            TypeTag::Struct(Box::new(StructTag::new(
2846                addr("0x1"),
2847                Identifier::OPTION_MODULE,
2848                Identifier::from_static("Option"),
2849                vec![TypeTag::U64],
2850            ))),
2851            I::Pure(bcs::to_bytes(&[vec![1u64], vec![], vec![3]]).unwrap()),
2852        );
2853
2854        let ptb_obj = ptb(
2855            TypeTag::Struct(Box::new(StructTag::new(
2856                addr("0xe0"),
2857                Identifier::from_static("m"),
2858                Identifier::from_static("O"),
2859                vec![],
2860            ))),
2861            I::ImmutableOrOwned(random_object_ref()),
2862        );
2863
2864        let inputs_u64 = resolver.pure_input_layouts(&ptb_u64).await.unwrap();
2865        let inputs_opt = resolver.pure_input_layouts(&ptb_opt).await.unwrap();
2866        let inputs_obj = resolver.pure_input_layouts(&ptb_obj).await.unwrap();
2867
2868        // Make the output format a little nicer for the snapshot
2869        let mut output = "---\n".to_string();
2870        for inputs in [inputs_u64, inputs_opt, inputs_obj] {
2871            for input in inputs {
2872                if let Some(layout) = input {
2873                    output += &format!("{layout:#}\n");
2874                } else {
2875                    output += "???\n";
2876                }
2877            }
2878            output += "---\n";
2879        }
2880
2881        insta::assert_snapshot!(output);
2882    }
2883
2884    /// Like the test above, but the inputs are re-used, which we want to detect
2885    /// (but is fine because they are assigned the same type at each usage).
2886    #[tokio::test]
2887    async fn test_pure_input_layouts_overlapping() {
2888        use CallArg as I;
2889        use TypeTag as T;
2890
2891        let (_, cache) = package_cache([
2892            (1, build_package("std").unwrap(), std_types()),
2893            (1, build_package("iota").unwrap(), iota_types()),
2894            (1, build_package("e0").unwrap(), e0_types()),
2895        ]);
2896
2897        let resolver = Resolver::new(cache);
2898
2899        // Helper function to generate a PTB calling 0xe0::m::foo.
2900        let ptb = ProgrammableTransaction {
2901            inputs: vec![
2902                I::ImmutableOrOwned(random_object_ref()),
2903                I::Pure(bcs::to_bytes(&42u64).unwrap()),
2904                I::ImmutableOrOwned(random_object_ref()),
2905                I::Pure(bcs::to_bytes(&43u64).unwrap()),
2906                I::ImmutableOrOwned(random_object_ref()),
2907                I::Pure(bcs::to_bytes("hello").unwrap()),
2908                I::Pure(bcs::to_bytes("world").unwrap()),
2909            ],
2910            commands: vec![
2911                Command::new_move_call(
2912                    obj_id("0xe0"),
2913                    Identifier::from_static("m"),
2914                    Identifier::from_static("foo"),
2915                    vec![T::U64],
2916                    (0..=6).map(Argument::Input).collect(),
2917                ),
2918                Command::new_move_call(
2919                    obj_id("0xe0"),
2920                    Identifier::from_static("m"),
2921                    Identifier::from_static("foo"),
2922                    vec![T::U64],
2923                    (0..=6).map(Argument::Input).collect(),
2924                ),
2925            ],
2926        };
2927
2928        let inputs = resolver.pure_input_layouts(&ptb).await.unwrap();
2929
2930        // Make the output format a little nicer for the snapshot
2931        let mut output = String::new();
2932        for input in inputs {
2933            if let Some(layout) = input {
2934                output += &format!("{layout:#}\n");
2935            } else {
2936                output += "???\n";
2937            }
2938        }
2939
2940        insta::assert_snapshot!(output);
2941    }
2942    #[tokio::test]
2943    async fn test_pure_input_layouts_conflicting() {
2944        use CallArg as I;
2945        use TypeTag as T;
2946
2947        let (_, cache) = package_cache([
2948            (1, build_package("std").unwrap(), std_types()),
2949            (1, build_package("iota").unwrap(), iota_types()),
2950            (1, build_package("e0").unwrap(), e0_types()),
2951        ]);
2952
2953        let resolver = Resolver::new(cache);
2954
2955        let ptb = ProgrammableTransaction {
2956            inputs: vec![
2957                I::ImmutableOrOwned(random_object_ref()),
2958                I::Pure(bcs::to_bytes(&42u64).unwrap()),
2959                I::ImmutableOrOwned(random_object_ref()),
2960                I::Pure(bcs::to_bytes(&43u64).unwrap()),
2961                I::ImmutableOrOwned(random_object_ref()),
2962                I::Pure(bcs::to_bytes("hello").unwrap()),
2963                I::Pure(bcs::to_bytes("world").unwrap()),
2964            ],
2965            commands: vec![
2966                Command::new_move_call(
2967                    obj_id("0xe0"),
2968                    Identifier::from_static("m"),
2969                    Identifier::from_static("foo"),
2970                    vec![T::U64],
2971                    (0..=6).map(Argument::Input).collect(),
2972                ),
2973                // This command is using the input that was previously used as a U64, but now as a
2974                // U32, which will cause an error.
2975                Command::new_make_move_vector(Some(T::U32), vec![Argument::Input(3)]),
2976            ],
2977        };
2978
2979        insta::assert_snapshot!(
2980            resolver.pure_input_layouts(&ptb).await.unwrap_err(),
2981            @"Conflicting types for input 3: u64 and u32"
2982        );
2983    }
2984
2985    // *** Test Helpers
2986    // ************************************************************************
2987    // **
2988
2989    type TypeOriginTable = Vec<DatatypeKey>;
2990
2991    fn a0_types() -> TypeOriginTable {
2992        vec![
2993            datakey("0xa0", "m", "T0"),
2994            datakey("0xa0", "m", "T1"),
2995            datakey("0xa0", "m", "T2"),
2996            datakey("0xa0", "m", "E0"),
2997            datakey("0xa0", "m", "E1"),
2998            datakey("0xa0", "m", "E2"),
2999            datakey("0xa0", "n", "T0"),
3000            datakey("0xa0", "n", "E0"),
3001        ]
3002    }
3003
3004    fn a1_types() -> TypeOriginTable {
3005        let mut types = a0_types();
3006
3007        types.extend([
3008            datakey("0xa1", "m", "T3"),
3009            datakey("0xa1", "m", "T4"),
3010            datakey("0xa1", "n", "T1"),
3011            datakey("0xa1", "m", "E3"),
3012            datakey("0xa1", "m", "E4"),
3013            datakey("0xa1", "n", "E1"),
3014        ]);
3015
3016        types
3017    }
3018
3019    fn b0_types() -> TypeOriginTable {
3020        vec![datakey("0xb0", "m", "T0"), datakey("0xb0", "m", "E0")]
3021    }
3022
3023    fn c0_types() -> TypeOriginTable {
3024        vec![datakey("0xc0", "m", "T0"), datakey("0xc0", "m", "E0")]
3025    }
3026
3027    fn d0_types() -> TypeOriginTable {
3028        vec![
3029            datakey("0xd0", "m", "O"),
3030            datakey("0xd0", "m", "P"),
3031            datakey("0xd0", "m", "Q"),
3032            datakey("0xd0", "m", "R"),
3033            datakey("0xd0", "m", "S"),
3034            datakey("0xd0", "m", "T"),
3035            datakey("0xd0", "m", "EO"),
3036            datakey("0xd0", "m", "EP"),
3037            datakey("0xd0", "m", "EQ"),
3038            datakey("0xd0", "m", "ER"),
3039            datakey("0xd0", "m", "ES"),
3040            datakey("0xd0", "m", "ET"),
3041        ]
3042    }
3043
3044    fn e0_types() -> TypeOriginTable {
3045        vec![datakey("0xe0", "m", "O")]
3046    }
3047
3048    fn s0_types() -> TypeOriginTable {
3049        vec![datakey("0x1", "m", "T0"), datakey("0x1", "m", "E0")]
3050    }
3051
3052    fn s1_types() -> TypeOriginTable {
3053        let mut types = s0_types();
3054
3055        types.extend([datakey("0x1", "m", "T1"), datakey("0x1", "m", "E1")]);
3056
3057        types
3058    }
3059
3060    fn iota_types() -> TypeOriginTable {
3061        vec![datakey("0x2", "object", "UID")]
3062    }
3063
3064    fn std_types() -> TypeOriginTable {
3065        vec![
3066            datakey("0x1", "ascii", "String"),
3067            datakey("0x1", "option", "Option"),
3068            datakey("0x1", "string", "String"),
3069        ]
3070    }
3071
3072    /// Build an in-memory package cache from locally compiled packages.
3073    /// Assumes that all packages in `packages` are published (all modules
3074    /// have a non-zero package address and all packages
3075    /// have a 'published-at' address), and their transitive dependencies are
3076    /// also in `packages`.
3077    fn package_cache(
3078        packages: impl IntoIterator<Item = (u64, CompiledPackage, TypeOriginTable)>,
3079    ) -> (
3080        Arc<RwLock<InnerStore>>,
3081        PackageStoreWithLruCache<InMemoryPackageStore>,
3082    ) {
3083        let packages_by_storage_id: BTreeMap<Address, _> = packages
3084            .into_iter()
3085            .map(|(version, package, origins)| {
3086                (package_storage_id(&package), (version, package, origins))
3087            })
3088            .collect();
3089
3090        let packages = packages_by_storage_id
3091            .iter()
3092            .map(|(&storage_id, (version, compiled_package, origins))| {
3093                let linkage = compiled_package
3094                    .dependency_ids
3095                    .published
3096                    .values()
3097                    .map(|dep_id| {
3098                        let storage_id = Address::from(*dep_id);
3099                        let runtime_id = package_runtime_id(
3100                            &packages_by_storage_id
3101                                .get(&storage_id)
3102                                .unwrap_or_else(|| panic!("Dependency {storage_id} not in store"))
3103                                .1,
3104                        );
3105
3106                        (runtime_id, storage_id)
3107                    })
3108                    .collect();
3109
3110                let package = cached_package(*version, linkage, compiled_package, origins);
3111                (storage_id, package)
3112            })
3113            .collect();
3114
3115        let inner = Arc::new(RwLock::new(InnerStore {
3116            packages,
3117            fetches: 0,
3118        }));
3119
3120        let store = InMemoryPackageStore {
3121            inner: inner.clone(),
3122        };
3123
3124        (inner, PackageStoreWithLruCache::new(store))
3125    }
3126
3127    fn cached_package(
3128        version: u64,
3129        linkage: Linkage,
3130        package: &CompiledPackage,
3131        origins: &TypeOriginTable,
3132    ) -> Package {
3133        let storage_id = package_storage_id(package);
3134        let runtime_id = package_runtime_id(package);
3135        let version = Version::from_u64(version);
3136
3137        let mut modules = BTreeMap::new();
3138        for unit in &package.package.root_compiled_units {
3139            let NamedCompiledModule { name, module, .. } = &unit.unit;
3140
3141            let origins = origins
3142                .iter()
3143                .filter(|key| key.module == name.as_str())
3144                .map(|key| (key.name.to_string(), key.package))
3145                .collect();
3146
3147            let module = match Module::read(module.clone(), origins) {
3148                Ok(module) => module,
3149                Err(struct_) => {
3150                    panic!("Missing type origin for {}::{struct_}", module.self_id());
3151                }
3152            };
3153
3154            modules.insert(name.to_string(), module);
3155        }
3156
3157        Package {
3158            storage_id,
3159            runtime_id,
3160            linkage,
3161            version,
3162            modules,
3163        }
3164    }
3165
3166    fn package_storage_id(package: &CompiledPackage) -> Address {
3167        Address::new(
3168            package
3169                .published_at
3170                .as_ref()
3171                .unwrap_or_else(|_| {
3172                    panic!(
3173                        "Package {} doesn't have published-at set",
3174                        package.package.compiled_package_info.package_name,
3175                    )
3176                })
3177                .into_bytes(),
3178        )
3179    }
3180
3181    fn package_runtime_id(package: &CompiledPackage) -> Address {
3182        Address::new(
3183            package
3184                .published_root_module()
3185                .expect("No compiled module")
3186                .address()
3187                .into_bytes(),
3188        )
3189    }
3190
3191    fn build_package(dir: &str) -> IotaResult<CompiledPackage> {
3192        let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
3193        path.extend(["tests", "packages", dir]);
3194        BuildConfig::new_for_testing().build(&path)
3195    }
3196
3197    fn addr(a: &str) -> Address {
3198        Address::from_str(a).unwrap()
3199    }
3200
3201    fn obj_id(a: &str) -> ObjectId {
3202        ObjectId::from_str(a).unwrap()
3203    }
3204
3205    fn datakey(a: &str, m: &'static str, n: &'static str) -> DatatypeKey {
3206        DatatypeKey {
3207            package: addr(a),
3208            module: m.into(),
3209            name: n.into(),
3210        }
3211    }
3212
3213    fn type_(t: &str) -> TypeTag {
3214        TypeTag::from_str(t).unwrap()
3215    }
3216
3217    fn key(t: &str) -> DatatypeKey {
3218        let tag = StructTag::from_str(t).unwrap();
3219        DatatypeRef::from(&tag).as_key()
3220    }
3221
3222    struct InMemoryPackageStore {
3223        /// All the contents are stored in an `InnerStore` that can be probed
3224        /// and queried from outside.
3225        inner: Arc<RwLock<InnerStore>>,
3226    }
3227
3228    struct InnerStore {
3229        packages: BTreeMap<Address, Package>,
3230        fetches: usize,
3231    }
3232
3233    #[async_trait]
3234    impl PackageStore for InMemoryPackageStore {
3235        async fn fetch(&self, id: Address) -> Result<Arc<Package>> {
3236            let mut inner = self.inner.as_ref().write().unwrap();
3237            inner.fetches += 1;
3238            inner
3239                .packages
3240                .get(&id)
3241                .cloned()
3242                .ok_or_else(|| Error::PackageNotFound(id))
3243                .map(Arc::new)
3244        }
3245    }
3246
3247    impl InnerStore {
3248        fn replace(&mut self, id: Address, package: Package) {
3249            self.packages.insert(id, package);
3250        }
3251    }
3252}