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