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