Skip to main content

iota_package_resolver/
lib.rs

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