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