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 c1a9a660ff5..6cab9a9c132 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 fb6b00350c1..7b286bbbfae 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 5dbdf6a7733..f3df08d0b07 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 ba030eb3d98..2daf68d9ce0 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 790eabc0d39..7542b2235f6 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 69747bba5cd..447955c4d8f 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 bf30512eba1..db719dbf15e 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 ca472091c88..fb32f586954 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 0dac7172326..51f09268267 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 b5407421d32..23ab98b0fde 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 0ae6a7f11ce..1c671677547 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 58dd94b4ce0..dec705315c8 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 4acbb3c57cc..07956b5fc77 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 46d8baf7d2e..0a5601fa9a0 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 2036999b147..c15c2c7008b 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 f658cb82a94..d165a8b5b72 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 d53fc3517b6..e588df9de46 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 1383002d058..e7f1a9cbabd 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 2bc974bcaae..428accefc39 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 28da4d9cb23..fce1889116f 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 1b113331b05..ea709bdfbe9 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 7b286bbbfae..664322e7f04 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 1c671677547..6eab277d162 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 0a5601fa9a0..7e52a32b0b8 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 9e215717ba7..eb7795d015c 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 e588df9de46..3d0cfe4402f 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 00000000000..13566b81b01 --- /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 00000000000..e52ed05fd72 --- /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 00000000000..0798285f09d --- /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 00000000000..35eb1ddfbbc --- /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 bb4b742c5ea..9eedc034ee4 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 664322e7f04..90601bb213c 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 76d6d6a1eb2..1d325fb5692 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 6eab277d162..49e7dd96381 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 07956b5fc77..b95a423b4ef 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 421c92a5f30..3ae20b3018d 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 00000000000..e43771e5c30 --- /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 00000000000..84e827de051 --- /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 00000000000..74e595c6de8 --- /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 00000000000..118afb1eb17 --- /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 ea709bdfbe9..5d60613027c 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 84471d5f79d..737f9bb89e1 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 e8c23317b1d..d414f29d565 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 7101544b93e..7ebab3a7c7e 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 0fcf8ce9f45..21b92bc51bc 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 d5730eee213..67893789961 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 99087f2b51c..7582f2a15c2 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 b3781159671..0da71853bf7 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 e542e880c0c..3aa8a805b74 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 c6418df8cf0..b5dba1afb28 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 33dee250415..cc74017436f 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 24dfe00bc5d..2be15ec8121 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 ad3c2b27ac8..95d45537b9e 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 29c65d9615d..94caf39dccf 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 cdde97feb79..3168335a67c 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 e44f82c0445..922f3777b85 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 3a0cef0f7b2..bc619b19899 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 a33937b0861..b8069624fb1 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 74037923929..e64d38d8146 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 6676399dc6f..9b40617be97 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 0ba6d47f661..5af1026c08f 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 2d0cd3535df..84d45a91b0a 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 06fd1620b45..7484faf031e 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 da92152db68..2ee9c921f63 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 86ca398df1e..3d6a3f352d7 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 00000000000..66873508010 --- /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 15202a2c81e..3dd203b4d4a 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 745cb6e49f7..abb792b0038 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 8326b74e9c3..229df39f15c 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 4f2952c514e..3c923d7b8f5 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 a1f5a0524f8..284acc45005 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 e954985afec..a4e6d9e5ea8 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 024f999a20c..9e2d7c917e6 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 b0a9b7a4b77..93d9f65ed8d 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 6ab123fba0e..b0d8499a4c3 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 fee507687a6..e7e00a93470 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 4d2a1e40277..4ff2c46f373 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 90aa30a65d0..7a02f009b12 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 9eedc034ee4..42a18373b99 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 90601bb213c..e6443dd3d0f 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 e6443dd3d0f..933c87ba4ef 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 933c87ba4ef..3dcb74edcd4 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 3a905f1e9dd..ef52b11d014 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 13566b81b01..00000000000 --- 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 e52ed05fd72..00000000000 --- 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 0798285f09d..00000000000 --- 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 35eb1ddfbbc..00000000000 --- 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 19adfa2a22c..a96840693f9 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 f8dcfcb97e5..b320eef3e3a 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 2f82dd4f53f..f62de29fb0c 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 0b4b172eb5f..63d73323c49 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 56c97e35180..7e4dea386b7 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