sui_package_resolver/
lib.rs

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