diff --git a/third_party/move/move-core/types/src/value.rs b/third_party/move/move-core/types/src/value.rs index 464675a9f68cb..f90fd9e6cec2c 100644 --- a/third_party/move/move-core/types/src/value.rs +++ b/third_party/move/move-core/types/src/value.rs @@ -9,8 +9,9 @@ use crate::{ account_address::AccountAddress, + ident_str, identifier::Identifier, - language_storage::{StructTag, TypeTag}, + language_storage::{ModuleId, StructTag, TypeTag}, u256, }; use anyhow::{anyhow, bail, Result as AResult}; @@ -197,6 +198,31 @@ pub enum IdentifierMappingKind { DerivedString, } +impl IdentifierMappingKind { + /// If the struct identifier has a special mapping, return it. + pub fn from_ident( + module_id: &ModuleId, + struct_id: &Identifier, + ) -> Option { + if module_id.address().eq(&AccountAddress::ONE) + && module_id.name().eq(ident_str!("aggregator_v2")) + { + let ident_str = struct_id.as_ident_str(); + if ident_str.eq(ident_str!("Aggregator")) { + Some(IdentifierMappingKind::Aggregator) + } else if ident_str.eq(ident_str!("AggregatorSnapshot")) { + Some(IdentifierMappingKind::Snapshot) + } else if ident_str.eq(ident_str!("DerivedStringSnapshot")) { + Some(IdentifierMappingKind::DerivedString) + } else { + None + } + } else { + None + } + } +} + #[derive(Debug, Clone, Hash, Serialize, Deserialize, PartialEq, Eq)] #[cfg_attr( any(test, feature = "fuzzing"), @@ -850,7 +876,7 @@ impl fmt::Display for MoveTypeLayout { U256 => write!(f, "u256"), Address => write!(f, "address"), Vector(typ) => write!(f, "vector<{}>", typ), - Struct(s) => write!(f, "{}", s), + Struct(s) => fmt::Display::fmt(s, f), Signer => write!(f, "signer"), // TODO[agg_v2](cleanup): consider printing the tag as well. Native(_, typ) => write!(f, "native<{}>", typ), diff --git a/third_party/move/move-vm/runtime/src/data_cache.rs b/third_party/move/move-vm/runtime/src/data_cache.rs index 197516b5d1dcd..6f39749240ea7 100644 --- a/third_party/move/move-vm/runtime/src/data_cache.rs +++ b/third_party/move/move-vm/runtime/src/data_cache.rs @@ -5,8 +5,10 @@ use crate::{ loader::{LegacyModuleStorageAdapter, Loader}, logging::expect_no_verification_errors, - storage::module_storage::FunctionValueExtensionAdapter, - ModuleStorage, + storage::{ + module_storage::FunctionValueExtensionAdapter, ty_layout_converter::LoaderLayoutConverter, + }, + LayoutConverter, ModuleStorage, }; use bytes::Bytes; use move_binary_format::{ @@ -229,8 +231,9 @@ impl<'r> TransactionDataCache<'r> { }, }; // TODO(Gas): Shall we charge for this? - let (ty_layout, has_aggregator_lifting) = loader - .type_to_type_layout_with_identifier_mappings(ty, module_store, module_storage)?; + let (ty_layout, has_aggregator_lifting) = + LoaderLayoutConverter::new(loader, module_store, module_storage) + .type_to_type_layout_with_identifier_mappings(ty)?; let (data, bytes_loaded) = match loader { Loader::V1(_) => { diff --git a/third_party/move/move-vm/runtime/src/lib.rs b/third_party/move/move-vm/runtime/src/lib.rs index b4e7641d52cfe..e668f911147e4 100644 --- a/third_party/move/move-vm/runtime/src/lib.rs +++ b/third_party/move/move-vm/runtime/src/lib.rs @@ -48,4 +48,5 @@ pub use storage::{ }, module_storage::{ambassador_impl_ModuleStorage, AsFunctionValueExtension, ModuleStorage}, publishing::{StagingModuleStorage, VerifiedModuleBundle}, + ty_layout_converter::{LayoutConverter, StorageLayoutConverter}, }; diff --git a/third_party/move/move-vm/runtime/src/loader/mod.rs b/third_party/move/move-vm/runtime/src/loader/mod.rs index 11a9eda168eb7..2753b3775b850 100644 --- a/third_party/move/move-vm/runtime/src/loader/mod.rs +++ b/third_party/move/move-vm/runtime/src/loader/mod.rs @@ -5,6 +5,7 @@ use crate::{ config::VMConfig, data_cache::TransactionDataCache, logging::expect_no_verification_errors, module_traversal::TraversalContext, storage::module_storage::ModuleStorage, CodeStorage, + LayoutConverter, }; use hashbrown::Equivalent; use lazy_static::lazy_static; @@ -15,7 +16,6 @@ use move_binary_format::{ CompiledModule, CompiledScript, Constant, ConstantPoolIndex, FieldHandleIndex, FieldInstantiationIndex, FunctionHandleIndex, FunctionInstantiationIndex, SignatureIndex, StructDefInstantiationIndex, StructDefinitionIndex, StructFieldInformation, TableIndex, - TypeParameterIndex, }, IndexKind, }; @@ -23,17 +23,14 @@ use move_bytecode_verifier::{self, cyclic_dependencies, dependencies}; use move_core_types::{ account_address::AccountAddress, gas_algebra::{NumBytes, NumTypeNodes}, - ident_str, identifier::IdentStr, language_storage::{ModuleId, StructTag, TypeTag}, - value::{IdentifierMappingKind, MoveFieldLayout, MoveStructLayout, MoveTypeLayout}, + value::MoveTypeLayout, vm_status::StatusCode, }; use move_vm_types::{ gas::GasMeter, - loaded_data::runtime_types::{ - AbilityInfo, DepthFormula, StructIdentifier, StructNameIndex, StructType, Type, - }, + loaded_data::runtime_types::{AbilityInfo, StructNameIndex, StructType, Type}, sha3_256, }; use parking_lot::{Mutex, RwLock}; @@ -56,7 +53,7 @@ use crate::{ storage::{ loader::LoaderV2, module_storage::FunctionValueExtensionAdapter, struct_name_index_map::StructNameIndexMap, ty_cache::StructInfoCache, - ty_tag_cache::TypeTagBuilder, + ty_layout_converter::LoaderLayoutConverter, ty_tag_converter::TypeTagConverter, }, }; pub use function::{Function, LoadedFunction}; @@ -64,12 +61,12 @@ pub(crate) use function::{FunctionHandle, FunctionInstantiation, LoadedFunctionO pub use modules::Module; pub(crate) use modules::{LegacyModuleCache, LegacyModuleStorage, LegacyModuleStorageAdapter}; use move_binary_format::file_format::{ - StructVariantHandleIndex, StructVariantInstantiationIndex, VariantFieldHandleIndex, - VariantFieldInstantiationIndex, VariantIndex, + StructVariantHandleIndex, StructVariantInstantiationIndex, TypeParameterIndex, + VariantFieldHandleIndex, VariantFieldInstantiationIndex, VariantIndex, }; use move_vm_metrics::{Timer, VM_TIMER}; use move_vm_types::{ - loaded_data::runtime_types::{StructLayout, TypeBuilder}, + loaded_data::runtime_types::{DepthFormula, StructLayout, TypeBuilder}, value_serde::FunctionValueExtension, }; pub use script::Script; @@ -153,7 +150,10 @@ impl Loader { versioned_loader_getter!(ty_builder, TypeBuilder); - fn ty_cache<'a>(&'a self, module_storage: &'a dyn ModuleStorage) -> &StructInfoCache { + pub(crate) fn ty_cache<'a>( + &'a self, + module_storage: &'a dyn ModuleStorage, + ) -> &StructInfoCache { match self { Self::V1(loader) => &loader.type_cache, Self::V2(_) => module_storage.runtime_environment().ty_cache(), @@ -1607,27 +1607,26 @@ impl<'a> Resolver<'a> { } pub(crate) fn type_to_type_layout(&self, ty: &Type) -> PartialVMResult { - self.loader - .type_to_type_layout(ty, self.module_store, self.module_storage) + self.layout_converter().type_to_type_layout(ty) } pub(crate) fn type_to_type_layout_with_identifier_mappings( &self, ty: &Type, ) -> PartialVMResult<(MoveTypeLayout, bool)> { - self.loader.type_to_type_layout_with_identifier_mappings( - ty, - self.module_store, - self.module_storage, - ) + self.layout_converter() + .type_to_type_layout_with_identifier_mappings(ty) } pub(crate) fn type_to_fully_annotated_layout( &self, ty: &Type, ) -> PartialVMResult { - self.loader - .type_to_fully_annotated_layout(ty, self.module_store, self.module_storage) + self.layout_converter().type_to_fully_annotated_layout(ty) + } + + pub(crate) fn layout_converter(&self) -> LoaderLayoutConverter { + LoaderLayoutConverter::new(self.loader, self.module_store, self.module_storage) } // @@ -1668,10 +1667,6 @@ impl<'a> FunctionValueExtension for Resolver<'a> { /// Maximal depth of a value in terms of type depth. pub const VALUE_DEPTH_MAX: u64 = 128; -/// Maximal nodes which are allowed when converting to layout. This includes the types of -/// fields for struct types. -const MAX_TYPE_TO_LAYOUT_NODES: u64 = 256; - pub(crate) struct PseudoGasContext { // Parameters for metering type tag construction: // - maximum allowed cost, @@ -1754,7 +1749,7 @@ impl LoaderV1 { Ok(struct_tag) } - fn type_to_type_tag_impl( + pub(crate) fn type_to_type_tag_impl( &self, ty: &Type, gas_context: &mut PseudoGasContext, @@ -1793,400 +1788,21 @@ impl LoaderV1 { } impl Loader { - fn struct_name_to_type_layout( - &self, - struct_name_idx: StructNameIndex, - module_store: &LegacyModuleStorageAdapter, - module_storage: &dyn ModuleStorage, - ty_args: &[Type], - count: &mut u64, - depth: u64, - ) -> PartialVMResult<(MoveTypeLayout, bool)> { - let ty_cache = self.ty_cache(module_storage); - if let Some((struct_layout, node_count, has_identifier_mappings)) = - ty_cache.get_struct_layout_info(&struct_name_idx, ty_args) - { - *count += node_count; - return Ok((struct_layout, has_identifier_mappings)); - } - - let count_before = *count; - let struct_type = - self.fetch_struct_ty_by_idx(struct_name_idx, module_store, module_storage)?; - - let mut has_identifier_mappings = false; - - let layout = match &struct_type.layout { - StructLayout::Single(fields) => { - // Some types can have fields which are lifted at serialization or deserialization - // times. Right now these are Aggregator and AggregatorSnapshot. - let struct_name = self - .struct_name_index_map(module_storage) - .idx_to_struct_name_ref(struct_name_idx)?; - let maybe_mapping = self.get_identifier_mapping_kind(struct_name.as_ref()); - - let field_tys = fields - .iter() - .map(|(_, ty)| self.ty_builder().create_ty_with_subst(ty, ty_args)) - .collect::>>()?; - let (mut field_layouts, field_has_identifier_mappings): ( - Vec, - Vec, - ) = field_tys - .iter() - .map(|ty| { - self.type_to_type_layout_impl( - ty, - module_store, - module_storage, - count, - depth, - ) - }) - .collect::>>()? - .into_iter() - .unzip(); - - has_identifier_mappings = - maybe_mapping.is_some() || field_has_identifier_mappings.into_iter().any(|b| b); - - let layout = if Some(IdentifierMappingKind::DerivedString) == maybe_mapping { - // For DerivedString, the whole object should be lifted. - MoveTypeLayout::Native( - IdentifierMappingKind::DerivedString, - Box::new(MoveTypeLayout::Struct(MoveStructLayout::new(field_layouts))), - ) - } else { - // For aggregators / snapshots, the first field should be lifted. - if let Some(kind) = &maybe_mapping { - if let Some(l) = field_layouts.first_mut() { - *l = MoveTypeLayout::Native(kind.clone(), Box::new(l.clone())); - } - } - MoveTypeLayout::Struct(MoveStructLayout::new(field_layouts)) - }; - layout - }, - StructLayout::Variants(variants) => { - // We do not support variants to have direct identifier mappings, - // but their inner types may. - let variant_layouts = variants - .iter() - .map(|variant| { - variant - .1 - .iter() - .map(|(_, ty)| { - let ty = self.ty_builder().create_ty_with_subst(ty, ty_args)?; - let (ty, has_id_mappings) = self.type_to_type_layout_impl( - &ty, - module_store, - module_storage, - count, - depth, - )?; - has_identifier_mappings |= has_id_mappings; - Ok(ty) - }) - .collect::>>() - }) - .collect::>>()?; - MoveTypeLayout::Struct(MoveStructLayout::RuntimeVariants(variant_layouts)) - }, - }; - - let field_node_count = *count - count_before; - ty_cache.store_struct_layout_info( - struct_name_idx, - ty_args.to_vec(), - layout.clone(), - field_node_count, - has_identifier_mappings, - ); - Ok((layout, has_identifier_mappings)) - } - - // TODO[agg_v2](cleanup): - // Currently aggregator checks are hardcoded and leaking to loader. - // It seems that this is only because there is no support for native - // types. - // Let's think how we can do this nicer. - fn get_identifier_mapping_kind( - &self, - struct_name: &StructIdentifier, - ) -> Option { - if !self.vm_config().delayed_field_optimization_enabled { - return None; - } - - let ident_str_to_kind = |ident_str: &IdentStr| -> Option { - if ident_str.eq(ident_str!("Aggregator")) { - Some(IdentifierMappingKind::Aggregator) - } else if ident_str.eq(ident_str!("AggregatorSnapshot")) { - Some(IdentifierMappingKind::Snapshot) - } else if ident_str.eq(ident_str!("DerivedStringSnapshot")) { - Some(IdentifierMappingKind::DerivedString) - } else { - None - } - }; - - (struct_name.module.address().eq(&AccountAddress::ONE) - && struct_name.module.name().eq(ident_str!("aggregator_v2"))) - .then_some(ident_str_to_kind(struct_name.name.as_ident_str())) - .flatten() - } - - fn type_to_type_layout_impl( + pub(crate) fn type_to_type_tag( &self, ty: &Type, - module_store: &LegacyModuleStorageAdapter, - module_storage: &dyn ModuleStorage, - count: &mut u64, - depth: u64, - ) -> PartialVMResult<(MoveTypeLayout, bool)> { - if *count > MAX_TYPE_TO_LAYOUT_NODES { - return Err( - PartialVMError::new(StatusCode::TOO_MANY_TYPE_NODES).with_message(format!( - "Number of type nodes when constructing type layout exceeded the maximum of {}", - MAX_TYPE_TO_LAYOUT_NODES - )), - ); - } - if depth > VALUE_DEPTH_MAX { - return Err( - PartialVMError::new(StatusCode::VM_MAX_VALUE_DEPTH_REACHED).with_message(format!( - "Depth of a layout exceeded the maximum of {} during construction", - VALUE_DEPTH_MAX - )), - ); - } - Ok(match ty { - Type::Bool => { - *count += 1; - (MoveTypeLayout::Bool, false) - }, - Type::U8 => { - *count += 1; - (MoveTypeLayout::U8, false) - }, - Type::U16 => { - *count += 1; - (MoveTypeLayout::U16, false) - }, - Type::U32 => { - *count += 1; - (MoveTypeLayout::U32, false) - }, - Type::U64 => { - *count += 1; - (MoveTypeLayout::U64, false) - }, - Type::U128 => { - *count += 1; - (MoveTypeLayout::U128, false) - }, - Type::U256 => { - *count += 1; - (MoveTypeLayout::U256, false) - }, - Type::Address => { - *count += 1; - (MoveTypeLayout::Address, false) - }, - Type::Signer => { - *count += 1; - (MoveTypeLayout::Signer, false) - }, - Type::Vector(ty) => { - *count += 1; - let (layout, has_identifier_mappings) = self.type_to_type_layout_impl( - ty, - module_store, - module_storage, - count, - depth + 1, - )?; - ( - MoveTypeLayout::Vector(Box::new(layout)), - has_identifier_mappings, - ) - }, - Type::Struct { idx, .. } => { - *count += 1; - let (layout, has_identifier_mappings) = self.struct_name_to_type_layout( - *idx, - module_store, - module_storage, - &[], - count, - depth + 1, - )?; - (layout, has_identifier_mappings) - }, - Type::StructInstantiation { idx, ty_args, .. } => { - *count += 1; - let (layout, has_identifier_mappings) = self.struct_name_to_type_layout( - *idx, - module_store, - module_storage, - ty_args, - count, - depth + 1, - )?; - (layout, has_identifier_mappings) - }, - Type::Reference(_) | Type::MutableReference(_) | Type::TyParam(_) => { - return Err( - PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR) - .with_message(format!("No type layout for {:?}", ty)), - ); - }, - }) - } - - fn struct_name_to_fully_annotated_layout( - &self, - struct_name_idx: StructNameIndex, - module_store: &LegacyModuleStorageAdapter, module_storage: &dyn ModuleStorage, - ty_args: &[Type], - count: &mut u64, - depth: u64, - ) -> PartialVMResult { - let ty_cache = self.ty_cache(module_storage); - if let Some((layout, annotated_node_count)) = - ty_cache.get_annotated_struct_layout_info(&struct_name_idx, ty_args) - { - *count += annotated_node_count; - return Ok(layout); - } - - let struct_type = - self.fetch_struct_ty_by_idx(struct_name_idx, module_store, module_storage)?; - - // TODO(#13806): have annotated layouts for variants. Currently, we just return the raw - // layout for them. - if matches!(struct_type.layout, StructLayout::Variants(_)) { - return self - .struct_name_to_type_layout( - struct_name_idx, - module_store, - module_storage, - ty_args, - count, - depth, - ) - .map(|(l, _)| l); - } - - let count_before = *count; - let struct_tag = match self { + ) -> PartialVMResult { + match self { Loader::V1(loader) => { - let mut gas_context = PseudoGasContext::new(loader.vm_config()); - loader.struct_name_to_type_tag(struct_name_idx, ty_args, &mut gas_context)? + let mut gas_context = PseudoGasContext::new(self.vm_config()); + loader.type_to_type_tag_impl(ty, &mut gas_context) }, Loader::V2(_) => { - let ty_tag_builder = TypeTagBuilder::new(module_storage.runtime_environment()); - ty_tag_builder.struct_name_idx_to_struct_tag(&struct_name_idx, ty_args)? + let ty_tag_builder = TypeTagConverter::new(module_storage.runtime_environment()); + ty_tag_builder.ty_to_ty_tag(ty) }, - }; - let fields = struct_type.fields(None)?; - - let field_layouts = fields - .iter() - .map(|(n, ty)| { - let ty = self.ty_builder().create_ty_with_subst(ty, ty_args)?; - let l = self.type_to_fully_annotated_layout_impl( - &ty, - module_store, - module_storage, - count, - depth, - )?; - Ok(MoveFieldLayout::new(n.clone(), l)) - }) - .collect::>>()?; - let struct_layout = - MoveTypeLayout::Struct(MoveStructLayout::with_types(struct_tag, field_layouts)); - let field_node_count = *count - count_before; - - ty_cache.store_annotated_struct_layout_info( - struct_name_idx, - ty_args.to_vec(), - struct_layout.clone(), - field_node_count, - ); - Ok(struct_layout) - } - - fn type_to_fully_annotated_layout_impl( - &self, - ty: &Type, - module_store: &LegacyModuleStorageAdapter, - module_storage: &dyn ModuleStorage, - count: &mut u64, - depth: u64, - ) -> PartialVMResult { - if *count > MAX_TYPE_TO_LAYOUT_NODES { - return Err( - PartialVMError::new(StatusCode::TOO_MANY_TYPE_NODES).with_message(format!( - "Number of type nodes when constructing type layout exceeded the maximum of {}", - MAX_TYPE_TO_LAYOUT_NODES - )), - ); - } - if depth > VALUE_DEPTH_MAX { - return Err( - PartialVMError::new(StatusCode::VM_MAX_VALUE_DEPTH_REACHED).with_message(format!( - "Depth of a layout exceeded the maximum of {} during construction", - VALUE_DEPTH_MAX - )), - ); } - Ok(match ty { - Type::Bool => MoveTypeLayout::Bool, - Type::U8 => MoveTypeLayout::U8, - Type::U16 => MoveTypeLayout::U16, - Type::U32 => MoveTypeLayout::U32, - Type::U64 => MoveTypeLayout::U64, - Type::U128 => MoveTypeLayout::U128, - Type::U256 => MoveTypeLayout::U256, - Type::Address => MoveTypeLayout::Address, - Type::Signer => MoveTypeLayout::Signer, - Type::Vector(ty) => { - MoveTypeLayout::Vector(Box::new(self.type_to_fully_annotated_layout_impl( - ty, - module_store, - module_storage, - count, - depth + 1, - )?)) - }, - Type::Struct { idx, .. } => self.struct_name_to_fully_annotated_layout( - *idx, - module_store, - module_storage, - &[], - count, - depth + 1, - )?, - Type::StructInstantiation { idx, ty_args, .. } => self - .struct_name_to_fully_annotated_layout( - *idx, - module_store, - module_storage, - ty_args, - count, - depth + 1, - )?, - Type::Reference(_) | Type::MutableReference(_) | Type::TyParam(_) => { - return Err( - PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR) - .with_message(format!("No type layout for {:?}", ty)), - ); - }, - }) } pub(crate) fn calculate_depth_of_struct( @@ -2279,55 +1895,6 @@ impl Loader { }, }) } - - pub(crate) fn type_to_type_tag( - &self, - ty: &Type, - module_storage: &dyn ModuleStorage, - ) -> PartialVMResult { - match self { - Loader::V1(loader) => { - let mut gas_context = PseudoGasContext::new(self.vm_config()); - loader.type_to_type_tag_impl(ty, &mut gas_context) - }, - Loader::V2(_) => { - let ty_tag_builder = TypeTagBuilder::new(module_storage.runtime_environment()); - ty_tag_builder.ty_to_ty_tag(ty) - }, - } - } - - pub(crate) fn type_to_type_layout_with_identifier_mappings( - &self, - ty: &Type, - module_store: &LegacyModuleStorageAdapter, - module_storage: &dyn ModuleStorage, - ) -> PartialVMResult<(MoveTypeLayout, bool)> { - let mut count = 0; - self.type_to_type_layout_impl(ty, module_store, module_storage, &mut count, 1) - } - - pub(crate) fn type_to_type_layout( - &self, - ty: &Type, - module_store: &LegacyModuleStorageAdapter, - module_storage: &dyn ModuleStorage, - ) -> PartialVMResult { - let mut count = 0; - let (layout, _has_identifier_mappings) = - self.type_to_type_layout_impl(ty, module_store, module_storage, &mut count, 1)?; - Ok(layout) - } - - pub(crate) fn type_to_fully_annotated_layout( - &self, - ty: &Type, - module_store: &LegacyModuleStorageAdapter, - module_storage: &dyn ModuleStorage, - ) -> PartialVMResult { - let mut count = 0; - self.type_to_fully_annotated_layout_impl(ty, module_store, module_storage, &mut count, 1) - } } // Public APIs for external uses. @@ -2345,7 +1912,8 @@ impl Loader { module_storage_adapter, module_storage, )?; - self.type_to_type_layout(&ty, module_storage_adapter, module_storage) + LoaderLayoutConverter::new(self, module_storage_adapter, module_storage) + .type_to_type_layout(&ty) .map_err(|e| e.finish(Location::Undefined)) } @@ -2362,7 +1930,8 @@ impl Loader { module_storage_adapter, module_storage, )?; - self.type_to_fully_annotated_layout(&ty, module_storage_adapter, module_storage) + LoaderLayoutConverter::new(self, module_storage_adapter, module_storage) + .type_to_fully_annotated_layout(&ty) .map_err(|e| e.finish(Location::Undefined)) } } diff --git a/third_party/move/move-vm/runtime/src/runtime.rs b/third_party/move/move-vm/runtime/src/runtime.rs index d33a49edfd645..398a2051efdc0 100644 --- a/third_party/move/move-vm/runtime/src/runtime.rs +++ b/third_party/move/move-vm/runtime/src/runtime.rs @@ -11,8 +11,11 @@ use crate::{ module_traversal::TraversalContext, native_extensions::NativeContextExtensions, session::SerializedReturnValues, - storage::{code_storage::CodeStorage, module_storage::ModuleStorage}, - AsFunctionValueExtension, RuntimeEnvironment, + storage::{ + code_storage::CodeStorage, module_storage::ModuleStorage, + ty_layout_converter::LoaderLayoutConverter, + }, + AsFunctionValueExtension, LayoutConverter, RuntimeEnvironment, }; use move_binary_format::{ access::ModuleAccess, @@ -246,18 +249,18 @@ impl VMRuntime { ty: &Type, arg: impl Borrow<[u8]>, ) -> PartialVMResult { - let (layout, has_identifier_mappings) = match self - .loader - .type_to_type_layout_with_identifier_mappings(ty, module_store, module_storage) - { - Ok(layout) => layout, - Err(_err) => { - return Err(PartialVMError::new( - StatusCode::INVALID_PARAM_TYPE_FOR_DESERIALIZATION, - ) - .with_message("[VM] failed to get layout from type".to_string())); - }, - }; + let (layout, has_identifier_mappings) = + match LoaderLayoutConverter::new(&self.loader, module_store, module_storage) + .type_to_type_layout_with_identifier_mappings(ty) + { + Ok(layout) => layout, + Err(_err) => { + return Err(PartialVMError::new( + StatusCode::INVALID_PARAM_TYPE_FOR_DESERIALIZATION, + ) + .with_message("[VM] failed to get layout from type".to_string())); + }, + }; let deserialization_error = || -> PartialVMError { PartialVMError::new(StatusCode::FAILED_TO_DESERIALIZE_ARGUMENT) @@ -339,15 +342,16 @@ impl VMRuntime { _ => (ty, value), }; - let (layout, has_identifier_mappings) = self - .loader - .type_to_type_layout_with_identifier_mappings(ty, module_store, module_storage) - .map_err(|_err| { - // TODO: Should we use `err` instead of mapping? - PartialVMError::new(StatusCode::VERIFICATION_ERROR).with_message( - "entry point functions cannot have non-serializable return types".to_string(), - ) - })?; + let (layout, has_identifier_mappings) = + LoaderLayoutConverter::new(&self.loader, module_store, module_storage) + .type_to_type_layout_with_identifier_mappings(ty) + .map_err(|_err| { + // TODO: Should we use `err` instead of mapping? + PartialVMError::new(StatusCode::VERIFICATION_ERROR).with_message( + "entry point functions cannot have non-serializable return types" + .to_string(), + ) + })?; let serialization_error = || -> PartialVMError { PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR) diff --git a/third_party/move/move-vm/runtime/src/session.rs b/third_party/move/move-vm/runtime/src/session.rs index 1ba2d0c4bc0a2..3bfc582495ed0 100644 --- a/third_party/move/move-vm/runtime/src/session.rs +++ b/third_party/move/move-vm/runtime/src/session.rs @@ -9,8 +9,8 @@ use crate::{ module_traversal::TraversalContext, move_vm::MoveVM, native_extensions::NativeContextExtensions, - storage::module_storage::ModuleStorage, - CodeStorage, + storage::{module_storage::ModuleStorage, ty_layout_converter::LoaderLayoutConverter}, + CodeStorage, LayoutConverter, }; use bytes::Bytes; use move_binary_format::{compatibility::Compatibility, errors::*, file_format::LocalIndex}; @@ -487,11 +487,13 @@ impl<'r, 'l> Session<'r, 'l> { ty: &Type, module_storage: &impl ModuleStorage, ) -> VMResult { - self.move_vm - .runtime - .loader() - .type_to_type_layout(ty, &self.module_store, module_storage) - .map_err(|e| e.finish(Location::Undefined)) + LoaderLayoutConverter::new( + self.move_vm.runtime.loader(), + &self.module_store, + module_storage, + ) + .type_to_type_layout(ty) + .map_err(|e| e.finish(Location::Undefined)) } pub fn get_fully_annotated_type_layout_from_ty( @@ -499,11 +501,13 @@ impl<'r, 'l> Session<'r, 'l> { ty: &Type, module_storage: &impl ModuleStorage, ) -> VMResult { - self.move_vm - .runtime - .loader() - .type_to_fully_annotated_layout(ty, &self.module_store, module_storage) - .map_err(|e| e.finish(Location::Undefined)) + LoaderLayoutConverter::new( + self.move_vm.runtime.loader(), + &self.module_store, + module_storage, + ) + .type_to_fully_annotated_layout(ty) + .map_err(|e| e.finish(Location::Undefined)) } /// Gets the underlying native extensions. diff --git a/third_party/move/move-vm/runtime/src/storage/environment.rs b/third_party/move/move-vm/runtime/src/storage/environment.rs index 515188d04e2af..678c7ad35f935 100644 --- a/third_party/move/move-vm/runtime/src/storage/environment.rs +++ b/third_party/move/move-vm/runtime/src/storage/environment.rs @@ -7,7 +7,7 @@ use crate::{ native_functions::{NativeFunction, NativeFunctions}, storage::{ struct_name_index_map::StructNameIndexMap, ty_cache::StructInfoCache, - ty_tag_cache::TypeTagCache, verified_module_cache::VERIFIED_MODULES_V2, + ty_tag_converter::TypeTagCache, verified_module_cache::VERIFIED_MODULES_V2, }, Module, Script, }; diff --git a/third_party/move/move-vm/runtime/src/storage/mod.rs b/third_party/move/move-vm/runtime/src/storage/mod.rs index b10a70b52a156..134f241346d94 100644 --- a/third_party/move/move-vm/runtime/src/storage/mod.rs +++ b/third_party/move/move-vm/runtime/src/storage/mod.rs @@ -4,7 +4,7 @@ pub(crate) mod loader; pub(crate) mod struct_name_index_map; pub(crate) mod ty_cache; -pub(crate) mod ty_tag_cache; +pub(crate) mod ty_tag_converter; mod verified_module_cache; pub mod code_storage; @@ -12,3 +12,4 @@ pub mod environment; pub mod implementations; pub mod module_storage; pub mod publishing; +pub mod ty_layout_converter; diff --git a/third_party/move/move-vm/runtime/src/storage/ty_layout_converter.rs b/third_party/move/move-vm/runtime/src/storage/ty_layout_converter.rs new file mode 100644 index 0000000000000..22bdb610c005b --- /dev/null +++ b/third_party/move/move-vm/runtime/src/storage/ty_layout_converter.rs @@ -0,0 +1,506 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::{ + config::VMConfig, + loader::{LegacyModuleStorageAdapter, Loader, PseudoGasContext, VALUE_DEPTH_MAX}, + storage::{ + struct_name_index_map::StructNameIndexMap, ty_cache::StructInfoCache, + ty_tag_converter::TypeTagConverter, + }, + ModuleStorage, +}; +use move_binary_format::errors::{PartialVMError, PartialVMResult}; +use move_core_types::{ + language_storage::StructTag, + value::{IdentifierMappingKind, MoveFieldLayout, MoveStructLayout, MoveTypeLayout}, + vm_status::StatusCode, +}; +use move_vm_types::loaded_data::runtime_types::{StructLayout, StructNameIndex, StructType, Type}; +use std::sync::Arc; + +/// Maximal nodes which are allowed when converting to layout. This includes the types of +/// fields for struct types. +const MAX_TYPE_TO_LAYOUT_NODES: u64 = 256; + +/// A trait allowing to convert runtime types into other types used throughout the stack. +#[allow(private_bounds)] +pub trait LayoutConverter: LayoutConverterBase { + /// Converts a runtime type to a type layout. + fn type_to_type_layout(&self, ty: &Type) -> PartialVMResult { + let mut count = 0; + self.type_to_type_layout_impl(ty, &mut count, 1) + .map(|(l, _)| l) + } + + /// Converts a runtime type to a type layout. + fn type_to_type_layout_with_identifier_mappings( + &self, + ty: &Type, + ) -> PartialVMResult<(MoveTypeLayout, bool)> { + let mut count = 0; + self.type_to_type_layout_impl(ty, &mut count, 1) + } + + /// Converts a runtime type to a fully annotated type layout, containing information about + /// field names. + fn type_to_fully_annotated_layout(&self, ty: &Type) -> PartialVMResult { + let mut count = 0; + self.type_to_fully_annotated_layout_impl(ty, &mut count, 1) + } +} + +// This is not intended to be implemented or used externally, so put abstract and other functions +// into this crate trait. +pub(crate) trait LayoutConverterBase { + fn vm_config(&self) -> &VMConfig; + fn struct_info_cache(&self) -> &StructInfoCache; + fn fetch_struct_ty_by_idx(&self, idx: StructNameIndex) -> PartialVMResult>; + fn struct_name_index_map(&self) -> &StructNameIndexMap; + + /// Required for annotated layout. + fn struct_name_idx_to_struct_tag( + &self, + idx: StructNameIndex, + ty_args: &[Type], + ) -> PartialVMResult; + + // ------------------------------------------------------------------------------------- + // Layout + + fn check_type_layout_bounds(&self, node_count: u64, depth: u64) -> PartialVMResult<()> { + if node_count > MAX_TYPE_TO_LAYOUT_NODES { + return Err( + PartialVMError::new(StatusCode::TOO_MANY_TYPE_NODES).with_message(format!( + "Number of type nodes when constructing type layout exceeded the maximum of {}", + MAX_TYPE_TO_LAYOUT_NODES + )), + ); + } + if depth > VALUE_DEPTH_MAX { + return Err( + PartialVMError::new(StatusCode::VM_MAX_VALUE_DEPTH_REACHED).with_message(format!( + "Depth of a layout exceeded the maximum of {} during construction", + VALUE_DEPTH_MAX + )), + ); + } + Ok(()) + } + + fn type_to_type_layout_impl( + &self, + ty: &Type, + count: &mut u64, + depth: u64, + ) -> PartialVMResult<(MoveTypeLayout, bool)> { + self.check_type_layout_bounds(*count, depth)?; + Ok(match ty { + Type::Bool => { + *count += 1; + (MoveTypeLayout::Bool, false) + }, + Type::U8 => { + *count += 1; + (MoveTypeLayout::U8, false) + }, + Type::U16 => { + *count += 1; + (MoveTypeLayout::U16, false) + }, + Type::U32 => { + *count += 1; + (MoveTypeLayout::U32, false) + }, + Type::U64 => { + *count += 1; + (MoveTypeLayout::U64, false) + }, + Type::U128 => { + *count += 1; + (MoveTypeLayout::U128, false) + }, + Type::U256 => { + *count += 1; + (MoveTypeLayout::U256, false) + }, + Type::Address => { + *count += 1; + (MoveTypeLayout::Address, false) + }, + Type::Signer => { + *count += 1; + (MoveTypeLayout::Signer, false) + }, + Type::Vector(ty) => { + *count += 1; + let (layout, has_identifier_mappings) = + self.type_to_type_layout_impl(ty, count, depth + 1)?; + ( + MoveTypeLayout::Vector(Box::new(layout)), + has_identifier_mappings, + ) + }, + Type::Struct { idx, .. } => { + *count += 1; + let (layout, has_identifier_mappings) = + self.struct_name_to_type_layout(*idx, &[], count, depth + 1)?; + (layout, has_identifier_mappings) + }, + Type::StructInstantiation { idx, ty_args, .. } => { + *count += 1; + self.struct_name_to_type_layout(*idx, ty_args, count, depth + 1)? + }, + Type::Reference(_) | Type::MutableReference(_) | Type::TyParam(_) => { + return Err( + PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR) + .with_message(format!("No type layout for {:?}", ty)), + ); + }, + }) + } + + fn struct_name_to_type_layout( + &self, + struct_name_idx: StructNameIndex, + ty_args: &[Type], + count: &mut u64, + depth: u64, + ) -> PartialVMResult<(MoveTypeLayout, bool)> { + let struct_cache = self.struct_info_cache(); + if let Some((struct_layout, node_count, has_identifier_mappings)) = + struct_cache.get_struct_layout_info(&struct_name_idx, ty_args) + { + *count += node_count; + return Ok((struct_layout, has_identifier_mappings)); + } + + let count_before = *count; + let struct_type = self.fetch_struct_ty_by_idx(struct_name_idx)?; + + let mut has_identifier_mappings = false; + + let layout = match &struct_type.layout { + StructLayout::Single(fields) => { + // Some types can have fields which are lifted at serialization or deserialization + // times. Right now these are Aggregator and AggregatorSnapshot. + let maybe_mapping = self.get_identifier_mapping_kind(struct_name_idx)?; + let field_tys = fields + .iter() + .map(|(_, ty)| { + self.vm_config() + .ty_builder + .create_ty_with_subst(ty, ty_args) + }) + .collect::>>()?; + let (mut field_layouts, field_has_identifier_mappings): ( + Vec, + Vec, + ) = field_tys + .iter() + .map(|ty| self.type_to_type_layout_impl(ty, count, depth)) + .collect::>>()? + .into_iter() + .unzip(); + + has_identifier_mappings = + maybe_mapping.is_some() || field_has_identifier_mappings.into_iter().any(|b| b); + + let layout = if Some(IdentifierMappingKind::DerivedString) == maybe_mapping { + // For DerivedString, the whole object should be lifted. + MoveTypeLayout::Native( + IdentifierMappingKind::DerivedString, + Box::new(MoveTypeLayout::Struct(MoveStructLayout::new(field_layouts))), + ) + } else { + // For aggregators / snapshots, the first field should be lifted. + if let Some(kind) = &maybe_mapping { + if let Some(l) = field_layouts.first_mut() { + *l = MoveTypeLayout::Native(kind.clone(), Box::new(l.clone())); + } + } + MoveTypeLayout::Struct(MoveStructLayout::new(field_layouts)) + }; + layout + }, + StructLayout::Variants(variants) => { + // We do not support variants to have direct identifier mappings, + // but their inner types may. + let variant_layouts = variants + .iter() + .map(|variant| { + variant + .1 + .iter() + .map(|(_, ty)| { + let ty = self + .vm_config() + .ty_builder + .create_ty_with_subst(ty, ty_args)?; + let (ty, has_id_mappings) = + self.type_to_type_layout_impl(&ty, count, depth)?; + has_identifier_mappings |= has_id_mappings; + Ok(ty) + }) + .collect::>>() + }) + .collect::>>()?; + MoveTypeLayout::Struct(MoveStructLayout::RuntimeVariants(variant_layouts)) + }, + }; + + let field_node_count = *count - count_before; + struct_cache.store_struct_layout_info( + struct_name_idx, + ty_args.to_vec(), + layout.clone(), + field_node_count, + has_identifier_mappings, + ); + Ok((layout, has_identifier_mappings)) + } + + fn get_identifier_mapping_kind( + &self, + idx: StructNameIndex, + ) -> PartialVMResult> { + if !self.vm_config().delayed_field_optimization_enabled { + return Ok(None); + } + let struct_name = self.struct_name_index_map().idx_to_struct_name(idx)?; + Ok(IdentifierMappingKind::from_ident( + &struct_name.module, + &struct_name.name, + )) + } + + // ------------------------------------------------------------------------------------- + // Decorated Layout + + fn type_to_fully_annotated_layout_impl( + &self, + ty: &Type, + count: &mut u64, + depth: u64, + ) -> PartialVMResult { + if *count > MAX_TYPE_TO_LAYOUT_NODES { + return Err( + PartialVMError::new(StatusCode::TOO_MANY_TYPE_NODES).with_message(format!( + "Number of type nodes when constructing type layout exceeded the maximum of {}", + MAX_TYPE_TO_LAYOUT_NODES + )), + ); + } + if depth > VALUE_DEPTH_MAX { + return Err( + PartialVMError::new(StatusCode::VM_MAX_VALUE_DEPTH_REACHED).with_message(format!( + "Depth of a layout exceeded the maximum of {} during construction", + VALUE_DEPTH_MAX + )), + ); + } + Ok(match ty { + Type::Bool => MoveTypeLayout::Bool, + Type::U8 => MoveTypeLayout::U8, + Type::U16 => MoveTypeLayout::U16, + Type::U32 => MoveTypeLayout::U32, + Type::U64 => MoveTypeLayout::U64, + Type::U128 => MoveTypeLayout::U128, + Type::U256 => MoveTypeLayout::U256, + Type::Address => MoveTypeLayout::Address, + Type::Signer => MoveTypeLayout::Signer, + Type::Vector(ty) => MoveTypeLayout::Vector(Box::new( + self.type_to_fully_annotated_layout_impl(ty, count, depth + 1)?, + )), + Type::Struct { idx, .. } => { + self.struct_name_to_fully_annotated_layout(*idx, &[], count, depth + 1)? + }, + Type::StructInstantiation { idx, ty_args, .. } => { + self.struct_name_to_fully_annotated_layout(*idx, ty_args, count, depth + 1)? + }, + Type::Reference(_) | Type::MutableReference(_) | Type::TyParam(_) => { + return Err( + PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR) + .with_message(format!("No type layout for {:?}", ty)), + ); + }, + }) + } + + fn struct_name_to_fully_annotated_layout( + &self, + struct_name_idx: StructNameIndex, + ty_args: &[Type], + count: &mut u64, + depth: u64, + ) -> PartialVMResult { + let struct_info_cache = self.struct_info_cache(); + if let Some((layout, annotated_node_count)) = + struct_info_cache.get_annotated_struct_layout_info(&struct_name_idx, ty_args) + { + *count += annotated_node_count; + return Ok(layout); + } + + let struct_type = self.fetch_struct_ty_by_idx(struct_name_idx)?; + + // TODO(#13806): have annotated layouts for variants. Currently, we just return the raw + // layout for them. + if matches!(struct_type.layout, StructLayout::Variants(_)) { + return self + .struct_name_to_type_layout(struct_name_idx, ty_args, count, depth) + .map(|(l, _)| l); + } + + let count_before = *count; + let struct_tag = self.struct_name_idx_to_struct_tag(struct_name_idx, ty_args)?; + let fields = struct_type.fields(None)?; + + let field_layouts = fields + .iter() + .map(|(n, ty)| { + let ty = self + .vm_config() + .ty_builder + .create_ty_with_subst(ty, ty_args)?; + let l = self.type_to_fully_annotated_layout_impl(&ty, count, depth)?; + Ok(MoveFieldLayout::new(n.clone(), l)) + }) + .collect::>>()?; + let struct_layout = + MoveTypeLayout::Struct(MoveStructLayout::with_types(struct_tag, field_layouts)); + let field_node_count = *count - count_before; + + struct_info_cache.store_annotated_struct_layout_info( + struct_name_idx, + ty_args.to_vec(), + struct_layout.clone(), + field_node_count, + ); + Ok(struct_layout) + } +} + +// -------------------------------------------------------------------------------------------- +// Layout converter based on ModuleStorage + +pub struct StorageLayoutConverter<'a> { + storage: &'a dyn ModuleStorage, +} + +impl<'a> StorageLayoutConverter<'a> { + pub fn new(storage: &'a dyn ModuleStorage) -> Self { + Self { storage } + } +} + +impl<'a> LayoutConverterBase for StorageLayoutConverter<'a> { + fn vm_config(&self) -> &VMConfig { + self.storage.runtime_environment().vm_config() + } + + fn struct_info_cache(&self) -> &StructInfoCache { + self.storage.runtime_environment().ty_cache() + } + + fn fetch_struct_ty_by_idx(&self, idx: StructNameIndex) -> PartialVMResult> { + let struct_name = self.struct_name_index_map().idx_to_struct_name_ref(idx)?; + self.storage.fetch_struct_ty( + struct_name.module.address(), + struct_name.module.name(), + struct_name.name.as_ident_str(), + ) + } + + fn struct_name_index_map(&self) -> &StructNameIndexMap { + self.storage.runtime_environment().struct_name_index_map() + } + + fn struct_name_idx_to_struct_tag( + &self, + idx: StructNameIndex, + ty_args: &[Type], + ) -> PartialVMResult { + let ty_tag_builder = TypeTagConverter::new(self.storage.runtime_environment()); + ty_tag_builder.struct_name_idx_to_struct_tag(&idx, ty_args) + } +} + +impl<'a> LayoutConverter for StorageLayoutConverter<'a> {} + +// -------------------------------------------------------------------------------------------- +// Layout converter based on `Loader` + +// This should go away once we eliminated loader v1. + +pub(crate) struct LoaderLayoutConverter<'a> { + loader: &'a Loader, + module_store: &'a LegacyModuleStorageAdapter, + module_storage: &'a dyn ModuleStorage, +} + +impl<'a> LoaderLayoutConverter<'a> { + pub fn new( + loader: &'a Loader, + module_store: &'a LegacyModuleStorageAdapter, + module_storage: &'a dyn ModuleStorage, + ) -> Self { + Self { + loader, + module_store, + module_storage, + } + } +} + +impl<'a> LayoutConverterBase for LoaderLayoutConverter<'a> { + fn vm_config(&self) -> &VMConfig { + self.loader.vm_config() + } + + fn struct_info_cache(&self) -> &StructInfoCache { + self.loader.ty_cache(self.module_storage) + } + + fn fetch_struct_ty_by_idx(&self, idx: StructNameIndex) -> PartialVMResult> { + match self.loader { + Loader::V1(..) => { + self.loader + .fetch_struct_ty_by_idx(idx, self.module_store, self.module_storage) + }, + Loader::V2(..) => { + let struct_name = self.struct_name_index_map().idx_to_struct_name_ref(idx)?; + self.module_storage.fetch_struct_ty( + struct_name.module.address(), + struct_name.module.name(), + struct_name.name.as_ident_str(), + ) + }, + } + } + + fn struct_name_index_map(&self) -> &StructNameIndexMap { + self.loader.struct_name_index_map(self.module_storage) + } + + fn struct_name_idx_to_struct_tag( + &self, + idx: StructNameIndex, + ty_args: &[Type], + ) -> PartialVMResult { + match self.loader { + Loader::V1(loader) => { + let mut gas_context = PseudoGasContext::new(self.vm_config()); + let arg_tags = ty_args + .iter() + .map(|t| loader.type_to_type_tag_impl(t, &mut gas_context)) + .collect::>>()?; + loader.name_cache.idx_to_struct_tag(idx, arg_tags) + }, + Loader::V2(..) => TypeTagConverter::new(self.module_storage.runtime_environment()) + .struct_name_idx_to_struct_tag(&idx, ty_args), + } + } +} + +impl<'a> LayoutConverter for LoaderLayoutConverter<'a> {} diff --git a/third_party/move/move-vm/runtime/src/storage/ty_tag_cache.rs b/third_party/move/move-vm/runtime/src/storage/ty_tag_converter.rs similarity index 93% rename from third_party/move/move-vm/runtime/src/storage/ty_tag_cache.rs rename to third_party/move/move-vm/runtime/src/storage/ty_tag_converter.rs index e77c0d3cab25c..b082ccaa63d19 100644 --- a/third_party/move/move-vm/runtime/src/storage/ty_tag_cache.rs +++ b/third_party/move/move-vm/runtime/src/storage/ty_tag_converter.rs @@ -103,13 +103,13 @@ impl TypeTagCache { /// Responsible for building type tags, while also doing the metering in order to bound space and /// time complexity. -pub(crate) struct TypeTagBuilder<'a> { +pub(crate) struct TypeTagConverter<'a> { /// Stores caches for struct names and tags, as well as pseudo-gas metering configs. runtime_environment: &'a RuntimeEnvironment, } -impl<'a> TypeTagBuilder<'a> { - /// Creates a new builder for the specified environment and configs. +impl<'a> TypeTagConverter<'a> { + /// Creates a new converter for the specified environment and configs. pub(crate) fn new(runtime_environment: &'a RuntimeEnvironment) -> Self { Self { runtime_environment, @@ -267,7 +267,7 @@ mod tests { let ty_builder = TypeBuilder::with_limits(10, 10); let runtime_environment = RuntimeEnvironment::new(vec![]); - let ty_tag_builder = TypeTagBuilder::new(&runtime_environment); + let ty_tag_converter = TypeTagConverter::new(&runtime_environment); let disallowed_tys = [ Type::TyParam(0), @@ -279,7 +279,7 @@ mod tests { .unwrap(), ]; for ty in disallowed_tys { - assert_err!(ty_tag_builder.ty_to_ty_tag(&ty)); + assert_err!(ty_tag_converter.ty_to_ty_tag(&ty)); } let allowed_primitive_tys = [ @@ -294,7 +294,7 @@ mod tests { (ty_builder.create_signer_ty(), TypeTag::Signer), ]; for (ty, expected_tag) in allowed_primitive_tys { - let actual_tag = assert_ok!(ty_tag_builder.ty_to_ty_tag(&ty)); + let actual_tag = assert_ok!(ty_tag_converter.ty_to_ty_tag(&ty)); assert_eq!(actual_tag, expected_tag); } @@ -304,7 +304,7 @@ mod tests { .unwrap(); let bool_vec_tag = TypeTag::Vector(Box::new(TypeTag::Bool)); assert_ok_eq!( - ty_tag_builder.ty_to_ty_tag(&bool_vec_ty), + ty_tag_converter.ty_to_ty_tag(&bool_vec_ty), bool_vec_tag.clone() ); @@ -328,7 +328,7 @@ mod tests { ty_builder.create_struct_ty(bar_idx, AbilityInfo::struct_(AbilitySet::EMPTY)); let struct_tag = StructTag::from_str("0x1::foo::Bar").unwrap(); assert_ok_eq!( - ty_tag_builder.ty_to_ty_tag(&struct_ty), + ty_tag_converter.ty_to_ty_tag(&struct_ty), TypeTag::Struct(Box::new(struct_tag)) ); @@ -352,7 +352,7 @@ mod tests { .unwrap(); let struct_tag = StructTag::from_str("0x2::foo::Foo>").unwrap(); assert_ok_eq!( - ty_tag_builder.ty_to_ty_tag(&generic_struct_ty), + ty_tag_converter.ty_to_ty_tag(&generic_struct_ty), TypeTag::Struct(Box::new(struct_tag)) ); } @@ -367,19 +367,19 @@ mod tests { ..Default::default() }; let runtime_environment = RuntimeEnvironment::new_with_config(vec![], vm_config); - let ty_tag_builder = TypeTagBuilder::new(&runtime_environment); + let ty_tag_converter = TypeTagConverter::new(&runtime_environment); let bool_ty = ty_builder.create_bool_ty(); - assert_ok_eq!(ty_tag_builder.ty_to_ty_tag(&bool_ty), TypeTag::Bool); + assert_ok_eq!(ty_tag_converter.ty_to_ty_tag(&bool_ty), TypeTag::Bool); let vec_ty = ty_builder.create_vec_ty(&bool_ty).unwrap(); assert_ok_eq!( - ty_tag_builder.ty_to_ty_tag(&vec_ty), + ty_tag_converter.ty_to_ty_tag(&vec_ty), TypeTag::Vector(Box::new(TypeTag::Bool)) ); let vec_ty = ty_builder.create_vec_ty(&vec_ty).unwrap(); - let err = assert_err!(ty_tag_builder.ty_to_ty_tag(&vec_ty)); + let err = assert_err!(ty_tag_converter.ty_to_ty_tag(&vec_ty)); assert_eq!(err.major_status(), StatusCode::TYPE_TAG_LIMIT_EXCEEDED); } @@ -393,7 +393,7 @@ mod tests { ..Default::default() }; let runtime_environment = RuntimeEnvironment::new_with_config(vec![], vm_config); - let ty_tag_builder = TypeTagBuilder::new(&runtime_environment); + let ty_tag_converter = TypeTagConverter::new(&runtime_environment); let id = StructIdentifier { module: ModuleId::new(AccountAddress::ONE, Identifier::new("foo").unwrap()), @@ -407,7 +407,7 @@ mod tests { let mut gas_context = PseudoGasContext::new(runtime_environment.vm_config()); assert_ok_eq!( - ty_tag_builder.struct_name_idx_to_struct_tag_impl(&idx, &[], &mut gas_context), + ty_tag_converter.struct_name_idx_to_struct_tag_impl(&idx, &[], &mut gas_context), struct_tag.clone() ); @@ -430,7 +430,7 @@ mod tests { let runtime_environment = RuntimeEnvironment::new_with_config(vec![], vm_config); let mut gas_context = PseudoGasContext::new(runtime_environment.vm_config()); - let err = assert_err!(ty_tag_builder.struct_name_idx_to_struct_tag_impl( + let err = assert_err!(ty_tag_converter.struct_name_idx_to_struct_tag_impl( &idx, &[], &mut gas_context