From fea2488b71171e4e51b60e791d5c62f60c282c79 Mon Sep 17 00:00:00 2001 From: Artemka374 Date: Tue, 9 May 2023 15:50:39 +0300 Subject: [PATCH 01/11] initial adding of allow_reentrancy modifier --- crates/env/src/api.rs | 10 ++ crates/env/src/backend.rs | 21 +++- crates/env/src/engine/off_chain/impls.rs | 7 ++ crates/env/src/engine/on_chain/ext/riscv32.rs | 5 + crates/env/src/engine/on_chain/ext/wasm32.rs | 7 ++ crates/env/src/engine/on_chain/impls.rs | 7 ++ crates/ink/codegen/src/generator/dispatch.rs | 103 ++++++++++++++++ .../ink/codegen/src/generator/item_impls.rs | 10 ++ crates/ink/codegen/src/generator/metadata.rs | 10 ++ .../src/generator/trait_def/trait_registry.rs | 3 + crates/ink/ir/src/ir/attrs.rs | 15 +++ crates/ink/ir/src/ir/item_impl/callable.rs | 11 ++ crates/ink/ir/src/ir/item_impl/constructor.rs | 9 ++ crates/ink/ir/src/ir/item_impl/message.rs | 8 ++ crates/ink/src/codegen/dispatch/execution.rs | 14 +++ crates/ink/src/codegen/dispatch/mod.rs | 5 +- crates/ink/src/codegen/mod.rs | 1 + crates/ink/src/codegen/trait_def/mod.rs | 1 + .../src/codegen/trait_def/trait_message.rs | 10 ++ crates/ink/src/reflect/dispatch.rs | 8 ++ crates/metadata/src/specs.rs | 114 ++++++++++++++---- 21 files changed, 350 insertions(+), 29 deletions(-) diff --git a/crates/env/src/api.rs b/crates/env/src/api.rs index c1a9a660ff..6cab9a9c13 100644 --- a/crates/env/src/api.rs +++ b/crates/env/src/api.rs @@ -768,3 +768,13 @@ where TypedEnvBackend::call_runtime::(instance, call) }) } + +/// Returns how many times caller exists on call stack. +pub fn reentrance_count() -> u32 +where + E: Environment, +{ + ::on_instance(|instance| { + TypedEnvBackend::reentrance_count::(instance) + }) +} diff --git a/crates/env/src/backend.rs b/crates/env/src/backend.rs index fb6b00350c..7b286bbbfa 100644 --- a/crates/env/src/backend.rs +++ b/crates/env/src/backend.rs @@ -62,7 +62,7 @@ impl ReturnFlags { /// The flags used to change the behavior of a contract call. #[must_use] -#[derive(Copy, Clone, Debug, Default)] +#[derive(Copy, Clone, Debug)] pub struct CallFlags { forward_input: bool, clone_input: bool, @@ -70,6 +70,17 @@ pub struct CallFlags { allow_reentry: bool, } +impl Default for CallFlags { + fn default() -> Self { + Self { + forward_input: false, + clone_input: false, + tail_call: false, + allow_reentry: true, + } + } +} + impl CallFlags { /// Forwards the input for the current function to the callee. /// @@ -114,7 +125,7 @@ impl CallFlags { /// Without this flag any reentrancy into the current contract that originates from /// the callee (or any of its callees) is denied. This includes the first callee: /// You cannot call into yourself with this flag set. - pub const fn set_allow_reentry(mut self, allow_reentry: bool) -> Self { + pub const fn set_deny_reentry(mut self, allow_reentry: bool) -> Self { self.allow_reentry = allow_reentry; self } @@ -162,7 +173,7 @@ impl CallFlags { /// # Note /// /// See [`Self::set_allow_reentry`] for more information. - pub const fn allow_reentry(&self) -> bool { + pub const fn deny_reentry(&self) -> bool { self.allow_reentry } } @@ -520,4 +531,8 @@ pub trait TypedEnvBackend: EnvBackend { where E: Environment, Call: scale::Encode; + + fn reentrance_count(&mut self) -> u32 + where + E: Environment; } diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index 5dbdf6a773..f3df08d0b0 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -550,4 +550,11 @@ impl TypedEnvBackend for EnvInstance { { unimplemented!("off-chain environment does not support `call_runtime`") } + + fn reentrance_count(&mut self) -> u32 + where + E: Environment, + { + unimplemented!("off-chain environment does not support `reentrance_count`") + } } diff --git a/crates/env/src/engine/on_chain/ext/riscv32.rs b/crates/env/src/engine/on_chain/ext/riscv32.rs index ba030eb3d9..2daf68d9ce 100644 --- a/crates/env/src/engine/on_chain/ext/riscv32.rs +++ b/crates/env/src/engine/on_chain/ext/riscv32.rs @@ -372,6 +372,11 @@ pub fn ecdsa_to_eth_address(pubkey: &[u8; 33], output: &mut [u8; 20]) -> Result ret_code.into() } +pub fn reentrance_count() -> u32 { + let ret_val = sys::call0(FUNC_ID); + ret_val.into_u32() +} + pub fn is_contract(account_id: &[u8]) -> bool { let ret_val = sys::call(FUNC_ID, Ptr32::from_slice(account_id)); ret_val.into_bool() diff --git a/crates/env/src/engine/on_chain/ext/wasm32.rs b/crates/env/src/engine/on_chain/ext/wasm32.rs index 790eabc0d3..7542b2235f 100644 --- a/crates/env/src/engine/on_chain/ext/wasm32.rs +++ b/crates/env/src/engine/on_chain/ext/wasm32.rs @@ -155,6 +155,8 @@ mod sys { #[cfg(feature = "call-runtime")] pub fn call_runtime(call_ptr: Ptr32<[u8]>, call_len: u32) -> ReturnCode; + + pub fn reentrance_count() -> ReturnCode; } #[link(wasm_import_module = "seal1")] @@ -597,6 +599,11 @@ pub fn ecdsa_to_eth_address(pubkey: &[u8; 33], output: &mut [u8; 20]) -> Result ret_code.into() } +pub fn reentrance_count() -> u32 { + let ret_code = unsafe { sys::reentrance_count() }; + ret_code.into_u32() +} + pub fn is_contract(account_id: &[u8]) -> bool { let ret_val = unsafe { sys::is_contract(Ptr32::from_slice(account_id)) }; ret_val.into_bool() diff --git a/crates/env/src/engine/on_chain/impls.rs b/crates/env/src/engine/on_chain/impls.rs index 69747bba5c..447955c4d8 100644 --- a/crates/env/src/engine/on_chain/impls.rs +++ b/crates/env/src/engine/on_chain/impls.rs @@ -588,4 +588,11 @@ impl TypedEnvBackend for EnvInstance { let enc_call = scope.take_encoded(call); ext::call_runtime(enc_call).map_err(Into::into) } + + fn reentrance_count(&mut self) -> u32 + where + E: Environment, + { + ext::reentrance_count() + } } diff --git a/crates/ink/codegen/src/generator/dispatch.rs b/crates/ink/codegen/src/generator/dispatch.rs index bf30512eba..db719dbf15 100644 --- a/crates/ink/codegen/src/generator/dispatch.rs +++ b/crates/ink/codegen/src/generator/dispatch.rs @@ -189,6 +189,7 @@ impl Dispatch<'_> { let constructor_span = constructor.span(); let constructor_ident = constructor.ident(); let payable = constructor.is_payable(); + let allow_reentrancy = constructor.allow_reentrancy(); let selector_id = constructor.composed_selector().into_be_u32().hex_padded_suffixed(); let selector_bytes = constructor.composed_selector().hex_lits(); let cfg_attrs = constructor.get_cfg_attrs(constructor_span); @@ -214,6 +215,7 @@ impl Dispatch<'_> { #storage_ident::#constructor_ident(#( #input_bindings ),* ) }; const PAYABLE: ::core::primitive::bool = #payable; + const ALLOW_REENTRANCY: ::core::primitive::bool = #allow_reentrancy; const SELECTOR: [::core::primitive::u8; 4usize] = [ #( #selector_bytes ),* ]; const LABEL: &'static ::core::primitive::str = ::core::stringify!(#constructor_ident); } @@ -241,6 +243,7 @@ impl Dispatch<'_> { let message_span = message.span(); let message_ident = message.ident(); let payable = message.is_payable(); + let allow_reentrancy = message.allow_reentrancy(); let mutates = message.receiver().is_ref_mut(); let selector_id = message.composed_selector().into_be_u32().hex_padded_suffixed(); let selector_bytes = message.composed_selector().hex_lits(); @@ -265,6 +268,7 @@ impl Dispatch<'_> { }; const SELECTOR: [::core::primitive::u8; 4usize] = [ #( #selector_bytes ),* ]; const PAYABLE: ::core::primitive::bool = #payable; + const ALLOW_REENTRANCY: ::core::primitive::bool = #allow_reentrancy; const MUTATES: ::core::primitive::bool = #mutates; const LABEL: &'static ::core::primitive::str = ::core::stringify!(#message_ident); } @@ -295,6 +299,11 @@ impl Dispatch<'_> { as #trait_path>::__ink_TraitInfo as ::ink::reflect::TraitMessageInfo<#local_id>>::PAYABLE }}; + let allow_reentrancy = quote! {{ + <<::ink::reflect::TraitDefinitionRegistry<<#storage_ident as ::ink::env::ContractEnv>::Env> + as #trait_path>::__ink_TraitInfo + as ::ink::reflect::TraitMessageInfo<#local_id>>::ALLOW_REENTRANCY + }}; let selector = quote! {{ <<::ink::reflect::TraitDefinitionRegistry<<#storage_ident as ::ink::env::ContractEnv>::Env> as #trait_path>::__ink_TraitInfo @@ -325,6 +334,7 @@ impl Dispatch<'_> { }; const SELECTOR: [::core::primitive::u8; 4usize] = #selector; const PAYABLE: ::core::primitive::bool = #payable; + const ALLOW_REENTRANCY: ::core::primitive::bool = #allow_reentrancy; const MUTATES: ::core::primitive::bool = #mutates; const LABEL: &'static ::core::primitive::str = #label; } @@ -350,6 +360,10 @@ impl Dispatch<'_> { let any_constructor_accept_payment = self.any_constructor_accepts_payment(constructors); let any_message_accepts_payment = self.any_message_accepts_payment(messages); + let any_constructor_accept_reentrancy = + self.any_constructor_accepts_reentrancy(constructors); + let any_message_accepts_reentrancy = + self.any_message_accepts_reentrancy(messages); quote_spanned!(span=> #[allow(clippy::nonminimal_bool)] fn internal_deploy() { @@ -358,6 +372,11 @@ impl Dispatch<'_> { .unwrap_or_else(|error| ::core::panic!("{}", error)) } + if !#any_constructor_accept_reentrancy { + ::ink::codegen::deny_reentrancy::<<#storage_ident as ::ink::env::ContractEnv>::Env>() + .unwrap_or_else(|error| ::core::panic!("{}", error)) + } + let dispatchable = match ::ink::env::decode_input::< <#storage_ident as ::ink::reflect::ContractConstructorDecoder>::Type, >() { @@ -394,6 +413,11 @@ impl Dispatch<'_> { .unwrap_or_else(|error| ::core::panic!("{}", error)) } + if !#any_message_accepts_reentrancy { + ::ink::codegen::deny_reentrancy::<<#storage_ident as ::ink::env::ContractEnv>::Env>() + .unwrap_or_else(|error| ::core::panic!("{}", error)) + } + let dispatchable = match ::ink::env::decode_input::< <#storage_ident as ::ink::reflect::ContractMessageDecoder>::Type, >() { @@ -560,6 +584,9 @@ impl Dispatch<'_> { let deny_payment = quote_spanned!(constructor_span=> !<#storage_ident as ::ink::reflect::DispatchableConstructorInfo< #id >>::PAYABLE ); + let deny_reentrancy = quote_spanned!(constructor_span=> + !<#storage_ident as ::ink::reflect::DispatchableConstructorInfo< #id >>::ALLOW_REENTRANCY + ); let constructor_value = quote_spanned!(constructor_span=> <::ink::reflect::ConstructorOutputValue<#constructor_output> as ::ink::reflect::ConstructorOutput::<#storage_ident>> @@ -568,6 +595,9 @@ impl Dispatch<'_> { let constructor_accept_payment_assignment = self.any_constructor_accepts_payment(constructors); + let constructor_accept_reentrancy_assignment = + self.any_constructor_accepts_reentrancy(constructors); + quote_spanned!(constructor_span=> #( #cfg_attrs )* Self::#constructor_ident(input) => { @@ -577,6 +607,11 @@ impl Dispatch<'_> { <#storage_ident as ::ink::env::ContractEnv>::Env>()?; } + if #constructor_accept_reentrancy_assignment && #deny_reentrancy { + ::ink::codegen::deny_reentrancy::< + <#storage_ident as ::ink::env::ContractEnv>::Env>()?; + } + let result: #constructor_output = #constructor_callable(input); let output_value = ::ink::reflect::ConstructorOutputValue::new(result); let output_result = #constructor_value::as_result(&output_value); @@ -763,6 +798,9 @@ impl Dispatch<'_> { let deny_payment = quote_spanned!(message_span=> !<#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::PAYABLE ); + let deny_reentrancy = quote_spanned!(message_span=> + !<#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::ALLOW_REENTRANCY + ); let mutates_storage = quote_spanned!(message_span=> <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::MUTATES ); @@ -770,6 +808,9 @@ impl Dispatch<'_> { let any_message_accepts_payment = self.any_message_accepts_payment(messages); + let any_message_accepts_reentrancy = + self.any_message_accepts_reentrancy(messages); + quote_spanned!(message_span=> #( #cfg_attrs )* Self::#message_ident(input) => { @@ -779,6 +820,11 @@ impl Dispatch<'_> { <#storage_ident as ::ink::env::ContractEnv>::Env>()?; } + if #any_message_accepts_reentrancy && #deny_reentrancy { + ::ink::codegen::deny_reentrancy::< + <#storage_ident as ::ink::env::ContractEnv>::Env>()?; + } + let result: #message_output = #message_callable(&mut contract, input); let is_reverted = ::ink::is_result_type!(#message_output) && ::ink::is_result_err!(result); @@ -913,6 +959,36 @@ impl Dispatch<'_> { ) } + fn any_message_accepts_reentrancy( + &self, + messages: &[MessageDispatchable], + ) -> TokenStream2 { + let span = self.contract.module().storage().span(); + let storage_ident = self.contract.module().storage().ident(); + let message_is_reentrant = messages + .iter() + .enumerate() + .map(|(index, item)| { + let message_span = item.message.span(); + let cfg_attrs = item.message.get_cfg_attrs(message_span); + let id = item.id.clone(); + let ident = quote::format_ident!("message_{}", index); + quote_spanned!(message_span=> + { + let #ident = false; + #( #cfg_attrs )* + let #ident = <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::ALLOW_REENTRANCY; + #ident + } + ) + }); + quote_spanned!(span=> + { + false #( || #message_is_reentrant )* + } + ) + } + /// Generates code to express if any dispatchable ink! constructor accepts payment. /// /// Generates code in the form of variable assignments @@ -948,4 +1024,31 @@ impl Dispatch<'_> { } ) } + + fn any_constructor_accepts_reentrancy( + &self, + constructors: &[ConstructorDispatchable], + ) -> TokenStream2 { + let span = self.contract.module().storage().span(); + let storage_ident = self.contract.module().storage().ident(); + let constructor_is_reentrant = constructors.iter().enumerate().map(|(index, item)| { + let constructor_span = item.constructor.span(); + let cfg_attrs = item.constructor.get_cfg_attrs(constructor_span); + let id = item.id.clone(); + let ident = quote::format_ident!("constructor_{}", index); + quote_spanned!(constructor_span=> + { + let #ident = false; + #( #cfg_attrs )* + let #ident = <#storage_ident as ::ink::reflect::DispatchableConstructorInfo< #id >>::ALLOW_REENTRANCY; + #ident + } + ) + }); + quote_spanned!(span=> + { + false #( || #constructor_is_reentrant )* + } + ) + } } diff --git a/crates/ink/codegen/src/generator/item_impls.rs b/crates/ink/codegen/src/generator/item_impls.rs index ca472091c8..fb32f58695 100644 --- a/crates/ink/codegen/src/generator/item_impls.rs +++ b/crates/ink/codegen/src/generator/item_impls.rs @@ -97,6 +97,15 @@ impl ItemImpls<'_> { }> = ::ink::codegen::TraitMessagePayable::; ) }); + let message_guard_reentrant = message.allow_reentrancy().then(|| { + quote_spanned!(message_span=> + const _: ::ink::codegen::TraitMessageReentrant<{ + <<::ink::reflect::TraitDefinitionRegistry<<#storage_ident as ::ink::env::ContractEnv>::Env> + as #trait_path>::__ink_TraitInfo + as ::ink::reflect::TraitMessageInfo<#message_local_id>>::ALLOW_REENTRANCY + }> = ::ink::codegen::TraitMessageReentrant::; + ) + }); let message_guard_selector = message.user_provided_selector().map(|selector| { let given_selector = selector.into_be_u32().hex_padded_suffixed(); quote_spanned!(message_span=> @@ -111,6 +120,7 @@ impl ItemImpls<'_> { }); quote_spanned!(message_span=> #message_guard_payable + #message_guard_reentrant #message_guard_selector ) }); diff --git a/crates/ink/codegen/src/generator/metadata.rs b/crates/ink/codegen/src/generator/metadata.rs index 0dac717232..51f0926826 100644 --- a/crates/ink/codegen/src/generator/metadata.rs +++ b/crates/ink/codegen/src/generator/metadata.rs @@ -147,6 +147,7 @@ impl Metadata<'_> { let selector_bytes = constructor.composed_selector().hex_lits(); let selector_id = constructor.composed_selector().into_be_u32(); let is_payable = constructor.is_payable(); + let allow_reentrancy = constructor.allow_reentrancy(); let is_default = constructor.is_default(); let constructor = constructor.callable(); let ident = constructor.ident(); @@ -164,6 +165,7 @@ impl Metadata<'_> { #( #args ),* ]) .payable(#is_payable) + .allow_reentrancy(#allow_reentrancy) .default(#is_default) .returns(#ret_ty) .docs([ @@ -244,6 +246,7 @@ impl Metadata<'_> { .filter_map(|attr| attr.extract_docs()); let selector_bytes = message.composed_selector().hex_lits(); let is_payable = message.is_payable(); + let allow_reentrancy = message.allow_reentrancy(); let is_default = message.is_default(); let message = message.callable(); let mutates = message.receiver().is_ref_mut(); @@ -263,6 +266,7 @@ impl Metadata<'_> { .returns(#ret_ty) .mutates(#mutates) .payable(#is_payable) + .allow_reentrancy(#allow_reentrancy) .default(#is_default) .docs([ #( #docs ),* @@ -308,6 +312,11 @@ impl Metadata<'_> { as #trait_path>::__ink_TraitInfo as ::ink::reflect::TraitMessageInfo<#local_id>>::PAYABLE }}; + let allow_reentrancy = quote! {{ + <<::ink::reflect::TraitDefinitionRegistry<<#storage_ident as ::ink::env::ContractEnv>::Env> + as #trait_path>::__ink_TraitInfo + as ::ink::reflect::TraitMessageInfo<#local_id>>::ALLOW_REENTRANCY + }}; let selector = quote! {{ <<::ink::reflect::TraitDefinitionRegistry<<#storage_ident as ::ink::env::ContractEnv>::Env> as #trait_path>::__ink_TraitInfo @@ -325,6 +334,7 @@ impl Metadata<'_> { .returns(#ret_ty) .mutates(#mutates) .payable(#is_payable) + .allow_reentrancy(#allow_reentrancy) .docs([ #( #message_docs ),* ]) 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 b5407421d3..23ab98b0fd 100644 --- a/crates/ink/codegen/src/generator/trait_def/trait_registry.rs +++ b/crates/ink/codegen/src/generator/trait_def/trait_registry.rs @@ -325,10 +325,13 @@ impl TraitRegistry<'_> { let local_id = message.local_id(); let selector_bytes = selector.hex_lits(); let is_payable = message.ink_attrs().is_payable(); + let allow_reentrancy = message.ink_attrs().allow_reentrancy(); quote_spanned!(span=> impl ::ink::reflect::TraitMessageInfo<#local_id> for #trait_info_ident { const PAYABLE: ::core::primitive::bool = #is_payable; + const ALLOW_REENTRANCY: ::core::primitive::bool = #allow_reentrancy; + const SELECTOR: [::core::primitive::u8; 4usize] = [ #( #selector_bytes ),* ]; } ) diff --git a/crates/ink/ir/src/ir/attrs.rs b/crates/ink/ir/src/ir/attrs.rs index 0ae6a7f11c..1c67167754 100644 --- a/crates/ink/ir/src/ir/attrs.rs +++ b/crates/ink/ir/src/ir/attrs.rs @@ -288,6 +288,11 @@ impl InkAttribute { .any(|arg| matches!(arg.kind(), AttributeArg::Payable)) } + pub fn allow_reentrancy(&self) -> bool { + self.args() + .any(|arg| matches!(arg.kind(), AttributeArg::AllowReentrancy)) + } + /// Returns `true` if the ink! attribute contains the `default` argument. pub fn is_default(&self) -> bool { self.args() @@ -358,6 +363,8 @@ pub enum AttributeArgKind { Constructor, /// `#[ink(payable)]` Payable, + /// `#[ink(allow_reentrancy)]` + AllowReentrancy, /// `#[ink(default)]` Default, /// `#[ink(selector = _)]` @@ -412,6 +419,11 @@ pub enum AttributeArg { /// Applied on ink! constructors or messages in order to specify that they /// can receive funds from callers. Payable, + /// `#[ink(allow_reentrancy)]` + /// + /// Applied on ink! constructors or messages in order to indicate + /// they are reentrant. + AllowReentrancy, /// Applied on ink! constructors or messages in order to indicate /// they are default. Default, @@ -464,6 +476,7 @@ impl core::fmt::Display for AttributeArgKind { Self::Message => write!(f, "message"), Self::Constructor => write!(f, "constructor"), Self::Payable => write!(f, "payable"), + Self::AllowReentrancy => write!(f, "allow_reentrancy"), Self::Selector => { write!(f, "selector = S:[u8; 4] || _") } @@ -491,6 +504,7 @@ impl AttributeArg { Self::Message => AttributeArgKind::Message, Self::Constructor => AttributeArgKind::Constructor, Self::Payable => AttributeArgKind::Payable, + Self::AllowReentrancy => AttributeArgKind::AllowReentrancy, Self::Selector(_) => AttributeArgKind::Selector, Self::Extension(_) => AttributeArgKind::Extension, Self::Namespace(_) => AttributeArgKind::Namespace, @@ -511,6 +525,7 @@ impl core::fmt::Display for AttributeArg { Self::Message => write!(f, "message"), Self::Constructor => write!(f, "constructor"), Self::Payable => write!(f, "payable"), + Self::AllowReentrancy => write!(f, "allow_reentrancy"), Self::Selector(selector) => core::fmt::Display::fmt(&selector, f), Self::Extension(extension) => { write!(f, "extension = {:?}", extension.into_u32()) diff --git a/crates/ink/ir/src/ir/item_impl/callable.rs b/crates/ink/ir/src/ir/item_impl/callable.rs index 58dd94b4ce..dec705315c 100644 --- a/crates/ink/ir/src/ir/item_impl/callable.rs +++ b/crates/ink/ir/src/ir/item_impl/callable.rs @@ -116,6 +116,10 @@ where ::is_payable(self.callable) } + fn allow_reentrancy(&self) -> bool { + ::allow_reentrancy(self.callable) + } + fn is_default(&self) -> bool { ::is_default(self.callable) } @@ -174,6 +178,13 @@ pub trait Callable { /// Flagging as payable is done using the `#[ink(payable)]` attribute. fn is_payable(&self) -> bool; + /// Returns `true` if the ink! callable is flagged as reentrant. + /// + /// # Note + /// + /// Flagging as reentrant is done using the `#[ink(allow_reentrancy)]` attribute. + fn allow_reentrancy(&self) -> bool; + /// Returns `true` if the ink! callable is flagged as default. /// /// # Note diff --git a/crates/ink/ir/src/ir/item_impl/constructor.rs b/crates/ink/ir/src/ir/item_impl/constructor.rs index 4acbb3c57c..07956b5fc7 100644 --- a/crates/ink/ir/src/ir/item_impl/constructor.rs +++ b/crates/ink/ir/src/ir/item_impl/constructor.rs @@ -70,6 +70,8 @@ pub struct Constructor { pub(super) item: syn::ImplItemFn, /// If the ink! constructor can receive funds. is_payable: bool, + /// If the ink! constructor can be called multiple times. + allow_reentrancy: bool, /// If the ink! constructor is default. is_default: bool, /// An optional user provided selector. @@ -141,6 +143,7 @@ impl Constructor { match arg.kind() { ir::AttributeArg::Constructor | ir::AttributeArg::Payable + | ir::AttributeArg::AllowReentrancy | ir::AttributeArg::Default | ir::AttributeArg::Selector(_) => Ok(()), _ => Err(None), @@ -159,11 +162,13 @@ impl TryFrom for Constructor { Self::ensure_no_self_receiver(&method_item)?; let (ink_attrs, other_attrs) = Self::sanitize_attributes(&method_item)?; let is_payable = ink_attrs.is_payable(); + let allow_reentrancy = ink_attrs.allow_reentrancy(); let is_default = ink_attrs.is_default(); let selector = ink_attrs.selector(); Ok(Constructor { selector, is_payable, + allow_reentrancy, is_default, item: syn::ImplItemFn { attrs: other_attrs, @@ -201,6 +206,10 @@ impl Callable for Constructor { self.is_payable } + fn allow_reentrancy(&self) -> bool { + self.allow_reentrancy + } + fn is_default(&self) -> bool { self.is_default } diff --git a/crates/ink/ir/src/ir/item_impl/message.rs b/crates/ink/ir/src/ir/item_impl/message.rs index 46d8baf7d2..0a5601fa9a 100644 --- a/crates/ink/ir/src/ir/item_impl/message.rs +++ b/crates/ink/ir/src/ir/item_impl/message.rs @@ -100,6 +100,8 @@ pub struct Message { pub(super) item: syn::ImplItemFn, /// If the ink! message can receive funds. is_payable: bool, + /// If the ink! message is allowed to re-enter the contract. + allow_reentrancy: bool, /// If the ink! message is default. is_default: bool, /// An optional user provided selector. @@ -205,10 +207,12 @@ impl TryFrom for Message { Self::ensure_not_return_self(&method_item)?; let (ink_attrs, other_attrs) = Self::sanitize_attributes(&method_item)?; let is_payable = ink_attrs.is_payable(); + let allow_reentrancy = ink_attrs.allow_reentrancy(); let is_default = ink_attrs.is_default(); let selector = ink_attrs.selector(); Ok(Self { is_payable, + allow_reentrancy, is_default, selector, item: syn::ImplItemFn { @@ -247,6 +251,10 @@ impl Callable for Message { self.is_payable } + fn allow_reentrancy(&self) -> bool { + self.allow_reentrancy + } + fn is_default(&self) -> bool { self.is_default } diff --git a/crates/ink/src/codegen/dispatch/execution.rs b/crates/ink/src/codegen/dispatch/execution.rs index 2036999b14..c15c2c7008 100644 --- a/crates/ink/src/codegen/dispatch/execution.rs +++ b/crates/ink/src/codegen/dispatch/execution.rs @@ -31,3 +31,17 @@ where } Ok(()) } + +#[inline] +pub fn deny_reentrancy() -> Result<(), DispatchError> +where + E: Environment, +{ + let reentrance_count = ink_env::reentrance_count::(); + + if reentrance_count != 0 { + return Err(DispatchError::ReentranceDenied) + } + + Ok(()) +} diff --git a/crates/ink/src/codegen/dispatch/mod.rs b/crates/ink/src/codegen/dispatch/mod.rs index f658cb82a9..d165a8b5b7 100644 --- a/crates/ink/src/codegen/dispatch/mod.rs +++ b/crates/ink/src/codegen/dispatch/mod.rs @@ -17,7 +17,10 @@ mod info; mod type_check; pub use self::{ - execution::deny_payment, + execution::{ + deny_payment, + deny_reentrancy, + }, info::ContractCallBuilder, type_check::{ DispatchInput, diff --git a/crates/ink/src/codegen/mod.rs b/crates/ink/src/codegen/mod.rs index d53fc3517b..e588df9de4 100644 --- a/crates/ink/src/codegen/mod.rs +++ b/crates/ink/src/codegen/mod.rs @@ -24,6 +24,7 @@ pub mod utils; pub use self::{ dispatch::{ deny_payment, + deny_reentrancy, ContractCallBuilder, DispatchInput, DispatchOutput, diff --git a/crates/ink/src/codegen/trait_def/mod.rs b/crates/ink/src/codegen/trait_def/mod.rs index 1383002d05..e7f1a9cbab 100644 --- a/crates/ink/src/codegen/trait_def/mod.rs +++ b/crates/ink/src/codegen/trait_def/mod.rs @@ -23,6 +23,7 @@ pub use self::{ }, trait_message::{ TraitMessagePayable, + TraitMessageReentrant, TraitMessageSelector, }, }; diff --git a/crates/ink/src/codegen/trait_def/trait_message.rs b/crates/ink/src/codegen/trait_def/trait_message.rs index 2bc974bcaa..428accefc3 100644 --- a/crates/ink/src/codegen/trait_def/trait_message.rs +++ b/crates/ink/src/codegen/trait_def/trait_message.rs @@ -22,6 +22,16 @@ /// the same ink! message as defined by the ink! trait message. pub struct TraitMessagePayable; +/// Used as `allow_reentrancy` property guard for ink! trait messages. +/// +/// # Note +/// +/// When an ink! trait message is annotated with `#[ink(allow_reentrancy)]` +/// a compile time check is generated by ink! to guard that the +/// reentrancy allowance of the ink! trait message matches the reentrancy +/// allowance of the same ink! message as defined by the ink! trait message. +pub struct TraitMessageReentrant; + /// Used as `selector` property guard for ink! trait messages. /// /// # Note diff --git a/crates/ink/src/reflect/dispatch.rs b/crates/ink/src/reflect/dispatch.rs index 28da4d9cb2..fce1889116 100644 --- a/crates/ink/src/reflect/dispatch.rs +++ b/crates/ink/src/reflect/dispatch.rs @@ -115,6 +115,8 @@ pub trait DispatchableMessageInfo { const MUTATES: bool; /// Yields `true` if the dispatchable ink! message is payable. const PAYABLE: bool; + /// Yields `true` if the dispatchable ink! message allows reentrancy. + const ALLOW_REENTRANCY: bool; /// The selectors of the dispatchable ink! message. const SELECTOR: [u8; 4]; /// The label of the dispatchable ink! message. @@ -208,6 +210,9 @@ pub trait DispatchableConstructorInfo { /// Yields `true` if the dispatchable ink! constructor is payable. const PAYABLE: bool; + /// Yields `true` if the dispatchable ink! constructor allows reentrancy. + const ALLOW_REENTRANCY: bool; + /// The selectors of the dispatchable ink! constructor. const SELECTOR: [u8; 4]; @@ -496,6 +501,8 @@ pub enum DispatchError { CouldNotReadInput, /// Invalidly paid an unpayable dispatchable. PaidUnpayableMessage, + /// Tried to recursively call the same ink! message, which is not allowed. + ReentranceDenied, } impl Display for DispatchError { @@ -514,6 +521,7 @@ impl DispatchError { Self::InvalidParameters => "unable to decode input", Self::CouldNotReadInput => "could not read input", Self::PaidUnpayableMessage => "paid an unpayable message", + Self::ReentranceDenied => "reentrance denied", } } } diff --git a/crates/metadata/src/specs.rs b/crates/metadata/src/specs.rs index 1b113331b0..ea709bdfbe 100644 --- a/crates/metadata/src/specs.rs +++ b/crates/metadata/src/specs.rs @@ -306,6 +306,8 @@ pub struct ConstructorSpec { pub selector: Selector, /// If the constructor accepts any `value` from the caller. pub payable: bool, + /// If the constructor allows reentrancy. + pub allow_reentrancy: bool, /// The parameters of the deployment handler. pub args: Vec>, /// The return type of the constructor.. @@ -324,6 +326,7 @@ impl IntoPortable for ConstructorSpec { label: self.label.to_string(), selector: self.selector, payable: self.payable, + allow_reentrancy: self.allow_reentrancy, args: self .args .into_iter() @@ -358,6 +361,11 @@ where &self.payable } + /// Returns if the constructor allows reentrancy. + pub fn allow_reentrancy(&self) -> &bool { + &self.allow_reentrancy + } + /// Returns the parameters of the deployment handler. pub fn args(&self) -> &[MessageParamSpec] { &self.args @@ -387,9 +395,10 @@ where /// debug code-gen macros. #[allow(clippy::type_complexity)] #[must_use] -pub struct ConstructorSpecBuilder { +pub struct ConstructorSpecBuilder +{ spec: ConstructorSpec, - marker: PhantomData (Selector, IsPayable, Returns)>, + marker: PhantomData (Selector, IsPayable, AllowReentrancy, Returns)>, } impl ConstructorSpec @@ -403,6 +412,7 @@ where F, Missing, Missing, + Missing, Missing, > { ConstructorSpecBuilder { @@ -410,6 +420,7 @@ where label, selector: Selector::default(), payable: Default::default(), + allow_reentrancy: Default::default(), args: Vec::new(), return_type: ReturnTypeSpec::new(None), docs: Vec::new(), @@ -420,7 +431,7 @@ where } } -impl ConstructorSpecBuilder, P, R> +impl ConstructorSpecBuilder, P, A, R> where F: Form, { @@ -428,7 +439,7 @@ where pub fn selector( self, selector: [u8; 4], - ) -> ConstructorSpecBuilder { + ) -> ConstructorSpecBuilder { ConstructorSpecBuilder { spec: ConstructorSpec { selector: selector.into(), @@ -439,7 +450,7 @@ where } } -impl ConstructorSpecBuilder, R> +impl ConstructorSpecBuilder, A, R> where F: Form, { @@ -447,7 +458,7 @@ where pub fn payable( self, is_payable: bool, - ) -> ConstructorSpecBuilder { + ) -> ConstructorSpecBuilder { ConstructorSpecBuilder { spec: ConstructorSpec { payable: is_payable, @@ -458,7 +469,26 @@ where } } -impl ConstructorSpecBuilder> +impl ConstructorSpecBuilder, R> +where + F: Form, +{ + /// Sets if the constructor is payable, thus accepting value for the caller. + pub fn allow_reentrancy( + self, + allow_reentrancy: bool, + ) -> ConstructorSpecBuilder { + ConstructorSpecBuilder { + spec: ConstructorSpec { + allow_reentrancy, + ..self.spec + }, + marker: PhantomData, + } + } +} + +impl ConstructorSpecBuilder> where F: Form, { @@ -466,7 +496,7 @@ where pub fn returns( self, return_type: ReturnTypeSpec, - ) -> ConstructorSpecBuilder { + ) -> ConstructorSpecBuilder { ConstructorSpecBuilder { spec: ConstructorSpec { return_type, @@ -477,14 +507,14 @@ where } } -impl ConstructorSpecBuilder +impl ConstructorSpecBuilder where F: Form, { /// Sets the input arguments of the constructor specification. - pub fn args(self, args: A) -> Self + pub fn args(self, args: T) -> Self where - A: IntoIterator>, + T: IntoIterator>, { let mut this = self; debug_assert!(this.spec.args.is_empty()); @@ -519,7 +549,14 @@ where } } -impl ConstructorSpecBuilder +impl + ConstructorSpecBuilder< + F, + state::Selector, + state::IsPayable, + state::AllowReentrancy, + state::Returns, + > where F: Form, { @@ -548,6 +585,8 @@ pub struct MessageSpec { mutates: bool, /// If the message accepts any `value` from the caller. payable: bool, + /// If the message is allowed to re-enter the contract. + allow_reentrancy: bool, /// The parameters of the message. args: Vec>, /// The return type of the message. @@ -572,6 +611,8 @@ mod state { pub struct Mutates; /// Type state for telling if the message is payable. pub struct IsPayable; + /// Type state for the telling if the message is allowed to be reentrant. + pub struct AllowReentrancy; /// Type state for the message return type. pub struct Returns; /// Type state for the `AccountId` type of the environment. @@ -602,6 +643,7 @@ where Missing, Missing, Missing, + Missing, Missing, > { MessageSpecBuilder { @@ -610,6 +652,7 @@ where selector: Selector::default(), mutates: false, payable: false, + allow_reentrancy: false, args: Vec::new(), return_type: ReturnTypeSpec::new(None), docs: Vec::new(), @@ -676,15 +719,15 @@ where /// debug code-gen macros. #[allow(clippy::type_complexity)] #[must_use] -pub struct MessageSpecBuilder +pub struct MessageSpecBuilder where F: Form, { spec: MessageSpec, - marker: PhantomData (Selector, Mutates, IsPayable, Returns)>, + marker: PhantomData (Selector, Mutates, IsPayable, AllowReentrancy, Returns)>, } -impl MessageSpecBuilder, M, P, R> +impl MessageSpecBuilder, M, P, A, R> where F: Form, { @@ -692,7 +735,7 @@ where pub fn selector( self, selector: [u8; 4], - ) -> MessageSpecBuilder { + ) -> MessageSpecBuilder { MessageSpecBuilder { spec: MessageSpec { selector: selector.into(), @@ -703,7 +746,7 @@ where } } -impl MessageSpecBuilder, P, R> +impl MessageSpecBuilder, P, A, R> where F: Form, { @@ -712,7 +755,7 @@ where pub fn mutates( self, mutates: bool, - ) -> MessageSpecBuilder { + ) -> MessageSpecBuilder { MessageSpecBuilder { spec: MessageSpec { mutates, @@ -723,7 +766,7 @@ where } } -impl MessageSpecBuilder, R> +impl MessageSpecBuilder, A, R> where F: Form, { @@ -731,7 +774,7 @@ where pub fn payable( self, is_payable: bool, - ) -> MessageSpecBuilder { + ) -> MessageSpecBuilder { MessageSpecBuilder { spec: MessageSpec { payable: is_payable, @@ -742,7 +785,26 @@ where } } -impl MessageSpecBuilder> +impl MessageSpecBuilder, R> +where + F: Form, +{ + /// Sets if the message is payable, thus accepting value for the caller. + pub fn allow_reentrancy( + self, + allow_reentrancy: bool, + ) -> MessageSpecBuilder { + MessageSpecBuilder { + spec: MessageSpec { + allow_reentrancy, + ..self.spec + }, + marker: PhantomData, + } + } +} + +impl MessageSpecBuilder> where F: Form, { @@ -750,7 +812,7 @@ where pub fn returns( self, return_type: ReturnTypeSpec, - ) -> MessageSpecBuilder { + ) -> MessageSpecBuilder { MessageSpecBuilder { spec: MessageSpec { return_type, @@ -761,14 +823,14 @@ where } } -impl MessageSpecBuilder +impl MessageSpecBuilder where F: Form, { /// Sets the input arguments of the message specification. - pub fn args(self, args: A) -> Self + pub fn args(self, args: T) -> Self where - A: IntoIterator>, + T: IntoIterator>, { let mut this = self; debug_assert!(this.spec.args.is_empty()); @@ -805,6 +867,7 @@ impl state::Selector, state::Mutates, state::IsPayable, + state::AllowReentrancy, state::Returns, > where @@ -825,6 +888,7 @@ impl IntoPortable for MessageSpec { selector: self.selector, mutates: self.mutates, payable: self.payable, + allow_reentrancy: self.allow_reentrancy, default: self.default, args: self .args From cd45587f2e566ad844e943273ae27c30cebb0cc0 Mon Sep 17 00:00:00 2001 From: Artemka374 Date: Wed, 10 May 2023 17:35:55 +0300 Subject: [PATCH 02/11] make feature work --- crates/env/src/backend.rs | 2 +- crates/ink/ir/src/ir/attrs.rs | 3 +++ crates/ink/ir/src/ir/item_impl/message.rs | 1 + crates/ink/ir/src/ir/trait_def/item/trait_item.rs | 1 + crates/ink/src/codegen/mod.rs | 1 + 5 files changed, 7 insertions(+), 1 deletion(-) diff --git a/crates/env/src/backend.rs b/crates/env/src/backend.rs index 7b286bbbfa..664322e7f0 100644 --- a/crates/env/src/backend.rs +++ b/crates/env/src/backend.rs @@ -126,7 +126,7 @@ impl CallFlags { /// the callee (or any of its callees) is denied. This includes the first callee: /// You cannot call into yourself with this flag set. pub const fn set_deny_reentry(mut self, allow_reentry: bool) -> Self { - self.allow_reentry = allow_reentry; + self.allow_reentry = !allow_reentry; self } diff --git a/crates/ink/ir/src/ir/attrs.rs b/crates/ink/ir/src/ir/attrs.rs index 1c67167754..6eab277d16 100644 --- a/crates/ink/ir/src/ir/attrs.rs +++ b/crates/ink/ir/src/ir/attrs.rs @@ -997,6 +997,7 @@ impl Parse for AttributeFrag { "anonymous" => Ok(AttributeArg::Anonymous), "topic" => Ok(AttributeArg::Topic), "payable" => Ok(AttributeArg::Payable), + "allow_reentrancy" => Ok(AttributeArg::AllowReentrancy), "default" => Ok(AttributeArg::Default), "impl" => Ok(AttributeArg::Implementation), _ => match ident.to_string().as_str() { @@ -1437,6 +1438,7 @@ mod tests { event, topic, payable, + allow_reentrancy, impl, )] }, @@ -1447,6 +1449,7 @@ mod tests { AttributeArg::Event, AttributeArg::Topic, AttributeArg::Payable, + AttributeArg::AllowReentrancy, AttributeArg::Implementation, ])), ); diff --git a/crates/ink/ir/src/ir/item_impl/message.rs b/crates/ink/ir/src/ir/item_impl/message.rs index 0a5601fa9a..7e52a32b0b 100644 --- a/crates/ink/ir/src/ir/item_impl/message.rs +++ b/crates/ink/ir/src/ir/item_impl/message.rs @@ -189,6 +189,7 @@ impl Message { match arg.kind() { ir::AttributeArg::Message | ir::AttributeArg::Payable + | ir::AttributeArg::AllowReentrancy | ir::AttributeArg::Default | ir::AttributeArg::Selector(_) => Ok(()), _ => Err(None), 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 9e215717ba..eb7795d015 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 @@ -92,6 +92,7 @@ impl<'a> InkTraitMessage<'a> { Err(Some(format_err!(arg.span(), "wildcard selectors are only supported for inherent ink! messages or constructors, not for traits."))), ir::AttributeArg::Message | ir::AttributeArg::Payable + | ir::AttributeArg::AllowReentrancy | ir::AttributeArg::Default | ir::AttributeArg::Selector(_) => Ok(()), _ => Err(None), diff --git a/crates/ink/src/codegen/mod.rs b/crates/ink/src/codegen/mod.rs index e588df9de4..3d0cfe4402 100644 --- a/crates/ink/src/codegen/mod.rs +++ b/crates/ink/src/codegen/mod.rs @@ -46,6 +46,7 @@ pub use self::{ TraitCallForwarder, TraitCallForwarderFor, TraitMessagePayable, + TraitMessageReentrant, TraitMessageSelector, }, }; From d539b3f5fa20b4c5c07d63a3321ca3b775624be3 Mon Sep 17 00:00:00 2001 From: Artemka374 Date: Mon, 15 May 2023 12:08:44 +0300 Subject: [PATCH 03/11] Auto stash before merge of "feature/allow_reentrancy-modifier" and "origin/master" --- .idea/.gitignore | 8 ++++++ .idea/brushfam-ink.iml | 25 +++++++++++++++++ .idea/modules.xml | 8 ++++++ .idea/vcs.xml | 6 +++++ README.md | 3 ++- crates/env/src/backend.rs | 2 +- crates/env/src/tests.rs | 24 ++++++++--------- crates/ink/ir/src/ir/attrs.rs | 1 + crates/ink/ir/src/ir/item_impl/constructor.rs | 2 +- crates/ink/src/reflect/trait_def/info.rs | 3 +++ ...trait-message-allow-reentrancy-mismatch.rs | 27 +++++++++++++++++++ .../pass/constructor-allow-reentrancy.rs | 21 +++++++++++++++ .../constructor-reentrancy-not-allowed.rs | 21 +++++++++++++++ .../contract/pass/message-allow-reentrancy.rs | 25 +++++++++++++++++ crates/metadata/src/specs.rs | 4 +-- crates/metadata/src/tests.rs | 26 ++++++++++++++++++ 16 files changed, 189 insertions(+), 17 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/brushfam-ink.iml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 crates/ink/tests/ui/contract/fail/trait-message-allow-reentrancy-mismatch.rs create mode 100644 crates/ink/tests/ui/contract/pass/constructor-allow-reentrancy.rs create mode 100644 crates/ink/tests/ui/contract/pass/constructor-reentrancy-not-allowed.rs create mode 100644 crates/ink/tests/ui/contract/pass/message-allow-reentrancy.rs diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000000..13566b81b0 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/brushfam-ink.iml b/.idea/brushfam-ink.iml new file mode 100644 index 0000000000..e52ed05fd7 --- /dev/null +++ b/.idea/brushfam-ink.iml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000000..0798285f09 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000000..35eb1ddfbb --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index bb4b742c5e..9eedc034ee 100644 --- a/README.md +++ b/README.md @@ -231,6 +231,7 @@ In a module annotated with `#[ink::contract]` these attributes are available: | `#[ink(anonymous)]` | Applicable to ink! events. | Tells the ink! codegen to treat the ink! event as anonymous which omits the event signature as topic upon emitting. Very similar to anonymous events in Solidity. | | `#[ink(topic)]` | Applicable on ink! event field. | Tells the ink! codegen to provide a topic hash for the given field. Every ink! event can only have a limited number of such topic fields. Similar semantics as to indexed event arguments in Solidity. | | `#[ink(payable)]` | Applicable to ink! messages. | Allows receiving value as part of the call of the ink! message. ink! constructors are implicitly payable. | +| `#[ink(allow_reentrancy)]` | Applicable to ink! messages. | Allows the ink! message to be called reentrantly. | | `#[ink(selector = S:u32)]` | Applicable to ink! messages and ink! constructors. | Specifies a concrete dispatch selector for the flagged entity. This allows a contract author to precisely control the selectors of their APIs making it possible to rename their API without breakage. | | `#[ink(selector = _)]` | Applicable to ink! messages. | Specifies a fallback message that is invoked if no other ink! message matches a selector. | | `#[ink(namespace = N:string)]` | Applicable to ink! trait implementation blocks. | Changes the resulting selectors of all the ink! messages and ink! constructors within the trait implementation. Allows to disambiguate between trait implementations with overlapping message or constructor names. Use only with great care and consideration! | @@ -253,7 +254,7 @@ We have [a very comprehensive documentation portal](https://use.ink), but if you are looking for the crate level documentation itself, then these are the relevant links: -| Crate | Docs | Description | +| Crate | Docs | Description |payable |:--|:--|:--| `ink` | [![][j1]][j2] | Language features exposed by ink!. See [here](https://paritytech.github.io/ink/ink/attr.contract.html) for a detailed description of attributes which you can use in an `#[ink::contract]`. | `ink_storage` | [![][f1]][f2] | Data structures available in ink!. | diff --git a/crates/env/src/backend.rs b/crates/env/src/backend.rs index 664322e7f0..90601bb213 100644 --- a/crates/env/src/backend.rs +++ b/crates/env/src/backend.rs @@ -174,7 +174,7 @@ impl CallFlags { /// /// See [`Self::set_allow_reentry`] for more information. pub const fn deny_reentry(&self) -> bool { - self.allow_reentry + !self.allow_reentry } } diff --git a/crates/env/src/tests.rs b/crates/env/src/tests.rs index 76d6d6a1eb..1d325fb569 100644 --- a/crates/env/src/tests.rs +++ b/crates/env/src/tests.rs @@ -70,34 +70,34 @@ fn test_call_flags() { // enable each flag one after the other let flags = flags.set_forward_input(true); assert!(flags.forward_input()); - assert_eq!(flags.into_u32(), 0b0000_0001); + assert_eq!(flags.into_u32(), 0b0000_1001); let flags = flags.set_clone_input(true); assert!(flags.clone_input()); - assert_eq!(flags.into_u32(), 0b0000_0011); + assert_eq!(flags.into_u32(), 0b0000_1011); let flags = flags.set_tail_call(true); assert!(flags.tail_call()); - assert_eq!(flags.into_u32(), 0b0000_0111); - - let flags = flags.set_allow_reentry(true); - assert!(flags.allow_reentry()); assert_eq!(flags.into_u32(), 0b0000_1111); - // disable each flag one after the other - let flags = flags.set_allow_reentry(false); - assert!(!flags.allow_reentry()); + let flags = flags.set_deny_reentry(true); + assert!(flags.deny_reentry()); assert_eq!(flags.into_u32(), 0b0000_0111); + // disable each flag one after the other + let flags = flags.set_deny_reentry(false); + assert!(!flags.deny_reentry()); + assert_eq!(flags.into_u32(), 0b0000_1111); + let flags = flags.set_tail_call(false); assert!(!flags.tail_call()); - assert_eq!(flags.into_u32(), 0b0000_0011); + assert_eq!(flags.into_u32(), 0b0000_1011); let flags = flags.set_clone_input(false); assert!(!flags.clone_input()); - assert_eq!(flags.into_u32(), 0b0000_0001); + assert_eq!(flags.into_u32(), 0b0000_1001); let flags = flags.set_forward_input(false); assert!(!flags.forward_input()); - assert_eq!(flags.into_u32(), 0b0000_0000); + assert_eq!(flags.into_u32(), 0b0000_1000); } diff --git a/crates/ink/ir/src/ir/attrs.rs b/crates/ink/ir/src/ir/attrs.rs index 6eab277d16..49e7dd9638 100644 --- a/crates/ink/ir/src/ir/attrs.rs +++ b/crates/ink/ir/src/ir/attrs.rs @@ -288,6 +288,7 @@ impl InkAttribute { .any(|arg| matches!(arg.kind(), AttributeArg::Payable)) } + /// Returns `true` if the ink! attribute contains the `allow_reentrancy` argument. pub fn allow_reentrancy(&self) -> bool { self.args() .any(|arg| matches!(arg.kind(), AttributeArg::AllowReentrancy)) diff --git a/crates/ink/ir/src/ir/item_impl/constructor.rs b/crates/ink/ir/src/ir/item_impl/constructor.rs index 07956b5fc7..b95a423b4e 100644 --- a/crates/ink/ir/src/ir/item_impl/constructor.rs +++ b/crates/ink/ir/src/ir/item_impl/constructor.rs @@ -70,7 +70,7 @@ pub struct Constructor { pub(super) item: syn::ImplItemFn, /// If the ink! constructor can receive funds. is_payable: bool, - /// If the ink! constructor can be called multiple times. + /// If the ink! constructor can be called multiple times by reentering. allow_reentrancy: bool, /// If the ink! constructor is default. is_default: bool, diff --git a/crates/ink/src/reflect/trait_def/info.rs b/crates/ink/src/reflect/trait_def/info.rs index 421c92a5f3..3ae20b3018 100644 --- a/crates/ink/src/reflect/trait_def/info.rs +++ b/crates/ink/src/reflect/trait_def/info.rs @@ -124,6 +124,9 @@ pub trait TraitMessageInfo { /// Is `true` if the ink! trait message has been annotated with `#[ink(payable)]`. const PAYABLE: bool; + /// Is `true` if the ink! trait message has been annotated with `#[ink(allow_reentrancy)]`. + const ALLOW_REENTRANCY: bool; + /// The unique selector of the ink! trait message. /// /// This might have been adjusted using `#[ink(selector = N:u32)]` at the diff --git a/crates/ink/tests/ui/contract/fail/trait-message-allow-reentrancy-mismatch.rs b/crates/ink/tests/ui/contract/fail/trait-message-allow-reentrancy-mismatch.rs new file mode 100644 index 0000000000..e43771e5c3 --- /dev/null +++ b/crates/ink/tests/ui/contract/fail/trait-message-allow-reentrancy-mismatch.rs @@ -0,0 +1,27 @@ +#[ink::trait_definition] +pub trait TraitDefinition { + #[ink(message)] + fn message(&self); +} + +#[ink::contract] +mod contract { + use super::TraitDefinition; + + #[ink(storage)] + pub struct Contract {} + + impl Contract { + #[ink(constructor)] + pub fn constructor() -> Self { + Self {} + } + } + + impl TraitDefinition for Contract { + #[ink(message, allow_reentrancy)] + fn message(&self) {} + } +} + +fn main() {} diff --git a/crates/ink/tests/ui/contract/pass/constructor-allow-reentrancy.rs b/crates/ink/tests/ui/contract/pass/constructor-allow-reentrancy.rs new file mode 100644 index 0000000000..84e827de05 --- /dev/null +++ b/crates/ink/tests/ui/contract/pass/constructor-allow-reentrancy.rs @@ -0,0 +1,21 @@ +#[ink::contract] +mod contract { + #[ink(storage)] + pub struct Contract {} + + impl Contract { + #[ink(constructor, selector = 0, allow_reentrancy)] + pub fn constructor() -> Self { + Self {} + } + + #[ink(message)] + pub fn message(&self) {} + } +} + +use contract::Contract; + +fn main() { + assert!(>::ALLOW_REENTRANCY); +} diff --git a/crates/ink/tests/ui/contract/pass/constructor-reentrancy-not-allowed.rs b/crates/ink/tests/ui/contract/pass/constructor-reentrancy-not-allowed.rs new file mode 100644 index 0000000000..74e595c6de --- /dev/null +++ b/crates/ink/tests/ui/contract/pass/constructor-reentrancy-not-allowed.rs @@ -0,0 +1,21 @@ +#[ink::contract] +mod contract { + #[ink(storage)] + pub struct Contract {} + + impl Contract { + #[ink(constructor, selector = 0)] + pub fn constructor() -> Self { + Self {} + } + + #[ink(message)] + pub fn message(&self) {} + } +} + +use contract::Contract; + +fn main() { + assert!(!>::ALLOW_REENTRANCY); +} diff --git a/crates/ink/tests/ui/contract/pass/message-allow-reentrancy.rs b/crates/ink/tests/ui/contract/pass/message-allow-reentrancy.rs new file mode 100644 index 0000000000..118afb1eb1 --- /dev/null +++ b/crates/ink/tests/ui/contract/pass/message-allow-reentrancy.rs @@ -0,0 +1,25 @@ +#[ink::contract] +mod contract { + #[ink(storage)] + pub struct Contract {} + + impl Contract { + #[ink(constructor)] + pub fn constructor() -> Self { + Self {} + } + + #[ink(message, selector = 1, allow_reentrancy)] + pub fn message_1(&self) {} + + #[ink(message, selector = 2)] + pub fn message_2(&self) {} + } +} + +use contract::Contract; + +fn main() { + assert!(>::ALLOW_REENTRANCY); + assert!(!>::ALLOW_REENTRANCY); +} diff --git a/crates/metadata/src/specs.rs b/crates/metadata/src/specs.rs index ea709bdfbe..5d60613027 100644 --- a/crates/metadata/src/specs.rs +++ b/crates/metadata/src/specs.rs @@ -473,7 +473,7 @@ impl ConstructorSpecBuilder where F: Form, { - /// Sets if the constructor is payable, thus accepting value for the caller. + /// Sets if the constructor is reentrant. pub fn allow_reentrancy( self, allow_reentrancy: bool, @@ -789,7 +789,7 @@ impl MessageSpecBuilder( vec!["i32"].into_iter().map(AsRef::as_ref), @@ -74,6 +77,7 @@ fn spec_contract_only_one_default_message_allowed() { .selector([231u8, 208u8, 89u8, 15u8]) .mutates(true) .payable(true) + .allow_reentrancy(true) .args(vec![MessageParamSpec::new("by") .of_type(TypeSpec::with_name_segs::( vec!["i32"].into_iter().map(AsRef::as_ref), @@ -86,6 +90,7 @@ fn spec_contract_only_one_default_message_allowed() { .selector([37u8, 68u8, 74u8, 254u8]) .mutates(false) .payable(false) + .allow_reentrancy(false) .args(Vec::new()) .returns(ReturnTypeSpec::new(TypeSpec::with_name_segs::( vec!["i32"].into_iter().map(AsRef::as_ref), @@ -111,6 +116,7 @@ fn spec_contract_only_one_default_constructor_allowed() { ConstructorSpec::from_label("new") .selector([94u8, 189u8, 136u8, 214u8]) .payable(true) + .allow_reentrancy(true) .args(vec![MessageParamSpec::new("init_value") .of_type(TypeSpec::with_name_segs::( vec!["i32"].into_iter().map(AsRef::as_ref), @@ -123,6 +129,7 @@ fn spec_contract_only_one_default_constructor_allowed() { ConstructorSpec::from_label("default") .selector([2u8, 34u8, 255u8, 24u8]) .payable(Default::default()) + .allow_reentrancy(Default::default()) .args(Vec::new()) .returns(ReturnTypeSpec::new(None)) .docs(Vec::new()) @@ -133,6 +140,7 @@ fn spec_contract_only_one_default_constructor_allowed() { .selector([231u8, 208u8, 89u8, 15u8]) .mutates(true) .payable(true) + .allow_reentrancy(true) .args(vec![MessageParamSpec::new("by") .of_type(TypeSpec::with_name_segs::( vec!["i32"].into_iter().map(AsRef::as_ref), @@ -170,6 +178,7 @@ fn spec_contract_json() { ConstructorSpec::from_label("new") .selector([94u8, 189u8, 136u8, 214u8]) .payable(true) + .allow_reentrancy(true) .args(vec![MessageParamSpec::new("init_value") .of_type(TypeSpec::with_name_segs::( vec!["i32"].into_iter().map(AsRef::as_ref), @@ -181,6 +190,7 @@ fn spec_contract_json() { ConstructorSpec::from_label("default") .selector([2u8, 34u8, 255u8, 24u8]) .payable(Default::default()) + .allow_reentrancy(Default::default()) .args(Vec::new()) .returns(ReturnTypeSpec::new(None)) .docs(Vec::new()) @@ -189,6 +199,7 @@ fn spec_contract_json() { ConstructorSpec::from_label("result_new") .selector([6u8, 3u8, 55u8, 123u8]) .payable(Default::default()) + .allow_reentrancy(Default::default()) .args(Vec::new()) .returns(ReturnTypeSpec::new(Some(TypeSpec::with_name_str::< Result<(), ()>, @@ -203,6 +214,7 @@ fn spec_contract_json() { .selector([231u8, 208u8, 89u8, 15u8]) .mutates(true) .payable(true) + .allow_reentrancy(true) .args(vec![MessageParamSpec::new("by") .of_type(TypeSpec::with_name_segs::( vec!["i32"].into_iter().map(AsRef::as_ref), @@ -215,6 +227,7 @@ fn spec_contract_json() { .selector([37u8, 68u8, 74u8, 254u8]) .mutates(false) .payable(false) + .allow_reentrancy(false) .args(Vec::new()) .returns(ReturnTypeSpec::new(TypeSpec::with_name_segs::( vec!["i32"].into_iter().map(AsRef::as_ref), @@ -297,6 +310,7 @@ fn spec_contract_json() { "default": false, "label": "new", "payable": true, + "allowReentrancy": true, "returnType": null, "selector": "0x5ebd88d6" }, @@ -306,6 +320,7 @@ fn spec_contract_json() { "default": true, "label": "default", "payable": false, + "allowReentrancy": false, "returnType": null, "selector": "0x0222ff18" }, @@ -315,6 +330,7 @@ fn spec_contract_json() { "default": false, "label": "result_new", "payable": false, + "allowReentrancy": false, "returnType": { "displayName": [ "core", @@ -391,6 +407,7 @@ fn spec_contract_json() { "docs": [], "mutates": true, "payable": true, + "allowReentrancy": true, "label": "inc", "returnType": null, "selector": "0xe7d0590f" @@ -401,6 +418,7 @@ fn spec_contract_json() { "docs": [], "mutates": false, "payable": false, + "allowReentrancy": false, "label": "get", "returnType": { "displayName": [ @@ -424,6 +442,7 @@ fn trim_docs() { .selector(123_456_789u32.to_be_bytes()) .docs(vec![" foobar "]) .payable(Default::default()) + .allow_reentrancy(Default::default()) .returns(ReturnTypeSpec::new(None)) .done(); let mut registry = Registry::new(); @@ -440,6 +459,7 @@ fn trim_docs() { json!({ "label": "foo", "payable": false, + "allowReentrancy": false, "returnType": null, "selector": "0x075bcd15", "args": [], @@ -466,6 +486,7 @@ fn trim_docs_with_code() { " ```", ]) .payable(Default::default()) + .allow_reentrancy(Default::default()) .returns(ReturnTypeSpec::new(None)) .done(); let mut registry = Registry::new(); @@ -482,6 +503,7 @@ fn trim_docs_with_code() { json!({ "label": "foo", "payable": false, + "allowReentrancy": false, "returnType": null, "selector": "0x075bcd15", "args": [], @@ -554,6 +576,7 @@ fn runtime_constructor_spec() -> ConstructorSpec { ConstructorSpec::from_label("foo".to_string()) .selector(Default::default()) .payable(true) + .allow_reentrancy(true) .args(args) .docs(vec!["foo", "bar"]) .returns(ret_spec) @@ -571,6 +594,7 @@ fn runtime_message_spec() -> MessageSpec { .selector(Default::default()) .mutates(false) .payable(true) + .allow_reentrancy(true) .args(args) .returns(ret_spec) .docs(["foo".to_string(), "bar".to_string()]) @@ -609,6 +633,7 @@ fn construct_runtime_contract_spec() { "label": "foo", "selector": "0x00000000", "payable": true, + "allowReentrancy": true, "returnType": null, "args": [ { @@ -637,6 +662,7 @@ fn construct_runtime_contract_spec() { "selector": "0x00000000", "mutates": false, "payable": true, + "allowReentrancy": true, "args": [ { "label": "foo_arg", From 461c1730bf4704903bda67bbf4ca357dadd02071 Mon Sep 17 00:00:00 2001 From: Artemka374 Date: Tue, 16 May 2023 15:18:54 +0300 Subject: [PATCH 04/11] update UI tests --- .../fail/constructor-input-non-codec.stderr | 24 ++++++++++---- ...tructor-multiple-wildcard-selectors.stderr | 16 +++++---- .../constructor-return-result-invalid.stderr | 6 ++-- ...uctor-return-result-non-codec-error.stderr | 21 +++++++++--- ...ctor-selector-and-wildcard-selector.stderr | 4 +-- .../fail/constructor-self-receiver-03.stderr | 24 +++++++------- .../event-too-many-topics-anonymous.stderr | 13 ++++++-- .../fail/event-too-many-topics.stderr | 13 ++++++-- .../fail/impl-block-for-non-storage-01.stderr | 4 +-- .../impl-block-using-env-no-marker.stderr | 2 +- ...pl-block-using-static-env-no-marker.stderr | 4 +-- .../contract/fail/message-hygiene-try.stderr | 2 +- .../fail/message-input-non-codec.stderr | 16 ++++++--- ...message-multiple-wildcard-selectors.stderr | 4 +-- .../fail/message-returns-non-codec.stderr | 22 +++++++++---- ...sage-selector-and-wildcard-selector.stderr | 4 +-- .../message-self-receiver-invalid-01.stderr | 2 +- .../message-self-receiver-invalid-02.stderr | 2 +- .../fail/message-self-receiver-missing.stderr | 5 +-- .../fail/module-missing-constructor.stderr | 14 +++++--- .../fail/module-missing-message.stderr | 14 +++++--- .../fail/module-missing-storage.stderr | 14 +++++--- .../fail/module-multiple-storages.stderr | 18 ++++++---- .../fail/trait-impl-namespace-invalid.stderr | 8 +++-- ...t-message-allow-reentrancy-mismatch.stderr | 8 +++++ .../trait-message-payable-mismatch.stderr | 2 +- .../trait-message-selector-mismatch.stderr | 2 +- .../trait-message-selector-overlap-1.stderr | 20 +++++++---- .../trait-message-selector-overlap-2.stderr | 20 +++++++---- .../trait-message-selector-overlap-3.stderr | 20 +++++++---- .../trait-message-wildcard-selector.stderr | 4 +-- .../fail/collections_only_packed_1.stderr | 4 +-- .../fail/collections_only_packed_2.stderr | 4 +-- .../fail/definition_constructor.stderr | 5 +-- .../ui/trait_def/fail/definition_empty.stderr | 2 +- .../fail/message_input_non_codec.stderr | 33 +++++++++++-------- .../fail/message_output_non_codec.stderr | 15 +++++---- 37 files changed, 263 insertions(+), 132 deletions(-) create mode 100644 crates/ink/tests/ui/contract/fail/trait-message-allow-reentrancy-mismatch.stderr diff --git a/crates/ink/tests/ui/contract/fail/constructor-input-non-codec.stderr b/crates/ink/tests/ui/contract/fail/constructor-input-non-codec.stderr index 84471d5f79..737f9bb89e 100644 --- a/crates/ink/tests/ui/contract/fail/constructor-input-non-codec.stderr +++ b/crates/ink/tests/ui/contract/fail/constructor-input-non-codec.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeDecode` is not satisfied --> tests/ui/contract/fail/constructor-input-non-codec.rs:11:28 | 11 | pub fn constructor(_input: NonCodecType) -> Self { - | ^^^^^^ the trait `WrapperTypeDecode` is not implemented for `NonCodecType` + | ^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `NonCodecType` | = help: the following other types implement trait `WrapperTypeDecode`: Arc @@ -12,14 +12,19 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeDecode` is not satisfied note: required by a bound in `DispatchInput` --> src/codegen/dispatch/type_check.rs | + | pub struct DispatchInput(T) + | ------------- required by a bound in this struct + | where | T: scale::Decode + 'static; | ^^^^^^^^^^^^^ required by this bound in `DispatchInput` error[E0277]: the trait bound `NonCodecType: WrapperTypeDecode` is not satisfied --> tests/ui/contract/fail/constructor-input-non-codec.rs:11:9 | -11 | pub fn constructor(_input: NonCodecType) -> Self { - | ^^^ the trait `WrapperTypeDecode` is not implemented for `NonCodecType` +11 | / pub fn constructor(_input: NonCodecType) -> Self { +12 | | Self {} +13 | | } + | |_________^ the trait `WrapperTypeDecode` is not implemented for `NonCodecType` | = help: the following other types implement trait `WrapperTypeDecode`: Arc @@ -30,11 +35,13 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeDecode` is not satisfied error[E0277]: the trait bound `NonCodecType: WrapperTypeEncode` is not satisfied --> tests/ui/contract/fail/constructor-input-non-codec.rs:1:1 | -1 | #[ink::contract] - | ^^^^^^^^^^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `NonCodecType` +1 | #[ink::contract] + | ^^^^^^^^^^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `NonCodecType` ... -11 | pub fn constructor(_input: NonCodecType) -> Self { - | --- required by a bound introduced by this call +11 | / pub fn constructor(_input: NonCodecType) -> Self { +12 | | Self {} +13 | | } + | |_________- required by a bound introduced by this call | = help: the following other types implement trait `WrapperTypeEncode`: &T @@ -50,5 +57,8 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeEncode` is not satisfied note: required by a bound in `ExecutionInput::>::push_arg` --> $WORKSPACE/crates/env/src/call/execution_input.rs | + | pub fn push_arg( + | -------- required by a bound in this associated function +... | T: scale::Encode, | ^^^^^^^^^^^^^ required by this bound in `ExecutionInput::>::push_arg` diff --git a/crates/ink/tests/ui/contract/fail/constructor-multiple-wildcard-selectors.stderr b/crates/ink/tests/ui/contract/fail/constructor-multiple-wildcard-selectors.stderr index e8c23317b1..d414f29d56 100644 --- a/crates/ink/tests/ui/contract/fail/constructor-multiple-wildcard-selectors.stderr +++ b/crates/ink/tests/ui/contract/fail/constructor-multiple-wildcard-selectors.stderr @@ -1,11 +1,15 @@ error: encountered ink! constructor with overlapping wildcard selectors --> tests/ui/contract/fail/constructor-multiple-wildcard-selectors.rs:13:9 | -13 | pub fn constructor2() -> Self { - | ^^^ +13 | / pub fn constructor2() -> Self { +14 | | Self {} +15 | | } + | |_________^ error: first ink! constructor with overlapping wildcard selector here - --> tests/ui/contract/fail/constructor-multiple-wildcard-selectors.rs:8:9 - | -8 | pub fn constructor1() -> Self { - | ^^^ + --> tests/ui/contract/fail/constructor-multiple-wildcard-selectors.rs:8:9 + | +8 | / pub fn constructor1() -> Self { +9 | | Self {} +10 | | } + | |_________^ diff --git a/crates/ink/tests/ui/contract/fail/constructor-return-result-invalid.stderr b/crates/ink/tests/ui/contract/fail/constructor-return-result-invalid.stderr index 7101544b93..7ebab3a7c7 100644 --- a/crates/ink/tests/ui/contract/fail/constructor-return-result-invalid.stderr +++ b/crates/ink/tests/ui/contract/fail/constructor-return-result-invalid.stderr @@ -1,8 +1,10 @@ error[E0277]: the trait bound `ConstructorOutputValue>: ConstructorOutput` is not satisfied --> tests/ui/contract/fail/constructor-return-result-invalid.rs:14:9 | -14 | pub fn constructor() -> Result { - | ^^^ the trait `ConstructorOutput` is not implemented for `ConstructorOutputValue>` +14 | / pub fn constructor() -> Result { +15 | | Ok(5_u8) +16 | | } + | |_________^ the trait `ConstructorOutput` is not implemented for `ConstructorOutputValue>` | = help: the following other types implement trait `ConstructorOutput`: ConstructorOutputValue diff --git a/crates/ink/tests/ui/contract/fail/constructor-return-result-non-codec-error.stderr b/crates/ink/tests/ui/contract/fail/constructor-return-result-non-codec-error.stderr index 0fcf8ce9f4..21b92bc51b 100644 --- a/crates/ink/tests/ui/contract/fail/constructor-return-result-non-codec-error.stderr +++ b/crates/ink/tests/ui/contract/fail/constructor-return-result-non-codec-error.stderr @@ -1,21 +1,28 @@ error[E0277]: the trait bound `Result, LangError>: Encode` is not satisfied --> tests/ui/contract/fail/constructor-return-result-non-codec-error.rs:13:9 | -13 | pub fn constructor() -> Result { - | ^^^ the trait `Encode` is not implemented for `Result, LangError>` +13 | / pub fn constructor() -> Result { +14 | | Ok(Self {}) +15 | | } + | |_________^ the trait `Encode` is not implemented for `Result, LangError>` | = help: the trait `Encode` is implemented for `Result` note: required by a bound in `return_value` --> $WORKSPACE/crates/env/src/api.rs | + | pub fn return_value(return_flags: ReturnFlags, return_value: &R) -> ! + | ------------ required by a bound in this function + | where | R: scale::Encode, | ^^^^^^^^^^^^^ required by this bound in `return_value` error[E0277]: the trait bound `contract::Error: WrapperTypeDecode` is not satisfied --> tests/ui/contract/fail/constructor-return-result-non-codec-error.rs:13:9 | -13 | pub fn constructor() -> Result { - | ^^^ the trait `WrapperTypeDecode` is not implemented for `contract::Error` +13 | / pub fn constructor() -> Result { +14 | | Ok(Self {}) +15 | | } + | |_________^ the trait `WrapperTypeDecode` is not implemented for `contract::Error` | = help: the following other types implement trait `WrapperTypeDecode`: Arc @@ -26,6 +33,9 @@ error[E0277]: the trait bound `contract::Error: WrapperTypeDecode` is not satisf note: required by a bound in `CreateBuilder::>>::returns` --> $WORKSPACE/crates/env/src/call/create_builder.rs | + | pub fn returns( + | ------- required by a bound in this associated function +... | R: ConstructorReturnType, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `CreateBuilder::>>::returns` @@ -51,5 +61,8 @@ error[E0277]: the trait bound `contract::Error: TypeInfo` is not satisfied note: required by a bound in `TypeSpec::with_name_str` --> $WORKSPACE/crates/metadata/src/specs.rs | + | pub fn with_name_str(display_name: &'static str) -> Self + | ------------- required by a bound in this associated function + | where | T: TypeInfo + 'static, | ^^^^^^^^ required by this bound in `TypeSpec::with_name_str` diff --git a/crates/ink/tests/ui/contract/fail/constructor-selector-and-wildcard-selector.stderr b/crates/ink/tests/ui/contract/fail/constructor-selector-and-wildcard-selector.stderr index d5730eee21..6789378996 100644 --- a/crates/ink/tests/ui/contract/fail/constructor-selector-and-wildcard-selector.stderr +++ b/crates/ink/tests/ui/contract/fail/constructor-selector-and-wildcard-selector.stderr @@ -2,10 +2,10 @@ error: encountered ink! attribute arguments with equal kinds --> tests/ui/contract/fail/constructor-selector-and-wildcard-selector.rs:7:51 | 7 | #[ink(constructor, selector = 0xCAFEBABA, selector = _)] - | ^^^^^^^^ + | ^^^^^^^^^^^^ error: first equal ink! attribute argument with equal kind here --> tests/ui/contract/fail/constructor-selector-and-wildcard-selector.rs:7:28 | 7 | #[ink(constructor, selector = 0xCAFEBABA, selector = _)] - | ^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/crates/ink/tests/ui/contract/fail/constructor-self-receiver-03.stderr b/crates/ink/tests/ui/contract/fail/constructor-self-receiver-03.stderr index 99087f2b51..7582f2a15c 100644 --- a/crates/ink/tests/ui/contract/fail/constructor-self-receiver-03.stderr +++ b/crates/ink/tests/ui/contract/fail/constructor-self-receiver-03.stderr @@ -8,7 +8,7 @@ error[E0411]: cannot find type `Self` in this scope --> tests/ui/contract/fail/constructor-self-receiver-03.rs:8:35 | 4 | pub struct Contract {} - | --- `Self` not allowed in a constant item + | ---------------------- `Self` not allowed in a constant item ... 8 | pub fn constructor(this: &Self) -> Self { | ^^^^ `Self` is only available in impls, traits, and type definitions @@ -23,13 +23,15 @@ error[E0411]: cannot find type `Self` in this scope | ^^^^ `Self` is only available in impls, traits, and type definitions error[E0277]: the trait bound `&Contract: WrapperTypeDecode` is not satisfied - --> tests/ui/contract/fail/constructor-self-receiver-03.rs:8:9 - | -8 | pub fn constructor(this: &Self) -> Self { - | ^^^ the trait `WrapperTypeDecode` is not implemented for `&Contract` - | - = help: the following other types implement trait `WrapperTypeDecode`: - Arc - Box - Rc - = note: required for `&Contract` to implement `parity_scale_codec::Decode` + --> tests/ui/contract/fail/constructor-self-receiver-03.rs:8:9 + | +8 | / pub fn constructor(this: &Self) -> Self { +9 | | Self {} +10 | | } + | |_________^ the trait `WrapperTypeDecode` is not implemented for `&Contract` + | + = help: the following other types implement trait `WrapperTypeDecode`: + Arc + Box + Rc + = note: required for `&Contract` to implement `parity_scale_codec::Decode` diff --git a/crates/ink/tests/ui/contract/fail/event-too-many-topics-anonymous.stderr b/crates/ink/tests/ui/contract/fail/event-too-many-topics-anonymous.stderr index b378115967..0da71853bf 100644 --- a/crates/ink/tests/ui/contract/fail/event-too-many-topics-anonymous.stderr +++ b/crates/ink/tests/ui/contract/fail/event-too-many-topics-anonymous.stderr @@ -1,8 +1,14 @@ error[E0277]: the trait bound `EventTopics<4>: RespectTopicLimit<2>` is not satisfied --> tests/ui/contract/fail/event-too-many-topics-anonymous.rs:25:5 | -25 | pub struct Event { - | ^^^ the trait `RespectTopicLimit<2>` is not implemented for `EventTopics<4>` +25 | / pub struct Event { +26 | | #[ink(topic)] +27 | | arg_1: i8, +28 | | #[ink(topic)] +... | +33 | | arg_4: i32, +34 | | } + | |_____^ the trait `RespectTopicLimit<2>` is not implemented for `EventTopics<4>` | = help: the following other types implement trait `RespectTopicLimit`: as RespectTopicLimit<10>> @@ -17,5 +23,8 @@ error[E0277]: the trait bound `EventTopics<4>: RespectTopicLimit<2>` is not sati note: required by a bound in `EventRespectsTopicLimit` --> src/codegen/event/topics.rs | + | pub struct EventRespectsTopicLimit + | ----------------------- required by a bound in this struct +... | ::LenTopics: RespectTopicLimit, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `EventRespectsTopicLimit` diff --git a/crates/ink/tests/ui/contract/fail/event-too-many-topics.stderr b/crates/ink/tests/ui/contract/fail/event-too-many-topics.stderr index e542e880c0..3aa8a805b7 100644 --- a/crates/ink/tests/ui/contract/fail/event-too-many-topics.stderr +++ b/crates/ink/tests/ui/contract/fail/event-too-many-topics.stderr @@ -1,8 +1,14 @@ error[E0277]: the trait bound `EventTopics<3>: RespectTopicLimit<2>` is not satisfied --> tests/ui/contract/fail/event-too-many-topics.rs:25:5 | -25 | pub struct Event { - | ^^^ the trait `RespectTopicLimit<2>` is not implemented for `EventTopics<3>` +25 | / pub struct Event { +26 | | #[ink(topic)] +27 | | arg_1: i8, +28 | | #[ink(topic)] +... | +31 | | arg_3: i32, +32 | | } + | |_____^ the trait `RespectTopicLimit<2>` is not implemented for `EventTopics<3>` | = help: the following other types implement trait `RespectTopicLimit`: as RespectTopicLimit<10>> @@ -17,5 +23,8 @@ error[E0277]: the trait bound `EventTopics<3>: RespectTopicLimit<2>` is not sati note: required by a bound in `EventRespectsTopicLimit` --> src/codegen/event/topics.rs | + | pub struct EventRespectsTopicLimit + | ----------------------- required by a bound in this struct +... | ::LenTopics: RespectTopicLimit, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `EventRespectsTopicLimit` diff --git a/crates/ink/tests/ui/contract/fail/impl-block-for-non-storage-01.stderr b/crates/ink/tests/ui/contract/fail/impl-block-for-non-storage-01.stderr index c6418df8cf..b5dba1afb2 100644 --- a/crates/ink/tests/ui/contract/fail/impl-block-for-non-storage-01.stderr +++ b/crates/ink/tests/ui/contract/fail/impl-block-for-non-storage-01.stderr @@ -11,7 +11,7 @@ error[E0599]: no function or associated item named `constructor_2` found for str --> tests/ui/contract/fail/impl-block-for-non-storage-01.rs:20:16 | 4 | pub struct Contract {} - | _____---________- + | _____------------------- | | | | | function or associated item `constructor_2` not found for this struct 5 | | @@ -30,7 +30,7 @@ error[E0599]: no function or associated item named `message_2` found for struct --> tests/ui/contract/fail/impl-block-for-non-storage-01.rs:25:16 | 4 | pub struct Contract {} - | _____---________- + | _____------------------- | | | | | function or associated item `message_2` not found for this struct 5 | | diff --git a/crates/ink/tests/ui/contract/fail/impl-block-using-env-no-marker.stderr b/crates/ink/tests/ui/contract/fail/impl-block-using-env-no-marker.stderr index 33dee25041..cc74017436 100644 --- a/crates/ink/tests/ui/contract/fail/impl-block-using-env-no-marker.stderr +++ b/crates/ink/tests/ui/contract/fail/impl-block-using-env-no-marker.stderr @@ -7,5 +7,5 @@ error[E0599]: no method named `env` found for reference `&Contract` in the curre = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: | -1 | use ink::codegen::Env; +1 + use ink::codegen::Env; | diff --git a/crates/ink/tests/ui/contract/fail/impl-block-using-static-env-no-marker.stderr b/crates/ink/tests/ui/contract/fail/impl-block-using-static-env-no-marker.stderr index 24dfe00bc5..2be15ec812 100644 --- a/crates/ink/tests/ui/contract/fail/impl-block-using-static-env-no-marker.stderr +++ b/crates/ink/tests/ui/contract/fail/impl-block-using-static-env-no-marker.stderr @@ -2,7 +2,7 @@ error[E0599]: no function or associated item named `env` found for struct `Contr --> tests/ui/contract/fail/impl-block-using-static-env-no-marker.rs:20:27 | 4 | pub struct Contract {} - | --- function or associated item `env` not found for this struct + | ------------------- function or associated item `env` not found for this struct ... 20 | let _ = Self::env().caller(); | ^^^ function or associated item not found in `Contract` @@ -10,5 +10,5 @@ error[E0599]: no function or associated item named `env` found for struct `Contr = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: | -1 | use ink::codegen::StaticEnv; +1 + use ink::codegen::StaticEnv; | diff --git a/crates/ink/tests/ui/contract/fail/message-hygiene-try.stderr b/crates/ink/tests/ui/contract/fail/message-hygiene-try.stderr index ad3c2b27ac..95d45537b9 100644 --- a/crates/ink/tests/ui/contract/fail/message-hygiene-try.stderr +++ b/crates/ink/tests/ui/contract/fail/message-hygiene-try.stderr @@ -5,4 +5,4 @@ error[E0592]: duplicate definitions with name `try_message` | ---------------- other definition for `try_message` ... 16 | pub fn try_message(&self) {} - | ^^^ duplicate definitions for `try_message` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definitions for `try_message` diff --git a/crates/ink/tests/ui/contract/fail/message-input-non-codec.stderr b/crates/ink/tests/ui/contract/fail/message-input-non-codec.stderr index 29c65d9615..94caf39dcc 100644 --- a/crates/ink/tests/ui/contract/fail/message-input-non-codec.stderr +++ b/crates/ink/tests/ui/contract/fail/message-input-non-codec.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeDecode` is not satisfied --> tests/ui/contract/fail/message-input-non-codec.rs:16:31 | 16 | pub fn message(&self, _input: NonCodecType) {} - | ^^^^^^ the trait `WrapperTypeDecode` is not implemented for `NonCodecType` + | ^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `NonCodecType` | = help: the following other types implement trait `WrapperTypeDecode`: Arc @@ -12,6 +12,9 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeDecode` is not satisfied note: required by a bound in `DispatchInput` --> src/codegen/dispatch/type_check.rs | + | pub struct DispatchInput(T) + | ------------- required by a bound in this struct + | where | T: scale::Decode + 'static; | ^^^^^^^^^^^^^ required by this bound in `DispatchInput` @@ -19,7 +22,7 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeDecode` is not satisfied --> tests/ui/contract/fail/message-input-non-codec.rs:16:9 | 16 | pub fn message(&self, _input: NonCodecType) {} - | ^^^ the trait `WrapperTypeDecode` is not implemented for `NonCodecType` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `NonCodecType` | = help: the following other types implement trait `WrapperTypeDecode`: Arc @@ -34,7 +37,7 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeEncode` is not satisfied | ^^^^^^^^^^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `NonCodecType` ... 16 | pub fn message(&self, _input: NonCodecType) {} - | --- required by a bound introduced by this call + | ---------------------------------------------- required by a bound introduced by this call | = help: the following other types implement trait `WrapperTypeEncode`: &T @@ -50,6 +53,9 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeEncode` is not satisfied note: required by a bound in `ExecutionInput::>::push_arg` --> $WORKSPACE/crates/env/src/call/execution_input.rs | + | pub fn push_arg( + | -------- required by a bound in this associated function +... | T: scale::Encode, | ^^^^^^^^^^^^^ required by this bound in `ExecutionInput::>::push_arg` @@ -57,7 +63,7 @@ error[E0599]: the method `try_invoke` exists for struct `CallBuilder tests/ui/contract/fail/message-input-non-codec.rs:16:9 | 16 | pub fn message(&self, _input: NonCodecType) {} - | ^^^ method cannot be called due to unsatisfied trait bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ method cannot be called due to unsatisfied trait bounds | ::: $WORKSPACE/crates/env/src/call/execution_input.rs | @@ -65,4 +71,4 @@ error[E0599]: the method `try_invoke` exists for struct `CallBuilder, ArgumentList>: Encode` + `ArgumentList, ArgumentList>: Encode` diff --git a/crates/ink/tests/ui/contract/fail/message-multiple-wildcard-selectors.stderr b/crates/ink/tests/ui/contract/fail/message-multiple-wildcard-selectors.stderr index cdde97feb7..3168335a67 100644 --- a/crates/ink/tests/ui/contract/fail/message-multiple-wildcard-selectors.stderr +++ b/crates/ink/tests/ui/contract/fail/message-multiple-wildcard-selectors.stderr @@ -2,10 +2,10 @@ error: encountered ink! messages with overlapping wildcard selectors --> tests/ui/contract/fail/message-multiple-wildcard-selectors.rs:16:9 | 16 | pub fn message2(&self) {} - | ^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: first ink! message with overlapping wildcard selector here --> tests/ui/contract/fail/message-multiple-wildcard-selectors.rs:13:9 | 13 | pub fn message1(&self) {} - | ^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/crates/ink/tests/ui/contract/fail/message-returns-non-codec.stderr b/crates/ink/tests/ui/contract/fail/message-returns-non-codec.stderr index e44f82c044..922f3777b8 100644 --- a/crates/ink/tests/ui/contract/fail/message-returns-non-codec.stderr +++ b/crates/ink/tests/ui/contract/fail/message-returns-non-codec.stderr @@ -18,30 +18,40 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeEncode` is not satisfied note: required by a bound in `DispatchOutput` --> src/codegen/dispatch/type_check.rs | + | pub struct DispatchOutput(T) + | -------------- required by a bound in this struct + | where | T: scale::Encode + 'static; | ^^^^^^^^^^^^^ required by this bound in `DispatchOutput` error[E0277]: the trait bound `Result: Encode` is not satisfied --> tests/ui/contract/fail/message-returns-non-codec.rs:16:9 | -16 | pub fn message(&self) -> NonCodecType { - | ^^^ the trait `Encode` is not implemented for `Result` +16 | / pub fn message(&self) -> NonCodecType { +17 | | NonCodecType +18 | | } + | |_________^ the trait `Encode` is not implemented for `Result` | = help: the trait `Encode` is implemented for `Result` note: required by a bound in `return_value` --> $WORKSPACE/crates/env/src/api.rs | + | pub fn return_value(return_flags: ReturnFlags, return_value: &R) -> ! + | ------------ required by a bound in this function + | where | R: scale::Encode, | ^^^^^^^^^^^^^ required by this bound in `return_value` error[E0599]: the method `try_invoke` exists for struct `CallBuilder>, Set>, ...>`, but its trait bounds were not satisfied --> tests/ui/contract/fail/message-returns-non-codec.rs:16:9 | -4 | pub struct NonCodecType; - | ----------------------- doesn't satisfy `NonCodecType: parity_scale_codec::Decode` +4 | pub struct NonCodecType; + | ----------------------- doesn't satisfy `NonCodecType: parity_scale_codec::Decode` ... -16 | pub fn message(&self) -> NonCodecType { - | ^^^ method cannot be called due to unsatisfied trait bounds +16 | / pub fn message(&self) -> NonCodecType { +17 | | NonCodecType +18 | | } + | |_________^ method cannot be called due to unsatisfied trait bounds | = note: the following trait bounds were not satisfied: `NonCodecType: parity_scale_codec::Decode` diff --git a/crates/ink/tests/ui/contract/fail/message-selector-and-wildcard-selector.stderr b/crates/ink/tests/ui/contract/fail/message-selector-and-wildcard-selector.stderr index 3a0cef0f7b..bc619b1989 100644 --- a/crates/ink/tests/ui/contract/fail/message-selector-and-wildcard-selector.stderr +++ b/crates/ink/tests/ui/contract/fail/message-selector-and-wildcard-selector.stderr @@ -2,10 +2,10 @@ error: encountered ink! attribute arguments with equal kinds --> tests/ui/contract/fail/message-selector-and-wildcard-selector.rs:12:47 | 12 | #[ink(message, selector = 0xCAFEBABA, selector = _)] - | ^^^^^^^^ + | ^^^^^^^^^^^^ error: first equal ink! attribute argument with equal kind here --> tests/ui/contract/fail/message-selector-and-wildcard-selector.rs:12:24 | 12 | #[ink(message, selector = 0xCAFEBABA, selector = _)] - | ^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/crates/ink/tests/ui/contract/fail/message-self-receiver-invalid-01.stderr b/crates/ink/tests/ui/contract/fail/message-self-receiver-invalid-01.stderr index a33937b086..b8069624fb 100644 --- a/crates/ink/tests/ui/contract/fail/message-self-receiver-invalid-01.stderr +++ b/crates/ink/tests/ui/contract/fail/message-self-receiver-invalid-01.stderr @@ -2,4 +2,4 @@ error: ink! messages must have `&self` or `&mut self` receiver --> tests/ui/contract/fail/message-self-receiver-invalid-01.rs:13:24 | 13 | pub fn message(this: &Self) {} - | ^^^^ + | ^^^^^^^^^^^ diff --git a/crates/ink/tests/ui/contract/fail/message-self-receiver-invalid-02.stderr b/crates/ink/tests/ui/contract/fail/message-self-receiver-invalid-02.stderr index 7403792392..e64d38d814 100644 --- a/crates/ink/tests/ui/contract/fail/message-self-receiver-invalid-02.stderr +++ b/crates/ink/tests/ui/contract/fail/message-self-receiver-invalid-02.stderr @@ -2,4 +2,4 @@ error: ink! messages must have `&self` or `&mut self` receiver --> tests/ui/contract/fail/message-self-receiver-invalid-02.rs:13:24 | 13 | pub fn message(this: &mut Self) {} - | ^^^^ + | ^^^^^^^^^^^^^^^ diff --git a/crates/ink/tests/ui/contract/fail/message-self-receiver-missing.stderr b/crates/ink/tests/ui/contract/fail/message-self-receiver-missing.stderr index 6676399dc6..9b40617be9 100644 --- a/crates/ink/tests/ui/contract/fail/message-self-receiver-missing.stderr +++ b/crates/ink/tests/ui/contract/fail/message-self-receiver-missing.stderr @@ -1,5 +1,6 @@ error: ink! messages must have `&self` or `&mut self` receiver --> tests/ui/contract/fail/message-self-receiver-missing.rs:12:9 | -12 | #[ink(message)] - | ^ +12 | / #[ink(message)] +13 | | pub fn message() {} + | |___________________________^ diff --git a/crates/ink/tests/ui/contract/fail/module-missing-constructor.stderr b/crates/ink/tests/ui/contract/fail/module-missing-constructor.stderr index 0ba6d47f66..5af1026c08 100644 --- a/crates/ink/tests/ui/contract/fail/module-missing-constructor.stderr +++ b/crates/ink/tests/ui/contract/fail/module-missing-constructor.stderr @@ -1,5 +1,11 @@ error: missing ink! constructor - --> tests/ui/contract/fail/module-missing-constructor.rs:2:1 - | -2 | mod contract { - | ^^^ + --> tests/ui/contract/fail/module-missing-constructor.rs:2:1 + | +2 | / mod contract { +3 | | #[ink(storage)] +4 | | pub struct Contract {} +5 | | +... | +9 | | } +10 | | } + | |_^ diff --git a/crates/ink/tests/ui/contract/fail/module-missing-message.stderr b/crates/ink/tests/ui/contract/fail/module-missing-message.stderr index 2d0cd3535d..84d45a91b0 100644 --- a/crates/ink/tests/ui/contract/fail/module-missing-message.stderr +++ b/crates/ink/tests/ui/contract/fail/module-missing-message.stderr @@ -1,5 +1,11 @@ error: missing ink! message - --> tests/ui/contract/fail/module-missing-message.rs:2:1 - | -2 | mod contract { - | ^^^ + --> tests/ui/contract/fail/module-missing-message.rs:2:1 + | +2 | / mod contract { +3 | | #[ink(storage)] +4 | | pub struct Contract {} +5 | | +... | +11 | | } +12 | | } + | |_^ diff --git a/crates/ink/tests/ui/contract/fail/module-missing-storage.stderr b/crates/ink/tests/ui/contract/fail/module-missing-storage.stderr index 06fd1620b4..7484faf031 100644 --- a/crates/ink/tests/ui/contract/fail/module-missing-storage.stderr +++ b/crates/ink/tests/ui/contract/fail/module-missing-storage.stderr @@ -1,5 +1,11 @@ error: missing ink! storage struct - --> tests/ui/contract/fail/module-missing-storage.rs:2:1 - | -2 | mod contract { - | ^^^ + --> tests/ui/contract/fail/module-missing-storage.rs:2:1 + | +2 | / mod contract { +3 | | // #[ink(storage)] +4 | | pub struct Contract {} +5 | | +... | +12 | | } +13 | | } + | |_^ diff --git a/crates/ink/tests/ui/contract/fail/module-multiple-storages.stderr b/crates/ink/tests/ui/contract/fail/module-multiple-storages.stderr index da92152db6..2ee9c921f6 100644 --- a/crates/ink/tests/ui/contract/fail/module-multiple-storages.stderr +++ b/crates/ink/tests/ui/contract/fail/module-multiple-storages.stderr @@ -1,17 +1,23 @@ error: encountered multiple ink! storage structs, expected exactly one - --> tests/ui/contract/fail/module-multiple-storages.rs:2:1 - | -2 | mod contract { - | ^^^ + --> tests/ui/contract/fail/module-multiple-storages.rs:2:1 + | +2 | / mod contract { +3 | | #[ink(storage)] +4 | | pub struct Contract {} +5 | | +... | +27 | | } +28 | | } + | |_^ error: ink! storage struct here --> tests/ui/contract/fail/module-multiple-storages.rs:4:5 | 4 | pub struct Contract {} - | ^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ error: ink! storage struct here --> tests/ui/contract/fail/module-multiple-storages.rs:17:5 | 17 | pub struct Contract2 {} - | ^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/crates/ink/tests/ui/contract/fail/trait-impl-namespace-invalid.stderr b/crates/ink/tests/ui/contract/fail/trait-impl-namespace-invalid.stderr index 86ca398df1..3d6a3f352d 100644 --- a/crates/ink/tests/ui/contract/fail/trait-impl-namespace-invalid.stderr +++ b/crates/ink/tests/ui/contract/fail/trait-impl-namespace-invalid.stderr @@ -1,5 +1,9 @@ error: namespace ink! property is not allowed on ink! trait implementation blocks --> tests/ui/contract/fail/trait-impl-namespace-invalid.rs:21:5 | -21 | #[ink(namespace = "namespace")] - | ^ +21 | / #[ink(namespace = "namespace")] +22 | | impl TraitDefinition for Contract { +23 | | #[ink(message)] +24 | | fn message(&self) {} +25 | | } + | |_____^ diff --git a/crates/ink/tests/ui/contract/fail/trait-message-allow-reentrancy-mismatch.stderr b/crates/ink/tests/ui/contract/fail/trait-message-allow-reentrancy-mismatch.stderr new file mode 100644 index 0000000000..6687350801 --- /dev/null +++ b/crates/ink/tests/ui/contract/fail/trait-message-allow-reentrancy-mismatch.stderr @@ -0,0 +1,8 @@ +error[E0308]: mismatched types + --> tests/ui/contract/fail/trait-message-allow-reentrancy-mismatch.rs:23:9 + | +23 | fn message(&self) {} + | ^^^^^^^^^^^^^^^^^^^^ expected `false`, found `true` + | + = note: expected struct `TraitMessageReentrant` + found struct `TraitMessageReentrant` diff --git a/crates/ink/tests/ui/contract/fail/trait-message-payable-mismatch.stderr b/crates/ink/tests/ui/contract/fail/trait-message-payable-mismatch.stderr index 15202a2c81..3dd203b4d4 100644 --- a/crates/ink/tests/ui/contract/fail/trait-message-payable-mismatch.stderr +++ b/crates/ink/tests/ui/contract/fail/trait-message-payable-mismatch.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> tests/ui/contract/fail/trait-message-payable-mismatch.rs:23:9 | 23 | fn message(&self) {} - | ^^ expected `false`, found `true` + | ^^^^^^^^^^^^^^^^^^^^ expected `false`, found `true` | = note: expected struct `TraitMessagePayable` found struct `TraitMessagePayable` diff --git a/crates/ink/tests/ui/contract/fail/trait-message-selector-mismatch.stderr b/crates/ink/tests/ui/contract/fail/trait-message-selector-mismatch.stderr index 745cb6e49f..abb792b003 100644 --- a/crates/ink/tests/ui/contract/fail/trait-message-selector-mismatch.stderr +++ b/crates/ink/tests/ui/contract/fail/trait-message-selector-mismatch.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> tests/ui/contract/fail/trait-message-selector-mismatch.rs:23:9 | 23 | fn message(&self) {} - | ^^ expected `1`, found `2` + | ^^^^^^^^^^^^^^^^^^^^ expected `1`, found `2` | = note: expected struct `TraitMessageSelector<1>` found struct `TraitMessageSelector<2>` diff --git a/crates/ink/tests/ui/contract/fail/trait-message-selector-overlap-1.stderr b/crates/ink/tests/ui/contract/fail/trait-message-selector-overlap-1.stderr index 8326b74e9c..229df39f15 100644 --- a/crates/ink/tests/ui/contract/fail/trait-message-selector-overlap-1.stderr +++ b/crates/ink/tests/ui/contract/fail/trait-message-selector-overlap-1.stderr @@ -2,16 +2,22 @@ error[E0119]: conflicting implementations of trait `DispatchableMessageInfo<1083 --> tests/ui/contract/fail/trait-message-selector-overlap-1.rs:41:9 | 36 | fn message(&self) {} - | -- first implementation here + | -------------------- first implementation here ... 41 | fn message(&self) {} - | ^^ conflicting implementation for `Contract` + | ^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Contract` error[E0119]: conflicting implementations of trait `TraitCallForwarderFor<1083895717>` for type `contract::_::CallBuilder` --> tests/ui/contract/fail/trait-message-selector-overlap-1.rs:39:5 | -34 | impl TraitDefinition1 for Contract { - | ---- first implementation here -... -39 | impl TraitDefinition2 for Contract { - | ^^^^ conflicting implementation for `contract::_::CallBuilder` +34 | / impl TraitDefinition1 for Contract { +35 | | #[ink(message)] +36 | | fn message(&self) {} +37 | | } + | |_____- first implementation here +38 | +39 | / impl TraitDefinition2 for Contract { +40 | | #[ink(message)] +41 | | fn message(&self) {} +42 | | } + | |_____^ conflicting implementation for `contract::_::CallBuilder` diff --git a/crates/ink/tests/ui/contract/fail/trait-message-selector-overlap-2.stderr b/crates/ink/tests/ui/contract/fail/trait-message-selector-overlap-2.stderr index 4f2952c514..3c923d7b8f 100644 --- a/crates/ink/tests/ui/contract/fail/trait-message-selector-overlap-2.stderr +++ b/crates/ink/tests/ui/contract/fail/trait-message-selector-overlap-2.stderr @@ -2,16 +2,22 @@ error[E0119]: conflicting implementations of trait `DispatchableMessageInfo<1518 --> tests/ui/contract/fail/trait-message-selector-overlap-2.rs:41:9 | 36 | fn message(&self) {} - | -- first implementation here + | -------------------- first implementation here ... 41 | fn message(&self) {} - | ^^ conflicting implementation for `Contract` + | ^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Contract` error[E0119]: conflicting implementations of trait `TraitCallForwarderFor<1518209067>` for type `contract::_::CallBuilder` --> tests/ui/contract/fail/trait-message-selector-overlap-2.rs:39:5 | -34 | impl TraitDefinition1 for Contract { - | ---- first implementation here -... -39 | impl TraitDefinition2 for Contract { - | ^^^^ conflicting implementation for `contract::_::CallBuilder` +34 | / impl TraitDefinition1 for Contract { +35 | | #[ink(message)] +36 | | fn message(&self) {} +37 | | } + | |_____- first implementation here +38 | +39 | / impl TraitDefinition2 for Contract { +40 | | #[ink(message)] +41 | | fn message(&self) {} +42 | | } + | |_____^ conflicting implementation for `contract::_::CallBuilder` diff --git a/crates/ink/tests/ui/contract/fail/trait-message-selector-overlap-3.stderr b/crates/ink/tests/ui/contract/fail/trait-message-selector-overlap-3.stderr index a1f5a0524f..284acc4500 100644 --- a/crates/ink/tests/ui/contract/fail/trait-message-selector-overlap-3.stderr +++ b/crates/ink/tests/ui/contract/fail/trait-message-selector-overlap-3.stderr @@ -2,16 +2,22 @@ error[E0119]: conflicting implementations of trait `DispatchableMessageInfo<42>` --> tests/ui/contract/fail/trait-message-selector-overlap-3.rs:41:9 | 36 | fn message1(&self) {} - | -- first implementation here + | --------------------- first implementation here ... 41 | fn message2(&self) {} - | ^^ conflicting implementation for `Contract` + | ^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Contract` error[E0119]: conflicting implementations of trait `TraitCallForwarderFor<42>` for type `contract::_::CallBuilder` --> tests/ui/contract/fail/trait-message-selector-overlap-3.rs:39:5 | -34 | impl TraitDefinition1 for Contract { - | ---- first implementation here -... -39 | impl TraitDefinition2 for Contract { - | ^^^^ conflicting implementation for `contract::_::CallBuilder` +34 | / impl TraitDefinition1 for Contract { +35 | | #[ink(message)] +36 | | fn message1(&self) {} +37 | | } + | |_____- first implementation here +38 | +39 | / impl TraitDefinition2 for Contract { +40 | | #[ink(message)] +41 | | fn message2(&self) {} +42 | | } + | |_____^ conflicting implementation for `contract::_::CallBuilder` diff --git a/crates/ink/tests/ui/contract/fail/trait-message-wildcard-selector.stderr b/crates/ink/tests/ui/contract/fail/trait-message-wildcard-selector.stderr index e954985afe..a4e6d9e5ea 100644 --- a/crates/ink/tests/ui/contract/fail/trait-message-wildcard-selector.stderr +++ b/crates/ink/tests/ui/contract/fail/trait-message-wildcard-selector.stderr @@ -2,13 +2,13 @@ error: encountered conflicting ink! attribute argument --> tests/ui/contract/fail/trait-message-wildcard-selector.rs:4:24 | 4 | #[ink(message, selector = _)] - | ^^^^^^^^ + | ^^^^^^^^^^^^ error: wildcard selectors are only supported for inherent ink! messages or constructors, not for traits. --> tests/ui/contract/fail/trait-message-wildcard-selector.rs:4:24 | 4 | #[ink(message, selector = _)] - | ^^^^^^^^ + | ^^^^^^^^^^^^ error[E0432]: unresolved import `super::foo::TraitDefinition` --> tests/ui/contract/fail/trait-message-wildcard-selector.rs:11:9 diff --git a/crates/ink/tests/ui/storage_item/fail/collections_only_packed_1.stderr b/crates/ink/tests/ui/storage_item/fail/collections_only_packed_1.stderr index 024f999a20..9e2d7c917e 100644 --- a/crates/ink/tests/ui/storage_item/fail/collections_only_packed_1.stderr +++ b/crates/ink/tests/ui/storage_item/fail/collections_only_packed_1.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `Vec: parity_scale_codec::Decode` is no --> tests/ui/storage_item/fail/collections_only_packed_1.rs:11:8 | 11 | a: Vec, - | ^^^ the trait `parity_scale_codec::Decode` is not implemented for `Vec` + | ^^^^^^^^^^^^^^ the trait `parity_scale_codec::Decode` is not implemented for `Vec` | = help: the trait `parity_scale_codec::Decode` is implemented for `Vec` = note: required for `Vec` to implement `Packed` @@ -13,7 +13,7 @@ error[E0277]: the trait bound `[NonPacked]: Encode` is not satisfied --> tests/ui/storage_item/fail/collections_only_packed_1.rs:11:8 | 11 | a: Vec, - | ^^^ the trait `Encode` is not implemented for `[NonPacked]` + | ^^^^^^^^^^^^^^ the trait `Encode` is not implemented for `[NonPacked]` | = help: the following other types implement trait `Encode`: [T; N] diff --git a/crates/ink/tests/ui/storage_item/fail/collections_only_packed_2.stderr b/crates/ink/tests/ui/storage_item/fail/collections_only_packed_2.stderr index b0a9b7a4b7..93d9f65ed8 100644 --- a/crates/ink/tests/ui/storage_item/fail/collections_only_packed_2.stderr +++ b/crates/ink/tests/ui/storage_item/fail/collections_only_packed_2.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `BTreeMap: parity_scale_codec::De --> tests/ui/storage_item/fail/collections_only_packed_2.rs:11:8 | 11 | a: BTreeMap, - | ^^^^^^^^ the trait `parity_scale_codec::Decode` is not implemented for `BTreeMap` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `parity_scale_codec::Decode` is not implemented for `BTreeMap` | = help: the trait `parity_scale_codec::Decode` is implemented for `BTreeMap` = note: required for `BTreeMap` to implement `Packed` @@ -13,7 +13,7 @@ error[E0277]: the trait bound `BTreeMap: Encode` is not satisfi --> tests/ui/storage_item/fail/collections_only_packed_2.rs:11:8 | 11 | a: BTreeMap, - | ^^^^^^^^ the trait `Encode` is not implemented for `BTreeMap` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Encode` is not implemented for `BTreeMap` | = help: the trait `Encode` is implemented for `BTreeMap` = note: required for `BTreeMap` to implement `Packed` diff --git a/crates/ink/tests/ui/trait_def/fail/definition_constructor.stderr b/crates/ink/tests/ui/trait_def/fail/definition_constructor.stderr index 6ab123fba0..b0d8499a4c 100644 --- a/crates/ink/tests/ui/trait_def/fail/definition_constructor.stderr +++ b/crates/ink/tests/ui/trait_def/fail/definition_constructor.stderr @@ -1,5 +1,6 @@ error: ink! trait definitions must not have constructors --> tests/ui/trait_def/fail/definition_constructor.rs:3:5 | -3 | #[ink(constructor)] - | ^ +3 | / #[ink(constructor)] +4 | | fn constructor() -> Self; + | |_____________________________^ diff --git a/crates/ink/tests/ui/trait_def/fail/definition_empty.stderr b/crates/ink/tests/ui/trait_def/fail/definition_empty.stderr index fee507687a..e7e00a9347 100644 --- a/crates/ink/tests/ui/trait_def/fail/definition_empty.stderr +++ b/crates/ink/tests/ui/trait_def/fail/definition_empty.stderr @@ -2,4 +2,4 @@ error: encountered invalid empty ink! trait definition --> tests/ui/trait_def/fail/definition_empty.rs:2:1 | 2 | pub trait TraitDefinition {} - | ^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/crates/ink/tests/ui/trait_def/fail/message_input_non_codec.stderr b/crates/ink/tests/ui/trait_def/fail/message_input_non_codec.stderr index 4d2a1e4027..4ff2c46f37 100644 --- a/crates/ink/tests/ui/trait_def/fail/message_input_non_codec.stderr +++ b/crates/ink/tests/ui/trait_def/fail/message_input_non_codec.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `NonCodec: WrapperTypeDecode` is not satisfied --> tests/ui/trait_def/fail/message_input_non_codec.rs:6:23 | 6 | fn message(&self, input: NonCodec); - | ^^^^^ the trait `WrapperTypeDecode` is not implemented for `NonCodec` + | ^^^^^^^^^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `NonCodec` | = help: the following other types implement trait `WrapperTypeDecode`: Arc @@ -12,17 +12,21 @@ error[E0277]: the trait bound `NonCodec: WrapperTypeDecode` is not satisfied note: required by a bound in `DispatchInput` --> src/codegen/dispatch/type_check.rs | + | pub struct DispatchInput(T) + | ------------- required by a bound in this struct + | where | T: scale::Decode + 'static; | ^^^^^^^^^^^^^ required by this bound in `DispatchInput` error[E0277]: the trait bound `NonCodec: WrapperTypeEncode` is not satisfied --> tests/ui/trait_def/fail/message_input_non_codec.rs:3:1 | -3 | #[ink::trait_definition] - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `NonCodec` -4 | pub trait TraitDefinition { -5 | #[ink(message)] - | - required by a bound introduced by this call +3 | #[ink::trait_definition] + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `NonCodec` +4 | pub trait TraitDefinition { +5 | / #[ink(message)] +6 | | fn message(&self, input: NonCodec); + | |_______________________________________- required by a bound introduced by this call | = help: the following other types implement trait `WrapperTypeEncode`: &T @@ -38,21 +42,24 @@ error[E0277]: the trait bound `NonCodec: WrapperTypeEncode` is not satisfied note: required by a bound in `ExecutionInput::>::push_arg` --> $WORKSPACE/crates/env/src/call/execution_input.rs | + | pub fn push_arg( + | -------- required by a bound in this associated function +... | T: scale::Encode, | ^^^^^^^^^^^^^ required by this bound in `ExecutionInput::>::push_arg` error[E0599]: the method `try_invoke` exists for struct `CallBuilder>, Set, ...>>>, ...>`, but its trait bounds were not satisfied --> tests/ui/trait_def/fail/message_input_non_codec.rs:5:5 | -5 | #[ink(message)] - | ^ - | | - | method cannot be called due to unsatisfied trait bounds +5 | #[ink(message)] + | _____^ +6 | | fn message(&self, input: NonCodec); + | |_______________________________________^ method cannot be called due to unsatisfied trait bounds | ::: $WORKSPACE/crates/env/src/call/execution_input.rs | - | pub struct ArgumentList { - | ----------------------------------- doesn't satisfy `_: Encode` + | pub struct ArgumentList { + | ----------------------------------- doesn't satisfy `_: Encode` | = note: the following trait bounds were not satisfied: - `ArgumentList, ArgumentList>: Encode` + `ArgumentList, ArgumentList>: Encode` diff --git a/crates/ink/tests/ui/trait_def/fail/message_output_non_codec.stderr b/crates/ink/tests/ui/trait_def/fail/message_output_non_codec.stderr index 90aa30a65d..7a02f009b1 100644 --- a/crates/ink/tests/ui/trait_def/fail/message_output_non_codec.stderr +++ b/crates/ink/tests/ui/trait_def/fail/message_output_non_codec.stderr @@ -18,19 +18,22 @@ error[E0277]: the trait bound `NonCodec: WrapperTypeEncode` is not satisfied note: required by a bound in `DispatchOutput` --> src/codegen/dispatch/type_check.rs | + | pub struct DispatchOutput(T) + | -------------- required by a bound in this struct + | where | T: scale::Encode + 'static; | ^^^^^^^^^^^^^ required by this bound in `DispatchOutput` error[E0599]: the method `try_invoke` exists for struct `CallBuilder>, Set>>, Set>>`, but its trait bounds were not satisfied --> tests/ui/trait_def/fail/message_output_non_codec.rs:5:5 | -1 | pub struct NonCodec; - | ------------------- doesn't satisfy `NonCodec: parity_scale_codec::Decode` +1 | pub struct NonCodec; + | ------------------- doesn't satisfy `NonCodec: parity_scale_codec::Decode` ... -5 | #[ink(message)] - | ^ - | | - | method cannot be called due to unsatisfied trait bounds +5 | #[ink(message)] + | _____^ +6 | | fn message(&self) -> NonCodec; + | |__________________________________^ method cannot be called due to unsatisfied trait bounds | = note: the following trait bounds were not satisfied: `NonCodec: parity_scale_codec::Decode` From 59cb2613ee14db5218205afb175e1607fc870662 Mon Sep 17 00:00:00 2001 From: Artemka374 Date: Thu, 18 May 2023 16:51:36 +0300 Subject: [PATCH 05/11] apply suggestions --- README.md | 2 +- crates/env/src/backend.rs | 11 ----------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/README.md b/README.md index 9eedc034ee..42a18373b9 100644 --- a/README.md +++ b/README.md @@ -254,7 +254,7 @@ We have [a very comprehensive documentation portal](https://use.ink), but if you are looking for the crate level documentation itself, then these are the relevant links: -| Crate | Docs | Description |payable +| Crate | Docs | Description | |:--|:--|:--| `ink` | [![][j1]][j2] | Language features exposed by ink!. See [here](https://paritytech.github.io/ink/ink/attr.contract.html) for a detailed description of attributes which you can use in an `#[ink::contract]`. | `ink_storage` | [![][f1]][f2] | Data structures available in ink!. | diff --git a/crates/env/src/backend.rs b/crates/env/src/backend.rs index 90601bb213..e6443dd3d0 100644 --- a/crates/env/src/backend.rs +++ b/crates/env/src/backend.rs @@ -70,17 +70,6 @@ pub struct CallFlags { allow_reentry: bool, } -impl Default for CallFlags { - fn default() -> Self { - Self { - forward_input: false, - clone_input: false, - tail_call: false, - allow_reentry: true, - } - } -} - impl CallFlags { /// Forwards the input for the current function to the callee. /// From 27f9588e09ad5f25bac487df861c19e3b37e5161 Mon Sep 17 00:00:00 2001 From: Artemka374 Date: Fri, 19 May 2023 13:06:41 +0300 Subject: [PATCH 06/11] apply suggestions --- crates/env/src/backend.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/env/src/backend.rs b/crates/env/src/backend.rs index e6443dd3d0..933c87ba4e 100644 --- a/crates/env/src/backend.rs +++ b/crates/env/src/backend.rs @@ -109,13 +109,13 @@ impl CallFlags { self } - /// Allow the callee to reenter into the current contract. + /// Disallow the callee to reenter into the current contract. /// /// Without this flag any reentrancy into the current contract that originates from - /// the callee (or any of its callees) is denied. This includes the first callee: + /// the callee (or any of its callees) is allowed. This includes the first callee: /// You cannot call into yourself with this flag set. - pub const fn set_deny_reentry(mut self, allow_reentry: bool) -> Self { - self.allow_reentry = !allow_reentry; + pub const fn set_deny_reentry(mut self, deny_reentry: bool) -> Self { + self.allow_reentry = !deny_reentry; self } From f1d4072f0db00f723d09b083ea5d1620b9dcc378 Mon Sep 17 00:00:00 2001 From: Artemka374 Date: Fri, 19 May 2023 13:07:24 +0300 Subject: [PATCH 07/11] impl default --- crates/env/src/backend.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/crates/env/src/backend.rs b/crates/env/src/backend.rs index 933c87ba4e..3dcb74edcd 100644 --- a/crates/env/src/backend.rs +++ b/crates/env/src/backend.rs @@ -70,6 +70,17 @@ pub struct CallFlags { allow_reentry: bool, } +impl Default for CallFlags { + fn default() -> Self { + Self { + forward_input: false, + clone_input: false, + tail_call: false, + allow_reentry: true, + } + } +} + impl CallFlags { /// Forwards the input for the current function to the callee. /// From c9a8510136ccfe35c93b7f9384781cb6597e09c1 Mon Sep 17 00:00:00 2001 From: Artemka374 Date: Fri, 19 May 2023 13:10:09 +0300 Subject: [PATCH 08/11] add .idea to gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 3a905f1e9d..ef52b11d01 100644 --- a/.gitignore +++ b/.gitignore @@ -14,5 +14,7 @@ # More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock Cargo.lock +.idea + # Ignore history files. **/.history/** From 023500505d60f37f6b912b5c70b74d71a42c3c22 Mon Sep 17 00:00:00 2001 From: Artemka374 Date: Thu, 25 May 2023 13:19:18 +0300 Subject: [PATCH 09/11] remove .idea --- .idea/.gitignore | 8 -------- .idea/brushfam-ink.iml | 25 ------------------------- .idea/modules.xml | 8 -------- .idea/vcs.xml | 6 ------ 4 files changed, 47 deletions(-) delete mode 100644 .idea/.gitignore delete mode 100644 .idea/brushfam-ink.iml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/vcs.xml diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 13566b81b0..0000000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml diff --git a/.idea/brushfam-ink.iml b/.idea/brushfam-ink.iml deleted file mode 100644 index e52ed05fd7..0000000000 --- a/.idea/brushfam-ink.iml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 0798285f09..0000000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1ddfbb..0000000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file From e4100a4e92e3468fe3c728439d18018de0922959 Mon Sep 17 00:00:00 2001 From: Artemka374 Date: Tue, 22 Aug 2023 14:39:07 +0300 Subject: [PATCH 10/11] apply fmt --- crates/ink/src/reflect/trait_def/info.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/ink/src/reflect/trait_def/info.rs b/crates/ink/src/reflect/trait_def/info.rs index 19adfa2a22..a96840693f 100644 --- a/crates/ink/src/reflect/trait_def/info.rs +++ b/crates/ink/src/reflect/trait_def/info.rs @@ -124,7 +124,8 @@ pub trait TraitMessageInfo { /// Is `true` if the ink! trait message has been annotated with `#[ink(payable)]`. const PAYABLE: bool; - /// Is `true` if the ink! trait message has been annotated with `#[ink(allow_reentrancy)]`. + /// Is `true` if the ink! trait message has been annotated with + /// `#[ink(allow_reentrancy)]`. const ALLOW_REENTRANCY: bool; /// The unique selector of the ink! trait message. From f33a3eaceb2375efe6a622587a046c1560cfbff6 Mon Sep 17 00:00:00 2001 From: Artemka374 Date: Wed, 23 Aug 2023 09:50:11 +0300 Subject: [PATCH 11/11] apply suggestions --- crates/env/src/backend.rs | 8 ++++---- crates/ink/codegen/src/generator/dispatch.rs | 18 ++++++++++++++++++ crates/ink/ir/src/ir/item_impl/message.rs | 3 ++- crates/metadata/src/specs.rs | 10 +++++----- 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/crates/env/src/backend.rs b/crates/env/src/backend.rs index f8dcfcb97e..b320eef3e3 100644 --- a/crates/env/src/backend.rs +++ b/crates/env/src/backend.rs @@ -125,8 +125,8 @@ impl CallFlags { /// Without this flag any reentrancy into the current contract that originates from /// the callee (or any of its callees) is allowed. This includes the first callee: /// You cannot call into yourself with this flag set. - pub const fn set_deny_reentry(mut self, deny_reentry: bool) -> Self { - self.allow_reentry = !deny_reentry; + pub const fn set_allow_reentry(mut self, allow_reentry: bool) -> Self { + self.allow_reentry = allow_reentry; self } @@ -173,8 +173,8 @@ impl CallFlags { /// # Note /// /// See [`Self::set_allow_reentry`] for more information. - pub const fn deny_reentry(&self) -> bool { - !self.allow_reentry + pub const fn allow_reentry(&self) -> bool { + self.allow_reentry } } diff --git a/crates/ink/codegen/src/generator/dispatch.rs b/crates/ink/codegen/src/generator/dispatch.rs index 2f82dd4f53..f62de29fb0 100644 --- a/crates/ink/codegen/src/generator/dispatch.rs +++ b/crates/ink/codegen/src/generator/dispatch.rs @@ -959,6 +959,15 @@ impl Dispatch<'_> { ) } + /// Generates code to express if any dispatchable ink! message accepts reentrancy. + /// + /// Generates code in the form of variable assignments + /// which can be conditionally omitted + /// in which case the default assignment `let message_{id} = false` exists. + /// + /// This information can be used to speed-up dispatch since denying of payment + /// can be generalized to work before dispatch happens if none of the ink! messages + /// accept payment anyways. fn any_message_accepts_reentrancy( &self, messages: &[MessageDispatchable], @@ -1025,6 +1034,15 @@ impl Dispatch<'_> { ) } + /// Generates code to express if any dispatchable ink! constructor accepts reentrancy. + /// + /// Generates code in the form of variable assignments + /// which can be conditionally omitted + /// in which case the default assignment `let constructor_{id} = false` exists. + /// + /// This information can be used to speed-up dispatch since denying of payment + /// can be generalized to work before dispatch happens if none of the ink! + /// constructors accept payment anyways. fn any_constructor_accepts_reentrancy( &self, constructors: &[ConstructorDispatchable], diff --git a/crates/ink/ir/src/ir/item_impl/message.rs b/crates/ink/ir/src/ir/item_impl/message.rs index 0b4b172eb5..63d73323c4 100644 --- a/crates/ink/ir/src/ir/item_impl/message.rs +++ b/crates/ink/ir/src/ir/item_impl/message.rs @@ -100,7 +100,8 @@ pub struct Message { pub(super) item: syn::ImplItemFn, /// If the ink! message can receive funds. is_payable: bool, - /// If the ink! message is allowed to re-enter the contract. + /// If it is allowed to re-enter the corresponding ink! message. If reentrancy is disabled by default, + /// this flag can be used to enable it for a specific message. allow_reentrancy: bool, /// If the ink! message is default. is_default: bool, diff --git a/crates/metadata/src/specs.rs b/crates/metadata/src/specs.rs index 56c97e3518..7e4dea386b 100644 --- a/crates/metadata/src/specs.rs +++ b/crates/metadata/src/specs.rs @@ -655,11 +655,11 @@ pub struct MessageSpec { /// The selector hash of the message. selector: Selector, /// If the message is allowed to mutate the contract state. - mutates: bool, + mutates: bool,allow_reentrancy /// If the message accepts any `value` from the caller. payable: bool, /// If the message is allowed to re-enter the contract. - allow_reentrancy: bool, + reentrancy_allowed: bool, /// The parameters of the message. args: Vec>, /// The return type of the message. @@ -727,7 +727,7 @@ where selector: Selector::default(), mutates: false, payable: false, - allow_reentrancy: false, + reentrancy_allowed: false, args: Vec::new(), return_type: ReturnTypeSpec::new(None), docs: Vec::new(), @@ -871,7 +871,7 @@ where ) -> MessageSpecBuilder { MessageSpecBuilder { spec: MessageSpec { - allow_reentrancy, + reentrancy_allowed: allow_reentrancy, ..self.spec }, marker: PhantomData, @@ -963,7 +963,7 @@ impl IntoPortable for MessageSpec { selector: self.selector, mutates: self.mutates, payable: self.payable, - allow_reentrancy: self.allow_reentrancy, + reentrancy_allowed: self.reentrancy_allowed, default: self.default, args: self .args