Skip to main content

sui_package_resolver/
lib.rs

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