diff --git a/CHANGELOG.md b/CHANGELOG.md index 7dfdb9f8d68..f90530b2057 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [Unreleased] +### Fixed +- `name` override fixes for message id computation and trait definitions - [#2649](https://github.com/use-ink/ink/pull/2649) + ## Version 6.0.0-alpha.4 ### Added diff --git a/crates/ink/codegen/src/generator/metadata.rs b/crates/ink/codegen/src/generator/metadata.rs index 5a953d79d13..185fb3c22ce 100644 --- a/crates/ink/codegen/src/generator/metadata.rs +++ b/crates/ink/codegen/src/generator/metadata.rs @@ -150,10 +150,7 @@ impl Metadata<'_> { let is_payable = constructor.is_payable(); let is_default = constructor.is_default(); let constructor = constructor.callable(); - let name = constructor - .name() - .map(ToString::to_string) - .unwrap_or_else(|| constructor.ident().to_string()); + let name = constructor.normalized_name(); let args = constructor.inputs().map(Self::generate_dispatch_argument); let storage_ident = self.contract.module().storage().ident(); let ret_ty = Self::generate_constructor_return_type(storage_ident, selector_id); @@ -218,10 +215,7 @@ impl Metadata<'_> { let is_default = message.is_default(); let message = message.callable(); let mutates = message.receiver().is_ref_mut(); - let name = message - .name() - .map(ToString::to_string) - .unwrap_or_else(|| message.ident().to_string()); + let name = message.normalized_name(); let args = message.inputs().map(Self::generate_dispatch_argument); let cfg_attrs = message.get_cfg_attrs(span); let ret_ty = @@ -268,9 +262,7 @@ impl Metadata<'_> { .map(|((trait_ident, trait_path), message)| { let message_span = message.span(); let message_name = message - .name() - .map(ToString::to_string) - .unwrap_or_else(|| message.ident().to_string()); + .normalized_name(); let message_docs = message .attrs() .iter() diff --git a/crates/ink/codegen/src/generator/sol/metadata.rs b/crates/ink/codegen/src/generator/sol/metadata.rs index 89202450a9e..e6ff2559aac 100644 --- a/crates/ink/codegen/src/generator/sol/metadata.rs +++ b/crates/ink/codegen/src/generator/sol/metadata.rs @@ -73,10 +73,7 @@ impl SolidityMetadata<'_> { .impls() .flat_map(|item_impl| item_impl.iter_constructors()) .map(|ctor| { - let name = ctor - .name() - .map(ToString::to_string) - .unwrap_or_else(|| ctor.ident().to_string()); + let name = ctor.normalized_name(); let inputs = params_info(ctor.inputs()); let is_payable = ctor.is_payable(); let is_default = ctor.is_default(); @@ -101,10 +98,7 @@ impl SolidityMetadata<'_> { .impls() .flat_map(|item_impl| item_impl.iter_messages()) .map(|msg| { - let name = msg - .name() - .map(ToString::to_string) - .unwrap_or_else(|| msg.ident().to_string()); + let name = msg.normalized_name(); let inputs = params_info(msg.inputs()); let output = msg .output() diff --git a/crates/ink/codegen/src/generator/sol/utils.rs b/crates/ink/codegen/src/generator/sol/utils.rs index 52bf36a81e6..8111339765b 100644 --- a/crates/ink/codegen/src/generator/sol/utils.rs +++ b/crates/ink/codegen/src/generator/sol/utils.rs @@ -51,10 +51,7 @@ pub fn sol_return_type(ty: &Type) -> TokenStream2 { /// Returns Solidity ABI compatible selector of an ink! message. pub fn selector(message: &Message) -> TokenStream2 { - let name = message - .name() - .map(ToString::to_string) - .unwrap_or_else(|| message.ident().to_string()); + let name = message.normalized_name(); let signature = call_signature(name, message.inputs()); quote! { const { diff --git a/crates/ink/codegen/src/generator/trait_def/message_builder.rs b/crates/ink/codegen/src/generator/trait_def/message_builder.rs index f4e20253014..c7b60050b52 100644 --- a/crates/ink/codegen/src/generator/trait_def/message_builder.rs +++ b/crates/ink/codegen/src/generator/trait_def/message_builder.rs @@ -205,11 +205,9 @@ impl MessageBuilder<'_> { (quote!([ #( #selector_bytes ),* ]), quote!(::ink::abi::Ink)) } Abi::Sol => { - let message_ident = message.ident(); - let signature = sol::utils::call_signature( - message_ident.to_string(), - message.inputs(), - ); + let name = message.normalized_name(); + let signature = + sol::utils::call_signature(name, message.inputs()); ( quote!(::ink::codegen::sol::selector_bytes(#signature)), quote!(::ink::abi::Sol), diff --git a/crates/ink/codegen/src/generator/trait_def/trait_registry.rs b/crates/ink/codegen/src/generator/trait_def/trait_registry.rs index 2cb384453e3..199e11ca8a7 100644 --- a/crates/ink/codegen/src/generator/trait_def/trait_registry.rs +++ b/crates/ink/codegen/src/generator/trait_def/trait_registry.rs @@ -354,8 +354,8 @@ impl TraitRegistry<'_> { ) } Abi::Sol => { - let ident_str = message.ident().to_string(); - let signature = sol::utils::call_signature(ident_str, message.inputs()); + let name = message.normalized_name(); + let signature = sol::utils::call_signature(name, message.inputs()); let selector_bytes = quote! { ::ink::codegen::sol::selector_bytes(#signature) }; diff --git a/crates/ink/ir/src/ir/item_impl/callable.rs b/crates/ink/ir/src/ir/item_impl/callable.rs index c907e886976..6657b3e35c5 100644 --- a/crates/ink/ir/src/ir/item_impl/callable.rs +++ b/crates/ink/ir/src/ir/item_impl/callable.rs @@ -143,6 +143,12 @@ where fn name(&self) -> Option<&str> { ::name(self.callable) } + + fn normalized_name(&self) -> String { + self.name() + .map(ToString::to_string) + .unwrap_or_else(|| self.ident().to_string()) + } } impl ::core::ops::Deref for CallableWithSelector<'_, C> { @@ -201,6 +207,13 @@ pub trait Callable { /// Returns the function name override (if any). fn name(&self) -> Option<&str>; + + /// Returns the "normalized" function name + /// + /// # Note + /// This returns the name override (if provided), otherwise the identifier is + /// returned. + fn normalized_name(&self) -> String; } /// Returns the composed selector of the ink! callable. @@ -339,10 +352,7 @@ fn compose_selector_preimage(item_impl: &ir::ItemImpl, callable: &C) -> Vec Option<&str> { self.name.as_deref() } + + fn normalized_name(&self) -> String { + self.normalized_name() + } } impl Constructor { @@ -281,6 +285,17 @@ impl Constructor { pub fn name(&self) -> Option<&str> { self.name.as_deref() } + + /// Returns the "normalized" function name + /// + /// # Note + /// This returns the name override (if provided), otherwise the identifier is + /// returned. + pub fn normalized_name(&self) -> String { + self.name() + .map(ToString::to_string) + .unwrap_or_else(|| self.ident().to_string()) + } } #[cfg(test)] diff --git a/crates/ink/ir/src/ir/item_impl/message.rs b/crates/ink/ir/src/ir/item_impl/message.rs index d880418e87c..4b3950e193a 100644 --- a/crates/ink/ir/src/ir/item_impl/message.rs +++ b/crates/ink/ir/src/ir/item_impl/message.rs @@ -305,6 +305,10 @@ impl Callable for Message { fn name(&self) -> Option<&str> { self.name.as_deref() } + + fn normalized_name(&self) -> String { + self.normalized_name() + } } impl Message { @@ -370,7 +374,7 @@ impl Message { /// Although the above scenario is very unlikely since the local ID is computed /// solely by the identifier of the ink! message. pub fn local_id(&self) -> u32 { - utils::local_message_id(self.ident()) + utils::local_message_id(&self.normalized_name()) } /// Returns the identifier of the message with an additional `try_` prefix attached. @@ -382,6 +386,17 @@ impl Message { pub fn name(&self) -> Option<&str> { self.name.as_deref() } + + /// Returns the "normalized" function name + /// + /// # Note + /// This returns the name override (if provided), otherwise the identifier is + /// returned. + pub fn normalized_name(&self) -> String { + self.name() + .map(ToString::to_string) + .unwrap_or_else(|| self.ident().to_string()) + } } #[cfg(test)] diff --git a/crates/ink/ir/src/ir/trait_def/item/mod.rs b/crates/ink/ir/src/ir/trait_def/item/mod.rs index ccc4a77bc4d..30b71a10580 100644 --- a/crates/ink/ir/src/ir/trait_def/item/mod.rs +++ b/crates/ink/ir/src/ir/trait_def/item/mod.rs @@ -373,9 +373,7 @@ impl InkItemTrait { manual_selector } _ => { - let name = ink_attrs - .name() - .unwrap_or_else(|| callable.ident().to_string()); + let name = callable.normalized_name(); Selector::compose(trait_prefix, name) } }; diff --git a/crates/ink/ir/src/ir/trait_def/item/trait_item.rs b/crates/ink/ir/src/ir/trait_def/item/trait_item.rs index d828154222e..a86f015c707 100644 --- a/crates/ink/ir/src/ir/trait_def/item/trait_item.rs +++ b/crates/ink/ir/src/ir/trait_def/item/trait_item.rs @@ -59,6 +59,24 @@ impl<'a> InkTraitItem<'a> { Self::Message(ink_trait_message) => Some(ink_trait_message), } } + + /// Returns the function name override (if any). + pub fn name(&self) -> Option { + match self { + Self::Message(message) => message.name(), + } + } + + /// Returns the "normalized" function name + /// + /// # Note + /// This returns the name override (if provided), otherwise the identifier is + /// returned. + pub fn normalized_name(&self) -> String { + match self { + Self::Message(message) => message.normalized_name(), + } + } } /// A checked ink! message of an ink! trait definition. @@ -173,7 +191,7 @@ impl<'a> InkTraitMessage<'a> { /// Although the above scenario is very unlikely since the local ID is computed /// solely by the identifier of the ink! message. pub fn local_id(&self) -> u32 { - utils::local_message_id(self.ident()) + utils::local_message_id(&self.normalized_name()) } /// Returns the span of the ink! message. @@ -188,6 +206,20 @@ impl<'a> InkTraitMessage<'a> { .map(|receiver| receiver.mutability.is_some()) .expect("encountered missing receiver for ink! message") } + + /// Returns the function name override (if any). + pub fn name(&self) -> Option { + self.ink_attrs().name() + } + + /// Returns the "normalized" function name + /// + /// # Note + /// This returns the name override (if provided), otherwise the identifier is + /// returned. + pub fn normalized_name(&self) -> String { + self.name().unwrap_or_else(|| self.ident().to_string()) + } } impl<'a> From<&'a InkTraitMessage<'a>> for InputsIter<'a> { diff --git a/crates/ink/ir/src/ir/utils.rs b/crates/ink/ir/src/ir/utils.rs index 16af4820acd..747d3d3dae0 100644 --- a/crates/ink/ir/src/ir/utils.rs +++ b/crates/ink/ir/src/ir/utils.rs @@ -58,9 +58,9 @@ pub fn ensure_pub_visibility( /// /// - The returned value is equal to the selector of the message identifier. /// - Used from within ink! trait definitions as well as ink! trait implementation blocks. -pub fn local_message_id(ident: &syn::Ident) -> u32 { - let input = ident.to_string().into_bytes(); - let selector = Selector::compute(&input); +pub fn local_message_id(ident: &str) -> u32 { + let input = ident.as_bytes(); + let selector = Selector::compute(input); selector.into_be_u32() } diff --git a/crates/ink/tests/ui/abi/all/pass/trait-def-message-name-override.rs b/crates/ink/tests/ui/abi/all/pass/trait-def-message-name-override.rs new file mode 100644 index 00000000000..2ff927be384 --- /dev/null +++ b/crates/ink/tests/ui/abi/all/pass/trait-def-message-name-override.rs @@ -0,0 +1,34 @@ +use ink::{ + reflect::{ + TraitDefinitionRegistry, + TraitMessageInfo, + }, + selector_bytes, + selector_id, +}; +use ink_env::DefaultEnvironment; + +#[ink::trait_definition] +pub trait TraitDefinition { + #[ink(message, name = "myMessage")] + fn message(&self); +} + +fn main() { + // Message selector and selector id both use the name override. + macro_rules! assert_selector_eq { + ( $message_id:expr, $expected_selector:expr $(,)? ) => { + assert_eq!( + < as TraitDefinition>::__ink_TraitInfo + as TraitMessageInfo<{$message_id}>>::SELECTOR, + $expected_selector + ); + } + } + + // ink! selector + assert_selector_eq!(selector_id!("myMessage"), selector_bytes!("TraitDefinition::myMessage")); + + // `keccak256("myMessage()")` == `0x1b008a9f` + assert_selector_eq!(0x1b008a9f_u32, [0x1b, 0x00, 0x8a, 0x9f]); +} diff --git a/crates/ink/tests/ui/abi/sol/pass/trait-def-message-name-override.rs b/crates/ink/tests/ui/abi/sol/pass/trait-def-message-name-override.rs new file mode 100644 index 00000000000..0bab71c7ddb --- /dev/null +++ b/crates/ink/tests/ui/abi/sol/pass/trait-def-message-name-override.rs @@ -0,0 +1,29 @@ +use ink::{ + reflect::{ + TraitDefinitionRegistry, + TraitMessageInfo, + }, +}; +use ink_env::DefaultEnvironment; + +#[ink::trait_definition] +pub trait TraitDefinition { + #[ink(message, name = "myMessage")] + fn message(&self); +} + +fn main() { + // Message selector and selector id both use the name override. + macro_rules! assert_selector_eq { + ( $message_id:literal, $expected_selector:expr $(,)? ) => { + assert_eq!( + < as TraitDefinition>::__ink_TraitInfo + as TraitMessageInfo<$message_id>>::SELECTOR, + $expected_selector + ); + } + } + + // `keccak256("myMessage()")` == `0x1b008a9f` + assert_selector_eq!(0x1b008a9f_u32, [0x1b, 0x00, 0x8a, 0x9f]); +} diff --git a/crates/ink/tests/ui/trait_def/pass/message-name-override-namespace.rs b/crates/ink/tests/ui/trait_def/pass/message-name-override-namespace.rs index de114300f09..e627381386b 100644 --- a/crates/ink/tests/ui/trait_def/pass/message-name-override-namespace.rs +++ b/crates/ink/tests/ui/trait_def/pass/message-name-override-namespace.rs @@ -15,6 +15,7 @@ pub trait TraitDefinition { } fn main() { + // Message selector and selector id both use the name override. macro_rules! assert_selector_eq { ( $message_id:literal, $expected_selector:expr $(,)? ) => { assert_eq!( @@ -26,7 +27,7 @@ fn main() { } assert_selector_eq!( - "message", + "myMessage", selector_bytes!("foo::TraitDefinition::myMessage"), ); } diff --git a/crates/ink/tests/ui/trait_def/pass/message-name-override.rs b/crates/ink/tests/ui/trait_def/pass/message-name-override.rs index 82d8b90e035..6ba09081b3f 100644 --- a/crates/ink/tests/ui/trait_def/pass/message-name-override.rs +++ b/crates/ink/tests/ui/trait_def/pass/message-name-override.rs @@ -15,6 +15,7 @@ pub trait TraitDefinition { } fn main() { + // Message selector and selector id both use the name override. macro_rules! assert_selector_eq { ( $message_id:literal, $expected_selector:expr $(,)? ) => { assert_eq!( @@ -25,5 +26,5 @@ fn main() { } } - assert_selector_eq!("message", selector_bytes!("TraitDefinition::myMessage"),); + assert_selector_eq!("myMessage", selector_bytes!("TraitDefinition::myMessage"),); } diff --git a/crates/ink/tests/ui/trait_def/pass/message-selector-precedence.rs b/crates/ink/tests/ui/trait_def/pass/message-selector-precedence.rs index 0045f3d6f04..9875a666729 100644 --- a/crates/ink/tests/ui/trait_def/pass/message-selector-precedence.rs +++ b/crates/ink/tests/ui/trait_def/pass/message-selector-precedence.rs @@ -14,6 +14,7 @@ pub trait TraitDefinition { } fn main() { + // Custom selector (i.e `selector = 1`) takes precedence over name override macro_rules! assert_selector_eq { ( $message_id:literal, $expected_selector:expr $(,)? ) => { assert_eq!( @@ -24,5 +25,5 @@ fn main() { } } - assert_selector_eq!("message", [0, 0, 0, 1]); + assert_selector_eq!("myMessage", [0, 0, 0, 1]); }