Skip to main content

sui_package_resolver/
lib.rs

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