1use std::{
6 borrow::Cow,
7 collections::{BTreeMap, BTreeSet},
8 num::NonZeroUsize,
9 sync::{Arc, Mutex},
10};
11
12use async_trait::async_trait;
13use iota_types::{
14 Identifier,
15 base_types::{SequenceNumber, is_primitive_type_tag},
16 move_package::{MovePackage, TypeOrigin},
17 object::Object,
18 transaction::{Argument, CallArg, Command, ProgrammableTransaction},
19 type_input::{StructInput, TypeInput},
20};
21use lru::LruCache;
22use move_binary_format::{
23 CompiledModule,
24 errors::Location,
25 file_format::{
26 AbilitySet, DatatypeHandleIndex, DatatypeTyParameter, EnumDefinitionIndex,
27 FunctionDefinitionIndex, Signature as MoveSignature, SignatureIndex, SignatureToken,
28 StructDefinitionIndex, StructFieldInformation, TableIndex, Visibility,
29 },
30};
31use move_command_line_common::{
32 display::{RenderResult, try_render_constant},
33 error_bitset::ErrorBitset,
34};
35use move_core_types::{
36 account_address::AccountAddress,
37 annotated_value::{MoveEnumLayout, MoveFieldLayout, MoveStructLayout, MoveTypeLayout},
38 language_storage::{ModuleId, StructTag, TypeTag},
39};
40
41use crate::error::Error;
42
43pub mod error;
44
45const PACKAGE_CACHE_SIZE: NonZeroUsize = NonZeroUsize::new(1024).unwrap();
48
49pub type Result<T> = std::result::Result<T, Error>;
50
51#[derive(Debug)]
55pub struct Resolver<S> {
56 package_store: S,
57 limits: Option<Limits>,
58}
59
60#[derive(Debug)]
63pub struct Limits {
64 pub max_type_argument_depth: usize,
66 pub max_type_argument_width: usize,
68 pub max_type_nodes: usize,
70 pub max_move_value_depth: usize,
72}
73
74pub struct PackageStoreWithLruCache<T> {
79 pub(crate) packages: Mutex<LruCache<AccountAddress, Arc<Package>>>,
80 pub(crate) inner: T,
81}
82
83#[derive(Clone, Debug)]
84pub struct Package {
85 storage_id: AccountAddress,
87
88 runtime_id: AccountAddress,
92
93 linkage: Linkage,
97
98 version: SequenceNumber,
101
102 modules: BTreeMap<String, Module>,
103}
104
105type Linkage = BTreeMap<AccountAddress, AccountAddress>;
106
107#[derive(Clone, Debug)]
114pub struct CleverError {
115 pub module_id: ModuleId,
117 pub error_info: ErrorConstants,
120 pub source_line_number: u16,
122}
123
124#[derive(Clone, Debug)]
135pub enum ErrorConstants {
136 None,
138 Rendered {
149 identifier: String,
151 constant: String,
153 },
154 Raw {
159 identifier: String,
161 bytes: Vec<u8>,
163 },
164}
165
166#[derive(Clone, Debug)]
167pub struct Module {
168 bytecode: CompiledModule,
169
170 struct_index: BTreeMap<String, (AccountAddress, StructDefinitionIndex)>,
173
174 enum_index: BTreeMap<String, (AccountAddress, EnumDefinitionIndex)>,
177
178 function_index: BTreeMap<String, FunctionDefinitionIndex>,
181}
182
183#[derive(Debug)]
185pub struct DataDef {
186 pub defining_id: AccountAddress,
188
189 pub abilities: AbilitySet,
191
192 pub type_params: Vec<DatatypeTyParameter>,
194
195 pub data: MoveData,
198}
199
200#[derive(Debug)]
201pub enum MoveData {
202 Struct(Vec<(String, OpenSignatureBody)>),
206
207 Enum(Vec<VariantDef>),
210}
211
212#[derive(Debug)]
215pub struct VariantDef {
216 pub name: String,
218
219 pub signatures: Vec<(String, OpenSignatureBody)>,
223}
224
225#[derive(Debug)]
227pub struct FunctionDef {
228 pub visibility: Visibility,
230
231 pub is_entry: bool,
233
234 pub type_params: Vec<AbilitySet>,
236
237 pub parameters: Vec<OpenSignature>,
239
240 pub return_: Vec<OpenSignature>,
242}
243
244#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Hash)]
248pub struct DatatypeRef<'m, 'n> {
249 pub package: AccountAddress,
250 pub module: Cow<'m, str>,
251 pub name: Cow<'n, str>,
252}
253
254pub type DatatypeKey = DatatypeRef<'static, 'static>;
256
257#[derive(Copy, Clone, Debug)]
258pub enum Reference {
259 Immutable,
260 Mutable,
261}
262
263#[derive(Clone, Debug)]
266pub struct Signature {
267 pub ref_: Option<Reference>,
268 pub body: TypeTag,
269}
270
271#[derive(Clone, Debug)]
274pub struct OpenSignature {
275 pub ref_: Option<Reference>,
276 pub body: OpenSignatureBody,
277}
278
279#[derive(Clone, Debug)]
282pub enum OpenSignatureBody {
283 Address,
284 Bool,
285 U8,
286 U16,
287 U32,
288 U64,
289 U128,
290 U256,
291 Vector(Box<OpenSignatureBody>),
292 Datatype(DatatypeKey, Vec<OpenSignatureBody>),
293 TypeParameter(u16),
294}
295
296#[derive(Debug, Default)]
298struct ResolutionContext<'l> {
299 datatypes: BTreeMap<DatatypeKey, DataDef>,
302
303 limits: Option<&'l Limits>,
305}
306
307#[async_trait]
310pub trait PackageStore: Send + Sync + 'static {
311 async fn fetch(&self, id: AccountAddress) -> Result<Arc<Package>>;
314}
315
316macro_rules! as_ref_impl {
317 ($type:ty) => {
318 #[async_trait]
319 impl PackageStore for $type {
320 async fn fetch(&self, id: AccountAddress) -> Result<Arc<Package>> {
321 self.as_ref().fetch(id).await
322 }
323 }
324 };
325}
326
327as_ref_impl!(Arc<dyn PackageStore>);
328as_ref_impl!(Box<dyn PackageStore>);
329
330macro_rules! check_max_limit {
333 ($err:ident, $config:expr; $limit:ident $op:tt $value:expr) => {
334 if let Some(l) = $config {
335 let max = l.$limit;
336 let val = $value;
337 if !(max $op val) {
338 return Err(Error::$err(max, val));
339 }
340 }
341 };
342}
343
344impl<S> Resolver<S> {
345 pub fn new(package_store: S) -> Self {
346 Self {
347 package_store,
348 limits: None,
349 }
350 }
351
352 pub fn new_with_limits(package_store: S, limits: Limits) -> Self {
353 Self {
354 package_store,
355 limits: Some(limits),
356 }
357 }
358
359 pub fn package_store(&self) -> &S {
360 &self.package_store
361 }
362
363 pub fn package_store_mut(&mut self) -> &mut S {
364 &mut self.package_store
365 }
366}
367
368impl<S: PackageStore> Resolver<S> {
369 pub async fn canonical_type(&self, mut tag: TypeTag) -> Result<TypeTag> {
380 let mut context = ResolutionContext::new(self.limits.as_ref());
381
382 context
385 .add_type_tag(
386 &mut tag,
387 &self.package_store,
388 false,
390 true,
392 )
393 .await?;
394
395 context.canonicalize_type(&mut tag)?;
397 Ok(tag)
398 }
399
400 pub async fn type_layout(&self, mut tag: TypeTag) -> Result<MoveTypeLayout> {
404 let mut context = ResolutionContext::new(self.limits.as_ref());
405
406 context
409 .add_type_tag(
410 &mut tag,
411 &self.package_store,
412 true,
414 true,
416 )
417 .await?;
418
419 let max_depth = self
421 .limits
422 .as_ref()
423 .map_or(usize::MAX, |l| l.max_move_value_depth);
424
425 Ok(context.resolve_type_layout(&tag, max_depth)?.0)
426 }
427
428 pub async fn abilities(&self, mut tag: TypeTag) -> Result<AbilitySet> {
435 let mut context = ResolutionContext::new(self.limits.as_ref());
436
437 context
440 .add_type_tag(
441 &mut tag,
442 &self.package_store,
443 false,
445 false,
447 )
448 .await?;
449
450 context.resolve_abilities(&tag)
452 }
453
454 pub async fn function_signature(
457 &self,
458 pkg: AccountAddress,
459 module: &str,
460 function: &str,
461 ) -> Result<FunctionDef> {
462 let mut context = ResolutionContext::new(self.limits.as_ref());
463
464 let package = self.package_store.fetch(pkg).await?;
465 let Some(mut def) = package.module(module)?.function_def(function)? else {
466 return Err(Error::FunctionNotFound(
467 pkg,
468 module.to_string(),
469 function.to_string(),
470 ));
471 };
472
473 for sig in def.parameters.iter().chain(def.return_.iter()) {
476 context
477 .add_signature(
478 sig.body.clone(),
479 &self.package_store,
480 package.as_ref(),
481 false,
483 )
484 .await?;
485 }
486
487 for sig in def.parameters.iter_mut().chain(def.return_.iter_mut()) {
489 context.relocate_signature(&mut sig.body)?;
490 }
491
492 Ok(def)
493 }
494
495 pub async fn pure_input_layouts(
507 &self,
508 tx: &ProgrammableTransaction,
509 ) -> Result<Vec<Option<MoveTypeLayout>>> {
510 let mut tags = vec![None; tx.inputs.len()];
511 let mut register_type = |arg: &Argument, tag: &TypeTag| {
512 let &Argument::Input(ix) = arg else {
513 return Ok(());
514 };
515
516 if !matches!(tx.inputs.get(ix as usize), Some(CallArg::Pure(_))) {
517 return Ok(());
518 }
519
520 let Some(type_) = tags.get_mut(ix as usize) else {
521 return Ok(());
522 };
523
524 match type_ {
525 None => *type_ = Some(tag.clone()),
526 Some(prev) => {
527 if prev != tag {
528 return Err(Error::InputTypeConflict(ix, prev.clone(), tag.clone()));
529 }
530 }
531 }
532
533 Ok(())
534 };
535
536 for cmd in &tx.commands {
538 match cmd {
539 Command::MoveCall(call) => {
540 let Ok(signature) = self
541 .function_signature(
542 call.package.into(),
543 call.module.as_str(),
544 call.function.as_str(),
545 )
546 .await
547 else {
548 continue;
549 };
550
551 for (open_sig, arg) in signature.parameters.iter().zip(call.arguments.iter()) {
552 let sig = open_sig.instantiate(&call.type_arguments)?;
553 register_type(arg, &sig.body)?;
554 }
555 }
556
557 Command::TransferObjects(_, arg) => register_type(arg, &TypeTag::Address)?,
558
559 Command::SplitCoins(_, amounts) => {
560 for amount in amounts {
561 register_type(amount, &TypeTag::U64)?;
562 }
563 }
564
565 Command::MakeMoveVec(Some(tag), elems) => {
566 let tag = as_type_tag(tag)?;
567 if is_primitive_type_tag(&tag) {
568 for elem in elems {
569 register_type(elem, &tag)?;
570 }
571 }
572 }
573
574 _ => { }
575 }
576 }
577
578 let unique_tags: BTreeSet<_> = tags.iter().filter_map(|t| t.clone()).collect();
582
583 let mut layouts = BTreeMap::new();
585 for tag in unique_tags {
586 let layout = self.type_layout(tag.clone()).await?;
587 layouts.insert(tag, layout);
588 }
589
590 Ok(tags
592 .iter()
593 .map(|t| t.as_ref().and_then(|t| layouts.get(t).cloned()))
594 .collect())
595 }
596
597 pub async fn resolve_module_id(
606 &self,
607 module_id: ModuleId,
608 context: AccountAddress,
609 ) -> Result<ModuleId> {
610 let package = self.package_store.fetch(context).await?;
611 let storage_id = package.relocate(*module_id.address())?;
612 Ok(ModuleId::new(storage_id, module_id.name().to_owned()))
613 }
614
615 pub async fn resolve_clever_error(
632 &self,
633 module_id: ModuleId,
634 abort_code: u64,
635 ) -> Option<CleverError> {
636 let bitset = ErrorBitset::from_u64(abort_code)?;
637 let package = self.package_store.fetch(*module_id.address()).await.ok()?;
638 let module = package.module(module_id.name().as_str()).ok()?.bytecode();
639 let source_line_number = bitset.line_number()?;
640
641 if bitset.identifier_index().is_none() && bitset.constant_index().is_none() {
643 return Some(CleverError {
644 module_id,
645 error_info: ErrorConstants::None,
646 source_line_number,
647 });
648 } else if bitset.identifier_index().is_none() || bitset.constant_index().is_none() {
649 return None;
650 }
651
652 let error_identifier_constant = module
653 .constant_pool()
654 .get(bitset.identifier_index()? as usize)?;
655 let error_value_constant = module
656 .constant_pool()
657 .get(bitset.constant_index()? as usize)?;
658
659 if !matches!(&error_identifier_constant.type_, SignatureToken::Vector(x) if x.as_ref() == &SignatureToken::U8)
660 {
661 return None;
662 };
663
664 let error_identifier = bcs::from_bytes::<Vec<u8>>(&error_identifier_constant.data)
665 .ok()
666 .and_then(|x| String::from_utf8(x).ok())?;
667 let bytes = error_value_constant.data.clone();
668
669 let rendered = try_render_constant(error_value_constant);
670
671 let error_info = match rendered {
672 RenderResult::NotRendered => ErrorConstants::Raw {
673 identifier: error_identifier,
674 bytes,
675 },
676 RenderResult::AsString(s) | RenderResult::AsValue(s) => ErrorConstants::Rendered {
677 identifier: error_identifier,
678 constant: s,
679 },
680 };
681
682 Some(CleverError {
683 module_id,
684 error_info,
685 source_line_number,
686 })
687 }
688}
689
690impl<T> PackageStoreWithLruCache<T> {
691 pub fn new(inner: T) -> Self {
692 let packages = Mutex::new(LruCache::new(PACKAGE_CACHE_SIZE));
693 Self { packages, inner }
694 }
695
696 pub fn evict(&self, ids: impl IntoIterator<Item = AccountAddress>) {
700 let mut packages = self.packages.lock().unwrap();
701 for id in ids {
702 packages.pop(&id);
703 }
704 }
705}
706
707#[async_trait]
708impl<T: PackageStore> PackageStore for PackageStoreWithLruCache<T> {
709 async fn fetch(&self, id: AccountAddress) -> Result<Arc<Package>> {
710 if let Some(package) = {
711 let mut packages = self.packages.lock().unwrap();
713 packages.get(&id).cloned()
714 } {
715 return Ok(package);
716 };
717
718 let package = self.inner.fetch(id).await?;
719
720 let mut packages = self.packages.lock().unwrap();
727 Ok(match packages.peek(&id) {
728 Some(prev) if package.version <= prev.version => {
729 let package = prev.clone();
730 packages.promote(&id);
731 package
732 }
733
734 Some(_) | None => {
735 packages.push(id, package.clone());
736 package
737 }
738 })
739 }
740}
741
742impl Package {
743 pub fn read_from_object(object: &Object) -> Result<Self> {
744 let storage_id = AccountAddress::from(object.id());
745 let Some(package) = object.data.try_as_package() else {
746 return Err(Error::NotAPackage(storage_id));
747 };
748
749 Self::read_from_package(package)
750 }
751
752 pub fn read_from_package(package: &MovePackage) -> Result<Self> {
753 let storage_id = AccountAddress::from(package.id());
754 let mut type_origins: BTreeMap<String, BTreeMap<String, AccountAddress>> = BTreeMap::new();
755 for TypeOrigin {
756 module_name,
757 datatype_name,
758 package,
759 } in package.type_origin_table()
760 {
761 type_origins
762 .entry(module_name.to_string())
763 .or_default()
764 .insert(datatype_name.to_string(), AccountAddress::from(*package));
765 }
766
767 let mut runtime_id = None;
768 let mut modules = BTreeMap::new();
769 for (name, bytes) in package.serialized_module_map() {
770 let origins = type_origins.remove(name).unwrap_or_default();
771 let bytecode = CompiledModule::deserialize_with_defaults(bytes)
772 .map_err(|e| Error::Deserialize(e.finish(Location::Undefined)))?;
773
774 runtime_id = Some(*bytecode.address());
775
776 let name = name.clone();
777 match Module::read(bytecode, origins) {
778 Ok(module) => modules.insert(name, module),
779 Err(struct_) => return Err(Error::NoTypeOrigin(storage_id, name, struct_)),
780 };
781 }
782
783 let Some(runtime_id) = runtime_id else {
784 return Err(Error::EmptyPackage(storage_id));
785 };
786
787 let linkage = package
788 .linkage_table()
789 .iter()
790 .map(|(&dep, linkage)| (dep.into(), linkage.upgraded_id.into()))
791 .collect();
792
793 Ok(Package {
794 storage_id,
795 runtime_id,
796 version: package.version(),
797 modules,
798 linkage,
799 })
800 }
801
802 pub fn module(&self, module: &str) -> Result<&Module> {
803 self.modules
804 .get(module)
805 .ok_or_else(|| Error::ModuleNotFound(self.storage_id, module.to_string()))
806 }
807
808 pub fn modules(&self) -> &BTreeMap<String, Module> {
809 &self.modules
810 }
811
812 fn data_def(&self, module_name: &str, datatype_name: &str) -> Result<DataDef> {
813 let module = self.module(module_name)?;
814 let Some(data_def) = module.data_def(datatype_name)? else {
815 return Err(Error::DatatypeNotFound(
816 self.storage_id,
817 module_name.to_string(),
818 datatype_name.to_string(),
819 ));
820 };
821 Ok(data_def)
822 }
823
824 fn relocate(&self, runtime_id: AccountAddress) -> Result<AccountAddress> {
828 if runtime_id == self.runtime_id {
831 return Ok(self.storage_id);
832 }
833
834 self.linkage
835 .get(&runtime_id)
836 .ok_or_else(|| Error::LinkageNotFound(runtime_id))
837 .copied()
838 }
839}
840
841impl Module {
842 fn read(
847 bytecode: CompiledModule,
848 mut origins: BTreeMap<String, AccountAddress>,
849 ) -> std::result::Result<Self, String> {
850 let mut struct_index = BTreeMap::new();
851 for (index, def) in bytecode.struct_defs.iter().enumerate() {
852 let sh = bytecode.datatype_handle_at(def.struct_handle);
853 let struct_ = bytecode.identifier_at(sh.name).to_string();
854 let index = StructDefinitionIndex::new(index as TableIndex);
855
856 let Some(defining_id) = origins.remove(&struct_) else {
857 return Err(struct_);
858 };
859
860 struct_index.insert(struct_, (defining_id, index));
861 }
862
863 let mut enum_index = BTreeMap::new();
864 for (index, def) in bytecode.enum_defs.iter().enumerate() {
865 let eh = bytecode.datatype_handle_at(def.enum_handle);
866 let enum_ = bytecode.identifier_at(eh.name).to_string();
867 let index = EnumDefinitionIndex::new(index as TableIndex);
868
869 let Some(defining_id) = origins.remove(&enum_) else {
870 return Err(enum_);
871 };
872
873 enum_index.insert(enum_, (defining_id, index));
874 }
875
876 let mut function_index = BTreeMap::new();
877 for (index, def) in bytecode.function_defs.iter().enumerate() {
878 let fh = bytecode.function_handle_at(def.function);
879 let function = bytecode.identifier_at(fh.name).to_string();
880 let index = FunctionDefinitionIndex::new(index as TableIndex);
881
882 function_index.insert(function, index);
883 }
884
885 Ok(Module {
886 bytecode,
887 struct_index,
888 enum_index,
889 function_index,
890 })
891 }
892
893 pub fn bytecode(&self) -> &CompiledModule {
894 &self.bytecode
895 }
896
897 pub fn name(&self) -> &str {
899 self.bytecode
900 .identifier_at(self.bytecode.self_handle().name)
901 .as_str()
902 }
903
904 pub fn structs(
907 &self,
908 after: Option<&str>,
909 before: Option<&str>,
910 ) -> impl DoubleEndedIterator<Item = &str> + Clone {
911 use std::ops::Bound as B;
912 self.struct_index
913 .range::<str, _>((
914 after.map_or(B::Unbounded, B::Excluded),
915 before.map_or(B::Unbounded, B::Excluded),
916 ))
917 .map(|(name, _)| name.as_str())
918 }
919
920 pub fn enums(
923 &self,
924 after: Option<&str>,
925 before: Option<&str>,
926 ) -> impl DoubleEndedIterator<Item = &str> + Clone {
927 use std::ops::Bound as B;
928 self.enum_index
929 .range::<str, _>((
930 after.map_or(B::Unbounded, B::Excluded),
931 before.map_or(B::Unbounded, B::Excluded),
932 ))
933 .map(|(name, _)| name.as_str())
934 }
935
936 pub fn datatypes(
940 &self,
941 after: Option<&str>,
942 before: Option<&str>,
943 ) -> impl DoubleEndedIterator<Item = &str> + Clone {
944 let mut names = self
945 .structs(after, before)
946 .chain(self.enums(after, before))
947 .collect::<Vec<_>>();
948 names.sort();
949 names.into_iter()
950 }
951
952 pub fn struct_def(&self, name: &str) -> Result<Option<DataDef>> {
957 let Some(&(defining_id, index)) = self.struct_index.get(name) else {
958 return Ok(None);
959 };
960
961 let struct_def = self.bytecode.struct_def_at(index);
962 let struct_handle = self.bytecode.datatype_handle_at(struct_def.struct_handle);
963 let abilities = struct_handle.abilities;
964 let type_params = struct_handle.type_parameters.clone();
965
966 let fields = match &struct_def.field_information {
967 StructFieldInformation::Native => vec![],
968 StructFieldInformation::Declared(fields) => fields
969 .iter()
970 .map(|f| {
971 Ok((
972 self.bytecode.identifier_at(f.name).to_string(),
973 OpenSignatureBody::read(&f.signature.0, &self.bytecode)?,
974 ))
975 })
976 .collect::<Result<_>>()?,
977 };
978
979 Ok(Some(DataDef {
980 defining_id,
981 abilities,
982 type_params,
983 data: MoveData::Struct(fields),
984 }))
985 }
986
987 pub fn enum_def(&self, name: &str) -> Result<Option<DataDef>> {
992 let Some(&(defining_id, index)) = self.enum_index.get(name) else {
993 return Ok(None);
994 };
995
996 let enum_def = self.bytecode.enum_def_at(index);
997 let enum_handle = self.bytecode.datatype_handle_at(enum_def.enum_handle);
998 let abilities = enum_handle.abilities;
999 let type_params = enum_handle.type_parameters.clone();
1000
1001 let variants = enum_def
1002 .variants
1003 .iter()
1004 .map(|variant| {
1005 let name = self
1006 .bytecode
1007 .identifier_at(variant.variant_name)
1008 .to_string();
1009 let signatures = variant
1010 .fields
1011 .iter()
1012 .map(|f| {
1013 Ok((
1014 self.bytecode.identifier_at(f.name).to_string(),
1015 OpenSignatureBody::read(&f.signature.0, &self.bytecode)?,
1016 ))
1017 })
1018 .collect::<Result<_>>()?;
1019
1020 Ok(VariantDef { name, signatures })
1021 })
1022 .collect::<Result<_>>()?;
1023
1024 Ok(Some(DataDef {
1025 defining_id,
1026 abilities,
1027 type_params,
1028 data: MoveData::Enum(variants),
1029 }))
1030 }
1031
1032 pub fn data_def(&self, name: &str) -> Result<Option<DataDef>> {
1037 self.struct_def(name)
1038 .transpose()
1039 .or_else(|| self.enum_def(name).transpose())
1040 .transpose()
1041 }
1042
1043 pub fn functions(
1046 &self,
1047 after: Option<&str>,
1048 before: Option<&str>,
1049 ) -> impl DoubleEndedIterator<Item = &str> + Clone {
1050 use std::ops::Bound as B;
1051 self.function_index
1052 .range::<str, _>((
1053 after.map_or(B::Unbounded, B::Excluded),
1054 before.map_or(B::Unbounded, B::Excluded),
1055 ))
1056 .map(|(name, _)| name.as_str())
1057 }
1058
1059 pub fn function_def(&self, name: &str) -> Result<Option<FunctionDef>> {
1064 let Some(&index) = self.function_index.get(name) else {
1065 return Ok(None);
1066 };
1067
1068 let function_def = self.bytecode.function_def_at(index);
1069 let function_handle = self.bytecode.function_handle_at(function_def.function);
1070
1071 Ok(Some(FunctionDef {
1072 visibility: function_def.visibility,
1073 is_entry: function_def.is_entry,
1074 type_params: function_handle.type_parameters.clone(),
1075 parameters: read_signature(function_handle.parameters, &self.bytecode)?,
1076 return_: read_signature(function_handle.return_, &self.bytecode)?,
1077 }))
1078 }
1079}
1080
1081impl OpenSignature {
1082 fn read(sig: &SignatureToken, bytecode: &CompiledModule) -> Result<Self> {
1083 use SignatureToken as S;
1084 Ok(match sig {
1085 S::Reference(sig) => OpenSignature {
1086 ref_: Some(Reference::Immutable),
1087 body: OpenSignatureBody::read(sig, bytecode)?,
1088 },
1089
1090 S::MutableReference(sig) => OpenSignature {
1091 ref_: Some(Reference::Mutable),
1092 body: OpenSignatureBody::read(sig, bytecode)?,
1093 },
1094
1095 sig => OpenSignature {
1096 ref_: None,
1097 body: OpenSignatureBody::read(sig, bytecode)?,
1098 },
1099 })
1100 }
1101
1102 pub fn instantiate(&self, type_params: &[TypeInput]) -> Result<Signature> {
1109 Ok(Signature {
1110 ref_: self.ref_,
1111 body: self.body.instantiate(type_params)?,
1112 })
1113 }
1114}
1115
1116impl OpenSignatureBody {
1117 fn read(sig: &SignatureToken, bytecode: &CompiledModule) -> Result<Self> {
1118 use OpenSignatureBody as O;
1119 use SignatureToken as S;
1120
1121 Ok(match sig {
1122 S::Signer => return Err(Error::UnexpectedSigner),
1123 S::Reference(_) | S::MutableReference(_) => return Err(Error::UnexpectedReference),
1124
1125 S::Address => O::Address,
1126 S::Bool => O::Bool,
1127 S::U8 => O::U8,
1128 S::U16 => O::U16,
1129 S::U32 => O::U32,
1130 S::U64 => O::U64,
1131 S::U128 => O::U128,
1132 S::U256 => O::U256,
1133 S::TypeParameter(ix) => O::TypeParameter(*ix),
1134
1135 S::Vector(sig) => O::Vector(Box::new(OpenSignatureBody::read(sig, bytecode)?)),
1136
1137 S::Datatype(ix) => O::Datatype(DatatypeKey::read(*ix, bytecode), vec![]),
1138 S::DatatypeInstantiation(inst) => {
1139 let (ix, params) = &**inst;
1140 O::Datatype(
1141 DatatypeKey::read(*ix, bytecode),
1142 params
1143 .iter()
1144 .map(|sig| OpenSignatureBody::read(sig, bytecode))
1145 .collect::<Result<_>>()?,
1146 )
1147 }
1148 })
1149 }
1150
1151 fn instantiate(&self, type_params: &[TypeInput]) -> Result<TypeTag> {
1152 use OpenSignatureBody as O;
1153 use TypeTag as T;
1154
1155 Ok(match self {
1156 O::Address => T::Address,
1157 O::Bool => T::Bool,
1158 O::U8 => T::U8,
1159 O::U16 => T::U16,
1160 O::U32 => T::U32,
1161 O::U64 => T::U64,
1162 O::U128 => T::U128,
1163 O::U256 => T::U256,
1164 O::Vector(s) => T::Vector(Box::new(s.instantiate(type_params)?)),
1165
1166 O::Datatype(key, dty_params) => T::Struct(Box::new(StructTag {
1167 address: key.package,
1168 module: ident(&key.module)?,
1169 name: ident(&key.name)?,
1170 type_params: dty_params
1171 .iter()
1172 .map(|p| p.instantiate(type_params))
1173 .collect::<Result<_>>()?,
1174 })),
1175
1176 O::TypeParameter(ix) => as_type_tag(
1177 type_params
1178 .get(*ix as usize)
1179 .ok_or_else(|| Error::TypeParamOOB(*ix, type_params.len()))?,
1180 )?,
1181 })
1182 }
1183}
1184
1185impl DatatypeRef<'_, '_> {
1186 pub fn as_key(&self) -> DatatypeKey {
1187 DatatypeKey {
1188 package: self.package,
1189 module: self.module.to_string().into(),
1190 name: self.name.to_string().into(),
1191 }
1192 }
1193}
1194
1195impl DatatypeKey {
1196 fn read(ix: DatatypeHandleIndex, bytecode: &CompiledModule) -> Self {
1197 let sh = bytecode.datatype_handle_at(ix);
1198 let mh = bytecode.module_handle_at(sh.module);
1199
1200 let package = *bytecode.address_identifier_at(mh.address);
1201 let module = bytecode.identifier_at(mh.name).to_string().into();
1202 let name = bytecode.identifier_at(sh.name).to_string().into();
1203
1204 DatatypeKey {
1205 package,
1206 module,
1207 name,
1208 }
1209 }
1210}
1211
1212impl<'l> ResolutionContext<'l> {
1213 fn new(limits: Option<&'l Limits>) -> Self {
1214 ResolutionContext {
1215 datatypes: BTreeMap::new(),
1216 limits,
1217 }
1218 }
1219
1220 async fn add_type_tag<S: PackageStore + ?Sized>(
1235 &mut self,
1236 tag: &mut TypeTag,
1237 store: &S,
1238 visit_fields: bool,
1239 visit_phantoms: bool,
1240 ) -> Result<()> {
1241 use TypeTag as T;
1242
1243 struct ToVisit<'t> {
1244 tag: &'t mut TypeTag,
1245 depth: usize,
1246 }
1247
1248 let mut frontier = vec![ToVisit { tag, depth: 0 }];
1249 while let Some(ToVisit { tag, depth }) = frontier.pop() {
1250 macro_rules! push_ty_param {
1251 ($tag:expr) => {{
1252 check_max_limit!(
1253 TypeParamNesting, self.limits;
1254 max_type_argument_depth > depth
1255 );
1256
1257 frontier.push(ToVisit { tag: $tag, depth: depth + 1 })
1258 }}
1259 }
1260
1261 match tag {
1262 T::Address
1263 | T::Bool
1264 | T::U8
1265 | T::U16
1266 | T::U32
1267 | T::U64
1268 | T::U128
1269 | T::U256
1270 | T::Signer => {
1271 }
1273
1274 T::Vector(tag) => push_ty_param!(tag),
1275
1276 T::Struct(s) => {
1277 let context = store.fetch(s.address).await?;
1278 let def = context
1279 .clone()
1280 .data_def(s.module.as_str(), s.name.as_str())?;
1281
1282 s.address = context.runtime_id;
1287 let key = DatatypeRef::from(s.as_ref()).as_key();
1288
1289 if def.type_params.len() != s.type_params.len() {
1290 return Err(Error::TypeArityMismatch(
1291 def.type_params.len(),
1292 s.type_params.len(),
1293 ));
1294 }
1295
1296 check_max_limit!(
1297 TooManyTypeParams, self.limits;
1298 max_type_argument_width >= s.type_params.len()
1299 );
1300
1301 for (param, def) in s.type_params.iter_mut().zip(def.type_params.iter()) {
1302 if !def.is_phantom || visit_phantoms {
1303 push_ty_param!(param);
1304 }
1305 }
1306
1307 if self.datatypes.contains_key(&key) {
1308 continue;
1309 }
1310
1311 if visit_fields {
1312 match &def.data {
1313 MoveData::Struct(fields) => {
1314 for (_, sig) in fields {
1315 self.add_signature(sig.clone(), store, &context, visit_fields)
1316 .await?;
1317 }
1318 }
1319 MoveData::Enum(variants) => {
1320 for variant in variants {
1321 for (_, sig) in &variant.signatures {
1322 self.add_signature(
1323 sig.clone(),
1324 store,
1325 &context,
1326 visit_fields,
1327 )
1328 .await?;
1329 }
1330 }
1331 }
1332 };
1333 }
1334
1335 check_max_limit!(
1336 TooManyTypeNodes, self.limits;
1337 max_type_nodes > self.datatypes.len()
1338 );
1339
1340 self.datatypes.insert(key, def);
1341 }
1342 }
1343 }
1344
1345 Ok(())
1346 }
1347
1348 async fn add_signature<T: PackageStore + ?Sized>(
1351 &mut self,
1352 sig: OpenSignatureBody,
1353 store: &T,
1354 context: &Package,
1355 visit_fields: bool,
1356 ) -> Result<()> {
1357 use OpenSignatureBody as O;
1358
1359 let mut frontier = vec![sig];
1360 while let Some(sig) = frontier.pop() {
1361 match sig {
1362 O::Address
1363 | O::Bool
1364 | O::U8
1365 | O::U16
1366 | O::U32
1367 | O::U64
1368 | O::U128
1369 | O::U256
1370 | O::TypeParameter(_) => {
1371 }
1373
1374 O::Vector(sig) => frontier.push(*sig),
1375
1376 O::Datatype(key, params) => {
1377 check_max_limit!(
1378 TooManyTypeParams, self.limits;
1379 max_type_argument_width >= params.len()
1380 );
1381
1382 let params_count = params.len();
1383 let data_count = self.datatypes.len();
1384 frontier.extend(params.into_iter());
1385
1386 let type_params = if let Some(def) = self.datatypes.get(&key) {
1387 &def.type_params
1388 } else {
1389 check_max_limit!(
1390 TooManyTypeNodes, self.limits;
1391 max_type_nodes > data_count
1392 );
1393
1394 let storage_id = context.relocate(key.package)?;
1396 let package = store.fetch(storage_id).await?;
1397
1398 let def = package.data_def(&key.module, &key.name)?;
1399 if visit_fields {
1400 match &def.data {
1401 MoveData::Struct(fields) => {
1402 frontier.extend(fields.iter().map(|f| &f.1).cloned());
1403 }
1404 MoveData::Enum(variants) => {
1405 frontier.extend(
1406 variants
1407 .iter()
1408 .flat_map(|v| v.signatures.iter().map(|(_, s)| s))
1409 .cloned(),
1410 );
1411 }
1412 };
1413 }
1414
1415 &self.datatypes.entry(key).or_insert(def).type_params
1416 };
1417
1418 if type_params.len() != params_count {
1419 return Err(Error::TypeArityMismatch(type_params.len(), params_count));
1420 }
1421 }
1422 }
1423 }
1424
1425 Ok(())
1426 }
1427
1428 fn canonicalize_type(&self, tag: &mut TypeTag) -> Result<()> {
1433 use TypeTag as T;
1434
1435 match tag {
1436 T::Signer => return Err(Error::UnexpectedSigner),
1437 T::Address | T::Bool | T::U8 | T::U16 | T::U32 | T::U64 | T::U128 | T::U256 => {
1438 }
1440
1441 T::Vector(tag) => self.canonicalize_type(tag.as_mut())?,
1442
1443 T::Struct(s) => {
1444 for tag in &mut s.type_params {
1445 self.canonicalize_type(tag)?;
1446 }
1447
1448 let key = DatatypeRef::from(s.as_ref());
1450 let def = &self.datatypes[&key];
1451
1452 s.address = def.defining_id;
1453 }
1454 }
1455
1456 Ok(())
1457 }
1458
1459 fn resolve_type_layout(
1468 &self,
1469 tag: &TypeTag,
1470 max_depth: usize,
1471 ) -> Result<(MoveTypeLayout, usize)> {
1472 use MoveTypeLayout as L;
1473 use TypeTag as T;
1474
1475 if max_depth == 0 {
1476 return Err(Error::ValueNesting(
1477 self.limits.map_or(0, |l| l.max_move_value_depth),
1478 ));
1479 }
1480
1481 Ok(match tag {
1482 T::Signer => return Err(Error::UnexpectedSigner),
1483
1484 T::Address => (L::Address, 1),
1485 T::Bool => (L::Bool, 1),
1486 T::U8 => (L::U8, 1),
1487 T::U16 => (L::U16, 1),
1488 T::U32 => (L::U32, 1),
1489 T::U64 => (L::U64, 1),
1490 T::U128 => (L::U128, 1),
1491 T::U256 => (L::U256, 1),
1492
1493 T::Vector(tag) => {
1494 let (layout, depth) = self.resolve_type_layout(tag, max_depth - 1)?;
1495 (L::Vector(Box::new(layout)), depth + 1)
1496 }
1497
1498 T::Struct(s) => {
1499 let param_layouts = s
1514 .type_params
1515 .iter()
1516 .map(|tag| self.resolve_type_layout(tag, max_depth - 1))
1519 .collect::<Result<Vec<_>>>()?;
1520
1521 let type_params = param_layouts.iter().map(|l| TypeTag::from(&l.0)).collect();
1526
1527 let key = DatatypeRef::from(s.as_ref());
1529 let def = &self.datatypes[&key];
1530
1531 let type_ = StructTag {
1532 address: def.defining_id,
1533 module: s.module.clone(),
1534 name: s.name.clone(),
1535 type_params,
1536 };
1537
1538 self.resolve_datatype_signature(def, type_, param_layouts, max_depth)?
1539 }
1540 })
1541 }
1542
1543 fn resolve_datatype_signature(
1551 &self,
1552 data_def: &DataDef,
1553 type_: StructTag,
1554 param_layouts: Vec<(MoveTypeLayout, usize)>,
1555 max_depth: usize,
1556 ) -> Result<(MoveTypeLayout, usize)> {
1557 Ok(match &data_def.data {
1558 MoveData::Struct(fields) => {
1559 let mut resolved_fields = Vec::with_capacity(fields.len());
1560 let mut field_depth = 0;
1561
1562 for (name, sig) in fields {
1563 let (layout, depth) =
1564 self.resolve_signature_layout(sig, ¶m_layouts, max_depth - 1)?;
1565
1566 field_depth = field_depth.max(depth);
1567 resolved_fields.push(MoveFieldLayout {
1568 name: ident(name.as_str())?,
1569 layout,
1570 })
1571 }
1572
1573 (
1574 MoveTypeLayout::Struct(Box::new(MoveStructLayout {
1575 type_,
1576 fields: resolved_fields,
1577 })),
1578 field_depth + 1,
1579 )
1580 }
1581 MoveData::Enum(variants) => {
1582 let mut field_depth = 0;
1583 let mut resolved_variants = BTreeMap::new();
1584
1585 for (tag, variant) in variants.iter().enumerate() {
1586 let mut fields = Vec::with_capacity(variant.signatures.len());
1587 for (name, sig) in &variant.signatures {
1588 let (layout, depth) =
1590 self.resolve_signature_layout(sig, ¶m_layouts, max_depth - 1)?;
1591
1592 field_depth = field_depth.max(depth);
1593 fields.push(MoveFieldLayout {
1594 name: ident(name.as_str())?,
1595 layout,
1596 })
1597 }
1598 resolved_variants.insert((ident(variant.name.as_str())?, tag as u16), fields);
1599 }
1600
1601 (
1602 MoveTypeLayout::Enum(Box::new(MoveEnumLayout {
1603 type_,
1604 variants: resolved_variants,
1605 })),
1606 field_depth + 1,
1607 )
1608 }
1609 })
1610 }
1611
1612 fn resolve_signature_layout(
1620 &self,
1621 sig: &OpenSignatureBody,
1622 param_layouts: &[(MoveTypeLayout, usize)],
1623 max_depth: usize,
1624 ) -> Result<(MoveTypeLayout, usize)> {
1625 use MoveTypeLayout as L;
1626 use OpenSignatureBody as O;
1627
1628 if max_depth == 0 {
1629 return Err(Error::ValueNesting(
1630 self.limits.map_or(0, |l| l.max_move_value_depth),
1631 ));
1632 }
1633
1634 Ok(match sig {
1635 O::Address => (L::Address, 1),
1636 O::Bool => (L::Bool, 1),
1637 O::U8 => (L::U8, 1),
1638 O::U16 => (L::U16, 1),
1639 O::U32 => (L::U32, 1),
1640 O::U64 => (L::U64, 1),
1641 O::U128 => (L::U128, 1),
1642 O::U256 => (L::U256, 1),
1643
1644 O::TypeParameter(ix) => {
1645 let (layout, depth) = param_layouts
1646 .get(*ix as usize)
1647 .ok_or_else(|| Error::TypeParamOOB(*ix, param_layouts.len()))
1648 .cloned()?;
1649
1650 if depth > max_depth {
1654 return Err(Error::ValueNesting(
1655 self.limits.map_or(0, |l| l.max_move_value_depth),
1656 ));
1657 }
1658
1659 (layout, depth)
1660 }
1661
1662 O::Vector(sig) => {
1663 let (layout, depth) =
1664 self.resolve_signature_layout(sig.as_ref(), param_layouts, max_depth - 1)?;
1665
1666 (L::Vector(Box::new(layout)), depth + 1)
1667 }
1668
1669 O::Datatype(key, params) => {
1670 let def = &self.datatypes[key];
1672
1673 let param_layouts = params
1674 .iter()
1675 .map(|sig| self.resolve_signature_layout(sig, param_layouts, max_depth - 1))
1676 .collect::<Result<Vec<_>>>()?;
1677
1678 let type_params: Vec<TypeTag> =
1683 param_layouts.iter().map(|l| TypeTag::from(&l.0)).collect();
1684
1685 let type_ = StructTag {
1686 address: def.defining_id,
1687 module: ident(&key.module)?,
1688 name: ident(&key.name)?,
1689 type_params,
1690 };
1691
1692 self.resolve_datatype_signature(def, type_, param_layouts, max_depth)?
1693 }
1694 })
1695 }
1696
1697 fn resolve_abilities(&self, tag: &TypeTag) -> Result<AbilitySet> {
1701 use TypeTag as T;
1702 Ok(match tag {
1703 T::Signer => return Err(Error::UnexpectedSigner),
1704
1705 T::Bool | T::U8 | T::U16 | T::U32 | T::U64 | T::U128 | T::U256 | T::Address => {
1706 AbilitySet::PRIMITIVES
1707 }
1708
1709 T::Vector(tag) => self.resolve_abilities(tag)?.intersect(AbilitySet::VECTOR),
1710
1711 T::Struct(s) => {
1712 let key = DatatypeRef::from(s.as_ref());
1714 let def = &self.datatypes[&key];
1715
1716 if def.type_params.len() != s.type_params.len() {
1717 return Err(Error::TypeArityMismatch(
1718 def.type_params.len(),
1719 s.type_params.len(),
1720 ));
1721 }
1722
1723 let param_abilities: Result<Vec<AbilitySet>> = s
1724 .type_params
1725 .iter()
1726 .zip(def.type_params.iter())
1727 .map(|(p, d)| {
1728 if d.is_phantom {
1729 Ok(AbilitySet::EMPTY)
1730 } else {
1731 self.resolve_abilities(p)
1732 }
1733 })
1734 .collect();
1735
1736 AbilitySet::polymorphic_abilities(
1737 def.abilities,
1738 def.type_params.iter().map(|p| p.is_phantom),
1739 param_abilities?.into_iter(),
1740 )
1741 .map_err(|e| Error::Unexpected(Arc::new(e)))?
1744 }
1745 })
1746 }
1747
1748 fn relocate_signature(&self, sig: &mut OpenSignatureBody) -> Result<()> {
1753 use OpenSignatureBody as O;
1754
1755 match sig {
1756 O::Address | O::Bool | O::U8 | O::U16 | O::U32 | O::U64 | O::U128 | O::U256 => {
1757 }
1759
1760 O::TypeParameter(_) => { }
1761
1762 O::Vector(sig) => self.relocate_signature(sig.as_mut())?,
1763
1764 O::Datatype(key, params) => {
1765 let defining_id = &self.datatypes[key].defining_id;
1767 for param in params {
1768 self.relocate_signature(param)?;
1769 }
1770
1771 key.package = *defining_id;
1772 }
1773 }
1774
1775 Ok(())
1776 }
1777}
1778
1779impl<'s> From<&'s StructTag> for DatatypeRef<'s, 's> {
1780 fn from(tag: &'s StructTag) -> Self {
1781 DatatypeRef {
1782 package: tag.address,
1783 module: tag.module.as_str().into(),
1784 name: tag.name.as_str().into(),
1785 }
1786 }
1787}
1788
1789fn ident(s: &str) -> Result<Identifier> {
1792 Identifier::new(s).map_err(|_| Error::NotAnIdentifier(s.to_string()))
1793}
1794
1795pub fn as_type_tag(type_input: &TypeInput) -> Result<TypeTag> {
1796 use TypeInput as I;
1798 use TypeTag as T;
1799 Ok(match type_input {
1800 I::Bool => T::Bool,
1801 I::U8 => T::U8,
1802 I::U16 => T::U16,
1803 I::U32 => T::U32,
1804 I::U64 => T::U64,
1805 I::U128 => T::U128,
1806 I::U256 => T::U256,
1807 I::Address => T::Address,
1808 I::Signer => T::Signer,
1809 I::Vector(t) => T::Vector(Box::new(as_type_tag(t)?)),
1810 I::Struct(s) => {
1811 let StructInput {
1812 address,
1813 module,
1814 name,
1815 type_params,
1816 } = s.as_ref();
1817 let type_params = type_params.iter().map(as_type_tag).collect::<Result<_>>()?;
1818 T::Struct(Box::new(StructTag {
1819 address: *address,
1820 module: ident(module)?,
1821 name: ident(name)?,
1822 type_params,
1823 }))
1824 }
1825 })
1826}
1827
1828fn read_signature(idx: SignatureIndex, bytecode: &CompiledModule) -> Result<Vec<OpenSignature>> {
1831 let MoveSignature(tokens) = bytecode.signature_at(idx);
1832 let mut sigs = Vec::with_capacity(tokens.len());
1833
1834 for token in tokens {
1835 sigs.push(OpenSignature::read(token, bytecode)?);
1836 }
1837
1838 Ok(sigs)
1839}
1840
1841#[cfg(test)]
1842mod tests {
1843 use std::{
1844 path::PathBuf,
1845 str::FromStr,
1846 sync::{Arc, RwLock},
1847 };
1848
1849 use async_trait::async_trait;
1850 use iota_move_build::{BuildConfig, CompiledPackage};
1851 use iota_types::{base_types::random_object_ref, error::IotaResult, transaction::ObjectArg};
1852 use move_binary_format::file_format::Ability;
1853 use move_compiler::compiled_unit::NamedCompiledModule;
1854 use move_core_types::ident_str;
1855
1856 use super::*;
1857
1858 fn fmt(struct_layout: MoveTypeLayout, enum_layout: MoveTypeLayout) -> String {
1859 format!("struct:\n{struct_layout:#}\n\nenum:\n{enum_layout:#}",)
1860 }
1861
1862 #[tokio::test]
1863 async fn test_simple_canonical_type() {
1864 let (_, cache) = package_cache([(1, build_package("a0").unwrap(), a0_types())]);
1865 let package_resolver = Resolver::new(cache);
1866
1867 let input = type_("0xa0::m::T0");
1868 let expect = input.clone();
1869 let actual = package_resolver.canonical_type(input).await.unwrap();
1870 assert_eq!(expect, actual);
1871 }
1872
1873 #[tokio::test]
1874 async fn test_upgraded_canonical_type() {
1875 let (_, cache) = package_cache([
1876 (1, build_package("a0").unwrap(), a0_types()),
1877 (2, build_package("a1").unwrap(), a1_types()),
1878 ]);
1879
1880 let package_resolver = Resolver::new(cache);
1881
1882 let input = type_("0xa1::m::T3");
1883 let expect = input.clone();
1884 let actual = package_resolver.canonical_type(input).await.unwrap();
1885 assert_eq!(expect, actual);
1886 }
1887
1888 #[tokio::test]
1889 async fn test_latest_canonical_type() {
1890 let (_, cache) = package_cache([
1891 (1, build_package("a0").unwrap(), a0_types()),
1892 (2, build_package("a1").unwrap(), a1_types()),
1893 ]);
1894
1895 let package_resolver = Resolver::new(cache);
1896
1897 let input = type_("0xa1::m::T0");
1898 let expect = type_("0xa0::m::T0");
1899 let actual = package_resolver.canonical_type(input).await.unwrap();
1900 assert_eq!(expect, actual);
1901 }
1902
1903 #[tokio::test]
1904 async fn test_type_param_canonical_type() {
1905 let (_, cache) = package_cache([
1906 (1, build_package("a0").unwrap(), a0_types()),
1907 (2, build_package("a1").unwrap(), a1_types()),
1908 ]);
1909
1910 let package_resolver = Resolver::new(cache);
1911
1912 let input = type_("0xa1::m::T1<0xa1::m::T0, 0xa1::m::T3>");
1913 let expect = type_("0xa0::m::T1<0xa0::m::T0, 0xa1::m::T3>");
1914 let actual = package_resolver.canonical_type(input).await.unwrap();
1915 assert_eq!(expect, actual);
1916 }
1917
1918 #[tokio::test]
1919 async fn test_canonical_err_package_too_old() {
1920 let (_, cache) = package_cache([
1921 (1, build_package("a0").unwrap(), a0_types()),
1922 (2, build_package("a1").unwrap(), a1_types()),
1923 ]);
1924
1925 let package_resolver = Resolver::new(cache);
1926
1927 let input = type_("0xa0::m::T3");
1928 let err = package_resolver.canonical_type(input).await.unwrap_err();
1929 assert!(matches!(err, Error::DatatypeNotFound(_, _, _)));
1930 }
1931
1932 #[tokio::test]
1933 async fn test_canonical_err_signer() {
1934 let (_, cache) = package_cache([(1, build_package("a0").unwrap(), a0_types())]);
1935
1936 let package_resolver = Resolver::new(cache);
1937
1938 let input = type_("0xa0::m::T1<0xa0::m::T0, signer>");
1939 let err = package_resolver.canonical_type(input).await.unwrap_err();
1940 assert!(matches!(err, Error::UnexpectedSigner));
1941 }
1942
1943 #[tokio::test]
1946 async fn test_simple_type_layout() {
1947 let (_, cache) = package_cache([(1, build_package("a0").unwrap(), a0_types())]);
1948 let package_resolver = Resolver::new(cache);
1949 let struct_layout = package_resolver
1950 .type_layout(type_("0xa0::m::T0"))
1951 .await
1952 .unwrap();
1953 let enum_layout = package_resolver
1954 .type_layout(type_("0xa0::m::E0"))
1955 .await
1956 .unwrap();
1957 insta::assert_snapshot!(fmt(struct_layout, enum_layout));
1958 }
1959
1960 #[tokio::test]
1962 async fn test_cross_module_layout() {
1963 let (_, cache) = package_cache([(1, build_package("a0").unwrap(), a0_types())]);
1964 let resolver = Resolver::new(cache);
1965 let struct_layout = resolver.type_layout(type_("0xa0::n::T0")).await.unwrap();
1966 let enum_layout = resolver.type_layout(type_("0xa0::n::E0")).await.unwrap();
1967 insta::assert_snapshot!(fmt(struct_layout, enum_layout));
1968 }
1969
1970 #[tokio::test]
1972 async fn test_cross_package_layout() {
1973 let (_, cache) = package_cache([
1974 (1, build_package("a0").unwrap(), a0_types()),
1975 (1, build_package("b0").unwrap(), b0_types()),
1976 ]);
1977 let resolver = Resolver::new(cache);
1978
1979 let struct_layout = resolver.type_layout(type_("0xb0::m::T0")).await.unwrap();
1980 let enum_layout = resolver.type_layout(type_("0xb0::m::E0")).await.unwrap();
1981 insta::assert_snapshot!(fmt(struct_layout, enum_layout));
1982 }
1983
1984 #[tokio::test]
1987 async fn test_upgraded_package_layout() {
1988 let (_, cache) = package_cache([
1989 (1, build_package("a0").unwrap(), a0_types()),
1990 (2, build_package("a1").unwrap(), a1_types()),
1991 ]);
1992 let resolver = Resolver::new(cache);
1993
1994 let struct_layout = resolver.type_layout(type_("0xa1::n::T1")).await.unwrap();
1995 let enum_layout = resolver.type_layout(type_("0xa1::n::E1")).await.unwrap();
1996 insta::assert_snapshot!(fmt(struct_layout, enum_layout));
1997 }
1998
1999 #[tokio::test]
2003 async fn test_multiple_linkage_contexts_layout() {
2004 let (_, cache) = package_cache([
2005 (1, build_package("a0").unwrap(), a0_types()),
2006 (2, build_package("a1").unwrap(), a1_types()),
2007 ]);
2008 let resolver = Resolver::new(cache);
2009
2010 let struct_layout = resolver
2011 .type_layout(type_("0xa0::m::T1<0xa0::m::T0, 0xa1::m::T3>"))
2012 .await
2013 .unwrap();
2014 let enum_layout = resolver
2015 .type_layout(type_("0xa0::m::E1<0xa0::m::E0, 0xa1::m::E3>"))
2016 .await
2017 .unwrap();
2018 insta::assert_snapshot!(fmt(struct_layout, enum_layout));
2019 }
2020
2021 #[tokio::test]
2027 async fn test_upgraded_package_non_defining_id_layout() {
2028 let (_, cache) = package_cache([
2029 (1, build_package("a0").unwrap(), a0_types()),
2030 (2, build_package("a1").unwrap(), a1_types()),
2031 ]);
2032 let resolver = Resolver::new(cache);
2033
2034 let struct_layout = resolver
2035 .type_layout(type_("0xa1::m::T1<0xa1::m::T3, 0xa1::m::T0>"))
2036 .await
2037 .unwrap();
2038 let enum_layout = resolver
2039 .type_layout(type_("0xa1::m::E1<0xa1::m::E3, 0xa1::m::E0>"))
2040 .await
2041 .unwrap();
2042 insta::assert_snapshot!(fmt(struct_layout, enum_layout));
2043 }
2044
2045 #[tokio::test]
2049 async fn test_relinking_layout() {
2050 let (_, cache) = package_cache([
2051 (1, build_package("a0").unwrap(), a0_types()),
2052 (2, build_package("a1").unwrap(), a1_types()),
2053 (1, build_package("b0").unwrap(), b0_types()),
2054 (1, build_package("c0").unwrap(), c0_types()),
2055 ]);
2056 let resolver = Resolver::new(cache);
2057
2058 let struct_layout = resolver.type_layout(type_("0xc0::m::T0")).await.unwrap();
2059 let enum_layout = resolver.type_layout(type_("0xc0::m::E0")).await.unwrap();
2060 insta::assert_snapshot!(fmt(struct_layout, enum_layout));
2061 }
2062
2063 #[tokio::test]
2064 async fn test_value_nesting_boundary_layout() {
2065 let (_, cache) = package_cache([(1, build_package("a0").unwrap(), a0_types())]);
2066
2067 let resolver = Resolver::new_with_limits(
2068 cache,
2069 Limits {
2070 max_type_argument_width: 100,
2071 max_type_argument_depth: 100,
2072 max_type_nodes: 100,
2073 max_move_value_depth: 3,
2074 },
2075 );
2076
2077 let struct_layout = resolver
2079 .type_layout(type_("0xa0::m::T1<u8, u8>"))
2080 .await
2081 .unwrap();
2082 let enum_layout = resolver
2083 .type_layout(type_("0xa0::m::E1<u8, u8>"))
2084 .await
2085 .unwrap();
2086 insta::assert_snapshot!(fmt(struct_layout, enum_layout));
2087 }
2088
2089 #[tokio::test]
2090 async fn test_err_value_nesting_simple_layout() {
2091 let (_, cache) = package_cache([(1, build_package("a0").unwrap(), a0_types())]);
2092
2093 let resolver = Resolver::new_with_limits(
2094 cache,
2095 Limits {
2096 max_type_argument_width: 100,
2097 max_type_argument_depth: 100,
2098 max_type_nodes: 100,
2099 max_move_value_depth: 2,
2100 },
2101 );
2102
2103 let struct_err = resolver
2105 .type_layout(type_("0xa0::m::T1<u8, u8>"))
2106 .await
2107 .unwrap_err();
2108 let enum_err = resolver
2109 .type_layout(type_("0xa0::m::E1<u8, u8>"))
2110 .await
2111 .unwrap_err();
2112 assert!(matches!(struct_err, Error::ValueNesting(2)));
2113 assert!(matches!(enum_err, Error::ValueNesting(2)));
2114 }
2115
2116 #[tokio::test]
2117 async fn test_err_value_nesting_big_type_param_layout() {
2118 let (_, cache) = package_cache([(1, build_package("a0").unwrap(), a0_types())]);
2119
2120 let resolver = Resolver::new_with_limits(
2121 cache,
2122 Limits {
2123 max_type_argument_width: 100,
2124 max_type_argument_depth: 100,
2125 max_type_nodes: 100,
2126 max_move_value_depth: 3,
2127 },
2128 );
2129
2130 let struct_err = resolver
2134 .type_layout(type_("0xa0::m::T1<vector<vector<u8>>, u8>"))
2135 .await
2136 .unwrap_err();
2137 let enum_err = resolver
2138 .type_layout(type_("0xa0::m::E1<vector<vector<u8>>, u8>"))
2139 .await
2140 .unwrap_err();
2141 assert!(matches!(struct_err, Error::ValueNesting(3)));
2142 assert!(matches!(enum_err, Error::ValueNesting(3)));
2143 }
2144
2145 #[tokio::test]
2146 async fn test_err_value_nesting_big_phantom_type_param_layout() {
2147 let (_, cache) = package_cache([
2148 (1, build_package("iota").unwrap(), iota_types()),
2149 (1, build_package("d0").unwrap(), d0_types()),
2150 ]);
2151
2152 let resolver = Resolver::new_with_limits(
2153 cache,
2154 Limits {
2155 max_type_argument_width: 100,
2156 max_type_argument_depth: 100,
2157 max_type_nodes: 100,
2158 max_move_value_depth: 3,
2159 },
2160 );
2161
2162 let _ = resolver
2164 .type_layout(type_("0xd0::m::O<u8, u8>"))
2165 .await
2166 .unwrap();
2167 let _ = resolver
2168 .type_layout(type_("0xd0::m::EO<u8, u8>"))
2169 .await
2170 .unwrap();
2171
2172 let struct_err = resolver
2177 .type_layout(type_("0xd0::m::O<u8, vector<vector<u8>>>"))
2178 .await
2179 .unwrap_err();
2180 let enum_err = resolver
2181 .type_layout(type_("0xd0::m::EO<u8, vector<vector<u8>>>"))
2182 .await
2183 .unwrap_err();
2184 assert!(matches!(struct_err, Error::ValueNesting(3)));
2185 assert!(matches!(enum_err, Error::ValueNesting(3)));
2186 }
2187
2188 #[tokio::test]
2189 async fn test_err_value_nesting_type_param_application_layout() {
2190 let (_, cache) = package_cache([
2191 (1, build_package("iota").unwrap(), iota_types()),
2192 (1, build_package("d0").unwrap(), d0_types()),
2193 ]);
2194
2195 let resolver = Resolver::new_with_limits(
2196 cache,
2197 Limits {
2198 max_type_argument_width: 100,
2199 max_type_argument_depth: 100,
2200 max_type_nodes: 100,
2201 max_move_value_depth: 3,
2202 },
2203 );
2204
2205 let struct_err = resolver
2209 .type_layout(type_("0xd0::m::O<vector<u8>, u8>"))
2210 .await
2211 .unwrap_err();
2212 let enum_err = resolver
2213 .type_layout(type_("0xd0::m::EO<vector<u8>, u8>"))
2214 .await
2215 .unwrap_err();
2216
2217 assert!(matches!(struct_err, Error::ValueNesting(3)));
2218 assert!(matches!(enum_err, Error::ValueNesting(3)));
2219 }
2220
2221 #[tokio::test]
2222 async fn test_system_package_invalidation() {
2223 let (inner, cache) = package_cache([(1, build_package("s0").unwrap(), s0_types())]);
2224 let resolver = Resolver::new(cache);
2225
2226 let struct_not_found = resolver.type_layout(type_("0x1::m::T1")).await.unwrap_err();
2227 let enum_not_found = resolver.type_layout(type_("0x1::m::E1")).await.unwrap_err();
2228 assert!(matches!(struct_not_found, Error::DatatypeNotFound(_, _, _)));
2229 assert!(matches!(enum_not_found, Error::DatatypeNotFound(_, _, _)));
2230
2231 inner.write().unwrap().replace(
2233 addr("0x1"),
2234 cached_package(
2235 2,
2236 BTreeMap::new(),
2237 &build_package("s1").unwrap(),
2238 &s1_types(),
2239 ),
2240 );
2241
2242 resolver.package_store().evict([addr("0x1")]);
2244
2245 let struct_layout = resolver.type_layout(type_("0x1::m::T1")).await.unwrap();
2246 let enum_layout = resolver.type_layout(type_("0x1::m::E1")).await.unwrap();
2247 insta::assert_snapshot!(fmt(struct_layout, enum_layout));
2248 }
2249
2250 #[tokio::test]
2251 async fn test_caching() {
2252 let (inner, cache) = package_cache([
2253 (1, build_package("a0").unwrap(), a0_types()),
2254 (1, build_package("s0").unwrap(), s0_types()),
2255 ]);
2256 let resolver = Resolver::new(cache);
2257
2258 assert_eq!(inner.read().unwrap().fetches, 0);
2259 let l0 = resolver.type_layout(type_("0xa0::m::T0")).await.unwrap();
2260
2261 assert_eq!(inner.read().unwrap().fetches, 1);
2263
2264 let l1 = resolver.type_layout(type_("0xa0::m::T0")).await.unwrap();
2266 assert_eq!(format!("{l0}"), format!("{l1}"));
2267 assert_eq!(inner.read().unwrap().fetches, 1);
2268
2269 let l2 = resolver.type_layout(type_("0xa0::m::T2")).await.unwrap();
2271 assert_ne!(format!("{l0}"), format!("{l2}"));
2272 assert_eq!(inner.read().unwrap().fetches, 1);
2273
2274 resolver.type_layout(type_("0xa0::m::E0")).await.unwrap();
2276 assert_eq!(inner.read().unwrap().fetches, 1);
2277
2278 let l3 = resolver.type_layout(type_("0x1::m::T0")).await.unwrap();
2280 assert_eq!(inner.read().unwrap().fetches, 2);
2281
2282 let l4 = resolver.type_layout(type_("0x1::m::T0")).await.unwrap();
2284 assert_eq!(format!("{l3}"), format!("{l4}"));
2285 assert_eq!(inner.read().unwrap().fetches, 2);
2286
2287 let el4 = resolver.type_layout(type_("0x1::m::E0")).await.unwrap();
2289 assert_ne!(format!("{el4}"), format!("{l4}"));
2290 assert_eq!(inner.read().unwrap().fetches, 2);
2291
2292 inner.write().unwrap().replace(
2294 addr("0x1"),
2295 cached_package(
2296 2,
2297 BTreeMap::new(),
2298 &build_package("s1").unwrap(),
2299 &s1_types(),
2300 ),
2301 );
2302
2303 resolver.package_store().evict([addr("0x1")]);
2305
2306 let l5 = resolver.type_layout(type_("0x1::m::T0")).await.unwrap();
2311 assert_eq!(format!("{l4}"), format!("{l5}"));
2312 assert_eq!(inner.read().unwrap().fetches, 3);
2313 }
2314
2315 #[tokio::test]
2316 async fn test_layout_err_not_a_package() {
2317 let (_, cache) = package_cache([(1, build_package("a0").unwrap(), a0_types())]);
2318 let resolver = Resolver::new(cache);
2319 let err = resolver
2320 .type_layout(type_("0x42::m::T0"))
2321 .await
2322 .unwrap_err();
2323 assert!(matches!(err, Error::PackageNotFound(_)));
2324 }
2325
2326 #[tokio::test]
2327 async fn test_layout_err_no_module() {
2328 let (_, cache) = package_cache([(1, build_package("a0").unwrap(), a0_types())]);
2329 let resolver = Resolver::new(cache);
2330 let err = resolver
2331 .type_layout(type_("0xa0::l::T0"))
2332 .await
2333 .unwrap_err();
2334 assert!(matches!(err, Error::ModuleNotFound(_, _)));
2335 }
2336
2337 #[tokio::test]
2338 async fn test_layout_err_no_struct() {
2339 let (_, cache) = package_cache([(1, build_package("a0").unwrap(), a0_types())]);
2340 let resolver = Resolver::new(cache);
2341
2342 let err = resolver
2343 .type_layout(type_("0xa0::m::T9"))
2344 .await
2345 .unwrap_err();
2346 assert!(matches!(err, Error::DatatypeNotFound(_, _, _)));
2347 }
2348
2349 #[tokio::test]
2350 async fn test_layout_err_type_arity() {
2351 let (_, cache) = package_cache([(1, build_package("a0").unwrap(), a0_types())]);
2352 let resolver = Resolver::new(cache);
2353
2354 let err = resolver
2356 .type_layout(type_("0xa0::m::T1<u8>"))
2357 .await
2358 .unwrap_err();
2359 assert!(matches!(err, Error::TypeArityMismatch(2, 1)));
2360
2361 let err = resolver
2363 .type_layout(type_("0xa0::m::T1<u8, u16, u32>"))
2364 .await
2365 .unwrap_err();
2366 assert!(matches!(err, Error::TypeArityMismatch(2, 3)));
2367 }
2368
2369 #[tokio::test]
2370 async fn test_structs() {
2371 let (_, cache) = package_cache([(1, build_package("a0").unwrap(), a0_types())]);
2372 let a0 = cache.fetch(addr("0xa0")).await.unwrap();
2373 let m = a0.module("m").unwrap();
2374
2375 assert_eq!(
2376 m.structs(None, None).collect::<Vec<_>>(),
2377 vec!["T0", "T1", "T2"],
2378 );
2379
2380 assert_eq!(m.structs(None, Some("T1")).collect::<Vec<_>>(), vec!["T0"],);
2381
2382 assert_eq!(
2383 m.structs(Some("T0"), Some("T2")).collect::<Vec<_>>(),
2384 vec!["T1"],
2385 );
2386
2387 assert_eq!(m.structs(Some("T1"), None).collect::<Vec<_>>(), vec!["T2"],);
2388
2389 let t0 = m.struct_def("T0").unwrap().unwrap();
2390 let t1 = m.struct_def("T1").unwrap().unwrap();
2391 let t2 = m.struct_def("T2").unwrap().unwrap();
2392
2393 insta::assert_snapshot!(format!(
2394 "a0::m::T0: {t0:#?}\n\
2395 a0::m::T1: {t1:#?}\n\
2396 a0::m::T2: {t2:#?}",
2397 ));
2398 }
2399
2400 #[tokio::test]
2401 async fn test_enums() {
2402 let (_, cache) = package_cache([(1, build_package("a0").unwrap(), a0_types())]);
2403 let a0 = cache
2404 .fetch(AccountAddress::from_str("0xa0").unwrap())
2405 .await
2406 .unwrap();
2407 let m = a0.module("m").unwrap();
2408
2409 assert_eq!(
2410 m.enums(None, None).collect::<Vec<_>>(),
2411 vec!["E0", "E1", "E2"],
2412 );
2413
2414 assert_eq!(m.enums(None, Some("E1")).collect::<Vec<_>>(), vec!["E0"],);
2415
2416 assert_eq!(
2417 m.enums(Some("E0"), Some("E2")).collect::<Vec<_>>(),
2418 vec!["E1"],
2419 );
2420
2421 assert_eq!(m.enums(Some("E1"), None).collect::<Vec<_>>(), vec!["E2"],);
2422
2423 let e0 = m.enum_def("E0").unwrap().unwrap();
2424 let e1 = m.enum_def("E1").unwrap().unwrap();
2425 let e2 = m.enum_def("E2").unwrap().unwrap();
2426
2427 insta::assert_snapshot!(format!(
2428 "a0::m::E0: {e0:#?}\n\
2429 a0::m::E1: {e1:#?}\n\
2430 a0::m::E2: {e2:#?}",
2431 ));
2432 }
2433
2434 #[tokio::test]
2435 async fn test_functions() {
2436 let (_, cache) = package_cache([
2437 (1, build_package("a0").unwrap(), a0_types()),
2438 (2, build_package("a1").unwrap(), a1_types()),
2439 (1, build_package("b0").unwrap(), b0_types()),
2440 (1, build_package("c0").unwrap(), c0_types()),
2441 ]);
2442
2443 let c0 = cache.fetch(addr("0xc0")).await.unwrap();
2444 let m = c0.module("m").unwrap();
2445
2446 assert_eq!(
2447 m.functions(None, None).collect::<Vec<_>>(),
2448 vec!["bar", "baz", "foo"],
2449 );
2450
2451 assert_eq!(
2452 m.functions(None, Some("baz")).collect::<Vec<_>>(),
2453 vec!["bar"],
2454 );
2455
2456 assert_eq!(
2457 m.functions(Some("bar"), Some("foo")).collect::<Vec<_>>(),
2458 vec!["baz"],
2459 );
2460
2461 assert_eq!(
2462 m.functions(Some("baz"), None).collect::<Vec<_>>(),
2463 vec!["foo"],
2464 );
2465
2466 let foo = m.function_def("foo").unwrap().unwrap();
2467 let bar = m.function_def("bar").unwrap().unwrap();
2468 let baz = m.function_def("baz").unwrap().unwrap();
2469
2470 insta::assert_snapshot!(format!(
2471 "c0::m::foo: {foo:#?}\n\
2472 c0::m::bar: {bar:#?}\n\
2473 c0::m::baz: {baz:#?}"
2474 ));
2475 }
2476
2477 #[tokio::test]
2478 async fn test_function_parameters() {
2479 let (_, cache) = package_cache([
2480 (1, build_package("a0").unwrap(), a0_types()),
2481 (2, build_package("a1").unwrap(), a1_types()),
2482 (1, build_package("b0").unwrap(), b0_types()),
2483 (1, build_package("c0").unwrap(), c0_types()),
2484 ]);
2485
2486 let resolver = Resolver::new(cache);
2487 let c0 = addr("0xc0");
2488
2489 let foo = resolver.function_signature(c0, "m", "foo").await.unwrap();
2490 let bar = resolver.function_signature(c0, "m", "bar").await.unwrap();
2491 let baz = resolver.function_signature(c0, "m", "baz").await.unwrap();
2492
2493 insta::assert_snapshot!(format!(
2494 "c0::m::foo: {foo:#?}\n\
2495 c0::m::bar: {bar:#?}\n\
2496 c0::m::baz: {baz:#?}"
2497 ));
2498 }
2499
2500 #[tokio::test]
2501 async fn test_signature_instantiation() {
2502 use OpenSignatureBody as O;
2503 use TypeInput as T;
2504
2505 let sig = O::Datatype(
2506 key("0x2::table::Table"),
2507 vec![
2508 O::TypeParameter(1),
2509 O::Vector(Box::new(O::Datatype(
2510 key("0x1::option::Option"),
2511 vec![O::TypeParameter(0)],
2512 ))),
2513 ],
2514 );
2515
2516 insta::assert_debug_snapshot!(sig.instantiate(&[T::U64, T::Bool]).unwrap());
2517 }
2518
2519 #[tokio::test]
2520 async fn test_signature_instantiation_error() {
2521 use OpenSignatureBody as O;
2522 use TypeInput as T;
2523
2524 let sig = O::Datatype(
2525 key("0x2::table::Table"),
2526 vec![
2527 O::TypeParameter(1),
2528 O::Vector(Box::new(O::Datatype(
2529 key("0x1::option::Option"),
2530 vec![O::TypeParameter(99)],
2531 ))),
2532 ],
2533 );
2534
2535 insta::assert_snapshot!(
2536 sig.instantiate(&[T::U64, T::Bool]).unwrap_err(),
2537 @"Type Parameter 99 out of bounds (2)"
2538 );
2539 }
2540
2541 #[tokio::test]
2543 async fn test_primitive_abilities() {
2544 use Ability as A;
2545 use AbilitySet as S;
2546
2547 let (_, cache) = package_cache([]);
2548 let resolver = Resolver::new(cache);
2549
2550 for prim in ["address", "bool", "u8", "u16", "u32", "u64", "u128", "u256"] {
2551 assert_eq!(
2552 resolver.abilities(type_(prim)).await.unwrap(),
2553 S::EMPTY | A::Copy | A::Drop | A::Store,
2554 "Unexpected primitive abilities for: {prim}",
2555 );
2556 }
2557 }
2558
2559 #[tokio::test]
2561 async fn test_simple_generic_abilities() {
2562 use Ability as A;
2563 use AbilitySet as S;
2564
2565 let (_, cache) = package_cache([
2566 (1, build_package("iota").unwrap(), iota_types()),
2567 (1, build_package("d0").unwrap(), d0_types()),
2568 ]);
2569 let resolver = Resolver::new(cache);
2570
2571 let a1 = resolver
2572 .abilities(type_("0xd0::m::T<u32, u64>"))
2573 .await
2574 .unwrap();
2575 assert_eq!(a1, S::EMPTY | A::Copy | A::Drop | A::Store);
2576
2577 let a2 = resolver
2578 .abilities(type_("0xd0::m::T<0xd0::m::S, u64>"))
2579 .await
2580 .unwrap();
2581 assert_eq!(a2, S::EMPTY | A::Drop | A::Store);
2582
2583 let a3 = resolver
2584 .abilities(type_("0xd0::m::T<0xd0::m::R, 0xd0::m::S>"))
2585 .await
2586 .unwrap();
2587 assert_eq!(a3, S::EMPTY | A::Drop);
2588
2589 let a4 = resolver
2590 .abilities(type_("0xd0::m::T<0xd0::m::Q, 0xd0::m::R>"))
2591 .await
2592 .unwrap();
2593 assert_eq!(a4, S::EMPTY);
2594 }
2595
2596 #[tokio::test]
2598 async fn test_nested_generic_abilities() {
2599 use Ability as A;
2600 use AbilitySet as S;
2601
2602 let (_, cache) = package_cache([
2603 (1, build_package("iota").unwrap(), iota_types()),
2604 (1, build_package("d0").unwrap(), d0_types()),
2605 ]);
2606 let resolver = Resolver::new(cache);
2607
2608 let a1 = resolver
2609 .abilities(type_("0xd0::m::T<0xd0::m::T<0xd0::m::R, u32>, u64>"))
2610 .await
2611 .unwrap();
2612 assert_eq!(a1, S::EMPTY | A::Copy | A::Drop);
2613 }
2614
2615 #[tokio::test]
2618 async fn test_key_abilities() {
2619 use Ability as A;
2620 use AbilitySet as S;
2621
2622 let (_, cache) = package_cache([
2623 (1, build_package("iota").unwrap(), iota_types()),
2624 (1, build_package("d0").unwrap(), d0_types()),
2625 ]);
2626 let resolver = Resolver::new(cache);
2627
2628 let a1 = resolver
2629 .abilities(type_("0xd0::m::O<u32, u64>"))
2630 .await
2631 .unwrap();
2632 assert_eq!(a1, S::EMPTY | A::Key | A::Store);
2633
2634 let a2 = resolver
2635 .abilities(type_("0xd0::m::O<0xd0::m::S, u64>"))
2636 .await
2637 .unwrap();
2638 assert_eq!(a2, S::EMPTY | A::Key | A::Store);
2639
2640 let a3 = resolver
2643 .abilities(type_("0xd0::m::O<0xd0::m::R, u64>"))
2644 .await
2645 .unwrap();
2646 assert_eq!(a3, S::EMPTY);
2647
2648 let a4 = resolver
2650 .abilities(type_("0xd0::m::O<0xd0::m::P, u32>"))
2651 .await
2652 .unwrap();
2653 assert_eq!(a4, S::EMPTY);
2654 }
2655
2656 #[tokio::test]
2658 async fn test_phantom_abilities() {
2659 use Ability as A;
2660 use AbilitySet as S;
2661
2662 let (_, cache) = package_cache([
2663 (1, build_package("iota").unwrap(), iota_types()),
2664 (1, build_package("d0").unwrap(), d0_types()),
2665 ]);
2666 let resolver = Resolver::new(cache);
2667
2668 let a1 = resolver
2669 .abilities(type_("0xd0::m::O<u32, 0xd0::m::R>"))
2670 .await
2671 .unwrap();
2672 assert_eq!(a1, S::EMPTY | A::Key | A::Store);
2673 }
2674
2675 #[tokio::test]
2676 async fn test_err_ability_arity() {
2677 let (_, cache) = package_cache([
2678 (1, build_package("iota").unwrap(), iota_types()),
2679 (1, build_package("d0").unwrap(), d0_types()),
2680 ]);
2681 let resolver = Resolver::new(cache);
2682
2683 let err = resolver
2685 .abilities(type_("0xd0::m::T<u8>"))
2686 .await
2687 .unwrap_err();
2688 assert!(matches!(err, Error::TypeArityMismatch(2, 1)));
2689
2690 let err = resolver
2692 .abilities(type_("0xd0::m::T<u8, u16, u32>"))
2693 .await
2694 .unwrap_err();
2695 assert!(matches!(err, Error::TypeArityMismatch(2, 3)));
2696 }
2697
2698 #[tokio::test]
2699 async fn test_err_ability_signer() {
2700 let (_, cache) = package_cache([]);
2701 let resolver = Resolver::new(cache);
2702
2703 let err = resolver.abilities(type_("signer")).await.unwrap_err();
2704 assert!(matches!(err, Error::UnexpectedSigner));
2705 }
2706
2707 #[tokio::test]
2708 async fn test_err_too_many_type_params() {
2709 let (_, cache) = package_cache([
2710 (1, build_package("iota").unwrap(), iota_types()),
2711 (1, build_package("d0").unwrap(), d0_types()),
2712 ]);
2713
2714 let resolver = Resolver::new_with_limits(
2715 cache,
2716 Limits {
2717 max_type_argument_width: 1,
2718 max_type_argument_depth: 100,
2719 max_type_nodes: 100,
2720 max_move_value_depth: 100,
2721 },
2722 );
2723
2724 let err = resolver
2725 .abilities(type_("0xd0::m::O<u32, u64>"))
2726 .await
2727 .unwrap_err();
2728 assert!(matches!(err, Error::TooManyTypeParams(1, 2)));
2729 }
2730
2731 #[tokio::test]
2732 async fn test_err_too_many_type_nodes() {
2733 use Ability as A;
2734 use AbilitySet as S;
2735
2736 let (_, cache) = package_cache([
2737 (1, build_package("iota").unwrap(), iota_types()),
2738 (1, build_package("d0").unwrap(), d0_types()),
2739 ]);
2740
2741 let resolver = Resolver::new_with_limits(
2742 cache,
2743 Limits {
2744 max_type_argument_width: 100,
2745 max_type_argument_depth: 100,
2746 max_type_nodes: 2,
2747 max_move_value_depth: 100,
2748 },
2749 );
2750
2751 let a1 = resolver
2754 .abilities(type_("0xd0::m::O<0xd0::m::S, 0xd0::m::Q>"))
2755 .await
2756 .unwrap();
2757 assert_eq!(a1, S::EMPTY | A::Key | A::Store);
2758
2759 let err = resolver
2761 .abilities(type_("0xd0::m::T<0xd0::m::P, 0xd0::m::Q>"))
2762 .await
2763 .unwrap_err();
2764 assert!(matches!(err, Error::TooManyTypeNodes(2, _)));
2765 }
2766
2767 #[tokio::test]
2768 async fn test_err_type_param_nesting() {
2769 use Ability as A;
2770 use AbilitySet as S;
2771
2772 let (_, cache) = package_cache([
2773 (1, build_package("iota").unwrap(), iota_types()),
2774 (1, build_package("d0").unwrap(), d0_types()),
2775 ]);
2776
2777 let resolver = Resolver::new_with_limits(
2778 cache,
2779 Limits {
2780 max_type_argument_width: 100,
2781 max_type_argument_depth: 2,
2782 max_type_nodes: 100,
2783 max_move_value_depth: 100,
2784 },
2785 );
2786
2787 let a1 = resolver
2790 .abilities(type_(
2791 "0xd0::m::O<0xd0::m::S, 0xd0::m::T<vector<u32>, vector<u64>>>",
2792 ))
2793 .await
2794 .unwrap();
2795 assert_eq!(a1, S::EMPTY | A::Key | A::Store);
2796
2797 let err = resolver
2799 .abilities(type_("vector<0xd0::m::T<0xd0::m::O<u64, u32>, u16>>"))
2800 .await
2801 .unwrap_err();
2802 assert!(matches!(err, Error::TypeParamNesting(2, _)));
2803 }
2804
2805 #[tokio::test]
2806 async fn test_pure_input_layouts() {
2807 use CallArg as I;
2808 use ObjectArg::ImmOrOwnedObject as O;
2809 use TypeTag as T;
2810
2811 let (_, cache) = package_cache([
2812 (1, build_package("std").unwrap(), std_types()),
2813 (1, build_package("iota").unwrap(), iota_types()),
2814 (1, build_package("e0").unwrap(), e0_types()),
2815 ]);
2816
2817 let resolver = Resolver::new(cache);
2818
2819 fn ptb(t: TypeTag, y: CallArg) -> ProgrammableTransaction {
2821 ProgrammableTransaction {
2822 inputs: vec![
2823 I::Object(O(random_object_ref())),
2824 I::Pure(bcs::to_bytes(&42u64).unwrap()),
2825 I::Object(O(random_object_ref())),
2826 y,
2827 I::Object(O(random_object_ref())),
2828 I::Pure(bcs::to_bytes("hello").unwrap()),
2829 I::Pure(bcs::to_bytes("world").unwrap()),
2830 ],
2831 commands: vec![Command::move_call(
2832 addr("0xe0").into(),
2833 ident_str!("m").to_owned(),
2834 ident_str!("foo").to_owned(),
2835 vec![t],
2836 (0..=6).map(Argument::Input).collect(),
2837 )],
2838 }
2839 }
2840
2841 let ptb_u64 = ptb(T::U64, I::Pure(bcs::to_bytes(&1u64).unwrap()));
2842
2843 let ptb_opt = ptb(
2844 TypeTag::Struct(Box::new(StructTag {
2845 address: addr("0x1"),
2846 module: ident_str!("option").to_owned(),
2847 name: ident_str!("Option").to_owned(),
2848 type_params: vec![TypeTag::U64],
2849 })),
2850 I::Pure(bcs::to_bytes(&[vec![1u64], vec![], vec![3]]).unwrap()),
2851 );
2852
2853 let ptb_obj = ptb(
2854 TypeTag::Struct(Box::new(StructTag {
2855 address: addr("0xe0"),
2856 module: ident_str!("m").to_owned(),
2857 name: ident_str!("O").to_owned(),
2858 type_params: vec![],
2859 })),
2860 I::Object(O(random_object_ref())),
2861 );
2862
2863 let inputs_u64 = resolver.pure_input_layouts(&ptb_u64).await.unwrap();
2864 let inputs_opt = resolver.pure_input_layouts(&ptb_opt).await.unwrap();
2865 let inputs_obj = resolver.pure_input_layouts(&ptb_obj).await.unwrap();
2866
2867 let mut output = "---\n".to_string();
2869 for inputs in [inputs_u64, inputs_opt, inputs_obj] {
2870 for input in inputs {
2871 if let Some(layout) = input {
2872 output += &format!("{layout:#}\n");
2873 } else {
2874 output += "???\n";
2875 }
2876 }
2877 output += "---\n";
2878 }
2879
2880 insta::assert_snapshot!(output);
2881 }
2882
2883 #[tokio::test]
2886 async fn test_pure_input_layouts_overlapping() {
2887 use CallArg as I;
2888 use ObjectArg::ImmOrOwnedObject as O;
2889 use TypeTag as T;
2890
2891 let (_, cache) = package_cache([
2892 (1, build_package("std").unwrap(), std_types()),
2893 (1, build_package("iota").unwrap(), iota_types()),
2894 (1, build_package("e0").unwrap(), e0_types()),
2895 ]);
2896
2897 let resolver = Resolver::new(cache);
2898
2899 let ptb = ProgrammableTransaction {
2901 inputs: vec![
2902 I::Object(O(random_object_ref())),
2903 I::Pure(bcs::to_bytes(&42u64).unwrap()),
2904 I::Object(O(random_object_ref())),
2905 I::Pure(bcs::to_bytes(&43u64).unwrap()),
2906 I::Object(O(random_object_ref())),
2907 I::Pure(bcs::to_bytes("hello").unwrap()),
2908 I::Pure(bcs::to_bytes("world").unwrap()),
2909 ],
2910 commands: vec![
2911 Command::move_call(
2912 addr("0xe0").into(),
2913 ident_str!("m").to_owned(),
2914 ident_str!("foo").to_owned(),
2915 vec![T::U64],
2916 (0..=6).map(Argument::Input).collect(),
2917 ),
2918 Command::move_call(
2919 addr("0xe0").into(),
2920 ident_str!("m").to_owned(),
2921 ident_str!("foo").to_owned(),
2922 vec![T::U64],
2923 (0..=6).map(Argument::Input).collect(),
2924 ),
2925 ],
2926 };
2927
2928 let inputs = resolver.pure_input_layouts(&ptb).await.unwrap();
2929
2930 let mut output = String::new();
2932 for input in inputs {
2933 if let Some(layout) = input {
2934 output += &format!("{layout:#}\n");
2935 } else {
2936 output += "???\n";
2937 }
2938 }
2939
2940 insta::assert_snapshot!(output);
2941 }
2942 #[tokio::test]
2943 async fn test_pure_input_layouts_conflicting() {
2944 use CallArg as I;
2945 use ObjectArg::ImmOrOwnedObject as O;
2946 use TypeInput as TI;
2947 use TypeTag as T;
2948
2949 let (_, cache) = package_cache([
2950 (1, build_package("std").unwrap(), std_types()),
2951 (1, build_package("iota").unwrap(), iota_types()),
2952 (1, build_package("e0").unwrap(), e0_types()),
2953 ]);
2954
2955 let resolver = Resolver::new(cache);
2956
2957 let ptb = ProgrammableTransaction {
2958 inputs: vec![
2959 I::Object(O(random_object_ref())),
2960 I::Pure(bcs::to_bytes(&42u64).unwrap()),
2961 I::Object(O(random_object_ref())),
2962 I::Pure(bcs::to_bytes(&43u64).unwrap()),
2963 I::Object(O(random_object_ref())),
2964 I::Pure(bcs::to_bytes("hello").unwrap()),
2965 I::Pure(bcs::to_bytes("world").unwrap()),
2966 ],
2967 commands: vec![
2968 Command::move_call(
2969 addr("0xe0").into(),
2970 ident_str!("m").to_owned(),
2971 ident_str!("foo").to_owned(),
2972 vec![T::U64],
2973 (0..=6).map(Argument::Input).collect(),
2974 ),
2975 Command::MakeMoveVec(Some(TI::U32), vec![Argument::Input(3)]),
2978 ],
2979 };
2980
2981 insta::assert_snapshot!(
2982 resolver.pure_input_layouts(&ptb).await.unwrap_err(),
2983 @"Conflicting types for input 3: u64 and u32"
2984 );
2985 }
2986
2987 type TypeOriginTable = Vec<DatatypeKey>;
2992
2993 fn a0_types() -> TypeOriginTable {
2994 vec![
2995 datakey("0xa0", "m", "T0"),
2996 datakey("0xa0", "m", "T1"),
2997 datakey("0xa0", "m", "T2"),
2998 datakey("0xa0", "m", "E0"),
2999 datakey("0xa0", "m", "E1"),
3000 datakey("0xa0", "m", "E2"),
3001 datakey("0xa0", "n", "T0"),
3002 datakey("0xa0", "n", "E0"),
3003 ]
3004 }
3005
3006 fn a1_types() -> TypeOriginTable {
3007 let mut types = a0_types();
3008
3009 types.extend([
3010 datakey("0xa1", "m", "T3"),
3011 datakey("0xa1", "m", "T4"),
3012 datakey("0xa1", "n", "T1"),
3013 datakey("0xa1", "m", "E3"),
3014 datakey("0xa1", "m", "E4"),
3015 datakey("0xa1", "n", "E1"),
3016 ]);
3017
3018 types
3019 }
3020
3021 fn b0_types() -> TypeOriginTable {
3022 vec![datakey("0xb0", "m", "T0"), datakey("0xb0", "m", "E0")]
3023 }
3024
3025 fn c0_types() -> TypeOriginTable {
3026 vec![datakey("0xc0", "m", "T0"), datakey("0xc0", "m", "E0")]
3027 }
3028
3029 fn d0_types() -> TypeOriginTable {
3030 vec![
3031 datakey("0xd0", "m", "O"),
3032 datakey("0xd0", "m", "P"),
3033 datakey("0xd0", "m", "Q"),
3034 datakey("0xd0", "m", "R"),
3035 datakey("0xd0", "m", "S"),
3036 datakey("0xd0", "m", "T"),
3037 datakey("0xd0", "m", "EO"),
3038 datakey("0xd0", "m", "EP"),
3039 datakey("0xd0", "m", "EQ"),
3040 datakey("0xd0", "m", "ER"),
3041 datakey("0xd0", "m", "ES"),
3042 datakey("0xd0", "m", "ET"),
3043 ]
3044 }
3045
3046 fn e0_types() -> TypeOriginTable {
3047 vec![datakey("0xe0", "m", "O")]
3048 }
3049
3050 fn s0_types() -> TypeOriginTable {
3051 vec![datakey("0x1", "m", "T0"), datakey("0x1", "m", "E0")]
3052 }
3053
3054 fn s1_types() -> TypeOriginTable {
3055 let mut types = s0_types();
3056
3057 types.extend([datakey("0x1", "m", "T1"), datakey("0x1", "m", "E1")]);
3058
3059 types
3060 }
3061
3062 fn iota_types() -> TypeOriginTable {
3063 vec![datakey("0x2", "object", "UID")]
3064 }
3065
3066 fn std_types() -> TypeOriginTable {
3067 vec![
3068 datakey("0x1", "ascii", "String"),
3069 datakey("0x1", "option", "Option"),
3070 datakey("0x1", "string", "String"),
3071 ]
3072 }
3073
3074 fn package_cache(
3080 packages: impl IntoIterator<Item = (u64, CompiledPackage, TypeOriginTable)>,
3081 ) -> (
3082 Arc<RwLock<InnerStore>>,
3083 PackageStoreWithLruCache<InMemoryPackageStore>,
3084 ) {
3085 let packages_by_storage_id: BTreeMap<AccountAddress, _> = packages
3086 .into_iter()
3087 .map(|(version, package, origins)| {
3088 (package_storage_id(&package), (version, package, origins))
3089 })
3090 .collect();
3091
3092 let packages = packages_by_storage_id
3093 .iter()
3094 .map(|(&storage_id, (version, compiled_package, origins))| {
3095 let linkage = compiled_package
3096 .dependency_ids
3097 .published
3098 .values()
3099 .map(|dep_id| {
3100 let storage_id = AccountAddress::from(*dep_id);
3101 let runtime_id = package_runtime_id(
3102 &packages_by_storage_id
3103 .get(&storage_id)
3104 .unwrap_or_else(|| panic!("Dependency {storage_id} not in store"))
3105 .1,
3106 );
3107
3108 (runtime_id, storage_id)
3109 })
3110 .collect();
3111
3112 let package = cached_package(*version, linkage, compiled_package, origins);
3113 (storage_id, package)
3114 })
3115 .collect();
3116
3117 let inner = Arc::new(RwLock::new(InnerStore {
3118 packages,
3119 fetches: 0,
3120 }));
3121
3122 let store = InMemoryPackageStore {
3123 inner: inner.clone(),
3124 };
3125
3126 (inner, PackageStoreWithLruCache::new(store))
3127 }
3128
3129 fn cached_package(
3130 version: u64,
3131 linkage: Linkage,
3132 package: &CompiledPackage,
3133 origins: &TypeOriginTable,
3134 ) -> Package {
3135 let storage_id = package_storage_id(package);
3136 let runtime_id = package_runtime_id(package);
3137 let version = SequenceNumber::from_u64(version);
3138
3139 let mut modules = BTreeMap::new();
3140 for unit in &package.package.root_compiled_units {
3141 let NamedCompiledModule { name, module, .. } = &unit.unit;
3142
3143 let origins = origins
3144 .iter()
3145 .filter(|key| key.module == name.as_str())
3146 .map(|key| (key.name.to_string(), key.package))
3147 .collect();
3148
3149 let module = match Module::read(module.clone(), origins) {
3150 Ok(module) => module,
3151 Err(struct_) => {
3152 panic!("Missing type origin for {}::{struct_}", module.self_id());
3153 }
3154 };
3155
3156 modules.insert(name.to_string(), module);
3157 }
3158
3159 Package {
3160 storage_id,
3161 runtime_id,
3162 linkage,
3163 version,
3164 modules,
3165 }
3166 }
3167
3168 fn package_storage_id(package: &CompiledPackage) -> AccountAddress {
3169 AccountAddress::from(*package.published_at.as_ref().unwrap_or_else(|_| {
3170 panic!(
3171 "Package {} doesn't have published-at set",
3172 package.package.compiled_package_info.package_name,
3173 )
3174 }))
3175 }
3176
3177 fn package_runtime_id(package: &CompiledPackage) -> AccountAddress {
3178 *package
3179 .published_root_module()
3180 .expect("No compiled module")
3181 .address()
3182 }
3183
3184 fn build_package(dir: &str) -> IotaResult<CompiledPackage> {
3185 let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
3186 path.extend(["tests", "packages", dir]);
3187 BuildConfig::new_for_testing().build(&path)
3188 }
3189
3190 fn addr(a: &str) -> AccountAddress {
3191 AccountAddress::from_str(a).unwrap()
3192 }
3193
3194 fn datakey(a: &str, m: &'static str, n: &'static str) -> DatatypeKey {
3195 DatatypeKey {
3196 package: addr(a),
3197 module: m.into(),
3198 name: n.into(),
3199 }
3200 }
3201
3202 fn type_(t: &str) -> TypeTag {
3203 TypeTag::from_str(t).unwrap()
3204 }
3205
3206 fn key(t: &str) -> DatatypeKey {
3207 let tag = StructTag::from_str(t).unwrap();
3208 DatatypeRef::from(&tag).as_key()
3209 }
3210
3211 struct InMemoryPackageStore {
3212 inner: Arc<RwLock<InnerStore>>,
3215 }
3216
3217 struct InnerStore {
3218 packages: BTreeMap<AccountAddress, Package>,
3219 fetches: usize,
3220 }
3221
3222 #[async_trait]
3223 impl PackageStore for InMemoryPackageStore {
3224 async fn fetch(&self, id: AccountAddress) -> Result<Arc<Package>> {
3225 let mut inner = self.inner.as_ref().write().unwrap();
3226 inner.fetches += 1;
3227 inner
3228 .packages
3229 .get(&id)
3230 .cloned()
3231 .ok_or_else(|| Error::PackageNotFound(id))
3232 .map(Arc::new)
3233 }
3234 }
3235
3236 impl InnerStore {
3237 fn replace(&mut self, id: AccountAddress, package: Package) {
3238 self.packages.insert(id, package);
3239 }
3240 }
3241}