From 2c42a21c43ea4fdd48e6f12771c9af165b604ffc Mon Sep 17 00:00:00 2001 From: ascjones Date: Thu, 31 Mar 2022 17:44:59 +0100 Subject: [PATCH 001/122] Add ui test for shared event --- .../ui/contract/pass/event-shared-external.rs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 crates/lang/tests/ui/contract/pass/event-shared-external.rs diff --git a/crates/lang/tests/ui/contract/pass/event-shared-external.rs b/crates/lang/tests/ui/contract/pass/event-shared-external.rs new file mode 100644 index 00000000000..5d5c335df75 --- /dev/null +++ b/crates/lang/tests/ui/contract/pass/event-shared-external.rs @@ -0,0 +1,28 @@ +use ink_lang as ink; + +#[derive(ink::Event)] +pub struct Event0 {} + +// #[ink(event)] +// pub enum Event1 {} + +#[ink::contract] +mod contract { + #[ink(storage)] + pub struct Contract {} + + #[ink(event)] + type Event0 = super::Event0; + + impl Contract { + #[ink(constructor)] + pub fn constructor() -> Self { + Self {} + } + + #[ink(message)] + pub fn message(&self) {} + } +} + +fn main() {} From 21fd910eb7586e1ce9cc33dc4bbc3edf45cf2736 Mon Sep 17 00:00:00 2001 From: ascjones Date: Fri, 1 Apr 2022 11:34:01 +0100 Subject: [PATCH 002/122] WIP adding ink::event_definition --- crates/lang/ir/src/ir/event_def.rs | 33 +++++++++++++++++++ crates/lang/ir/src/ir/mod.rs | 2 ++ crates/lang/ir/src/lib.rs | 1 + crates/lang/macro/src/event_def.rs | 29 ++++++++++++++++ crates/lang/macro/src/lib.rs | 8 +++++ .../ui/contract/pass/event-shared-external.rs | 5 +-- 6 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 crates/lang/ir/src/ir/event_def.rs create mode 100644 crates/lang/macro/src/event_def.rs diff --git a/crates/lang/ir/src/ir/event_def.rs b/crates/lang/ir/src/ir/event_def.rs new file mode 100644 index 00000000000..470a21a3ec0 --- /dev/null +++ b/crates/lang/ir/src/ir/event_def.rs @@ -0,0 +1,33 @@ +// Copyright 2018-2022 Parity Technologies (UK) Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use proc_macro2::TokenStream as TokenStream2; + +/// A checked ink! event definition. +#[derive(Debug, PartialEq, Eq)] +pub struct InkEventDefinition { + // config: TraitDefinitionConfig, + // item: InkItemTrait, +} + +impl InkEventDefinition { + /// Returns `Ok` if the input matches all requirements for an ink! trait definition. + pub fn new(config: TokenStream2, input: TokenStream2) -> Result { + // let parsed_config = syn::parse2::(config)?; + // let parsed_item = syn::parse2::(input)?; + // let config = TraitDefinitionConfig::try_from(parsed_config)?; + // let item = InkItemTrait::new(&config, parsed_item)?; + // Ok(Self { config, item }) + } +} \ No newline at end of file diff --git a/crates/lang/ir/src/ir/mod.rs b/crates/lang/ir/src/ir/mod.rs index 18c625241e0..9ca96240bdd 100644 --- a/crates/lang/ir/src/ir/mod.rs +++ b/crates/lang/ir/src/ir/mod.rs @@ -19,6 +19,7 @@ mod blake2; mod chain_extension; mod config; mod contract; +mod event_def; mod idents_lint; mod ink_test; mod item; @@ -66,6 +67,7 @@ pub use self::{ }, config::Config, contract::Contract, + event_def::InkEventDefinition, ink_test::InkTest, item::{ Event, diff --git a/crates/lang/ir/src/lib.rs b/crates/lang/ir/src/lib.rs index 8dfbc1c0ed6..bcc8f2d3b91 100644 --- a/crates/lang/ir/src/lib.rs +++ b/crates/lang/ir/src/lib.rs @@ -51,6 +51,7 @@ pub use self::{ Event, ExtensionId, ImplItem, + InkEventDefinition, InkItem, InkItemTrait, InkTest, diff --git a/crates/lang/macro/src/event_def.rs b/crates/lang/macro/src/event_def.rs new file mode 100644 index 00000000000..f8cdf5bc83f --- /dev/null +++ b/crates/lang/macro/src/event_def.rs @@ -0,0 +1,29 @@ +// Copyright 2018-2022 Parity Technologies (UK) Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use ink_lang_codegen::generate_code; +use proc_macro2::TokenStream as TokenStream2; +use syn::Result; + +pub fn generate(config: TokenStream2, input: TokenStream2) -> TokenStream2 { + match generate_or_err(config, input) { + Ok(tokens) => tokens, + Err(err) => err.to_compile_error(), + } +} + +pub fn generate_or_err(config: TokenStream2, input: TokenStream2) -> Result { + let trait_definition = ink_lang_ir::InkEventDefinition::new(config, input)?; + Ok(generate_code(&trait_definition)) +} diff --git a/crates/lang/macro/src/lib.rs b/crates/lang/macro/src/lib.rs index fa7cf4f7749..a72710f3184 100644 --- a/crates/lang/macro/src/lib.rs +++ b/crates/lang/macro/src/lib.rs @@ -17,6 +17,7 @@ extern crate proc_macro; mod blake2b; mod chain_extension; mod contract; +mod event_def; mod ink_test; mod selector; mod trait_def; @@ -665,6 +666,13 @@ pub fn trait_definition(attr: TokenStream, item: TokenStream) -> TokenStream { trait_def::analyze(attr.into(), item.into()).into() } +/// todo derive Event docs + +#[proc_macro_attribute] +pub fn event_definition(attr: TokenStream, item: TokenStream) -> TokenStream { + event_def::generate(attr.into(),item.into()).into() +} + /// Defines a unit test that makes use of ink!'s off-chain testing capabilities. /// /// If your unit test does not require the existence of an off-chain environment diff --git a/crates/lang/tests/ui/contract/pass/event-shared-external.rs b/crates/lang/tests/ui/contract/pass/event-shared-external.rs index 5d5c335df75..770bc563eea 100644 --- a/crates/lang/tests/ui/contract/pass/event-shared-external.rs +++ b/crates/lang/tests/ui/contract/pass/event-shared-external.rs @@ -1,11 +1,8 @@ use ink_lang as ink; -#[derive(ink::Event)] +#[ink::event_definition] pub struct Event0 {} -// #[ink(event)] -// pub enum Event1 {} - #[ink::contract] mod contract { #[ink(storage)] From ba6734d5d84abb800e26d668b56f1443aae0b198 Mon Sep 17 00:00:00 2001 From: ascjones Date: Fri, 1 Apr 2022 13:27:52 +0100 Subject: [PATCH 003/122] More event definition wiring --- .../lang/codegen/src/generator/event_def.rs | 40 +++++++++++++++++++ crates/lang/codegen/src/generator/mod.rs | 2 + crates/lang/codegen/src/lib.rs | 4 ++ crates/lang/ir/src/ir/event_def.rs | 2 + 4 files changed, 48 insertions(+) create mode 100644 crates/lang/codegen/src/generator/event_def.rs diff --git a/crates/lang/codegen/src/generator/event_def.rs b/crates/lang/codegen/src/generator/event_def.rs new file mode 100644 index 00000000000..30df506014d --- /dev/null +++ b/crates/lang/codegen/src/generator/event_def.rs @@ -0,0 +1,40 @@ +// Copyright 2018-2022 Parity Technologies (UK) Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::marker::PhantomData; +use crate::GenerateCode; +use derive_more::From; +use proc_macro2::{ + Span, + TokenStream as TokenStream2, +}; +use quote::{ + quote, + quote_spanned, +}; +use syn::spanned::Spanned as _; + +/// Generates code for an event definition. +#[derive(From)] +pub struct EventDefinition<'a> { + event_def: &'a ir::InkEventDefinition, +} + +impl GenerateCode for EventDefinition<'_> { + fn generate_code(&self) -> TokenStream2 { + todo!() + } +} + +impl<'a> EventDefinition<'a> {} \ No newline at end of file diff --git a/crates/lang/codegen/src/generator/mod.rs b/crates/lang/codegen/src/generator/mod.rs index a6d68df5e69..a8daf31ea2e 100644 --- a/crates/lang/codegen/src/generator/mod.rs +++ b/crates/lang/codegen/src/generator/mod.rs @@ -33,6 +33,7 @@ mod chain_extension; mod contract; mod dispatch; mod env; +mod event_def; mod events; mod ink_test; mod item_impls; @@ -57,6 +58,7 @@ pub use self::{ contract::Contract, dispatch::Dispatch, env::Env, + event_def::EventDefinition, events::Events, ink_test::InkTest, item_impls::ItemImpls, diff --git a/crates/lang/codegen/src/lib.rs b/crates/lang/codegen/src/lib.rs index 27b82bec914..345cce6cf7a 100644 --- a/crates/lang/codegen/src/lib.rs +++ b/crates/lang/codegen/src/lib.rs @@ -35,6 +35,10 @@ impl<'a> CodeGenerator for &'a ir::Contract { type Generator = generator::Contract<'a>; } +impl<'a> CodeGenerator for &'a ir::InkEventDefinition { + type Generator = generator::EventDefinition<'a>; +} + impl<'a> CodeGenerator for &'a ir::InkTraitDefinition { type Generator = generator::TraitDefinition<'a>; } diff --git a/crates/lang/ir/src/ir/event_def.rs b/crates/lang/ir/src/ir/event_def.rs index 470a21a3ec0..481ac4f3e0e 100644 --- a/crates/lang/ir/src/ir/event_def.rs +++ b/crates/lang/ir/src/ir/event_def.rs @@ -13,6 +13,7 @@ // limitations under the License. use proc_macro2::TokenStream as TokenStream2; +use syn::Result; /// A checked ink! event definition. #[derive(Debug, PartialEq, Eq)] @@ -24,6 +25,7 @@ pub struct InkEventDefinition { impl InkEventDefinition { /// Returns `Ok` if the input matches all requirements for an ink! trait definition. pub fn new(config: TokenStream2, input: TokenStream2) -> Result { + todo!() // let parsed_config = syn::parse2::(config)?; // let parsed_item = syn::parse2::(input)?; // let config = TraitDefinitionConfig::try_from(parsed_config)?; From 54fbe58125c55baabfce99637b3340b36fe079e9 Mon Sep 17 00:00:00 2001 From: ascjones Date: Mon, 4 Apr 2022 17:07:35 +0100 Subject: [PATCH 004/122] WIP building shared event def --- .../lang/codegen/src/generator/event_def.rs | 136 +++++++++++++++++- crates/lang/ir/src/ir/event_def.rs | 111 ++++++++++++-- crates/lang/macro/src/event_def.rs | 5 +- crates/lang/macro/src/lib.rs | 2 +- crates/lang/src/reflect/event.rs | 14 ++ crates/lang/src/reflect/mod.rs | 5 +- 6 files changed, 256 insertions(+), 17 deletions(-) diff --git a/crates/lang/codegen/src/generator/event_def.rs b/crates/lang/codegen/src/generator/event_def.rs index 30df506014d..88577e15fbe 100644 --- a/crates/lang/codegen/src/generator/event_def.rs +++ b/crates/lang/codegen/src/generator/event_def.rs @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::marker::PhantomData; use crate::GenerateCode; use derive_more::From; use proc_macro2::{ @@ -23,6 +22,7 @@ use quote::{ quote, quote_spanned, }; +use std::marker::PhantomData; use syn::spanned::Spanned as _; /// Generates code for an event definition. @@ -33,8 +33,138 @@ pub struct EventDefinition<'a> { impl GenerateCode for EventDefinition<'_> { fn generate_code(&self) -> TokenStream2 { - todo!() + let emit_event_trait_impl = self.generate_emit_event_trait_impl(); + let topic_guards = self.generate_topic_guard(); + let topics_impls = self.generate_topics_impl(); + let event_structs = self.generate_event_struct(); + quote! { + #emit_event_trait_impl + #( #topic_guards )* + #( #event_structs )* + #( #topics_impls )* + } } } -impl<'a> EventDefinition<'a> {} \ No newline at end of file +impl<'a> EventDefinition<'a> { + fn generate_event_struct(&'a self) -> TokenStream2 { + let span = self.event_def.span(); + let ident = self.event_def.ident(); + let attrs = self.event_def.attrs(); + let fields = self.event_def.fields().map(|event_field| { + let span = event_field.span(); + let attrs = event_field.attrs(); + let vis = event_field.vis(); + let ident = event_field.ident(); + let ty = event_field.ty(); + quote_spanned!(span=> + #( #attrs )* + #vis #ident : #ty + ) + }); + quote_spanned!(span => + #( #attrs )* + #[derive(scale::Encode, scale::Decode)] + pub struct #ident { + #( #fields ),* + } + ) + } + + /// Generate checks to guard against too many topics in event definitions. + fn generate_topics_guard(&self) -> TokenStream2 { + let span = self.event_def.span(); + let event_ident = self.event_def.ident(); + let len_topics = self + .event_def + .fields() + .filter(|event| event.is_topic) + .count(); + quote_spanned!(span=> + impl ::ink_lang::codegen::EventLenTopics for #event_ident { + type LenTopics = ::ink_lang::codegen::EventTopics<#len_topics>; + } + ) + } + + /// Generates the `Topics` trait implementations for the user defined events. + fn generate_topics_impls(&'a self) -> impl Iterator + 'a { + let span = self.event_def.span(); + let event_ident = self.event_def.ident(); + let len_topics = self.event_def.fields().filter(|field| field.is_topic).count(); + let topic_impls = self.event_def + .fields() + .enumerate() + .filter(|(_, field)| field.is_topic) + .map(|(n, topic_field)| { + let span = topic_field.span(); + let field_ident = topic_field + .ident() + .map(quote::ToTokens::into_token_stream) + .unwrap_or_else(|| quote_spanned!(span => #n)); + let field_type = topic_field.ty(); + quote_spanned!(span => + .push_topic::<::ink_env::topics::PrefixedValue<#field_type>>( + &::ink_env::topics::PrefixedValue { + value: &self.#field_ident, + // todo: deduplicate with EVENT_SIGNATURE + prefix: ::core::concat!( + ::core::module_path!(), + "::", + ::core::stringify!(#event_ident), + "::", + ::core::stringify!(#field_ident), + ).as_bytes(), + } + ) + ) + }); + // Only include topic for event signature in case of non-anonymous event. + let event_signature_topic = match self.event_def.anonymous { + true => None, + false => { + Some(quote_spanned!(span=> + .push_topic::<::ink_env::topics::PrefixedValue<[u8; EVENT_SIGNATURE.len()]>>( + &::ink_env::topics::PrefixedValue { + value: EVENT_SIGNATURE, prefix: b"" + } + ) + )) + } + }; + // Anonymous events require 1 fewer topics since they do not include their signature. + let anonymous_topics_offset = if self.event_def.anonymous { 0 } else { 1 }; + let remaining_topics_ty = match len_topics + anonymous_topics_offset { + 0 => quote_spanned!(span=> ::ink_env::topics::state::NoRemainingTopics), + n => { + quote_spanned!(span=> [::ink_env::topics::state::HasRemainingTopics; #n]) + } + }; + quote_spanned!(span => + const _: () = { + impl ::ink_env::Topics for #event_ident { + type RemainingTopics = #remaining_topics_ty; + + fn topics( + &self, + builder: ::ink_env::topics::TopicsBuilder<::ink_env::topics::state::Uninit, E, B>, + ) -> >::Output + where + E: ::ink_env::Environment, + B: ::ink_env::topics::TopicsBuilderBackend, + { + const EVENT_SIGNATURE: &[u8] = ::PATH.as_bytes(); + + builder + .build::() + #event_signature_topic + #( + #topic_impls + )* + .finish() + } + } + }; + ) + } +} diff --git a/crates/lang/ir/src/ir/event_def.rs b/crates/lang/ir/src/ir/event_def.rs index 481ac4f3e0e..668838c976f 100644 --- a/crates/lang/ir/src/ir/event_def.rs +++ b/crates/lang/ir/src/ir/event_def.rs @@ -12,24 +12,113 @@ // See the License for the specific language governing permissions and // limitations under the License. -use proc_macro2::TokenStream as TokenStream2; -use syn::Result; +use crate::ir; +use proc_macro2::{ + Ident, + Span, + TokenStream as TokenStream2, +}; +use syn::{Result, spanned::Spanned as _}; /// A checked ink! event definition. #[derive(Debug, PartialEq, Eq)] pub struct InkEventDefinition { - // config: TraitDefinitionConfig, - // item: InkItemTrait, + item: syn::ItemStruct, + pub anonymous: bool, } impl InkEventDefinition { - /// Returns `Ok` if the input matches all requirements for an ink! trait definition. + /// Returns `Ok` if the input matches all requirements for an ink! event definition. pub fn new(config: TokenStream2, input: TokenStream2) -> Result { - todo!() - // let parsed_config = syn::parse2::(config)?; - // let parsed_item = syn::parse2::(input)?; - // let config = TraitDefinitionConfig::try_from(parsed_config)?; + let _parsed_config = syn::parse2::(config)?; + let anonymous = false; // todo parse this from attr config + let item = syn::parse2::(input)?; // let item = InkItemTrait::new(&config, parsed_item)?; - // Ok(Self { config, item }) + Ok(Self { anonymous, item }) } -} \ No newline at end of file + + /// Returns the identifier of the event struct. + pub fn ident(&self) -> &Ident { + &self.item.ident + } + + /// Returns an iterator yielding all the `#[ink(topic)]` annotated fields + /// of the event struct. + pub fn fields(&self) -> EventFieldsIter { + EventFieldsIter::new(self) + } + + /// Returns all non-ink! attributes. + pub fn attrs(&self) -> &[syn::Attribute] { + &self.item.attrs + } +} + +/// An event field with a flag indicating if this field is an event topic. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct EventField<'a> { + /// The associated `field` is an event topic if this is `true`. + pub is_topic: bool, + /// The event field. + field: &'a syn::Field, +} + +impl<'a> EventField<'a> { + /// Returns the span of the event field. + pub fn span(self) -> Span { + self.field.span() + } + + /// Returns all non-ink! attributes of the event field. + pub fn attrs(self) -> Vec { + let (_, non_ink_attrs) = ir::partition_attributes(self.field.attrs.clone()) + .expect("encountered invalid event field attributes"); + non_ink_attrs + } + + /// Returns the visibility of the event field. + pub fn vis(self) -> &'a syn::Visibility { + &self.field.vis + } + + /// Returns the identifier of the event field if any. + pub fn ident(self) -> Option<&'a Ident> { + self.field.ident.as_ref() + } + + /// Returns the type of the event field. + pub fn ty(self) -> &'a syn::Type { + &self.field.ty + } +} + +/// Iterator yielding all `#[ink(topic)]` annotated fields of an event struct. +pub struct EventFieldsIter<'a> { + iter: syn::punctuated::Iter<'a, syn::Field>, +} + +impl<'a> EventFieldsIter<'a> { + /// Creates a new topics fields iterator for the given ink! event struct. + fn new(event: &'a InkEventDefinition) -> Self { + Self { + iter: event.item.fields.iter(), + } + } +} + +impl<'a> Iterator for EventFieldsIter<'a> { + type Item = EventField<'a>; + + fn next(&mut self) -> Option { + match self.iter.next() { + None => None, + Some(field) => { + let is_topic = ir::first_ink_attribute(&field.attrs) + .unwrap_or_default() + .map(|attr| matches!(attr.first().kind(), ir::AttributeArg::Topic)) + .unwrap_or_default(); + Some(EventField { is_topic, field }) + } + } + } +} diff --git a/crates/lang/macro/src/event_def.rs b/crates/lang/macro/src/event_def.rs index f8cdf5bc83f..cfd745ff3fc 100644 --- a/crates/lang/macro/src/event_def.rs +++ b/crates/lang/macro/src/event_def.rs @@ -23,7 +23,10 @@ pub fn generate(config: TokenStream2, input: TokenStream2) -> TokenStream2 { } } -pub fn generate_or_err(config: TokenStream2, input: TokenStream2) -> Result { +pub fn generate_or_err( + config: TokenStream2, + input: TokenStream2, +) -> Result { let trait_definition = ink_lang_ir::InkEventDefinition::new(config, input)?; Ok(generate_code(&trait_definition)) } diff --git a/crates/lang/macro/src/lib.rs b/crates/lang/macro/src/lib.rs index a72710f3184..790a4dfee68 100644 --- a/crates/lang/macro/src/lib.rs +++ b/crates/lang/macro/src/lib.rs @@ -670,7 +670,7 @@ pub fn trait_definition(attr: TokenStream, item: TokenStream) -> TokenStream { #[proc_macro_attribute] pub fn event_definition(attr: TokenStream, item: TokenStream) -> TokenStream { - event_def::generate(attr.into(),item.into()).into() + event_def::generate(attr.into(), item.into()).into() } /// Defines a unit test that makes use of ink!'s off-chain testing capabilities. diff --git a/crates/lang/src/reflect/event.rs b/crates/lang/src/reflect/event.rs index 887e2496da8..19b8e6a26fe 100644 --- a/crates/lang/src/reflect/event.rs +++ b/crates/lang/src/reflect/event.rs @@ -50,3 +50,17 @@ pub trait ContractEventBase { /// The generated base event enum. type Type; } + +/// todo: docs +pub trait EventInfo { + /// The complete path of the ink! event definition. + /// + /// This is equivalent to Rust's builtin `module_path!` macro + /// invocation at the definition site of the ink! event, concatenated with + /// the event identifier. + /// + /// todo: rename? + const PATH: &'static str; + + +} diff --git a/crates/lang/src/reflect/mod.rs b/crates/lang/src/reflect/mod.rs index 3f59becff34..3235771ae40 100644 --- a/crates/lang/src/reflect/mod.rs +++ b/crates/lang/src/reflect/mod.rs @@ -46,7 +46,10 @@ pub use self::{ DispatchableMessageInfo, ExecuteDispatchable, }, - event::ContractEventBase, + event::{ + ContractEventBase, + ContractEvent, + }, trait_def::{ TraitDefinitionRegistry, TraitInfo, From 88f3722415471c5ef8cfaceacb0706144428105a Mon Sep 17 00:00:00 2001 From: ascjones Date: Mon, 11 Apr 2022 12:50:31 +0100 Subject: [PATCH 005/122] Make event_definition attribute compile --- .../lang/codegen/src/generator/event_def.rs | 38 +++++++++++-------- crates/lang/ir/src/ir/event_def.rs | 8 ++++ crates/lang/src/lib.rs | 1 + crates/lang/src/reflect/mod.rs | 2 +- 4 files changed, 33 insertions(+), 16 deletions(-) diff --git a/crates/lang/codegen/src/generator/event_def.rs b/crates/lang/codegen/src/generator/event_def.rs index 88577e15fbe..333f573a194 100644 --- a/crates/lang/codegen/src/generator/event_def.rs +++ b/crates/lang/codegen/src/generator/event_def.rs @@ -15,14 +15,12 @@ use crate::GenerateCode; use derive_more::From; use proc_macro2::{ - Span, TokenStream as TokenStream2, }; use quote::{ quote, quote_spanned, }; -use std::marker::PhantomData; use syn::spanned::Spanned as _; /// Generates code for an event definition. @@ -33,15 +31,15 @@ pub struct EventDefinition<'a> { impl GenerateCode for EventDefinition<'_> { fn generate_code(&self) -> TokenStream2 { - let emit_event_trait_impl = self.generate_emit_event_trait_impl(); - let topic_guards = self.generate_topic_guard(); - let topics_impls = self.generate_topics_impl(); - let event_structs = self.generate_event_struct(); + let event_struct = self.generate_event_struct(); + let event_info_impl = self.generate_event_info_impl(); + let topics_impl = self.generate_topics_impl(); + let topics_guard = self.generate_topics_guard(); quote! { - #emit_event_trait_impl - #( #topic_guards )* - #( #event_structs )* - #( #topics_impls )* + #event_struct + #event_info_impl + #topics_impl + #topics_guard } } } @@ -71,6 +69,16 @@ impl<'a> EventDefinition<'a> { ) } + fn generate_event_info_impl(&'a self) -> TokenStream2 { + let span = self.event_def.span(); + let event_ident = self.event_def.ident(); + quote_spanned!(span=> + impl ::ink_lang::reflect::EventInfo for #event_ident { + const PATH: &'static str = module_path!(); + } + ) + } + /// Generate checks to guard against too many topics in event definitions. fn generate_topics_guard(&self) -> TokenStream2 { let span = self.event_def.span(); @@ -88,7 +96,7 @@ impl<'a> EventDefinition<'a> { } /// Generates the `Topics` trait implementations for the user defined events. - fn generate_topics_impls(&'a self) -> impl Iterator + 'a { + fn generate_topics_impl(&self) -> TokenStream2 { let span = self.event_def.span(); let event_ident = self.event_def.ident(); let len_topics = self.event_def.fields().filter(|field| field.is_topic).count(); @@ -106,7 +114,6 @@ impl<'a> EventDefinition<'a> { quote_spanned!(span => .push_topic::<::ink_env::topics::PrefixedValue<#field_type>>( &::ink_env::topics::PrefixedValue { - value: &self.#field_ident, // todo: deduplicate with EVENT_SIGNATURE prefix: ::core::concat!( ::core::module_path!(), @@ -115,6 +122,7 @@ impl<'a> EventDefinition<'a> { "::", ::core::stringify!(#field_ident), ).as_bytes(), + value: &self.#field_ident, } ) ) @@ -124,9 +132,9 @@ impl<'a> EventDefinition<'a> { true => None, false => { Some(quote_spanned!(span=> - .push_topic::<::ink_env::topics::PrefixedValue<[u8; EVENT_SIGNATURE.len()]>>( + .push_topic::<::ink_env::topics::PrefixedValue<()>>( &::ink_env::topics::PrefixedValue { - value: EVENT_SIGNATURE, prefix: b"" + prefix: EVENT_SIGNATURE, value: &(), } ) )) @@ -153,7 +161,7 @@ impl<'a> EventDefinition<'a> { E: ::ink_env::Environment, B: ::ink_env::topics::TopicsBuilderBackend, { - const EVENT_SIGNATURE: &[u8] = ::PATH.as_bytes(); + const EVENT_SIGNATURE: &[u8] = <#event_ident as ::ink_lang::reflect::EventInfo>::PATH.as_bytes(); builder .build::() diff --git a/crates/lang/ir/src/ir/event_def.rs b/crates/lang/ir/src/ir/event_def.rs index 668838c976f..ccf0a635388 100644 --- a/crates/lang/ir/src/ir/event_def.rs +++ b/crates/lang/ir/src/ir/event_def.rs @@ -27,6 +27,14 @@ pub struct InkEventDefinition { pub anonymous: bool, } +impl quote::ToTokens for InkEventDefinition { + /// We mainly implement this trait for this ink! type to have a derived + /// [`Spanned`](`syn::spanned::Spanned`) implementation for it. + fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { + self.item.to_tokens(tokens) + } +} + impl InkEventDefinition { /// Returns `Ok` if the input matches all requirements for an ink! event definition. pub fn new(config: TokenStream2, input: TokenStream2) -> Result { diff --git a/crates/lang/src/lib.rs b/crates/lang/src/lib.rs index b65981a7189..ad01e756c66 100644 --- a/crates/lang/src/lib.rs +++ b/crates/lang/src/lib.rs @@ -46,6 +46,7 @@ pub use ink_lang_macro::{ blake2x256, chain_extension, contract, + event_definition, selector_bytes, selector_id, test, diff --git a/crates/lang/src/reflect/mod.rs b/crates/lang/src/reflect/mod.rs index 3235771ae40..d73a9d09180 100644 --- a/crates/lang/src/reflect/mod.rs +++ b/crates/lang/src/reflect/mod.rs @@ -48,7 +48,7 @@ pub use self::{ }, event::{ ContractEventBase, - ContractEvent, + EventInfo, }, trait_def::{ TraitDefinitionRegistry, From 63a30c63baab0f6e03614b82f6e99649c2e563f7 Mon Sep 17 00:00:00 2001 From: ascjones Date: Tue, 12 Apr 2022 17:45:16 +0100 Subject: [PATCH 006/122] Parse ink(event) attribute on type alias --- crates/lang/codegen/src/generator/events.rs | 78 +-------------------- crates/lang/ir/src/ir/item/event.rs | 57 ++++++++++++--- crates/lang/ir/src/ir/item/mod.rs | 10 ++- 3 files changed, 57 insertions(+), 88 deletions(-) diff --git a/crates/lang/codegen/src/generator/events.rs b/crates/lang/codegen/src/generator/events.rs index 3f1ab62b923..f44c4e9ea2e 100644 --- a/crates/lang/codegen/src/generator/events.rs +++ b/crates/lang/codegen/src/generator/events.rs @@ -40,14 +40,14 @@ impl GenerateCode for Events<'_> { let emit_event_trait_impl = self.generate_emit_event_trait_impl(); let event_base = self.generate_event_base(); let topic_guards = self.generate_topic_guards(); - let topics_impls = self.generate_topics_impls(); + // let topics_impls = self.generate_topics_impls(); // todo: call into shared event_def code for inline events let event_structs = self.generate_event_structs(); quote! { #emit_event_trait_impl #event_base #( #topic_guards )* #( #event_structs )* - #( #topics_impls )* + // #( #topics_impls )* } } } @@ -181,80 +181,6 @@ impl<'a> Events<'a> { }) } - /// Generates the `Topics` trait implementations for the user defined events. - fn generate_topics_impls(&'a self) -> impl Iterator + 'a { - let contract_ident = self.contract.module().storage().ident(); - self.contract.module().events().map(move |event| { - let span = event.span(); - let event_ident = event.ident(); - let event_signature = syn::LitByteStr::new( - format!("{}::{}", contract_ident, event_ident - ).as_bytes(), span); - let len_event_signature = event_signature.value().len(); - let len_topics = event.fields().filter(|field| field.is_topic).count(); - let topic_impls = event - .fields() - .enumerate() - .filter(|(_, field)| field.is_topic) - .map(|(n, topic_field)| { - let span = topic_field.span(); - let field_ident = topic_field - .ident() - .map(quote::ToTokens::into_token_stream) - .unwrap_or_else(|| quote_spanned!(span => #n)); - let field_type = topic_field.ty(); - let signature = syn::LitByteStr::new( - format!("{}::{}::{}", contract_ident, event_ident, - field_ident - ).as_bytes(), span); - quote_spanned!(span => - .push_topic::<::ink_env::topics::PrefixedValue<#field_type>>( - &::ink_env::topics::PrefixedValue { value: &self.#field_ident, prefix: #signature } - ) - ) - }); - // Only include topic for event signature in case of non-anonymous event. - let event_signature_topic = match event.anonymous { - true => None, - false => Some(quote_spanned!(span=> - .push_topic::<::ink_env::topics::PrefixedValue<[u8; #len_event_signature]>>( - &::ink_env::topics::PrefixedValue { value: #event_signature, prefix: b"" } - ) - )) - }; - // Anonymous events require 1 fewer topics since they do not include their signature. - let anonymous_topics_offset = if event.anonymous { 0 } else { 1 }; - let remaining_topics_ty = match len_topics + anonymous_topics_offset { - 0 => quote_spanned!(span=> ::ink_env::topics::state::NoRemainingTopics), - n => quote_spanned!(span=> [::ink_env::topics::state::HasRemainingTopics; #n]), - }; - quote_spanned!(span => - const _: () = { - impl ::ink_env::Topics for #event_ident { - type RemainingTopics = #remaining_topics_ty; - - fn topics( - &self, - builder: ::ink_env::topics::TopicsBuilder<::ink_env::topics::state::Uninit, E, B>, - ) -> >::Output - where - E: ::ink_env::Environment, - B: ::ink_env::topics::TopicsBuilderBackend, - { - builder - .build::() - #event_signature_topic - #( - #topic_impls - )* - .finish() - } - } - }; - ) - }) - } - /// Generates all the user defined event struct definitions. fn generate_event_structs(&'a self) -> impl Iterator + 'a { self.contract.module().events().map(move |event| { diff --git a/crates/lang/ir/src/ir/item/event.rs b/crates/lang/ir/src/ir/item/event.rs index 631e3f692a6..356ff3bae13 100644 --- a/crates/lang/ir/src/ir/item/event.rs +++ b/crates/lang/ir/src/ir/item/event.rs @@ -22,6 +22,13 @@ use proc_macro2::{ Span, }; use syn::spanned::Spanned as _; +use crate::ast::PathOrLit::Path; + +#[derive(Debug, PartialEq, Eq)] +pub enum Event { + Inline(InlineEvent), + Imported(ImportedEvent), +} /// An ink! event struct definition. /// @@ -40,16 +47,25 @@ use syn::spanned::Spanned as _; /// # }).unwrap(); /// ``` #[derive(Debug, PartialEq, Eq)] -pub struct Event { +pub struct InlineEvent { item: syn::ItemStruct, pub anonymous: bool, } +/// todo add ImportedEvent docs +#[derive(Debug, PartialEq, Eq)] +pub struct ImportedEvent { + item: syn::ItemType, +} + impl quote::ToTokens for Event { /// We mainly implement this trait for this ink! type to have a derived /// [`Spanned`](`syn::spanned::Spanned`) implementation for it. fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { - self.item.to_tokens(tokens) + match self { + Event::Inline(inline) => inline.item.to_tokens(tokens), + Event::Imported(imported) => imported.item.to_tokens(tokens), + } } } @@ -61,15 +77,15 @@ impl Event { /// /// If the first found ink! attribute is malformed. pub(super) fn is_ink_event( - item_struct: &syn::ItemStruct, + attrs: &[syn::Attribute], ) -> Result { - if !ir::contains_ink_attributes(&item_struct.attrs) { + if !ir::contains_ink_attributes(attrs) { return Ok(false) } // At this point we know that there must be at least one ink! // attribute. This can be either the ink! storage struct, // an ink! event or an invalid ink! attribute. - let attr = ir::first_ink_attribute(&item_struct.attrs)? + let attr = ir::first_ink_attribute(attrs)? .expect("missing expected ink! attribute for struct"); Ok(matches!(attr.first().kind(), ir::AttributeArg::Event)) } @@ -123,31 +139,50 @@ impl TryFrom for Event { } } } - Ok(Self { + Ok(Self::Inline(InlineEvent { item: syn::ItemStruct { attrs: other_attrs, ..item_struct }, anonymous: ink_attrs.is_anonymous(), - }) + })) + } +} + +impl TryFrom for Event { + type Error = syn::Error; + + fn try_from(item_type: syn::ItemType) -> Result { + Ok(Self::Imported(ImportedEvent { + item: item_type + })) } } impl Event { /// Returns the identifier of the event struct. pub fn ident(&self) -> &Ident { - &self.item.ident + match self { + Event::Inline(inline) => &inline.item.ident, + Event::Imported(_) => unimplemented!() + } } /// Returns an iterator yielding all the `#[ink(topic)]` annotated fields /// of the event struct. pub fn fields(&self) -> EventFieldsIter { - EventFieldsIter::new(self) + match self { + Event::Inline(inline) => EventFieldsIter::new(inline), + Event::Imported(_) => unimplemented!(), + } } /// Returns all non-ink! attributes. pub fn attrs(&self) -> &[syn::Attribute] { - &self.item.attrs + match self { + Event::Inline(inline) => &inline.item.attrs, + Event::Imported(imported) => &imported.item.attrs, + } } } @@ -196,7 +231,7 @@ pub struct EventFieldsIter<'a> { impl<'a> EventFieldsIter<'a> { /// Creates a new topics fields iterator for the given ink! event struct. - fn new(event: &'a Event) -> Self { + fn new(event: &'a InlineEvent) -> Self { Self { iter: event.item.fields.iter(), } diff --git a/crates/lang/ir/src/ir/item/mod.rs b/crates/lang/ir/src/ir/item/mod.rs index 5bb3d6b83ed..68ff3b4ed91 100644 --- a/crates/lang/ir/src/ir/item/mod.rs +++ b/crates/lang/ir/src/ir/item/mod.rs @@ -95,6 +95,14 @@ impl TryFrom for Item { .map(Into::into) .map(Self::Ink) } + syn::Item::Type(item_type) => { + if !ir::Event::is_ink_event(&item_type.attrs)? { + return Ok(Self::Rust(item_type.into())) + } + >::try_from(item_type) + .map(Into::into) + .map(Self::Ink) + } item => { // This is an error if the item contains any unexpected // ink! attributes. Otherwise it is a normal Rust item. @@ -181,7 +189,7 @@ impl InkItem { match item { syn::Item::Struct(item_struct) => { if ir::Storage::is_ink_storage(item_struct)? - || ir::Event::is_ink_event(item_struct)? + || ir::Event::is_ink_event(&item_struct.attrs)? { return Ok(true) } From 90c2eb579714e899b2964a82a3c199c133703923 Mon Sep 17 00:00:00 2001 From: ascjones Date: Wed, 13 Apr 2022 17:22:49 +0100 Subject: [PATCH 007/122] Combining IR for external and inline event definitions --- crates/lang/ir/src/ir/event_def.rs | 73 +++++++++++++++++++++++- crates/lang/ir/src/ir/item/event.rs | 86 ++--------------------------- crates/lang/macro/src/event_def.rs | 2 +- 3 files changed, 76 insertions(+), 85 deletions(-) diff --git a/crates/lang/ir/src/ir/event_def.rs b/crates/lang/ir/src/ir/event_def.rs index ccf0a635388..46b2a7160a7 100644 --- a/crates/lang/ir/src/ir/event_def.rs +++ b/crates/lang/ir/src/ir/event_def.rs @@ -12,7 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::ir; +use crate::{ + error::ExtError as _, + ir, + ir::utils, +}; use proc_macro2::{ Ident, Span, @@ -23,10 +27,35 @@ use syn::{Result, spanned::Spanned as _}; /// A checked ink! event definition. #[derive(Debug, PartialEq, Eq)] pub struct InkEventDefinition { - item: syn::ItemStruct, + pub item: syn::ItemStruct, pub anonymous: bool, } +impl TryFrom for InkEventDefinition { + type Error = syn::Error; + + fn try_from(item_struct: syn::ItemStruct) -> Result { + let struct_span = item_struct.span(); + let (ink_attrs, other_attrs) = ir::sanitize_attributes( + struct_span, + item_struct.attrs, + &ir::AttributeArgKind::Event, + |arg| { + match arg.kind() { + ir::AttributeArg::Event | ir::AttributeArg::Anonymous => Ok(()), + _ => Err(None), + } + }, + )?; + let item_struct = syn::ItemStruct { + attrs: other_attrs, + ..item_struct + }; + Self::new(item_struct, ink_attrs.is_anonymous()) + } +} + + impl quote::ToTokens for InkEventDefinition { /// We mainly implement this trait for this ink! type to have a derived /// [`Spanned`](`syn::spanned::Spanned`) implementation for it. @@ -37,7 +66,45 @@ impl quote::ToTokens for InkEventDefinition { impl InkEventDefinition { /// Returns `Ok` if the input matches all requirements for an ink! event definition. - pub fn new(config: TokenStream2, input: TokenStream2) -> Result { + pub fn new(item_struct: syn::ItemStruct, anonymous: bool) -> Result { + if !item_struct.generics.params.is_empty() { + return Err(format_err_spanned!( + item_struct.generics.params, + "generic ink! event structs are not supported", + )) + } + let struct_span = item_struct.span(); + utils::ensure_pub_visibility("event structs", struct_span, &item_struct.vis)?; + 'repeat: for field in item_struct.fields.iter() { + let field_span = field.span(); + let (ink_attrs, _) = ir::partition_attributes(field.attrs.clone())?; + if ink_attrs.is_empty() { + continue 'repeat + } + let normalized = + ir::InkAttribute::from_expanded(ink_attrs).map_err(|err| { + err.into_combine(format_err!(field_span, "at this invocation",)) + })?; + if !matches!(normalized.first().kind(), ir::AttributeArg::Topic) { + return Err(format_err!( + field_span, + "first optional ink! attribute of an event field must be #[ink(topic)]", + )) + } + for arg in normalized.args() { + if !matches!(arg.kind(), ir::AttributeArg::Topic) { + return Err(format_err!( + arg.span(), + "encountered conflicting ink! attribute for event field", + )) + } + } + } + Ok(Self { item: item_struct, anonymous }) + } + + /// Returns `Ok` if the input matches all requirements for an ink! event definition. + pub fn from_event_def_tokens(config: TokenStream2, input: TokenStream2) -> Result { let _parsed_config = syn::parse2::(config)?; let anonymous = false; // todo parse this from attr config let item = syn::parse2::(input)?; diff --git a/crates/lang/ir/src/ir/item/event.rs b/crates/lang/ir/src/ir/item/event.rs index 356ff3bae13..b7dbda2abe8 100644 --- a/crates/lang/ir/src/ir/item/event.rs +++ b/crates/lang/ir/src/ir/item/event.rs @@ -12,46 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{ - error::ExtError as _, - ir, - ir::utils, -}; +use crate::{InkEventDefinition, ir}; use proc_macro2::{ Ident, Span, }; use syn::spanned::Spanned as _; -use crate::ast::PathOrLit::Path; #[derive(Debug, PartialEq, Eq)] pub enum Event { - Inline(InlineEvent), + Inline(ir::InkEventDefinition), Imported(ImportedEvent), } -/// An ink! event struct definition. -/// -/// # Example -/// -/// ``` -/// # let event = >::try_from(syn::parse_quote! { -/// #[ink(event)] -/// pub struct Transaction { -/// #[ink(topic)] -/// from: AccountId, -/// #[ink(topic)] -/// to: AccountId, -/// value: Balance, -/// } -/// # }).unwrap(); -/// ``` -#[derive(Debug, PartialEq, Eq)] -pub struct InlineEvent { - item: syn::ItemStruct, - pub anonymous: bool, -} - /// todo add ImportedEvent docs #[derive(Debug, PartialEq, Eq)] pub struct ImportedEvent { @@ -95,57 +68,8 @@ impl TryFrom for Event { type Error = syn::Error; fn try_from(item_struct: syn::ItemStruct) -> Result { - let struct_span = item_struct.span(); - let (ink_attrs, other_attrs) = ir::sanitize_attributes( - struct_span, - item_struct.attrs, - &ir::AttributeArgKind::Event, - |arg| { - match arg.kind() { - ir::AttributeArg::Event | ir::AttributeArg::Anonymous => Ok(()), - _ => Err(None), - } - }, - )?; - if !item_struct.generics.params.is_empty() { - return Err(format_err_spanned!( - item_struct.generics.params, - "generic ink! event structs are not supported", - )) - } - utils::ensure_pub_visibility("event structs", struct_span, &item_struct.vis)?; - 'repeat: for field in item_struct.fields.iter() { - let field_span = field.span(); - let (ink_attrs, _) = ir::partition_attributes(field.attrs.clone())?; - if ink_attrs.is_empty() { - continue 'repeat - } - let normalized = - ir::InkAttribute::from_expanded(ink_attrs).map_err(|err| { - err.into_combine(format_err!(field_span, "at this invocation",)) - })?; - if !matches!(normalized.first().kind(), ir::AttributeArg::Topic) { - return Err(format_err!( - field_span, - "first optional ink! attribute of an event field must be #[ink(topic)]", - )) - } - for arg in normalized.args() { - if !matches!(arg.kind(), ir::AttributeArg::Topic) { - return Err(format_err!( - arg.span(), - "encountered conflicting ink! attribute for event field", - )) - } - } - } - Ok(Self::Inline(InlineEvent { - item: syn::ItemStruct { - attrs: other_attrs, - ..item_struct - }, - anonymous: ink_attrs.is_anonymous(), - })) + let event_def = InkEventDefinition::try_from(item_struct)?; + Ok(Self::Inline(event_def)) } } @@ -231,7 +155,7 @@ pub struct EventFieldsIter<'a> { impl<'a> EventFieldsIter<'a> { /// Creates a new topics fields iterator for the given ink! event struct. - fn new(event: &'a InlineEvent) -> Self { + fn new(event: &'a InkEventDefinition) -> Self { Self { iter: event.item.fields.iter(), } diff --git a/crates/lang/macro/src/event_def.rs b/crates/lang/macro/src/event_def.rs index cfd745ff3fc..bfdc009c5d4 100644 --- a/crates/lang/macro/src/event_def.rs +++ b/crates/lang/macro/src/event_def.rs @@ -27,6 +27,6 @@ pub fn generate_or_err( config: TokenStream2, input: TokenStream2, ) -> Result { - let trait_definition = ink_lang_ir::InkEventDefinition::new(config, input)?; + let trait_definition = ink_lang_ir::InkEventDefinition::from_event_def_tokens(config, input)?; Ok(generate_code(&trait_definition)) } From ee9e74b74198a3a0751421fcba2b76991c7de39e Mon Sep 17 00:00:00 2001 From: ascjones Date: Wed, 13 Apr 2022 17:48:49 +0100 Subject: [PATCH 008/122] WIP generating Topics impls for inline events --- crates/lang/codegen/src/generator/events.rs | 27 ++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/crates/lang/codegen/src/generator/events.rs b/crates/lang/codegen/src/generator/events.rs index f44c4e9ea2e..82633a52c2f 100644 --- a/crates/lang/codegen/src/generator/events.rs +++ b/crates/lang/codegen/src/generator/events.rs @@ -12,7 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::GenerateCode; +use crate::{ + GenerateCode, + generator::EventDefinition, +}; use derive_more::From; use proc_macro2::{ Span, @@ -23,6 +26,7 @@ use quote::{ quote_spanned, }; use syn::spanned::Spanned as _; +use ir::Event; /// Generates code for the ink! event structs of the contract. #[derive(From)] @@ -40,14 +44,14 @@ impl GenerateCode for Events<'_> { let emit_event_trait_impl = self.generate_emit_event_trait_impl(); let event_base = self.generate_event_base(); let topic_guards = self.generate_topic_guards(); - // let topics_impls = self.generate_topics_impls(); // todo: call into shared event_def code for inline events + let topics_impls = self.generate_topics_impls(); // todo: call into shared event_def code for inline events let event_structs = self.generate_event_structs(); quote! { #emit_event_trait_impl #event_base #( #topic_guards )* #( #event_structs )* - // #( #topics_impls )* + #( #topics_impls )* } } } @@ -181,6 +185,23 @@ impl<'a> Events<'a> { }) } + /// Generates the `Topics` trait implementations for the user defined events. + fn generate_topics_impls(&'a self) -> impl Iterator + 'a { + let contract_ident = self.contract.module().storage().ident(); + self.contract.module().events().map(move |event| { + match event { + Event::Inline(event_def) => { + let event_def_gen = EventDefinition::from(event_def); + event_def_gen.generate_code() + } + Event::Imported(imported_event) => { + todo!() + } + } + }) + } + + /// Generates all the user defined event struct definitions. fn generate_event_structs(&'a self) -> impl Iterator + 'a { self.contract.module().events().map(move |event| { From 0edba13f8a992338ba9a013942ad879061f71376 Mon Sep 17 00:00:00 2001 From: ascjones Date: Thu, 14 Apr 2022 09:54:45 +0100 Subject: [PATCH 009/122] Remove duplicate topics impls --- crates/lang/codegen/src/generator/events.rs | 46 +++------------------ crates/lang/ir/src/ir/item/event.rs | 2 +- 2 files changed, 7 insertions(+), 41 deletions(-) diff --git a/crates/lang/codegen/src/generator/events.rs b/crates/lang/codegen/src/generator/events.rs index 82633a52c2f..910661b9a78 100644 --- a/crates/lang/codegen/src/generator/events.rs +++ b/crates/lang/codegen/src/generator/events.rs @@ -44,14 +44,12 @@ impl GenerateCode for Events<'_> { let emit_event_trait_impl = self.generate_emit_event_trait_impl(); let event_base = self.generate_event_base(); let topic_guards = self.generate_topic_guards(); - let topics_impls = self.generate_topics_impls(); // todo: call into shared event_def code for inline events - let event_structs = self.generate_event_structs(); + let event_defs = self.generate_event_definitions(); // todo: call into shared event_def code for inline events quote! { #emit_event_trait_impl #event_base #( #topic_guards )* - #( #event_structs )* - #( #topics_impls )* + #( #event_defs )* } } } @@ -155,16 +153,11 @@ impl<'a> Events<'a> { let span = event.span(); let storage_ident = self.contract.module().storage().ident(); let event_ident = event.ident(); - let len_topics = event.fields().filter(|event| event.is_topic).count(); let max_len_topics = quote_spanned!(span=> <<#storage_ident as ::ink_lang::reflect::ContractEnv>::Env as ::ink_env::Environment>::MAX_EVENT_TOPICS ); quote_spanned!(span=> - impl ::ink_lang::codegen::EventLenTopics for #event_ident { - type LenTopics = ::ink_lang::codegen::EventTopics<#len_topics>; - } - const _: () = ::ink_lang::codegen::utils::consume_type::< ::ink_lang::codegen::EventRespectsTopicLimit< #event_ident, @@ -186,8 +179,7 @@ impl<'a> Events<'a> { } /// Generates the `Topics` trait implementations for the user defined events. - fn generate_topics_impls(&'a self) -> impl Iterator + 'a { - let contract_ident = self.contract.module().storage().ident(); + fn generate_event_definitions(&'a self) -> impl Iterator + 'a { self.contract.module().events().map(move |event| { match event { Event::Inline(event_def) => { @@ -195,37 +187,11 @@ impl<'a> Events<'a> { event_def_gen.generate_code() } Event::Imported(imported_event) => { - todo!() + // todo: hook up to base event and figure out metadata + let item_type = &imported_event.item; + quote! { #item_type } } } }) } - - - /// Generates all the user defined event struct definitions. - fn generate_event_structs(&'a self) -> impl Iterator + 'a { - self.contract.module().events().map(move |event| { - let span = event.span(); - let ident = event.ident(); - let attrs = event.attrs(); - let fields = event.fields().map(|event_field| { - let span = event_field.span(); - let attrs = event_field.attrs(); - let vis = event_field.vis(); - let ident = event_field.ident(); - let ty = event_field.ty(); - quote_spanned!(span=> - #( #attrs )* - #vis #ident : #ty - ) - }); - quote_spanned!(span => - #( #attrs )* - #[derive(scale::Encode, scale::Decode)] - pub struct #ident { - #( #fields ),* - } - ) - }) - } } diff --git a/crates/lang/ir/src/ir/item/event.rs b/crates/lang/ir/src/ir/item/event.rs index b7dbda2abe8..c3a09338fd8 100644 --- a/crates/lang/ir/src/ir/item/event.rs +++ b/crates/lang/ir/src/ir/item/event.rs @@ -28,7 +28,7 @@ pub enum Event { /// todo add ImportedEvent docs #[derive(Debug, PartialEq, Eq)] pub struct ImportedEvent { - item: syn::ItemType, + pub item: syn::ItemType, } impl quote::ToTokens for Event { From 2d2541d11d056aac41b351d66a03b286c5cff98a Mon Sep 17 00:00:00 2001 From: ascjones Date: Thu, 14 Apr 2022 16:39:30 +0100 Subject: [PATCH 010/122] WIP implementing event spec metadata generation --- .../lang/codegen/src/generator/event_def.rs | 10 ++- .../codegen/src/generator/metadata/event.rs | 75 +++++++++++++++++++ .../{metadata.rs => metadata/mod.rs} | 65 ++++++++-------- crates/metadata/src/lib.rs | 6 ++ 4 files changed, 123 insertions(+), 33 deletions(-) create mode 100644 crates/lang/codegen/src/generator/metadata/event.rs rename crates/lang/codegen/src/generator/{metadata.rs => metadata/mod.rs} (91%) diff --git a/crates/lang/codegen/src/generator/event_def.rs b/crates/lang/codegen/src/generator/event_def.rs index 333f573a194..c050f7344e7 100644 --- a/crates/lang/codegen/src/generator/event_def.rs +++ b/crates/lang/codegen/src/generator/event_def.rs @@ -13,6 +13,7 @@ // limitations under the License. use crate::GenerateCode; + use derive_more::From; use proc_macro2::{ TokenStream as TokenStream2, @@ -33,11 +34,13 @@ impl GenerateCode for EventDefinition<'_> { fn generate_code(&self) -> TokenStream2 { let event_struct = self.generate_event_struct(); let event_info_impl = self.generate_event_info_impl(); + let event_metadata_impl = self.generate_event_metadata_impl(); let topics_impl = self.generate_topics_impl(); let topics_guard = self.generate_topics_guard(); quote! { #event_struct #event_info_impl + #event_metadata_impl #topics_impl #topics_guard } @@ -69,7 +72,7 @@ impl<'a> EventDefinition<'a> { ) } - fn generate_event_info_impl(&'a self) -> TokenStream2 { + fn generate_event_info_impl(&self) -> TokenStream2 { let span = self.event_def.span(); let event_ident = self.event_def.ident(); quote_spanned!(span=> @@ -79,6 +82,11 @@ impl<'a> EventDefinition<'a> { ) } + fn generate_event_metadata_impl(&self) -> TokenStream2 { + let event_metadata = super::metadata::EventMetadata::from(self.event_def); + event_metadata.generate_code() + } + /// Generate checks to guard against too many topics in event definitions. fn generate_topics_guard(&self) -> TokenStream2 { let span = self.event_def.span(); diff --git a/crates/lang/codegen/src/generator/metadata/event.rs b/crates/lang/codegen/src/generator/metadata/event.rs new file mode 100644 index 00000000000..46be1fae219 --- /dev/null +++ b/crates/lang/codegen/src/generator/metadata/event.rs @@ -0,0 +1,75 @@ +// Copyright 2018-2022 Parity Technologies (UK) Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::GenerateCode; + +use derive_more::From; +use ir::IsDocAttribute; +use proc_macro2::{ + TokenStream as TokenStream2, +}; +use quote::quote_spanned; +use syn::spanned::Spanned as _; + +/// Generates code for an event definition. +#[derive(From)] +pub struct EventMetadata<'a> { + event_def: &'a ir::InkEventDefinition, +} + +impl GenerateCode for EventMetadata<'_> { + fn generate_code(&self) -> TokenStream2 { + let span = self.event_def.span(); + let event_ident = self.event_def.ident(); + let docs = self.event_def.attrs().iter().filter_map(|attr| attr.extract_docs()); + let args = self.event_def.fields().map(|event_field| { + let span = event_field.span(); + let ident = event_field.ident(); + let is_topic = event_field.is_topic; + let docs = event_field + .attrs() + .into_iter() + .filter_map(|attr| attr.extract_docs()); + let ty = super::generate_type_spec(event_field.ty()); + quote_spanned!(span => + ::ink_metadata::EventParamSpec::new(::core::stringify!(#ident)) + .of_type(#ty) + .indexed(#is_topic) + .docs([ + #( #docs ),* + ]) + .done() + ) + }); + quote_spanned!(span=> + #[cfg(feature = "std")] + #[cfg(not(feature = "ink-as-dependency"))] + const _: () = { + impl ::ink_metadata::EventMetadata for #event_ident { + fn event_spec() -> ::ink_metadata::EventSpec { + // todo: insert event ident + ::ink_metadata::EventSpec::new(::core::stringify!(#event_ident)) + .args([ + #( #args ),* + ]) + .docs([ + #( #docs ),* + ]) + .done() + } + } + } + ) + } +} \ No newline at end of file diff --git a/crates/lang/codegen/src/generator/metadata.rs b/crates/lang/codegen/src/generator/metadata/mod.rs similarity index 91% rename from crates/lang/codegen/src/generator/metadata.rs rename to crates/lang/codegen/src/generator/metadata/mod.rs index 0142643a755..151be014dfc 100644 --- a/crates/lang/codegen/src/generator/metadata.rs +++ b/crates/lang/codegen/src/generator/metadata/mod.rs @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +mod event; + +pub use event::EventMetadata; + use crate::GenerateCode; use ::core::iter; use derive_more::From; @@ -142,7 +146,7 @@ impl Metadata<'_> { syn::Pat::Ident(ident) => &ident.ident, _ => unreachable!("encountered ink! dispatch input with missing identifier"), }; - let type_spec = Self::generate_type_spec(&pat_type.ty); + let type_spec = generate_type_spec(&pat_type.ty); quote! { ::ink_metadata::MessageParamSpec::new(::core::stringify!(#ident)) .of_type(#type_spec) @@ -310,42 +314,39 @@ impl Metadata<'_> { self.contract.module().events().map(|event| { let span = event.span(); let ident = event.ident(); - let docs = event.attrs().iter().filter_map(|attr| attr.extract_docs()); - let args = Self::generate_event_args(event); quote_spanned!(span => - ::ink_metadata::EventSpec::new(::core::stringify!(#ident)) - .args([ - #( #args ),* - ]) - .docs([ - #( #docs ),* - ]) - .done() + <#ident as ::ink_metadata::EventMetadata>::event_spec() ) }) } +} - /// Generate ink! metadata for a single argument of an ink! event definition. - fn generate_event_args(event: &ir::Event) -> impl Iterator + '_ { - event.fields().map(|event_field| { - let span = event_field.span(); - let ident = event_field.ident(); - let is_topic = event_field.is_topic; - let docs = event_field - .attrs() - .into_iter() - .filter_map(|attr| attr.extract_docs()); - let ty = Self::generate_type_spec(event_field.ty()); - quote_spanned!(span => - ::ink_metadata::EventParamSpec::new(::core::stringify!(#ident)) - .of_type(#ty) - .indexed(#is_topic) - .docs([ - #( #docs ),* - ]) - .done() - ) - }) +/// Generates the ink! metadata for the given type. +pub fn generate_type_spec(ty: &syn::Type) -> TokenStream2 { + fn without_display_name(ty: &syn::Type) -> TokenStream2 { + quote! { ::ink_metadata::TypeSpec::new::<#ty>() } + } + if let syn::Type::Path(type_path) = ty { + if type_path.qself.is_some() { + return without_display_name(ty) + } + let path = &type_path.path; + if path.segments.is_empty() { + return without_display_name(ty) + } + let segs = path + .segments + .iter() + .map(|seg| &seg.ident) + .collect::>(); + quote! { + ::ink_metadata::TypeSpec::with_name_segs::<#ty, _>( + ::core::iter::IntoIterator::into_iter([ #( ::core::stringify!(#segs) ),* ]) + .map(::core::convert::AsRef::as_ref) + ) + } + } else { + without_display_name(ty) } } diff --git a/crates/metadata/src/lib.rs b/crates/metadata/src/lib.rs index 86bc9e285ca..e2c4312cc26 100644 --- a/crates/metadata/src/lib.rs +++ b/crates/metadata/src/lib.rs @@ -129,3 +129,9 @@ impl InkProject { &self.spec } } + +/// todo EventMetadata docs +pub trait EventMetadata { + /// todo event_spec docs + fn event_spec() -> EventSpec; +} \ No newline at end of file From 05d35b5b6b7c3717455bbc0d6c11903ffa3fa7c7 Mon Sep 17 00:00:00 2001 From: ascjones Date: Thu, 14 Apr 2022 16:48:29 +0100 Subject: [PATCH 011/122] Add missing semicolon --- crates/lang/codegen/src/generator/metadata/event.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/lang/codegen/src/generator/metadata/event.rs b/crates/lang/codegen/src/generator/metadata/event.rs index 46be1fae219..aeebe794325 100644 --- a/crates/lang/codegen/src/generator/metadata/event.rs +++ b/crates/lang/codegen/src/generator/metadata/event.rs @@ -69,7 +69,7 @@ impl GenerateCode for EventMetadata<'_> { .done() } } - } + }; ) } } \ No newline at end of file From e73e17c9f8da7278ca566d413f09f3c3fb20656f Mon Sep 17 00:00:00 2001 From: ascjones Date: Thu, 14 Apr 2022 16:51:16 +0100 Subject: [PATCH 012/122] Remove unused fields iterator --- crates/lang/ir/src/ir/item/event.rs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/crates/lang/ir/src/ir/item/event.rs b/crates/lang/ir/src/ir/item/event.rs index c3a09338fd8..4a87c07a9a4 100644 --- a/crates/lang/ir/src/ir/item/event.rs +++ b/crates/lang/ir/src/ir/item/event.rs @@ -84,7 +84,7 @@ impl TryFrom for Event { } impl Event { - /// Returns the identifier of the event struct. + /// Returns the identifier of the event. pub fn ident(&self) -> &Ident { match self { Event::Inline(inline) => &inline.item.ident, @@ -92,15 +92,6 @@ impl Event { } } - /// Returns an iterator yielding all the `#[ink(topic)]` annotated fields - /// of the event struct. - pub fn fields(&self) -> EventFieldsIter { - match self { - Event::Inline(inline) => EventFieldsIter::new(inline), - Event::Imported(_) => unimplemented!(), - } - } - /// Returns all non-ink! attributes. pub fn attrs(&self) -> &[syn::Attribute] { match self { From a1a04f07b3647a44794b85e43f85019a8db82a68 Mon Sep 17 00:00:00 2001 From: ascjones Date: Thu, 14 Apr 2022 16:52:27 +0100 Subject: [PATCH 013/122] Fix imported event ident --- crates/lang/ir/src/ir/item/event.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/lang/ir/src/ir/item/event.rs b/crates/lang/ir/src/ir/item/event.rs index 4a87c07a9a4..0b00889a026 100644 --- a/crates/lang/ir/src/ir/item/event.rs +++ b/crates/lang/ir/src/ir/item/event.rs @@ -88,7 +88,7 @@ impl Event { pub fn ident(&self) -> &Ident { match self { Event::Inline(inline) => &inline.item.ident, - Event::Imported(_) => unimplemented!() + Event::Imported(imported) => &imported.item.ident, } } From 98c7f49ebb61ca24d6d5f6331f5d6ba7857ce81d Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 21 Apr 2022 05:28:10 +0100 Subject: [PATCH 014/122] Update trybuild to run ui tests in parallel (#1220) --- crates/lang/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/lang/Cargo.toml b/crates/lang/Cargo.toml index d648526971b..f5a57d3dbee 100644 --- a/crates/lang/Cargo.toml +++ b/crates/lang/Cargo.toml @@ -30,7 +30,7 @@ derive_more = { version = "0.99", default-features = false, features = ["from"] ink_lang_ir = { version = "3.0.1", path = "ir" } ink_metadata = { version = "3.0.1", default-features = false, path = "../metadata" } -trybuild = { version = "1.0.52", features = ["diff"] } +trybuild = { version = "1.0.60", features = ["diff"] } # Required for the doctest of `env_access::EnvAccess::instantiate_contract` scale-info = { version = "2", default-features = false, features = ["derive"] } From c931a389aca537c13fc8ff25d3d45488d54b7a00 Mon Sep 17 00:00:00 2001 From: andrew Date: Thu, 21 Apr 2022 17:38:50 +0300 Subject: [PATCH 015/122] Fix test errors --- crates/lang/ir/src/ir/item/event.rs | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/crates/lang/ir/src/ir/item/event.rs b/crates/lang/ir/src/ir/item/event.rs index 0b00889a026..738bd3f9944 100644 --- a/crates/lang/ir/src/ir/item/event.rs +++ b/crates/lang/ir/src/ir/item/event.rs @@ -389,12 +389,16 @@ mod tests { } }) .unwrap(); - let mut fields_iter = input.fields(); - for (is_topic, expected_field) in expected_fields { - let field = fields_iter.next().unwrap(); - assert_eq!(field.is_topic, is_topic); - assert_eq!(field.ident(), Some(expected_field.ident())); - assert_eq!(field.ty(), expected_field.ty()); + if let Event::Inline(event_def) = input { + let mut fields_iter = event_def.fields(); + for (is_topic, expected_field) in expected_fields { + let field = fields_iter.next().unwrap(); + assert_eq!(field.is_topic, is_topic); + assert_eq!(field.ident(), Some(expected_field.ident())); + assert_eq!(field.ty(), expected_field.ty()); + } + } else { + panic!("Expected an inline event definition") } } @@ -402,9 +406,10 @@ mod tests { fn anonymous_event_works() { fn assert_anonymous_event(event: syn::ItemStruct) { match Event::try_from(event) { - Ok(event) => { + Ok(Event::Inline(event)) => { assert!(event.anonymous); - } + }, + Ok(_) => panic!("Expected an inline event definition"), Err(_) => panic!("encountered unexpected invalid anonymous event"), } } From a2c60ea42a897c61ecee6d303df36d54a827e164 Mon Sep 17 00:00:00 2001 From: ascjones Date: Mon, 25 Apr 2022 12:17:23 +0100 Subject: [PATCH 016/122] Add todo --- crates/lang/ir/src/ir/item/event.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/lang/ir/src/ir/item/event.rs b/crates/lang/ir/src/ir/item/event.rs index 0b00889a026..1034f02a55d 100644 --- a/crates/lang/ir/src/ir/item/event.rs +++ b/crates/lang/ir/src/ir/item/event.rs @@ -77,6 +77,7 @@ impl TryFrom for Event { type Error = syn::Error; fn try_from(item_type: syn::ItemType) -> Result { + // todo: remove ink::event attribute and check no anonymous config Ok(Self::Imported(ImportedEvent { item: item_type })) From 3f1978a599937988c9a6104981a8cfbea5621f60 Mon Sep 17 00:00:00 2001 From: ascjones Date: Tue, 3 May 2022 12:23:14 +0100 Subject: [PATCH 017/122] Fix test errors --- crates/lang/ir/src/ir/item/event.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/crates/lang/ir/src/ir/item/event.rs b/crates/lang/ir/src/ir/item/event.rs index 1034f02a55d..35245b668d7 100644 --- a/crates/lang/ir/src/ir/item/event.rs +++ b/crates/lang/ir/src/ir/item/event.rs @@ -21,7 +21,7 @@ use syn::spanned::Spanned as _; #[derive(Debug, PartialEq, Eq)] pub enum Event { - Inline(ir::InkEventDefinition), + Inline(InkEventDefinition), Imported(ImportedEvent), } @@ -390,12 +390,16 @@ mod tests { } }) .unwrap(); - let mut fields_iter = input.fields(); - for (is_topic, expected_field) in expected_fields { - let field = fields_iter.next().unwrap(); - assert_eq!(field.is_topic, is_topic); - assert_eq!(field.ident(), Some(expected_field.ident())); - assert_eq!(field.ty(), expected_field.ty()); + if let Event::Inline(event_def) = input { + let mut fields_iter = event_def.fields(); + for (is_topic, expected_field) in expected_fields { + let field = fields_iter.next().unwrap(); + assert_eq!(field.is_topic, is_topic); + assert_eq!(field.ident(), Some(expected_field.ident())); + assert_eq!(field.ty(), expected_field.ty()); + } + } else { + panic!("Expected inline event definition") } } @@ -404,7 +408,9 @@ mod tests { fn assert_anonymous_event(event: syn::ItemStruct) { match Event::try_from(event) { Ok(event) => { - assert!(event.anonymous); + if let Event::Inline(event_def) = event { + assert!(event_def.anonymous) + } } Err(_) => panic!("encountered unexpected invalid anonymous event"), } From 00815445eaed7014a56ccb2d3a5169d89681f7c4 Mon Sep 17 00:00:00 2001 From: ascjones Date: Thu, 5 May 2022 12:02:15 +0100 Subject: [PATCH 018/122] Test out new interface api --- .../ui/contract/pass/event-shared-external.rs | 25 ------------ .../ui/contract/pass/interface-with-event.rs | 40 +++++++++++++++++++ 2 files changed, 40 insertions(+), 25 deletions(-) delete mode 100644 crates/lang/tests/ui/contract/pass/event-shared-external.rs create mode 100644 crates/lang/tests/ui/contract/pass/interface-with-event.rs diff --git a/crates/lang/tests/ui/contract/pass/event-shared-external.rs b/crates/lang/tests/ui/contract/pass/event-shared-external.rs deleted file mode 100644 index 770bc563eea..00000000000 --- a/crates/lang/tests/ui/contract/pass/event-shared-external.rs +++ /dev/null @@ -1,25 +0,0 @@ -use ink_lang as ink; - -#[ink::event_definition] -pub struct Event0 {} - -#[ink::contract] -mod contract { - #[ink(storage)] - pub struct Contract {} - - #[ink(event)] - type Event0 = super::Event0; - - impl Contract { - #[ink(constructor)] - pub fn constructor() -> Self { - Self {} - } - - #[ink(message)] - pub fn message(&self) {} - } -} - -fn main() {} diff --git a/crates/lang/tests/ui/contract/pass/interface-with-event.rs b/crates/lang/tests/ui/contract/pass/interface-with-event.rs new file mode 100644 index 00000000000..c52787ad3ce --- /dev/null +++ b/crates/lang/tests/ui/contract/pass/interface-with-event.rs @@ -0,0 +1,40 @@ +use ink_lang as ink; + +#[ink::interface] +pub mod contract_interface { + #[ink(trait_definition)] + pub trait ContractInterface { + #[ink(constructor)] + fn constructor() -> Self; + + #[ink(message)] + fn message(&self, value: bool) {} + } + + #[ink(event)] + pub enum Event { + MessageInvoked { value: bool } + } +} + +#[ink::contract] +mod contract { + use super::contract_interface; + + #[ink(storage)] + pub struct Contract {} + + impl contract_interface::ContractInterface for Contract { + #[ink(constructor)] + fn constructor() -> Self { + Self {} + } + + #[ink(message)] + fn message(&self, value: bool) { + self.env().emit_event(contract_interface::Event::MessageInvoked { value }) + } + } +} + +fn main() {} From 7f351891b914952230a480e60b53c2c7602f4cf6 Mon Sep 17 00:00:00 2001 From: ascjones Date: Mon, 1 Aug 2022 12:11:00 +0100 Subject: [PATCH 019/122] Revert "Test out new interface api" This reverts commit 00815445eaed7014a56ccb2d3a5169d89681f7c4. --- .../ui/contract/pass/event-shared-external.rs | 25 ++++++++++++ .../ui/contract/pass/interface-with-event.rs | 40 ------------------- 2 files changed, 25 insertions(+), 40 deletions(-) create mode 100644 crates/lang/tests/ui/contract/pass/event-shared-external.rs delete mode 100644 crates/lang/tests/ui/contract/pass/interface-with-event.rs diff --git a/crates/lang/tests/ui/contract/pass/event-shared-external.rs b/crates/lang/tests/ui/contract/pass/event-shared-external.rs new file mode 100644 index 00000000000..770bc563eea --- /dev/null +++ b/crates/lang/tests/ui/contract/pass/event-shared-external.rs @@ -0,0 +1,25 @@ +use ink_lang as ink; + +#[ink::event_definition] +pub struct Event0 {} + +#[ink::contract] +mod contract { + #[ink(storage)] + pub struct Contract {} + + #[ink(event)] + type Event0 = super::Event0; + + impl Contract { + #[ink(constructor)] + pub fn constructor() -> Self { + Self {} + } + + #[ink(message)] + pub fn message(&self) {} + } +} + +fn main() {} diff --git a/crates/lang/tests/ui/contract/pass/interface-with-event.rs b/crates/lang/tests/ui/contract/pass/interface-with-event.rs deleted file mode 100644 index c52787ad3ce..00000000000 --- a/crates/lang/tests/ui/contract/pass/interface-with-event.rs +++ /dev/null @@ -1,40 +0,0 @@ -use ink_lang as ink; - -#[ink::interface] -pub mod contract_interface { - #[ink(trait_definition)] - pub trait ContractInterface { - #[ink(constructor)] - fn constructor() -> Self; - - #[ink(message)] - fn message(&self, value: bool) {} - } - - #[ink(event)] - pub enum Event { - MessageInvoked { value: bool } - } -} - -#[ink::contract] -mod contract { - use super::contract_interface; - - #[ink(storage)] - pub struct Contract {} - - impl contract_interface::ContractInterface for Contract { - #[ink(constructor)] - fn constructor() -> Self { - Self {} - } - - #[ink(message)] - fn message(&self, value: bool) { - self.env().emit_event(contract_interface::Event::MessageInvoked { value }) - } - } -} - -fn main() {} From 5f3f2f0f31bca157ea3ab749cc7675a6149a2cdb Mon Sep 17 00:00:00 2001 From: ascjones Date: Thu, 4 Aug 2022 12:12:20 +0100 Subject: [PATCH 020/122] Update example to latest syntax --- .../lang/tests/ui/contract/pass/event-shared-external.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/crates/lang/tests/ui/contract/pass/event-shared-external.rs b/crates/lang/tests/ui/contract/pass/event-shared-external.rs index 770bc563eea..1cfb28c2bf9 100644 --- a/crates/lang/tests/ui/contract/pass/event-shared-external.rs +++ b/crates/lang/tests/ui/contract/pass/event-shared-external.rs @@ -1,16 +1,13 @@ use ink_lang as ink; #[ink::event_definition] -pub struct Event0 {} +pub struct SharedEvent; #[ink::contract] mod contract { #[ink(storage)] pub struct Contract {} - #[ink(event)] - type Event0 = super::Event0; - impl Contract { #[ink(constructor)] pub fn constructor() -> Self { @@ -18,7 +15,9 @@ mod contract { } #[ink(message)] - pub fn message(&self) {} + pub fn message(&self) { + self.env().emit_event(super::SharedEvent {}); + } } } From 35d8184a803cc15da64162fe21937304480b65fc Mon Sep 17 00:00:00 2001 From: ascjones Date: Thu, 4 Aug 2022 12:12:35 +0100 Subject: [PATCH 021/122] Fmt --- .../lang/codegen/src/generator/event_def.rs | 39 ++++++++++--------- crates/lang/codegen/src/generator/events.rs | 4 +- .../codegen/src/generator/metadata/event.rs | 12 +++--- .../codegen/src/generator/metadata/mod.rs | 10 ++--- crates/lang/ir/src/ir/event_def.rs | 16 ++++++-- crates/lang/ir/src/ir/item/event.rs | 15 ++++--- crates/lang/macro/src/event_def.rs | 3 +- crates/lang/src/reflect/event.rs | 2 - crates/metadata/src/lib.rs | 2 +- 9 files changed, 57 insertions(+), 46 deletions(-) diff --git a/crates/lang/codegen/src/generator/event_def.rs b/crates/lang/codegen/src/generator/event_def.rs index c050f7344e7..2894c389abb 100644 --- a/crates/lang/codegen/src/generator/event_def.rs +++ b/crates/lang/codegen/src/generator/event_def.rs @@ -15,9 +15,7 @@ use crate::GenerateCode; use derive_more::From; -use proc_macro2::{ - TokenStream as TokenStream2, -}; +use proc_macro2::TokenStream as TokenStream2; use quote::{ quote, quote_spanned, @@ -107,8 +105,13 @@ impl<'a> EventDefinition<'a> { fn generate_topics_impl(&self) -> TokenStream2 { let span = self.event_def.span(); let event_ident = self.event_def.ident(); - let len_topics = self.event_def.fields().filter(|field| field.is_topic).count(); - let topic_impls = self.event_def + let len_topics = self + .event_def + .fields() + .filter(|field| field.is_topic) + .count(); + let topic_impls = self + .event_def .fields() .enumerate() .filter(|(_, field)| field.is_topic) @@ -120,20 +123,20 @@ impl<'a> EventDefinition<'a> { .unwrap_or_else(|| quote_spanned!(span => #n)); let field_type = topic_field.ty(); quote_spanned!(span => - .push_topic::<::ink_env::topics::PrefixedValue<#field_type>>( - &::ink_env::topics::PrefixedValue { - // todo: deduplicate with EVENT_SIGNATURE - prefix: ::core::concat!( - ::core::module_path!(), - "::", - ::core::stringify!(#event_ident), - "::", - ::core::stringify!(#field_ident), - ).as_bytes(), - value: &self.#field_ident, - } - ) + .push_topic::<::ink_env::topics::PrefixedValue<#field_type>>( + &::ink_env::topics::PrefixedValue { + // todo: deduplicate with EVENT_SIGNATURE + prefix: ::core::concat!( + ::core::module_path!(), + "::", + ::core::stringify!(#event_ident), + "::", + ::core::stringify!(#field_ident), + ).as_bytes(), + value: &self.#field_ident, + } ) + ) }); // Only include topic for event signature in case of non-anonymous event. let event_signature_topic = match self.event_def.anonymous { diff --git a/crates/lang/codegen/src/generator/events.rs b/crates/lang/codegen/src/generator/events.rs index 910661b9a78..6e156f62768 100644 --- a/crates/lang/codegen/src/generator/events.rs +++ b/crates/lang/codegen/src/generator/events.rs @@ -13,10 +13,11 @@ // limitations under the License. use crate::{ - GenerateCode, generator::EventDefinition, + GenerateCode, }; use derive_more::From; +use ir::Event; use proc_macro2::{ Span, TokenStream as TokenStream2, @@ -26,7 +27,6 @@ use quote::{ quote_spanned, }; use syn::spanned::Spanned as _; -use ir::Event; /// Generates code for the ink! event structs of the contract. #[derive(From)] diff --git a/crates/lang/codegen/src/generator/metadata/event.rs b/crates/lang/codegen/src/generator/metadata/event.rs index aeebe794325..b58530e4b5f 100644 --- a/crates/lang/codegen/src/generator/metadata/event.rs +++ b/crates/lang/codegen/src/generator/metadata/event.rs @@ -16,9 +16,7 @@ use crate::GenerateCode; use derive_more::From; use ir::IsDocAttribute; -use proc_macro2::{ - TokenStream as TokenStream2, -}; +use proc_macro2::TokenStream as TokenStream2; use quote::quote_spanned; use syn::spanned::Spanned as _; @@ -32,7 +30,11 @@ impl GenerateCode for EventMetadata<'_> { fn generate_code(&self) -> TokenStream2 { let span = self.event_def.span(); let event_ident = self.event_def.ident(); - let docs = self.event_def.attrs().iter().filter_map(|attr| attr.extract_docs()); + let docs = self + .event_def + .attrs() + .iter() + .filter_map(|attr| attr.extract_docs()); let args = self.event_def.fields().map(|event_field| { let span = event_field.span(); let ident = event_field.ident(); @@ -72,4 +74,4 @@ impl GenerateCode for EventMetadata<'_> { }; ) } -} \ No newline at end of file +} diff --git a/crates/lang/codegen/src/generator/metadata/mod.rs b/crates/lang/codegen/src/generator/metadata/mod.rs index 151be014dfc..f1e8728f6b7 100644 --- a/crates/lang/codegen/src/generator/metadata/mod.rs +++ b/crates/lang/codegen/src/generator/metadata/mod.rs @@ -340,11 +340,11 @@ pub fn generate_type_spec(ty: &syn::Type) -> TokenStream2 { .map(|seg| &seg.ident) .collect::>(); quote! { - ::ink_metadata::TypeSpec::with_name_segs::<#ty, _>( - ::core::iter::IntoIterator::into_iter([ #( ::core::stringify!(#segs) ),* ]) - .map(::core::convert::AsRef::as_ref) - ) - } + ::ink_metadata::TypeSpec::with_name_segs::<#ty, _>( + ::core::iter::IntoIterator::into_iter([ #( ::core::stringify!(#segs) ),* ]) + .map(::core::convert::AsRef::as_ref) + ) + } } else { without_display_name(ty) } diff --git a/crates/lang/ir/src/ir/event_def.rs b/crates/lang/ir/src/ir/event_def.rs index 46b2a7160a7..663a9776bc5 100644 --- a/crates/lang/ir/src/ir/event_def.rs +++ b/crates/lang/ir/src/ir/event_def.rs @@ -22,7 +22,10 @@ use proc_macro2::{ Span, TokenStream as TokenStream2, }; -use syn::{Result, spanned::Spanned as _}; +use syn::{ + spanned::Spanned as _, + Result, +}; /// A checked ink! event definition. #[derive(Debug, PartialEq, Eq)] @@ -55,7 +58,6 @@ impl TryFrom for InkEventDefinition { } } - impl quote::ToTokens for InkEventDefinition { /// We mainly implement this trait for this ink! type to have a derived /// [`Spanned`](`syn::spanned::Spanned`) implementation for it. @@ -100,11 +102,17 @@ impl InkEventDefinition { } } } - Ok(Self { item: item_struct, anonymous }) + Ok(Self { + item: item_struct, + anonymous, + }) } /// Returns `Ok` if the input matches all requirements for an ink! event definition. - pub fn from_event_def_tokens(config: TokenStream2, input: TokenStream2) -> Result { + pub fn from_event_def_tokens( + config: TokenStream2, + input: TokenStream2, + ) -> Result { let _parsed_config = syn::parse2::(config)?; let anonymous = false; // todo parse this from attr config let item = syn::parse2::(input)?; diff --git a/crates/lang/ir/src/ir/item/event.rs b/crates/lang/ir/src/ir/item/event.rs index f69150436cd..31e312f0daf 100644 --- a/crates/lang/ir/src/ir/item/event.rs +++ b/crates/lang/ir/src/ir/item/event.rs @@ -12,7 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{InkEventDefinition, ir}; +use crate::{ + ir, + InkEventDefinition, +}; use proc_macro2::{ Ident, Span, @@ -49,9 +52,7 @@ impl Event { /// # Errors /// /// If the first found ink! attribute is malformed. - pub(super) fn is_ink_event( - attrs: &[syn::Attribute], - ) -> Result { + pub(super) fn is_ink_event(attrs: &[syn::Attribute]) -> Result { if !ir::contains_ink_attributes(attrs) { return Ok(false) } @@ -78,9 +79,7 @@ impl TryFrom for Event { fn try_from(item_type: syn::ItemType) -> Result { // todo: remove ink::event attribute and check no anonymous config - Ok(Self::Imported(ImportedEvent { - item: item_type - })) + Ok(Self::Imported(ImportedEvent { item: item_type })) } } @@ -409,7 +408,7 @@ mod tests { match Event::try_from(event) { Ok(Event::Inline(event)) => { assert!(event.anonymous); - }, + } Ok(_) => panic!("Expected an inline event definition"), Err(_) => panic!("encountered unexpected invalid anonymous event"), } diff --git a/crates/lang/macro/src/event_def.rs b/crates/lang/macro/src/event_def.rs index bfdc009c5d4..250056f5e61 100644 --- a/crates/lang/macro/src/event_def.rs +++ b/crates/lang/macro/src/event_def.rs @@ -27,6 +27,7 @@ pub fn generate_or_err( config: TokenStream2, input: TokenStream2, ) -> Result { - let trait_definition = ink_lang_ir::InkEventDefinition::from_event_def_tokens(config, input)?; + let trait_definition = + ink_lang_ir::InkEventDefinition::from_event_def_tokens(config, input)?; Ok(generate_code(&trait_definition)) } diff --git a/crates/lang/src/reflect/event.rs b/crates/lang/src/reflect/event.rs index 19b8e6a26fe..5e92e5242c1 100644 --- a/crates/lang/src/reflect/event.rs +++ b/crates/lang/src/reflect/event.rs @@ -61,6 +61,4 @@ pub trait EventInfo { /// /// todo: rename? const PATH: &'static str; - - } diff --git a/crates/metadata/src/lib.rs b/crates/metadata/src/lib.rs index e2c4312cc26..257e973b06e 100644 --- a/crates/metadata/src/lib.rs +++ b/crates/metadata/src/lib.rs @@ -134,4 +134,4 @@ impl InkProject { pub trait EventMetadata { /// todo event_spec docs fn event_spec() -> EventSpec; -} \ No newline at end of file +} From 6763b74d9762648301a06a150b95538959cc2385 Mon Sep 17 00:00:00 2001 From: ascjones Date: Thu, 4 Aug 2022 16:51:43 +0100 Subject: [PATCH 022/122] Remove EmitEvent impl --- crates/lang/codegen/src/generator/events.rs | 23 --------------------- crates/lang/src/env_access.rs | 8 +++++++ 2 files changed, 8 insertions(+), 23 deletions(-) diff --git a/crates/lang/codegen/src/generator/events.rs b/crates/lang/codegen/src/generator/events.rs index 6e156f62768..07b637a18ee 100644 --- a/crates/lang/codegen/src/generator/events.rs +++ b/crates/lang/codegen/src/generator/events.rs @@ -41,12 +41,10 @@ impl GenerateCode for Events<'_> { // Generate no code in case there are no event definitions. return TokenStream2::new() } - let emit_event_trait_impl = self.generate_emit_event_trait_impl(); let event_base = self.generate_event_base(); let topic_guards = self.generate_topic_guards(); let event_defs = self.generate_event_definitions(); // todo: call into shared event_def code for inline events quote! { - #emit_event_trait_impl #event_base #( #topic_guards )* #( #event_defs )* @@ -55,27 +53,6 @@ impl GenerateCode for Events<'_> { } impl<'a> Events<'a> { - /// Used to allow emitting user defined events directly instead of converting - /// them first into the automatically generated base trait of the contract. - fn generate_emit_event_trait_impl(&self) -> TokenStream2 { - let storage_ident = &self.contract.module().storage().ident(); - quote! { - const _: () = { - impl<'a> ::ink_lang::codegen::EmitEvent<#storage_ident> for ::ink_lang::EnvAccess<'a, Environment> { - fn emit_event(self, event: E) - where - E: Into<<#storage_ident as ::ink_lang::reflect::ContractEventBase>::Type>, - { - ::ink_env::emit_event::< - Environment, - <#storage_ident as ::ink_lang::reflect::ContractEventBase>::Type - >(event.into()); - } - } - }; - } - } - /// Generates the base event enum that comprises all user defined events. /// All emitted events are converted into a variant of this enum before being /// serialized and emitted to apply their unique event discriminant (ID). diff --git a/crates/lang/src/env_access.rs b/crates/lang/src/env_access.rs index 84e4cb02963..2dc156683da 100644 --- a/crates/lang/src/env_access.rs +++ b/crates/lang/src/env_access.rs @@ -422,6 +422,14 @@ where ink_env::minimum_balance::() } + /// todo: [AJ] docs + pub fn emit_event(self, event: Event) + where + Event: ink_env::Topics + scale::Encode, + { + ink_env::emit_event::(event) + } + /// Instantiates another contract. /// /// # Example From 7063bd3be54038347db19b00498b50cc340a54ee Mon Sep 17 00:00:00 2001 From: ascjones Date: Thu, 4 Aug 2022 16:59:47 +0100 Subject: [PATCH 023/122] Remove EmitEvent impl and ContractBaseEvent --- crates/lang/codegen/src/generator/events.rs | 75 ------------------- .../lang/codegen/src/generator/item_impls.rs | 6 -- crates/lang/codegen/src/generator/storage.rs | 6 -- crates/lang/src/codegen/event/emit.rs | 26 ------- crates/lang/src/codegen/event/mod.rs | 2 - crates/lang/src/codegen/mod.rs | 1 - crates/lang/src/reflect/event.rs | 39 ---------- crates/lang/src/reflect/mod.rs | 5 +- 8 files changed, 1 insertion(+), 159 deletions(-) delete mode 100644 crates/lang/src/codegen/event/emit.rs diff --git a/crates/lang/codegen/src/generator/events.rs b/crates/lang/codegen/src/generator/events.rs index 07b637a18ee..68e35edbdff 100644 --- a/crates/lang/codegen/src/generator/events.rs +++ b/crates/lang/codegen/src/generator/events.rs @@ -19,7 +19,6 @@ use crate::{ use derive_more::From; use ir::Event; use proc_macro2::{ - Span, TokenStream as TokenStream2, }; use quote::{ @@ -41,11 +40,9 @@ impl GenerateCode for Events<'_> { // Generate no code in case there are no event definitions. return TokenStream2::new() } - let event_base = self.generate_event_base(); let topic_guards = self.generate_topic_guards(); let event_defs = self.generate_event_definitions(); // todo: call into shared event_def code for inline events quote! { - #event_base #( #topic_guards )* #( #event_defs )* } @@ -53,78 +50,6 @@ impl GenerateCode for Events<'_> { } impl<'a> Events<'a> { - /// Generates the base event enum that comprises all user defined events. - /// All emitted events are converted into a variant of this enum before being - /// serialized and emitted to apply their unique event discriminant (ID). - /// - /// # Developer Note - /// - /// The `__ink_dylint_EventBase` config attribute is used here to convey the - /// information that the generated enum is an ink! event to `dylint`. - fn generate_event_base(&self) -> TokenStream2 { - let storage_ident = &self.contract.module().storage().ident(); - let event_idents = self - .contract - .module() - .events() - .map(|event| event.ident()) - .collect::>(); - let base_event_ident = - proc_macro2::Ident::new("__ink_EventBase", Span::call_site()); - quote! { - #[allow(non_camel_case_types)] - #[derive(::scale::Encode, ::scale::Decode)] - #[cfg(not(feature = "__ink_dylint_EventBase"))] - pub enum #base_event_ident { - #( #event_idents(#event_idents), )* - } - - const _: () = { - impl ::ink_lang::reflect::ContractEventBase for #storage_ident { - type Type = #base_event_ident; - } - }; - - #( - const _: () = { - impl From<#event_idents> for #base_event_ident { - fn from(event: #event_idents) -> Self { - Self::#event_idents(event) - } - } - }; - )* - - const _: () = { - pub enum __ink_UndefinedAmountOfTopics {} - impl ::ink_env::topics::EventTopicsAmount for __ink_UndefinedAmountOfTopics { - const AMOUNT: usize = 0; - } - - impl ::ink_env::Topics for #base_event_ident { - type RemainingTopics = __ink_UndefinedAmountOfTopics; - - fn topics( - &self, - builder: ::ink_env::topics::TopicsBuilder<::ink_env::topics::state::Uninit, E, B>, - ) -> >::Output - where - E: ::ink_env::Environment, - B: ::ink_env::topics::TopicsBuilderBackend, - { - match self { - #( - Self::#event_idents(event) => { - <#event_idents as ::ink_env::Topics>::topics::(event, builder) - } - )* - } - } - } - }; - } - } - /// Generate checks to guard against too many topics in event definitions. fn generate_topics_guard(&self, event: &ir::Event) -> TokenStream2 { let span = event.span(); diff --git a/crates/lang/codegen/src/generator/item_impls.rs b/crates/lang/codegen/src/generator/item_impls.rs index 17ff0e52614..bb8d637858b 100644 --- a/crates/lang/codegen/src/generator/item_impls.rs +++ b/crates/lang/codegen/src/generator/item_impls.rs @@ -46,16 +46,10 @@ impl GenerateCode for ItemImpls<'_> { .map(|item_impl| self.generate_item_impl(item_impl)); let inout_guards = self.generate_input_output_guards(); let trait_message_property_guards = self.generate_trait_message_property_guards(); - let use_emit_event = - self.contract.module().events().next().is_some().then(|| { - // Required to make `self.env().emit_event(...)` syntax available. - quote! { use ::ink_lang::codegen::EmitEvent as _; } - }); quote! { const _: () = { // Required to make `self.env()` and `Self::env()` syntax available. use ::ink_lang::codegen::{Env as _, StaticEnv as _}; - #use_emit_event #( #item_impls )* #inout_guards diff --git a/crates/lang/codegen/src/generator/storage.rs b/crates/lang/codegen/src/generator/storage.rs index 973048cbd89..fc6168b94d4 100644 --- a/crates/lang/codegen/src/generator/storage.rs +++ b/crates/lang/codegen/src/generator/storage.rs @@ -33,11 +33,6 @@ impl GenerateCode for Storage<'_> { let storage_span = self.contract.module().storage().span(); let access_env_impls = self.generate_access_env_trait_impls(); let storage_struct = self.generate_storage_struct(); - let use_emit_event = - self.contract.module().events().next().is_some().then(|| { - // Required to allow for `self.env().emit_event(...)` in messages and constructors. - quote! { use ::ink_lang::codegen::EmitEvent as _; } - }); quote_spanned!(storage_span => #storage_struct #access_env_impls @@ -49,7 +44,6 @@ impl GenerateCode for Storage<'_> { Env as _, StaticEnv as _, }; - #use_emit_event }; ) } diff --git a/crates/lang/src/codegen/event/emit.rs b/crates/lang/src/codegen/event/emit.rs deleted file mode 100644 index 702bfd687f5..00000000000 --- a/crates/lang/src/codegen/event/emit.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2018-2022 Parity Technologies (UK) Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::reflect::ContractEventBase; - -/// Allows for `self.env().emit_event(...)` syntax in ink! implementation blocks. -pub trait EmitEvent -where - C: ContractEventBase, -{ - /// Emits an event that can be trivially converted into the base event. - fn emit_event(self, event: E) - where - E: Into<::Type>; -} diff --git a/crates/lang/src/codegen/event/mod.rs b/crates/lang/src/codegen/event/mod.rs index 73002bdc4da..4328285b1f5 100644 --- a/crates/lang/src/codegen/event/mod.rs +++ b/crates/lang/src/codegen/event/mod.rs @@ -12,11 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -mod emit; mod topics; pub use self::{ - emit::EmitEvent, topics::{ EventLenTopics, EventRespectsTopicLimit, diff --git a/crates/lang/src/codegen/mod.rs b/crates/lang/src/codegen/mod.rs index e22b0079021..3e4a321d692 100644 --- a/crates/lang/src/codegen/mod.rs +++ b/crates/lang/src/codegen/mod.rs @@ -36,7 +36,6 @@ pub use self::{ StaticEnv, }, event::{ - EmitEvent, EventLenTopics, EventRespectsTopicLimit, EventTopics, diff --git a/crates/lang/src/reflect/event.rs b/crates/lang/src/reflect/event.rs index 5e92e5242c1..79941b6aae4 100644 --- a/crates/lang/src/reflect/event.rs +++ b/crates/lang/src/reflect/event.rs @@ -12,45 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -/// Defines a base event type for the contract. -/// -/// This is usually the event enum that comprises all defined event types. -/// -/// # Usage -/// -/// ``` -/// use ink_lang as ink; -/// -/// #[ink::contract] -/// pub mod contract { -/// #[ink(storage)] -/// pub struct Contract {} -/// -/// #[ink(event)] -/// pub struct Event1 {} -/// -/// #[ink(event)] -/// pub struct Event2 {} -/// -/// impl Contract { -/// #[ink(constructor)] -/// pub fn constructor() -> Self { Self {} } -/// -/// #[ink(message)] -/// pub fn message(&self) {} -/// } -/// } -/// -/// use contract::Contract; -/// # use ink_lang::reflect::ContractEventBase; -/// -/// type BaseEvent = ::Type; -/// ``` -pub trait ContractEventBase { - /// The generated base event enum. - type Type; -} - /// todo: docs pub trait EventInfo { /// The complete path of the ink! event definition. diff --git a/crates/lang/src/reflect/mod.rs b/crates/lang/src/reflect/mod.rs index d73a9d09180..29345d6a84a 100644 --- a/crates/lang/src/reflect/mod.rs +++ b/crates/lang/src/reflect/mod.rs @@ -46,10 +46,7 @@ pub use self::{ DispatchableMessageInfo, ExecuteDispatchable, }, - event::{ - ContractEventBase, - EventInfo, - }, + event::EventInfo, trait_def::{ TraitDefinitionRegistry, TraitInfo, From 7e115ec018abba847e2cda86fff2c9b8545269fe Mon Sep 17 00:00:00 2001 From: ascjones Date: Fri, 5 Aug 2022 09:46:25 +0100 Subject: [PATCH 024/122] Add args to shared event test --- .../lang/tests/ui/contract/pass/event-shared-external.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/crates/lang/tests/ui/contract/pass/event-shared-external.rs b/crates/lang/tests/ui/contract/pass/event-shared-external.rs index 1cfb28c2bf9..c5edf459dee 100644 --- a/crates/lang/tests/ui/contract/pass/event-shared-external.rs +++ b/crates/lang/tests/ui/contract/pass/event-shared-external.rs @@ -1,7 +1,11 @@ use ink_lang as ink; #[ink::event_definition] -pub struct SharedEvent; +pub struct SharedEvent { + arg_1: u8, + #[ink(topic)] + arg_2: u16, +} #[ink::contract] mod contract { @@ -16,7 +20,7 @@ mod contract { #[ink(message)] pub fn message(&self) { - self.env().emit_event(super::SharedEvent {}); + self.env().emit_event(super::SharedEvent { arg_1: 1, arg_2: 2 }); } } } From 100e53ba637d652cd4349a805e397ec997d1d27c Mon Sep 17 00:00:00 2001 From: ascjones Date: Fri, 5 Aug 2022 10:16:31 +0100 Subject: [PATCH 025/122] Convert inline event to use event_def codegen --- crates/lang/codegen/src/generator/events.rs | 14 +-- crates/lang/ir/src/ir/item/event.rs | 108 ++------------------ crates/lang/ir/src/ir/item/mod.rs | 8 -- 3 files changed, 8 insertions(+), 122 deletions(-) diff --git a/crates/lang/codegen/src/generator/events.rs b/crates/lang/codegen/src/generator/events.rs index 68e35edbdff..a022b293044 100644 --- a/crates/lang/codegen/src/generator/events.rs +++ b/crates/lang/codegen/src/generator/events.rs @@ -17,7 +17,6 @@ use crate::{ GenerateCode, }; use derive_more::From; -use ir::Event; use proc_macro2::{ TokenStream as TokenStream2, }; @@ -83,17 +82,8 @@ impl<'a> Events<'a> { /// Generates the `Topics` trait implementations for the user defined events. fn generate_event_definitions(&'a self) -> impl Iterator + 'a { self.contract.module().events().map(move |event| { - match event { - Event::Inline(event_def) => { - let event_def_gen = EventDefinition::from(event_def); - event_def_gen.generate_code() - } - Event::Imported(imported_event) => { - // todo: hook up to base event and figure out metadata - let item_type = &imported_event.item; - quote! { #item_type } - } - } + let event_def_gen = EventDefinition::from(&event.event_def); + event_def_gen.generate_code() }) } } diff --git a/crates/lang/ir/src/ir/item/event.rs b/crates/lang/ir/src/ir/item/event.rs index 31e312f0daf..0eac1ef8d32 100644 --- a/crates/lang/ir/src/ir/item/event.rs +++ b/crates/lang/ir/src/ir/item/event.rs @@ -18,30 +18,18 @@ use crate::{ }; use proc_macro2::{ Ident, - Span, }; -use syn::spanned::Spanned as _; #[derive(Debug, PartialEq, Eq)] -pub enum Event { - Inline(InkEventDefinition), - Imported(ImportedEvent), -} - -/// todo add ImportedEvent docs -#[derive(Debug, PartialEq, Eq)] -pub struct ImportedEvent { - pub item: syn::ItemType, +pub struct Event { + pub event_def: InkEventDefinition, } impl quote::ToTokens for Event { /// We mainly implement this trait for this ink! type to have a derived /// [`Spanned`](`syn::spanned::Spanned`) implementation for it. fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { - match self { - Event::Inline(inline) => inline.item.to_tokens(tokens), - Event::Imported(imported) => imported.item.to_tokens(tokens), - } + self.event_def.to_tokens(tokens) } } @@ -70,103 +58,19 @@ impl TryFrom for Event { fn try_from(item_struct: syn::ItemStruct) -> Result { let event_def = InkEventDefinition::try_from(item_struct)?; - Ok(Self::Inline(event_def)) - } -} - -impl TryFrom for Event { - type Error = syn::Error; - - fn try_from(item_type: syn::ItemType) -> Result { - // todo: remove ink::event attribute and check no anonymous config - Ok(Self::Imported(ImportedEvent { item: item_type })) + Ok(Self { event_def }) } } impl Event { /// Returns the identifier of the event. pub fn ident(&self) -> &Ident { - match self { - Event::Inline(inline) => &inline.item.ident, - Event::Imported(imported) => &imported.item.ident, - } + &self.event_def.item.ident } /// Returns all non-ink! attributes. pub fn attrs(&self) -> &[syn::Attribute] { - match self { - Event::Inline(inline) => &inline.item.attrs, - Event::Imported(imported) => &imported.item.attrs, - } - } -} - -/// An event field with a flag indicating if this field is an event topic. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct EventField<'a> { - /// The associated `field` is an event topic if this is `true`. - pub is_topic: bool, - /// The event field. - field: &'a syn::Field, -} - -impl<'a> EventField<'a> { - /// Returns the span of the event field. - pub fn span(self) -> Span { - self.field.span() - } - - /// Returns all non-ink! attributes of the event field. - pub fn attrs(self) -> Vec { - let (_, non_ink_attrs) = ir::partition_attributes(self.field.attrs.clone()) - .expect("encountered invalid event field attributes"); - non_ink_attrs - } - - /// Returns the visibility of the event field. - pub fn vis(self) -> &'a syn::Visibility { - &self.field.vis - } - - /// Returns the identifier of the event field if any. - pub fn ident(self) -> Option<&'a Ident> { - self.field.ident.as_ref() - } - - /// Returns the type of the event field. - pub fn ty(self) -> &'a syn::Type { - &self.field.ty - } -} - -/// Iterator yielding all `#[ink(topic)]` annotated fields of an event struct. -pub struct EventFieldsIter<'a> { - iter: syn::punctuated::Iter<'a, syn::Field>, -} - -impl<'a> EventFieldsIter<'a> { - /// Creates a new topics fields iterator for the given ink! event struct. - fn new(event: &'a InkEventDefinition) -> Self { - Self { - iter: event.item.fields.iter(), - } - } -} - -impl<'a> Iterator for EventFieldsIter<'a> { - type Item = EventField<'a>; - - fn next(&mut self) -> Option { - match self.iter.next() { - None => None, - Some(field) => { - let is_topic = ir::first_ink_attribute(&field.attrs) - .unwrap_or_default() - .map(|attr| matches!(attr.first().kind(), ir::AttributeArg::Topic)) - .unwrap_or_default(); - Some(EventField { is_topic, field }) - } - } + &self.event_def.item.attrs } } diff --git a/crates/lang/ir/src/ir/item/mod.rs b/crates/lang/ir/src/ir/item/mod.rs index 68ff3b4ed91..8db1b370fce 100644 --- a/crates/lang/ir/src/ir/item/mod.rs +++ b/crates/lang/ir/src/ir/item/mod.rs @@ -95,14 +95,6 @@ impl TryFrom for Item { .map(Into::into) .map(Self::Ink) } - syn::Item::Type(item_type) => { - if !ir::Event::is_ink_event(&item_type.attrs)? { - return Ok(Self::Rust(item_type.into())) - } - >::try_from(item_type) - .map(Into::into) - .map(Self::Ink) - } item => { // This is an error if the item contains any unexpected // ink! attributes. Otherwise it is a normal Rust item. From 71db3125eb4444e256cf6cf983f6baaafd5fdfcd Mon Sep 17 00:00:00 2001 From: ascjones Date: Fri, 5 Aug 2022 12:52:56 +0100 Subject: [PATCH 026/122] Remove ink item Event --- crates/lang/ir/src/ir/event_def.rs | 259 +++++++++++++++++++++ crates/lang/ir/src/ir/item/event.rs | 338 ---------------------------- crates/lang/ir/src/ir/item/mod.rs | 53 ++++- crates/lang/ir/src/ir/item_mod.rs | 8 +- crates/lang/ir/src/ir/mod.rs | 1 - crates/lang/ir/src/lib.rs | 1 - 6 files changed, 305 insertions(+), 355 deletions(-) delete mode 100644 crates/lang/ir/src/ir/item/event.rs diff --git a/crates/lang/ir/src/ir/event_def.rs b/crates/lang/ir/src/ir/event_def.rs index 663a9776bc5..8477f734cfc 100644 --- a/crates/lang/ir/src/ir/event_def.rs +++ b/crates/lang/ir/src/ir/event_def.rs @@ -205,3 +205,262 @@ impl<'a> Iterator for EventFieldsIter<'a> { } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn simple_try_from_works() { + let item_struct: syn::ItemStruct = syn::parse_quote! { + #[ink(event)] + pub struct MyEvent { + #[ink(topic)] + field_1: i32, + field_2: bool, + } + }; + assert!(InkEventDefinition::try_from(item_struct).is_ok()); + } + + fn assert_try_from_fails(item_struct: syn::ItemStruct, expected: &str) { + assert_eq!( + InkEventDefinition::try_from(item_struct).map_err(|err| err.to_string()), + Err(expected.to_string()) + ) + } + + #[test] + fn conflicting_struct_attributes_fails() { + assert_try_from_fails( + syn::parse_quote! { + #[ink(event)] + #[ink(storage)] + pub struct MyEvent { + #[ink(topic)] + field_1: i32, + field_2: bool, + } + }, + "encountered conflicting ink! attribute argument", + ) + } + + #[test] + fn duplicate_struct_attributes_fails() { + assert_try_from_fails( + syn::parse_quote! { + #[ink(event)] + #[ink(event)] + pub struct MyEvent { + #[ink(topic)] + field_1: i32, + field_2: bool, + } + }, + "encountered duplicate ink! attribute", + ) + } + + #[test] + fn wrong_first_struct_attribute_fails() { + assert_try_from_fails( + syn::parse_quote! { + #[ink(storage)] + #[ink(event)] + pub struct MyEvent { + #[ink(topic)] + field_1: i32, + field_2: bool, + } + }, + "unexpected first ink! attribute argument", + ) + } + + #[test] + fn missing_storage_attribute_fails() { + assert_try_from_fails( + syn::parse_quote! { + pub struct MyEvent { + #[ink(topic)] + field_1: i32, + field_2: bool, + } + }, + "encountered unexpected empty expanded ink! attribute arguments", + ) + } + + #[test] + fn generic_event_fails() { + assert_try_from_fails( + syn::parse_quote! { + #[ink(event)] + pub struct GenericEvent { + #[ink(topic)] + field_1: T, + field_2: bool, + } + }, + "generic ink! event structs are not supported", + ) + } + + #[test] + fn non_pub_event_struct() { + assert_try_from_fails( + syn::parse_quote! { + #[ink(event)] + struct PrivateEvent { + #[ink(topic)] + field_1: i32, + field_2: bool, + } + }, + "non `pub` ink! event structs are not supported", + ) + } + + #[test] + fn duplicate_field_attributes_fails() { + assert_try_from_fails( + syn::parse_quote! { + #[ink(event)] + pub struct MyEvent { + #[ink(topic)] + #[ink(topic)] + field_1: i32, + field_2: bool, + } + }, + "encountered duplicate ink! attribute", + ) + } + + #[test] + fn invalid_field_attributes_fails() { + assert_try_from_fails( + syn::parse_quote! { + #[ink(event)] + pub struct MyEvent { + #[ink(message)] + field_1: i32, + field_2: bool, + } + }, + "first optional ink! attribute of an event field must be #[ink(topic)]", + ) + } + + #[test] + fn conflicting_field_attributes_fails() { + assert_try_from_fails( + syn::parse_quote! { + #[ink(event)] + pub struct MyEvent { + #[ink(topic)] + #[ink(payable)] + field_1: i32, + field_2: bool, + } + }, + "encountered conflicting ink! attribute for event field", + ) + } + + /// Used for the event fields iterator unit test because `syn::Field` does + /// not provide a `syn::parse::Parse` implementation. + #[derive(Debug, PartialEq, Eq)] + struct NamedField(syn::Field); + + impl syn::parse::Parse for NamedField { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + Ok(Self(syn::Field::parse_named(input)?)) + } + } + + impl NamedField { + /// Returns the identifier of the named field. + pub fn ident(&self) -> &Ident { + self.0.ident.as_ref().unwrap() + } + + /// Returns the type of the named field. + pub fn ty(&self) -> &syn::Type { + &self.0.ty + } + } + + #[test] + fn event_fields_iter_works() { + let expected_fields: Vec<(bool, NamedField)> = vec![ + ( + true, + syn::parse_quote! { + field_1: i32 + }, + ), + ( + false, + syn::parse_quote! { + field_2: u64 + }, + ), + ( + true, + syn::parse_quote! { + field_3: [u8; 32] + }, + ), + ]; + let event_def = >::try_from(syn::parse_quote! { + #[ink(event)] + pub struct MyEvent { + #[ink(topic)] + field_1: i32, + field_2: u64, + #[ink(topic)] + field_3: [u8; 32], + } + }) + .unwrap(); + let mut fields_iter = event_def.fields(); + for (is_topic, expected_field) in expected_fields { + let field = fields_iter.next().unwrap(); + assert_eq!(field.is_topic, is_topic); + assert_eq!(field.ident(), Some(expected_field.ident())); + assert_eq!(field.ty(), expected_field.ty()); + } + } + + #[test] + fn anonymous_event_works() { + fn assert_anonymous_event(event: syn::ItemStruct) { + match InkEventDefinition::try_from(event) { + Ok(event) => { + assert!(event.anonymous); + } + Err(_) => panic!("encountered unexpected invalid anonymous event"), + } + } + assert_anonymous_event(syn::parse_quote! { + #[ink(event)] + #[ink(anonymous)] + pub struct MyEvent { + #[ink(topic)] + field_1: i32, + field_2: bool, + } + }); + assert_anonymous_event(syn::parse_quote! { + #[ink(event, anonymous)] + pub struct MyEvent { + #[ink(topic)] + field_1: i32, + field_2: bool, + } + }); + } +} + diff --git a/crates/lang/ir/src/ir/item/event.rs b/crates/lang/ir/src/ir/item/event.rs deleted file mode 100644 index 0eac1ef8d32..00000000000 --- a/crates/lang/ir/src/ir/item/event.rs +++ /dev/null @@ -1,338 +0,0 @@ -// Copyright 2018-2022 Parity Technologies (UK) Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::{ - ir, - InkEventDefinition, -}; -use proc_macro2::{ - Ident, -}; - -#[derive(Debug, PartialEq, Eq)] -pub struct Event { - pub event_def: InkEventDefinition, -} - -impl quote::ToTokens for Event { - /// We mainly implement this trait for this ink! type to have a derived - /// [`Spanned`](`syn::spanned::Spanned`) implementation for it. - fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { - self.event_def.to_tokens(tokens) - } -} - -impl Event { - /// Returns `true` if the first ink! annotation on the given struct is - /// `#[ink(event)]`. - /// - /// # Errors - /// - /// If the first found ink! attribute is malformed. - pub(super) fn is_ink_event(attrs: &[syn::Attribute]) -> Result { - if !ir::contains_ink_attributes(attrs) { - return Ok(false) - } - // At this point we know that there must be at least one ink! - // attribute. This can be either the ink! storage struct, - // an ink! event or an invalid ink! attribute. - let attr = ir::first_ink_attribute(attrs)? - .expect("missing expected ink! attribute for struct"); - Ok(matches!(attr.first().kind(), ir::AttributeArg::Event)) - } -} - -impl TryFrom for Event { - type Error = syn::Error; - - fn try_from(item_struct: syn::ItemStruct) -> Result { - let event_def = InkEventDefinition::try_from(item_struct)?; - Ok(Self { event_def }) - } -} - -impl Event { - /// Returns the identifier of the event. - pub fn ident(&self) -> &Ident { - &self.event_def.item.ident - } - - /// Returns all non-ink! attributes. - pub fn attrs(&self) -> &[syn::Attribute] { - &self.event_def.item.attrs - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn simple_try_from_works() { - let item_struct: syn::ItemStruct = syn::parse_quote! { - #[ink(event)] - pub struct MyEvent { - #[ink(topic)] - field_1: i32, - field_2: bool, - } - }; - assert!(Event::try_from(item_struct).is_ok()); - } - - fn assert_try_from_fails(item_struct: syn::ItemStruct, expected: &str) { - assert_eq!( - Event::try_from(item_struct).map_err(|err| err.to_string()), - Err(expected.to_string()) - ) - } - - #[test] - fn conflicting_struct_attributes_fails() { - assert_try_from_fails( - syn::parse_quote! { - #[ink(event)] - #[ink(storage)] - pub struct MyEvent { - #[ink(topic)] - field_1: i32, - field_2: bool, - } - }, - "encountered conflicting ink! attribute argument", - ) - } - - #[test] - fn duplicate_struct_attributes_fails() { - assert_try_from_fails( - syn::parse_quote! { - #[ink(event)] - #[ink(event)] - pub struct MyEvent { - #[ink(topic)] - field_1: i32, - field_2: bool, - } - }, - "encountered duplicate ink! attribute", - ) - } - - #[test] - fn wrong_first_struct_attribute_fails() { - assert_try_from_fails( - syn::parse_quote! { - #[ink(storage)] - #[ink(event)] - pub struct MyEvent { - #[ink(topic)] - field_1: i32, - field_2: bool, - } - }, - "unexpected first ink! attribute argument", - ) - } - - #[test] - fn missing_storage_attribute_fails() { - assert_try_from_fails( - syn::parse_quote! { - pub struct MyEvent { - #[ink(topic)] - field_1: i32, - field_2: bool, - } - }, - "encountered unexpected empty expanded ink! attribute arguments", - ) - } - - #[test] - fn generic_event_fails() { - assert_try_from_fails( - syn::parse_quote! { - #[ink(event)] - pub struct GenericEvent { - #[ink(topic)] - field_1: T, - field_2: bool, - } - }, - "generic ink! event structs are not supported", - ) - } - - #[test] - fn non_pub_event_struct() { - assert_try_from_fails( - syn::parse_quote! { - #[ink(event)] - struct PrivateEvent { - #[ink(topic)] - field_1: i32, - field_2: bool, - } - }, - "non `pub` ink! event structs are not supported", - ) - } - - #[test] - fn duplicate_field_attributes_fails() { - assert_try_from_fails( - syn::parse_quote! { - #[ink(event)] - pub struct MyEvent { - #[ink(topic)] - #[ink(topic)] - field_1: i32, - field_2: bool, - } - }, - "encountered duplicate ink! attribute", - ) - } - - #[test] - fn invalid_field_attributes_fails() { - assert_try_from_fails( - syn::parse_quote! { - #[ink(event)] - pub struct MyEvent { - #[ink(message)] - field_1: i32, - field_2: bool, - } - }, - "first optional ink! attribute of an event field must be #[ink(topic)]", - ) - } - - #[test] - fn conflicting_field_attributes_fails() { - assert_try_from_fails( - syn::parse_quote! { - #[ink(event)] - pub struct MyEvent { - #[ink(topic)] - #[ink(payable)] - field_1: i32, - field_2: bool, - } - }, - "encountered conflicting ink! attribute for event field", - ) - } - - /// Used for the event fields iterator unit test because `syn::Field` does - /// not provide a `syn::parse::Parse` implementation. - #[derive(Debug, PartialEq, Eq)] - struct NamedField(syn::Field); - - impl syn::parse::Parse for NamedField { - fn parse(input: syn::parse::ParseStream) -> syn::Result { - Ok(Self(syn::Field::parse_named(input)?)) - } - } - - impl NamedField { - /// Returns the identifier of the named field. - pub fn ident(&self) -> &Ident { - self.0.ident.as_ref().unwrap() - } - - /// Returns the type of the named field. - pub fn ty(&self) -> &syn::Type { - &self.0.ty - } - } - - #[test] - fn event_fields_iter_works() { - let expected_fields: Vec<(bool, NamedField)> = vec![ - ( - true, - syn::parse_quote! { - field_1: i32 - }, - ), - ( - false, - syn::parse_quote! { - field_2: u64 - }, - ), - ( - true, - syn::parse_quote! { - field_3: [u8; 32] - }, - ), - ]; - let input = >::try_from(syn::parse_quote! { - #[ink(event)] - pub struct MyEvent { - #[ink(topic)] - field_1: i32, - field_2: u64, - #[ink(topic)] - field_3: [u8; 32], - } - }) - .unwrap(); - if let Event::Inline(event_def) = input { - let mut fields_iter = event_def.fields(); - for (is_topic, expected_field) in expected_fields { - let field = fields_iter.next().unwrap(); - assert_eq!(field.is_topic, is_topic); - assert_eq!(field.ident(), Some(expected_field.ident())); - assert_eq!(field.ty(), expected_field.ty()); - } - } else { - panic!("Expected an inline event definition") - } - } - - #[test] - fn anonymous_event_works() { - fn assert_anonymous_event(event: syn::ItemStruct) { - match Event::try_from(event) { - Ok(Event::Inline(event)) => { - assert!(event.anonymous); - } - Ok(_) => panic!("Expected an inline event definition"), - Err(_) => panic!("encountered unexpected invalid anonymous event"), - } - } - assert_anonymous_event(syn::parse_quote! { - #[ink(event)] - #[ink(anonymous)] - pub struct MyEvent { - #[ink(topic)] - field_1: i32, - field_2: bool, - } - }); - assert_anonymous_event(syn::parse_quote! { - #[ink(event, anonymous)] - pub struct MyEvent { - #[ink(topic)] - field_1: i32, - field_2: bool, - } - }); - } -} diff --git a/crates/lang/ir/src/ir/item/mod.rs b/crates/lang/ir/src/ir/item/mod.rs index 8db1b370fce..5d59f324dc4 100644 --- a/crates/lang/ir/src/ir/item/mod.rs +++ b/crates/lang/ir/src/ir/item/mod.rs @@ -12,20 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. -mod event; mod storage; #[cfg(test)] mod tests; pub use self::{ - event::Event, storage::Storage, }; use crate::{ error::ExtError as _, ir, + ir::event_def::InkEventDefinition, ir::attrs::Attrs as _, }; use syn::spanned::Spanned as _; @@ -73,7 +72,7 @@ impl TryFrom for Item { .map(Self::Ink) } ir::AttributeArg::Event => { - >::try_from(item_struct) + >::try_from(item_struct) .map(Into::into) .map(Self::Ink) } @@ -154,7 +153,7 @@ pub enum InkItem { /// The ink! storage struct definition. Storage(ir::Storage), /// An ink! event definition. - Event(ir::Event), + Event(InkEventDefinition), /// An ink! implementation block. ImplBlock(ir::ItemImpl), } @@ -180,8 +179,8 @@ impl InkItem { pub fn is_ink_item(item: &syn::Item) -> Result { match item { syn::Item::Struct(item_struct) => { - if ir::Storage::is_ink_storage(item_struct)? - || ir::Event::is_ink_event(&item_struct.attrs)? + if ir::Storage::is_ink_storage(item_struct)? || + Self::is_ink_event(&item_struct.attrs)? { return Ok(true) } @@ -193,6 +192,24 @@ impl InkItem { } Ok(false) } + + /// Returns `true` if the first ink! annotation on the given struct is + /// `#[ink(event)]`. + /// + /// # Errors + /// + /// If the first found ink! attribute is malformed. + fn is_ink_event(attrs: &[syn::Attribute]) -> Result { + if !ir::contains_ink_attributes(attrs) { + return Ok(false) + } + // At this point we know that there must be at least one ink! + // attribute. This can be either the ink! storage struct, + // an ink! event or an invalid ink! attribute. + let attr = ir::first_ink_attribute(attrs)? + .expect("missing expected ink! attribute for struct"); + Ok(matches!(attr.first().kind(), ir::AttributeArg::Event)) + } } impl From for InkItem { @@ -201,8 +218,8 @@ impl From for InkItem { } } -impl From for InkItem { - fn from(event: ir::Event) -> Self { +impl From for InkItem { + fn from(event: InkEventDefinition) -> Self { Self::Event(event) } } @@ -232,7 +249,7 @@ impl InkItem { /// Returns `Some` if `self` is an ink! event struct definition. /// /// Otherwise, returns `None`. - pub fn filter_map_event_item(&self) -> Option<&ir::Event> { + pub fn filter_map_event_item(&self) -> Option<&InkEventDefinition> { match self { InkItem::Event(event) => Some(event), _ => None, @@ -244,6 +261,24 @@ impl InkItem { self.filter_map_event_item().is_some() } + /// Returns `true` if the first ink! annotation on the given struct is + /// `#[ink(event)]`. + /// + /// # Errors + /// + /// If the first found ink! attribute is malformed. + // pub(super) fn is_ink_event(attrs: &[syn::Attribute]) -> Result { + // if !ir::contains_ink_attributes(attrs) { + // return Ok(false) + // } + // // At this point we know that there must be at least one ink! + // // attribute. This can be either the ink! storage struct, + // // an ink! event or an invalid ink! attribute. + // let attr = ir::first_ink_attribute(attrs)? + // .expect("missing expected ink! attribute for struct"); + // Ok(matches!(attr.first().kind(), ir::AttributeArg::Event)) + // } + /// Returns `Some` if `self` is an ink! implementation block. /// /// Otherwise, returns `None`. diff --git a/crates/lang/ir/src/ir/item_mod.rs b/crates/lang/ir/src/ir/item_mod.rs index b26890a84a4..aceff81ab66 100644 --- a/crates/lang/ir/src/ir/item_mod.rs +++ b/crates/lang/ir/src/ir/item_mod.rs @@ -12,11 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{ - ir, - ir::idents_lint, - Callable, -}; +use crate::{ir, ir::idents_lint, Callable}; use proc_macro2::{ Ident, Span, @@ -535,7 +531,7 @@ impl<'a> IterEvents<'a> { } impl<'a> Iterator for IterEvents<'a> { - type Item = &'a ir::Event; + type Item = &'a ir::InkEventDefinition; fn next(&mut self) -> Option { 'repeat: loop { diff --git a/crates/lang/ir/src/ir/mod.rs b/crates/lang/ir/src/ir/mod.rs index 9ca96240bdd..f4fe4881dbe 100644 --- a/crates/lang/ir/src/ir/mod.rs +++ b/crates/lang/ir/src/ir/mod.rs @@ -70,7 +70,6 @@ pub use self::{ event_def::InkEventDefinition, ink_test::InkTest, item::{ - Event, InkItem, Item, Storage, diff --git a/crates/lang/ir/src/lib.rs b/crates/lang/ir/src/lib.rs index bcc8f2d3b91..a800e35e81d 100644 --- a/crates/lang/ir/src/lib.rs +++ b/crates/lang/ir/src/lib.rs @@ -48,7 +48,6 @@ pub use self::{ Config, Constructor, Contract, - Event, ExtensionId, ImplItem, InkEventDefinition, From c73ea8da87e62ec2617d2fd11ffbc0c1ecd04d14 Mon Sep 17 00:00:00 2001 From: ascjones Date: Fri, 5 Aug 2022 12:53:52 +0100 Subject: [PATCH 027/122] Fmt --- crates/lang/codegen/src/generator/events.rs | 4 +--- crates/lang/ir/src/ir/event_def.rs | 25 +++++++++++---------- crates/lang/ir/src/ir/item/mod.rs | 14 ++++++------ crates/lang/ir/src/ir/item_mod.rs | 6 ++++- crates/lang/src/codegen/event/mod.rs | 12 +++++----- crates/lang/src/env_access.rs | 4 ++-- 6 files changed, 33 insertions(+), 32 deletions(-) diff --git a/crates/lang/codegen/src/generator/events.rs b/crates/lang/codegen/src/generator/events.rs index a022b293044..01fb851e7f7 100644 --- a/crates/lang/codegen/src/generator/events.rs +++ b/crates/lang/codegen/src/generator/events.rs @@ -17,9 +17,7 @@ use crate::{ GenerateCode, }; use derive_more::From; -use proc_macro2::{ - TokenStream as TokenStream2, -}; +use proc_macro2::TokenStream as TokenStream2; use quote::{ quote, quote_spanned, diff --git a/crates/lang/ir/src/ir/event_def.rs b/crates/lang/ir/src/ir/event_def.rs index 8477f734cfc..4bbdae07f32 100644 --- a/crates/lang/ir/src/ir/event_def.rs +++ b/crates/lang/ir/src/ir/event_def.rs @@ -414,17 +414,19 @@ mod tests { }, ), ]; - let event_def = >::try_from(syn::parse_quote! { - #[ink(event)] - pub struct MyEvent { - #[ink(topic)] - field_1: i32, - field_2: u64, - #[ink(topic)] - field_3: [u8; 32], - } - }) - .unwrap(); + let event_def = >::try_from( + syn::parse_quote! { + #[ink(event)] + pub struct MyEvent { + #[ink(topic)] + field_1: i32, + field_2: u64, + #[ink(topic)] + field_3: [u8; 32], + } + }, + ) + .unwrap(); let mut fields_iter = event_def.fields(); for (is_topic, expected_field) in expected_fields { let field = fields_iter.next().unwrap(); @@ -463,4 +465,3 @@ mod tests { }); } } - diff --git a/crates/lang/ir/src/ir/item/mod.rs b/crates/lang/ir/src/ir/item/mod.rs index 5d59f324dc4..ee86a7fa422 100644 --- a/crates/lang/ir/src/ir/item/mod.rs +++ b/crates/lang/ir/src/ir/item/mod.rs @@ -17,15 +17,15 @@ mod storage; #[cfg(test)] mod tests; -pub use self::{ - storage::Storage, -}; +pub use self::storage::Storage; use crate::{ error::ExtError as _, ir, - ir::event_def::InkEventDefinition, - ir::attrs::Attrs as _, + ir::{ + attrs::Attrs as _, + event_def::InkEventDefinition, + }, }; use syn::spanned::Spanned as _; @@ -179,8 +179,8 @@ impl InkItem { pub fn is_ink_item(item: &syn::Item) -> Result { match item { syn::Item::Struct(item_struct) => { - if ir::Storage::is_ink_storage(item_struct)? || - Self::is_ink_event(&item_struct.attrs)? + if ir::Storage::is_ink_storage(item_struct)? + || Self::is_ink_event(&item_struct.attrs)? { return Ok(true) } diff --git a/crates/lang/ir/src/ir/item_mod.rs b/crates/lang/ir/src/ir/item_mod.rs index aceff81ab66..b3272570842 100644 --- a/crates/lang/ir/src/ir/item_mod.rs +++ b/crates/lang/ir/src/ir/item_mod.rs @@ -12,7 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{ir, ir::idents_lint, Callable}; +use crate::{ + ir, + ir::idents_lint, + Callable, +}; use proc_macro2::{ Ident, Span, diff --git a/crates/lang/src/codegen/event/mod.rs b/crates/lang/src/codegen/event/mod.rs index 4328285b1f5..d2c2bac9080 100644 --- a/crates/lang/src/codegen/event/mod.rs +++ b/crates/lang/src/codegen/event/mod.rs @@ -14,11 +14,9 @@ mod topics; -pub use self::{ - topics::{ - EventLenTopics, - EventRespectsTopicLimit, - EventTopics, - RespectTopicLimit, - }, +pub use self::topics::{ + EventLenTopics, + EventRespectsTopicLimit, + EventTopics, + RespectTopicLimit, }; diff --git a/crates/lang/src/env_access.rs b/crates/lang/src/env_access.rs index 2dc156683da..4992c8877a9 100644 --- a/crates/lang/src/env_access.rs +++ b/crates/lang/src/env_access.rs @@ -424,8 +424,8 @@ where /// todo: [AJ] docs pub fn emit_event(self, event: Event) - where - Event: ink_env::Topics + scale::Encode, + where + Event: ink_env::Topics + scale::Encode, { ink_env::emit_event::(event) } From 7e59e74fcd93789844ab4c67677cd5aa368740cf Mon Sep 17 00:00:00 2001 From: ascjones Date: Thu, 25 Aug 2022 11:09:42 +0100 Subject: [PATCH 028/122] Rewire contract internal event definitions --- crates/lang/codegen/src/generator/events.rs | 38 ++------------------- 1 file changed, 2 insertions(+), 36 deletions(-) diff --git a/crates/lang/codegen/src/generator/events.rs b/crates/lang/codegen/src/generator/events.rs index 01fb851e7f7..3ddbb52f6da 100644 --- a/crates/lang/codegen/src/generator/events.rs +++ b/crates/lang/codegen/src/generator/events.rs @@ -20,9 +20,7 @@ use derive_more::From; use proc_macro2::TokenStream as TokenStream2; use quote::{ quote, - quote_spanned, }; -use syn::spanned::Spanned as _; /// Generates code for the ink! event structs of the contract. #[derive(From)] @@ -37,50 +35,18 @@ impl GenerateCode for Events<'_> { // Generate no code in case there are no event definitions. return TokenStream2::new() } - let topic_guards = self.generate_topic_guards(); - let event_defs = self.generate_event_definitions(); // todo: call into shared event_def code for inline events + let event_defs = self.generate_event_definitions(); quote! { - #( #topic_guards )* #( #event_defs )* } } } impl<'a> Events<'a> { - /// Generate checks to guard against too many topics in event definitions. - fn generate_topics_guard(&self, event: &ir::Event) -> TokenStream2 { - let span = event.span(); - let storage_ident = self.contract.module().storage().ident(); - let event_ident = event.ident(); - let max_len_topics = quote_spanned!(span=> - <<#storage_ident as ::ink_lang::reflect::ContractEnv>::Env - as ::ink_env::Environment>::MAX_EVENT_TOPICS - ); - quote_spanned!(span=> - const _: () = ::ink_lang::codegen::utils::consume_type::< - ::ink_lang::codegen::EventRespectsTopicLimit< - #event_ident, - { #max_len_topics }, - > - >(); - ) - } - - /// Generates the guard code that protects against having too many topics defined on an ink! event. - fn generate_topic_guards(&'a self) -> impl Iterator + 'a { - self.contract.module().events().map(move |event| { - let span = event.span(); - let topics_guard = self.generate_topics_guard(event); - quote_spanned!(span => - #topics_guard - ) - }) - } - /// Generates the `Topics` trait implementations for the user defined events. fn generate_event_definitions(&'a self) -> impl Iterator + 'a { self.contract.module().events().map(move |event| { - let event_def_gen = EventDefinition::from(&event.event_def); + let event_def_gen = EventDefinition::from(event); event_def_gen.generate_code() }) } From c6a8cecf600ec7b4658b44fbf8fc8f0ff641cdd2 Mon Sep 17 00:00:00 2001 From: ascjones Date: Tue, 30 Aug 2022 09:41:22 +0100 Subject: [PATCH 029/122] add todos --- .../lang/tests/ui/contract/pass/event-shared-external.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/crates/lang/tests/ui/contract/pass/event-shared-external.rs b/crates/lang/tests/ui/contract/pass/event-shared-external.rs index c5edf459dee..4a5a18865d1 100644 --- a/crates/lang/tests/ui/contract/pass/event-shared-external.rs +++ b/crates/lang/tests/ui/contract/pass/event-shared-external.rs @@ -1,5 +1,13 @@ use ink_lang as ink; +// todo: add the wiring to detect the events metadata, and in cargo-contract merge together +// todo: consider the possibility of enforcing shared events to be an enum, and tied to an ink! trait def +// only a single event type per interface which encapsulates all the possible events +// inside an impl the emit_event is restricted to that trait impl type. +// in libs there is no such restriction, can just ink_env::emit_event? +// either way still need to do the metadata scanning +// also with cross-contract call even those events will not be included in the metadata. + #[ink::event_definition] pub struct SharedEvent { arg_1: u8, From 0dfc495b4b16a009dd51fa036cbccee182aeefaf Mon Sep 17 00:00:00 2001 From: ascjones Date: Mon, 5 Sep 2022 16:27:34 +0100 Subject: [PATCH 030/122] WIP changing event def to be an enum --- crates/lang/ir/src/ir/event_def.rs | 2 +- .../tests/ui/contract/pass/event-shared-external.rs | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/crates/lang/ir/src/ir/event_def.rs b/crates/lang/ir/src/ir/event_def.rs index 4bbdae07f32..acf25f0a71e 100644 --- a/crates/lang/ir/src/ir/event_def.rs +++ b/crates/lang/ir/src/ir/event_def.rs @@ -30,7 +30,7 @@ use syn::{ /// A checked ink! event definition. #[derive(Debug, PartialEq, Eq)] pub struct InkEventDefinition { - pub item: syn::ItemStruct, + pub item: syn::ItemEnum, pub anonymous: bool, } diff --git a/crates/lang/tests/ui/contract/pass/event-shared-external.rs b/crates/lang/tests/ui/contract/pass/event-shared-external.rs index 4a5a18865d1..c4c2052917f 100644 --- a/crates/lang/tests/ui/contract/pass/event-shared-external.rs +++ b/crates/lang/tests/ui/contract/pass/event-shared-external.rs @@ -9,10 +9,12 @@ use ink_lang as ink; // also with cross-contract call even those events will not be included in the metadata. #[ink::event_definition] -pub struct SharedEvent { - arg_1: u8, - #[ink(topic)] - arg_2: u16, +pub enum SharedEvent { + Event1 { + arg_1: u8, + #[ink(topic)] + arg_2: u16, + } } #[ink::contract] @@ -28,7 +30,7 @@ mod contract { #[ink(message)] pub fn message(&self) { - self.env().emit_event(super::SharedEvent { arg_1: 1, arg_2: 2 }); + self.env().emit_event(super::SharedEvent::Event1 { arg_1: 1, arg_2: 2 }); } } } From 34da8a6f9900a543ab258d786d8a03227dfcc4cd Mon Sep 17 00:00:00 2001 From: ascjones Date: Tue, 6 Sep 2022 10:14:35 +0100 Subject: [PATCH 031/122] WIP adding EventVariantInfo trait for EVENT_SIGNATURE --- .../lang/codegen/src/generator/event_def.rs | 47 +++--- crates/lang/ir/src/ir/event_def.rs | 154 +++++++++--------- crates/lang/ir/src/ir/item/mod.rs | 13 +- crates/lang/src/reflect/event.rs | 10 ++ 4 files changed, 123 insertions(+), 101 deletions(-) diff --git a/crates/lang/codegen/src/generator/event_def.rs b/crates/lang/codegen/src/generator/event_def.rs index 2894c389abb..6eccb5c60df 100644 --- a/crates/lang/codegen/src/generator/event_def.rs +++ b/crates/lang/codegen/src/generator/event_def.rs @@ -48,25 +48,10 @@ impl GenerateCode for EventDefinition<'_> { impl<'a> EventDefinition<'a> { fn generate_event_struct(&'a self) -> TokenStream2 { let span = self.event_def.span(); - let ident = self.event_def.ident(); - let attrs = self.event_def.attrs(); - let fields = self.event_def.fields().map(|event_field| { - let span = event_field.span(); - let attrs = event_field.attrs(); - let vis = event_field.vis(); - let ident = event_field.ident(); - let ty = event_field.ty(); - quote_spanned!(span=> - #( #attrs )* - #vis #ident : #ty - ) - }); + let event_enum = &self.event_def.item; quote_spanned!(span => - #( #attrs )* #[derive(scale::Encode, scale::Decode)] - pub struct #ident { - #( #fields ),* - } + #event_enum ) } @@ -80,6 +65,25 @@ impl<'a> EventDefinition<'a> { ) } + fn generate_event_variant_info_impls(&self) -> TokenStream2 { + let span = self.event_def.span(); + let event_ident = self.event_def.ident(); + let impls = + self.event_def.variants().map(|ev| { + let index = ev.index(); + quote_spanned!(span=> + impl ::ink_lang::reflect::EventVariantInfo<#index> for #event_ident { + const SIGNATURE: [u8: 32] = todo!(); + } + ) + }); + quote_spanned!(span=> + #( + #impls + )* + ) + } + fn generate_event_metadata_impl(&self) -> TokenStream2 { let event_metadata = super::metadata::EventMetadata::from(self.event_def); event_metadata.generate_code() @@ -91,9 +95,8 @@ impl<'a> EventDefinition<'a> { let event_ident = self.event_def.ident(); let len_topics = self .event_def - .fields() - .filter(|event| event.is_topic) - .count(); + .max_len_topics(); + quote_spanned!(span=> impl ::ink_lang::codegen::EventLenTopics for #event_ident { type LenTopics = ::ink_lang::codegen::EventTopics<#len_topics>; @@ -107,9 +110,7 @@ impl<'a> EventDefinition<'a> { let event_ident = self.event_def.ident(); let len_topics = self .event_def - .fields() - .filter(|field| field.is_topic) - .count(); + .max_len_topics(); let topic_impls = self .event_def .fields() diff --git a/crates/lang/ir/src/ir/event_def.rs b/crates/lang/ir/src/ir/event_def.rs index acf25f0a71e..3fe3d53a52d 100644 --- a/crates/lang/ir/src/ir/event_def.rs +++ b/crates/lang/ir/src/ir/event_def.rs @@ -34,14 +34,14 @@ pub struct InkEventDefinition { pub anonymous: bool, } -impl TryFrom for InkEventDefinition { +impl TryFrom for InkEventDefinition { type Error = syn::Error; - fn try_from(item_struct: syn::ItemStruct) -> Result { - let struct_span = item_struct.span(); + fn try_from(item_enum: syn::ItemEnum) -> Result { + let enum_span = item_enum.span(); let (ink_attrs, other_attrs) = ir::sanitize_attributes( - struct_span, - item_struct.attrs, + enum_span, + item_enum.attrs, &ir::AttributeArgKind::Event, |arg| { match arg.kind() { @@ -50,11 +50,11 @@ impl TryFrom for InkEventDefinition { } }, )?; - let item_struct = syn::ItemStruct { + let item_enum = syn::ItemEnum { attrs: other_attrs, - ..item_struct + ..item_enum }; - Self::new(item_struct, ink_attrs.is_anonymous()) + Self::new(item_enum, ink_attrs.is_anonymous()) } } @@ -68,42 +68,44 @@ impl quote::ToTokens for InkEventDefinition { impl InkEventDefinition { /// Returns `Ok` if the input matches all requirements for an ink! event definition. - pub fn new(item_struct: syn::ItemStruct, anonymous: bool) -> Result { - if !item_struct.generics.params.is_empty() { + pub fn new(item_enum: syn::ItemEnum, anonymous: bool) -> Result { + if !item_enum.generics.params.is_empty() { return Err(format_err_spanned!( - item_struct.generics.params, - "generic ink! event structs are not supported", + item_enum.generics.params, + "generic ink! event enums are not supported", )) } - let struct_span = item_struct.span(); - utils::ensure_pub_visibility("event structs", struct_span, &item_struct.vis)?; - 'repeat: for field in item_struct.fields.iter() { - let field_span = field.span(); - let (ink_attrs, _) = ir::partition_attributes(field.attrs.clone())?; - if ink_attrs.is_empty() { - continue 'repeat - } - let normalized = - ir::InkAttribute::from_expanded(ink_attrs).map_err(|err| { - err.into_combine(format_err!(field_span, "at this invocation",)) - })?; - if !matches!(normalized.first().kind(), ir::AttributeArg::Topic) { - return Err(format_err!( - field_span, - "first optional ink! attribute of an event field must be #[ink(topic)]", - )) - } - for arg in normalized.args() { - if !matches!(arg.kind(), ir::AttributeArg::Topic) { + let struct_span = item_enum.span(); + utils::ensure_pub_visibility("event enums", struct_span, &item_enum.vis)?; + for variant in item_enum.variants.iter() { + 'repeat: for field in variant.fields.iter() { + let field_span = field.span(); + let (ink_attrs, _) = ir::partition_attributes(field.attrs.clone())?; + if ink_attrs.is_empty() { + continue 'repeat + } + let normalized = + ir::InkAttribute::from_expanded(ink_attrs).map_err(|err| { + err.into_combine(format_err!(field_span, "at this invocation",)) + })?; + if !matches!(normalized.first().kind(), ir::AttributeArg::Topic) { return Err(format_err!( - arg.span(), - "encountered conflicting ink! attribute for event field", + field_span, + "first optional ink! attribute of an event field must be #[ink(topic)]", )) } + for arg in normalized.args() { + if !matches!(arg.kind(), ir::AttributeArg::Topic) { + return Err(format_err!( + arg.span(), + "encountered conflicting ink! attribute for event field", + )) + } + } } } Ok(Self { - item: item_struct, + item: item_enum, anonymous, }) } @@ -115,7 +117,7 @@ impl InkEventDefinition { ) -> Result { let _parsed_config = syn::parse2::(config)?; let anonymous = false; // todo parse this from attr config - let item = syn::parse2::(input)?; + let item = syn::parse2::(input)?; // let item = InkItemTrait::new(&config, parsed_item)?; Ok(Self { anonymous, item }) } @@ -125,16 +127,53 @@ impl InkEventDefinition { &self.item.ident } - /// Returns an iterator yielding all the `#[ink(topic)]` annotated fields - /// of the event struct. - pub fn fields(&self) -> EventFieldsIter { - EventFieldsIter::new(self) - } - /// Returns all non-ink! attributes. pub fn attrs(&self) -> &[syn::Attribute] { &self.item.attrs } + + /// Returns all event variants. + pub fn variants(&self) -> impl Iterator> { + self.item.variants.iter().enumerate().map(|(i, v) | EventVariant { index: i, item: v}) + } + + /// Returns the maximum number of topics of any event variant. + pub fn max_len_topics(&self) -> usize { + self + .variants() + .map(|v| v.fields() + .filter(|event| event.is_topic) + .count()) + .max() + .unwrap_or_default() + } +} + +/// A variant of an event. +pub struct EventVariant<'a> { + index: usize, + item: &'a syn::Variant, +} + +impl<'a> EventVariant<'a> { + /// The index of the the event variant in the enum definition. + pub fn index(&self) -> usize { + self.index + } + + /// Returns an iterator yielding all the `#[ink(topic)]` annotated fields + /// of the event variant struct. + pub fn fields(&self) -> impl Iterator> { + self.item.fields + .iter() + .map(|field| { + let is_topic = ir::first_ink_attribute(&field.attrs) + .unwrap_or_default() + .map(|attr| matches!(attr.first().kind(), ir::AttributeArg::Topic)) + .unwrap_or_default(); + EventField { is_topic, field } + }) + } } /// An event field with a flag indicating if this field is an event topic. @@ -175,37 +214,6 @@ impl<'a> EventField<'a> { } } -/// Iterator yielding all `#[ink(topic)]` annotated fields of an event struct. -pub struct EventFieldsIter<'a> { - iter: syn::punctuated::Iter<'a, syn::Field>, -} - -impl<'a> EventFieldsIter<'a> { - /// Creates a new topics fields iterator for the given ink! event struct. - fn new(event: &'a InkEventDefinition) -> Self { - Self { - iter: event.item.fields.iter(), - } - } -} - -impl<'a> Iterator for EventFieldsIter<'a> { - type Item = EventField<'a>; - - fn next(&mut self) -> Option { - match self.iter.next() { - None => None, - Some(field) => { - let is_topic = ir::first_ink_attribute(&field.attrs) - .unwrap_or_default() - .map(|attr| matches!(attr.first().kind(), ir::AttributeArg::Topic)) - .unwrap_or_default(); - Some(EventField { is_topic, field }) - } - } - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/crates/lang/ir/src/ir/item/mod.rs b/crates/lang/ir/src/ir/item/mod.rs index ee86a7fa422..b987050eb1e 100644 --- a/crates/lang/ir/src/ir/item/mod.rs +++ b/crates/lang/ir/src/ir/item/mod.rs @@ -71,11 +71,6 @@ impl TryFrom for Item { .map(Into::into) .map(Self::Ink) } - ir::AttributeArg::Event => { - >::try_from(item_struct) - .map(Into::into) - .map(Self::Ink) - } _invalid => { Err(format_err!( attr.span(), @@ -84,6 +79,14 @@ impl TryFrom for Item { } } } + syn::Item::Enum(item_enum) => { + todo!("recognise ink::event_definition or simply ink(event) still") + // ir::AttributeArg::Event => { + // >::try_from(item_struct) + // .map(Into::into) + // .map(Self::Ink) + // } + } syn::Item::Impl(item_impl) => { if !ir::ItemImpl::is_ink_impl_block(&item_impl)? { return Ok(Self::Rust(item_impl.into())) diff --git a/crates/lang/src/reflect/event.rs b/crates/lang/src/reflect/event.rs index 79941b6aae4..3f650e7d61d 100644 --- a/crates/lang/src/reflect/event.rs +++ b/crates/lang/src/reflect/event.rs @@ -23,3 +23,13 @@ pub trait EventInfo { /// todo: rename? const PATH: &'static str; } + +/// todo: docs +/// The ID is the index of the event variant in the enum +pub trait EventVariantInfo { + const NAME: &'static str; + /// todo: docs + /// Will be hashed unique path of Event -> Variant, used for topic of Event variant + /// Should be able to compute up front + const SIGNATURE: [u8; 32]; +} From 14d6e30b767cbf3053226eaf37b6e599e8cbb01e Mon Sep 17 00:00:00 2001 From: ascjones Date: Tue, 6 Sep 2022 12:22:15 +0100 Subject: [PATCH 032/122] WIP adapting to synstructure --- .../lang/codegen/src/generator/event_def.rs | 17 +++ crates/lang/ir/Cargo.toml | 1 + crates/lang/ir/src/ir/event_def.rs | 131 ++++++++---------- crates/lang/macro/Cargo.toml | 1 + crates/lang/macro/src/event_def.rs | 6 +- crates/lang/macro/src/lib.rs | 6 +- 6 files changed, 84 insertions(+), 78 deletions(-) diff --git a/crates/lang/codegen/src/generator/event_def.rs b/crates/lang/codegen/src/generator/event_def.rs index 6eccb5c60df..d86b042f7b7 100644 --- a/crates/lang/codegen/src/generator/event_def.rs +++ b/crates/lang/codegen/src/generator/event_def.rs @@ -22,6 +22,23 @@ use quote::{ }; use syn::spanned::Spanned as _; +/// todo: docs +pub fn generate(attr: TokenStream2, structure: synstructure::Structure) -> TokenStream2 { + let body = s.each(|bi| quote!{ + walk(#bi) + }); + + s.gen_impl(quote! { + extern crate synstructure_test_traits; + + gen impl synstructure_test_traits::WalkFields for @Self { + fn walk_fields(&self, walk: &mut FnMut(&synstructure_test_traits::WalkFields)) { + match *self { #body } + } + } + }) +} + /// Generates code for an event definition. #[derive(From)] pub struct EventDefinition<'a> { diff --git a/crates/lang/ir/Cargo.toml b/crates/lang/ir/Cargo.toml index 6b4330af264..bf669fd23e6 100644 --- a/crates/lang/ir/Cargo.toml +++ b/crates/lang/ir/Cargo.toml @@ -20,6 +20,7 @@ name = "ink_lang_ir" [dependencies] quote = "1" syn = { version = "1.0", features = ["parsing", "full", "visit", "extra-traits"] } +synstructure = "0.12.6" proc-macro2 = "1.0" itertools = { version = "0.10", default-features = false } either = { version = "1.5", default-features = false } diff --git a/crates/lang/ir/src/ir/event_def.rs b/crates/lang/ir/src/ir/event_def.rs index 3fe3d53a52d..72bb2631dc6 100644 --- a/crates/lang/ir/src/ir/event_def.rs +++ b/crates/lang/ir/src/ir/event_def.rs @@ -29,97 +29,86 @@ use syn::{ /// A checked ink! event definition. #[derive(Debug, PartialEq, Eq)] -pub struct InkEventDefinition { - pub item: syn::ItemEnum, +pub struct InkEventDefinition<'a> { + pub structure: synstructure::Structure<'a>, pub anonymous: bool, } -impl TryFrom for InkEventDefinition { - type Error = syn::Error; - - fn try_from(item_enum: syn::ItemEnum) -> Result { - let enum_span = item_enum.span(); - let (ink_attrs, other_attrs) = ir::sanitize_attributes( - enum_span, - item_enum.attrs, - &ir::AttributeArgKind::Event, - |arg| { - match arg.kind() { - ir::AttributeArg::Event | ir::AttributeArg::Anonymous => Ok(()), - _ => Err(None), - } - }, - )?; - let item_enum = syn::ItemEnum { - attrs: other_attrs, - ..item_enum - }; - Self::new(item_enum, ink_attrs.is_anonymous()) - } -} +// impl TryFrom for InkEventDefinition { +// type Error = syn::Error; +// +// fn try_from(item_enum: syn::ItemEnum) -> Result { +// let enum_span = item_enum.span(); +// let (ink_attrs, other_attrs) = ir::sanitize_attributes( +// enum_span, +// item_enum.attrs, +// &ir::AttributeArgKind::Event, +// |arg| { +// match arg.kind() { +// ir::AttributeArg::Event | ir::AttributeArg::Anonymous => Ok(()), +// _ => Err(None), +// } +// }, +// )?; +// let item_enum = syn::ItemEnum { +// attrs: other_attrs, +// ..item_enum +// }; +// Self::new(item_enum, ink_attrs.is_anonymous()) +// } +// } impl quote::ToTokens for InkEventDefinition { /// We mainly implement this trait for this ink! type to have a derived /// [`Spanned`](`syn::spanned::Spanned`) implementation for it. fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { - self.item.to_tokens(tokens) + self.structure.ast().to_tokens(tokens) } } impl InkEventDefinition { /// Returns `Ok` if the input matches all requirements for an ink! event definition. - pub fn new(item_enum: syn::ItemEnum, anonymous: bool) -> Result { - if !item_enum.generics.params.is_empty() { - return Err(format_err_spanned!( - item_enum.generics.params, - "generic ink! event enums are not supported", - )) - } - let struct_span = item_enum.span(); - utils::ensure_pub_visibility("event enums", struct_span, &item_enum.vis)?; - for variant in item_enum.variants.iter() { - 'repeat: for field in variant.fields.iter() { - let field_span = field.span(); - let (ink_attrs, _) = ir::partition_attributes(field.attrs.clone())?; - if ink_attrs.is_empty() { - continue 'repeat - } - let normalized = - ir::InkAttribute::from_expanded(ink_attrs).map_err(|err| { - err.into_combine(format_err!(field_span, "at this invocation",)) - })?; - if !matches!(normalized.first().kind(), ir::AttributeArg::Topic) { - return Err(format_err!( - field_span, - "first optional ink! attribute of an event field must be #[ink(topic)]", - )) - } - for arg in normalized.args() { - if !matches!(arg.kind(), ir::AttributeArg::Topic) { - return Err(format_err!( - arg.span(), - "encountered conflicting ink! attribute for event field", - )) - } - } - } - } + pub fn new(structure: synstructure::Structure, anonymous: bool) -> Result { + // for variant in structure.variants() { + // 'repeat: for field in variant.ast().fields { + // let field_span = field.span(); + // let (ink_attrs, _) = ir::partition_attributes(field.attrs.clone())?; + // if ink_attrs.is_empty() { + // continue 'repeat + // } + // let normalized = + // ir::InkAttribute::from_expanded(ink_attrs).map_err(|err| { + // err.into_combine(format_err!(field_span, "at this invocation",)) + // })?; + // if !matches!(normalized.first().kind(), ir::AttributeArg::Topic) { + // return Err(format_err!( + // field_span, + // "first optional ink! attribute of an event field must be #[ink(topic)]", + // )) + // } + // for arg in normalized.args() { + // if !matches!(arg.kind(), ir::AttributeArg::Topic) { + // return Err(format_err!( + // arg.span(), + // "encountered conflicting ink! attribute for event field", + // )) + // } + // } + // } + // } Ok(Self { - item: item_enum, + structure, anonymous, }) } - /// Returns `Ok` if the input matches all requirements for an ink! event definition. - pub fn from_event_def_tokens( - config: TokenStream2, - input: TokenStream2, + pub fn from_structure( + attr: TokenStream2, + structure: synstructure::Structure, ) -> Result { let _parsed_config = syn::parse2::(config)?; let anonymous = false; // todo parse this from attr config - let item = syn::parse2::(input)?; - // let item = InkItemTrait::new(&config, parsed_item)?; - Ok(Self { anonymous, item }) + Self::new(structure, anonymous) } /// Returns the identifier of the event struct. @@ -140,7 +129,9 @@ impl InkEventDefinition { /// Returns the maximum number of topics of any event variant. pub fn max_len_topics(&self) -> usize { self + .structure .variants() + .iter() .map(|v| v.fields() .filter(|event| event.is_topic) .count()) diff --git a/crates/lang/macro/Cargo.toml b/crates/lang/macro/Cargo.toml index ebb602f81fe..78f7bed4362 100644 --- a/crates/lang/macro/Cargo.toml +++ b/crates/lang/macro/Cargo.toml @@ -21,6 +21,7 @@ ink_primitives = { version = "4.0.0-alpha.1", path = "../../primitives/", defaul scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } syn = "1" +synstructure = "0.12.6" proc-macro2 = "1" [dev-dependencies] diff --git a/crates/lang/macro/src/event_def.rs b/crates/lang/macro/src/event_def.rs index 250056f5e61..142ff933d92 100644 --- a/crates/lang/macro/src/event_def.rs +++ b/crates/lang/macro/src/event_def.rs @@ -16,8 +16,8 @@ use ink_lang_codegen::generate_code; use proc_macro2::TokenStream as TokenStream2; use syn::Result; -pub fn generate(config: TokenStream2, input: TokenStream2) -> TokenStream2 { - match generate_or_err(config, input) { +pub fn generate(attr: TokenStream2, structure: synstructure::Structure) -> TokenStream2 { + match generate_or_err(attr, structure) { Ok(tokens) => tokens, Err(err) => err.to_compile_error(), } @@ -25,7 +25,7 @@ pub fn generate(config: TokenStream2, input: TokenStream2) -> TokenStream2 { pub fn generate_or_err( config: TokenStream2, - input: TokenStream2, + structure: synstructure::Structure, ) -> Result { let trait_definition = ink_lang_ir::InkEventDefinition::from_event_def_tokens(config, input)?; diff --git a/crates/lang/macro/src/lib.rs b/crates/lang/macro/src/lib.rs index 790a4dfee68..5e471b73bf3 100644 --- a/crates/lang/macro/src/lib.rs +++ b/crates/lang/macro/src/lib.rs @@ -667,11 +667,7 @@ pub fn trait_definition(attr: TokenStream, item: TokenStream) -> TokenStream { } /// todo derive Event docs - -#[proc_macro_attribute] -pub fn event_definition(attr: TokenStream, item: TokenStream) -> TokenStream { - event_def::generate(attr.into(), item.into()).into() -} +synstructure::decl_attribute!([event_definition] => event_def::generate); /// Defines a unit test that makes use of ink!'s off-chain testing capabilities. /// From 99bb6bdc4e588e08fa22460c15bb6a49c77be372 Mon Sep 17 00:00:00 2001 From: ascjones Date: Tue, 6 Sep 2022 13:47:00 +0100 Subject: [PATCH 033/122] WIP generating event signature topics impls --- .../lang/codegen/src/generator/event_def.rs | 228 +++++++++--------- crates/lang/ir/src/ir/event_def.rs | 2 +- 2 files changed, 113 insertions(+), 117 deletions(-) diff --git a/crates/lang/codegen/src/generator/event_def.rs b/crates/lang/codegen/src/generator/event_def.rs index d86b042f7b7..60f9c7761bb 100644 --- a/crates/lang/codegen/src/generator/event_def.rs +++ b/crates/lang/codegen/src/generator/event_def.rs @@ -22,52 +22,37 @@ use quote::{ }; use syn::spanned::Spanned as _; -/// todo: docs -pub fn generate(attr: TokenStream2, structure: synstructure::Structure) -> TokenStream2 { - let body = s.each(|bi| quote!{ - walk(#bi) - }); - - s.gen_impl(quote! { - extern crate synstructure_test_traits; - - gen impl synstructure_test_traits::WalkFields for @Self { - fn walk_fields(&self, walk: &mut FnMut(&synstructure_test_traits::WalkFields)) { - match *self { #body } - } - } - }) -} - /// Generates code for an event definition. #[derive(From)] pub struct EventDefinition<'a> { - event_def: &'a ir::InkEventDefinition, + event_def: &'a ir::InkEventDefinition<'a>, } impl GenerateCode for EventDefinition<'_> { fn generate_code(&self) -> TokenStream2 { - let event_struct = self.generate_event_struct(); - let event_info_impl = self.generate_event_info_impl(); - let event_metadata_impl = self.generate_event_metadata_impl(); - let topics_impl = self.generate_topics_impl(); - let topics_guard = self.generate_topics_guard(); + let event_enum = self.generate_event_enum(); + // let event_info_impl = self.generate_event_info_impl(); + // let event_metadata_impl = self.generate_event_metadata_impl(); + let event_variants_impls = self.generate_event_variant_info_impls(); + let topics_impl = self.generate_topics_impl2(); + // let topics_guard = self.generate_topics_guard(); quote! { - #event_struct - #event_info_impl - #event_metadata_impl - #topics_impl - #topics_guard + #[derive(::scale::Encode, ::scale::Decode)] + #event_enum + // #event_info_impl + // #event_metadata_impl + // #topics_impl + // #topics_guard } } } impl<'a> EventDefinition<'a> { - fn generate_event_struct(&'a self) -> TokenStream2 { - let span = self.event_def.span(); - let event_enum = &self.event_def.item; + fn generate_event_enum(&'a self) -> TokenStream2 { + let span = self.event_def.structure.span(); + let event_enum = &self.event_def.structure.ast(); quote_spanned!(span => - #[derive(scale::Encode, scale::Decode)] + #[derive(::scale::Encode, ::scale::Decode)] #event_enum ) } @@ -85,12 +70,19 @@ impl<'a> EventDefinition<'a> { fn generate_event_variant_info_impls(&self) -> TokenStream2 { let span = self.event_def.span(); let event_ident = self.event_def.ident(); + let impls = - self.event_def.variants().map(|ev| { - let index = ev.index(); + self.event_def.structure.variants().iter().enumerate().map(|(index, ev)| { + let event_variant_ident = ev.ast().ident; quote_spanned!(span=> impl ::ink_lang::reflect::EventVariantInfo<#index> for #event_ident { - const SIGNATURE: [u8: 32] = todo!(); + const SIGNATURE: [u8: 32] = ::ink_lang::blake2x256!(::core::concat!( + ::core::module_path!(), + "::", + ::core::stringify!(#event_ident), + "::", + ::core::stringify!(#event_variant_ident) + )); } ) }); @@ -121,87 +113,91 @@ impl<'a> EventDefinition<'a> { ) } - /// Generates the `Topics` trait implementations for the user defined events. - fn generate_topics_impl(&self) -> TokenStream2 { - let span = self.event_def.span(); - let event_ident = self.event_def.ident(); - let len_topics = self - .event_def - .max_len_topics(); - let topic_impls = self - .event_def - .fields() - .enumerate() - .filter(|(_, field)| field.is_topic) - .map(|(n, topic_field)| { - let span = topic_field.span(); - let field_ident = topic_field - .ident() - .map(quote::ToTokens::into_token_stream) - .unwrap_or_else(|| quote_spanned!(span => #n)); - let field_type = topic_field.ty(); - quote_spanned!(span => - .push_topic::<::ink_env::topics::PrefixedValue<#field_type>>( - &::ink_env::topics::PrefixedValue { - // todo: deduplicate with EVENT_SIGNATURE - prefix: ::core::concat!( - ::core::module_path!(), - "::", - ::core::stringify!(#event_ident), - "::", - ::core::stringify!(#field_ident), - ).as_bytes(), - value: &self.#field_ident, - } - ) - ) - }); - // Only include topic for event signature in case of non-anonymous event. - let event_signature_topic = match self.event_def.anonymous { - true => None, - false => { - Some(quote_spanned!(span=> - .push_topic::<::ink_env::topics::PrefixedValue<()>>( - &::ink_env::topics::PrefixedValue { - prefix: EVENT_SIGNATURE, value: &(), - } - ) - )) - } - }; - // Anonymous events require 1 fewer topics since they do not include their signature. - let anonymous_topics_offset = if self.event_def.anonymous { 0 } else { 1 }; - let remaining_topics_ty = match len_topics + anonymous_topics_offset { - 0 => quote_spanned!(span=> ::ink_env::topics::state::NoRemainingTopics), - n => { - quote_spanned!(span=> [::ink_env::topics::state::HasRemainingTopics; #n]) - } - }; - quote_spanned!(span => - const _: () = { - impl ::ink_env::Topics for #event_ident { - type RemainingTopics = #remaining_topics_ty; - - fn topics( - &self, - builder: ::ink_env::topics::TopicsBuilder<::ink_env::topics::state::Uninit, E, B>, - ) -> >::Output - where - E: ::ink_env::Environment, - B: ::ink_env::topics::TopicsBuilderBackend, - { - const EVENT_SIGNATURE: &[u8] = <#event_ident as ::ink_lang::reflect::EventInfo>::PATH.as_bytes(); + fn generate_topics_impl2(&self) -> TokenStream2 { - builder - .build::() - #event_signature_topic - #( - #topic_impls - )* - .finish() - } - } - }; - ) } + + // /// Generates the `Topics` trait implementations for the user defined events. + // fn generate_topics_impl(&self) -> TokenStream2 { + // let span = self.event_def.span(); + // let event_ident = self.event_def.ident(); + // let len_topics = self + // .event_def + // .max_len_topics(); + // let topic_impls = self + // .event_def + // .fields() + // .enumerate() + // .filter(|(_, field)| field.is_topic) + // .map(|(n, topic_field)| { + // let span = topic_field.span(); + // let field_ident = topic_field + // .ident() + // .map(quote::ToTokens::into_token_stream) + // .unwrap_or_else(|| quote_spanned!(span => #n)); + // let field_type = topic_field.ty(); + // quote_spanned!(span => + // .push_topic::<::ink_env::topics::PrefixedValue<#field_type>>( + // &::ink_env::topics::PrefixedValue { + // // todo: deduplicate with EVENT_SIGNATURE + // prefix: ::core::concat!( + // ::core::module_path!(), + // "::", + // ::core::stringify!(#event_ident), + // "::", + // ::core::stringify!(#field_ident), + // ).as_bytes(), + // value: &self.#field_ident, + // } + // ) + // ) + // }); + // // Only include topic for event signature in case of non-anonymous event. + // let event_signature_topic = match self.event_def.anonymous { + // true => None, + // false => { + // Some(quote_spanned!(span=> + // .push_topic::<::ink_env::topics::PrefixedValue<()>>( + // &::ink_env::topics::PrefixedValue { + // prefix: EVENT_SIGNATURE, value: &(), + // } + // ) + // )) + // } + // }; + // // Anonymous events require 1 fewer topics since they do not include their signature. + // let anonymous_topics_offset = if self.event_def.anonymous { 0 } else { 1 }; + // let remaining_topics_ty = match len_topics + anonymous_topics_offset { + // 0 => quote_spanned!(span=> ::ink_env::topics::state::NoRemainingTopics), + // n => { + // quote_spanned!(span=> [::ink_env::topics::state::HasRemainingTopics; #n]) + // } + // }; + // quote_spanned!(span => + // const _: () = { + // impl ::ink_env::Topics for #event_ident { + // type RemainingTopics = #remaining_topics_ty; + // + // fn topics( + // &self, + // builder: ::ink_env::topics::TopicsBuilder<::ink_env::topics::state::Uninit, E, B>, + // ) -> >::Output + // where + // E: ::ink_env::Environment, + // B: ::ink_env::topics::TopicsBuilderBackend, + // { + // const EVENT_SIGNATURE: &[u8] = <#event_ident as ::ink_lang::reflect::EventInfo>::PATH.as_bytes(); + // + // builder + // .build::() + // #event_signature_topic + // #( + // #topic_impls + // )* + // .finish() + // } + // } + // }; + // ) + // } } diff --git a/crates/lang/ir/src/ir/event_def.rs b/crates/lang/ir/src/ir/event_def.rs index 72bb2631dc6..410f595a526 100644 --- a/crates/lang/ir/src/ir/event_def.rs +++ b/crates/lang/ir/src/ir/event_def.rs @@ -113,7 +113,7 @@ impl InkEventDefinition { /// Returns the identifier of the event struct. pub fn ident(&self) -> &Ident { - &self.item.ident + &self.structure.ast().ident } /// Returns all non-ink! attributes. From 1e5dae3f20ca2927bfca8934a511d97c09b5f818 Mon Sep 17 00:00:00 2001 From: ascjones Date: Tue, 6 Sep 2022 17:00:28 +0100 Subject: [PATCH 034/122] Revert previous work attempting to use synstructure --- .../lang/codegen/src/generator/event_def.rs | 15 +- .../codegen/src/generator/metadata/event.rs | 40 +++--- crates/lang/ir/Cargo.toml | 1 - crates/lang/ir/src/ir/event_def.rs | 130 +++++++++--------- crates/lang/macro/Cargo.toml | 1 - crates/lang/macro/src/event_def.rs | 6 +- crates/lang/macro/src/lib.rs | 5 +- crates/lang/tests/unique_topics.rs | 24 ++-- 8 files changed, 118 insertions(+), 104 deletions(-) diff --git a/crates/lang/codegen/src/generator/event_def.rs b/crates/lang/codegen/src/generator/event_def.rs index 60f9c7761bb..0864e05a082 100644 --- a/crates/lang/codegen/src/generator/event_def.rs +++ b/crates/lang/codegen/src/generator/event_def.rs @@ -25,7 +25,7 @@ use syn::spanned::Spanned as _; /// Generates code for an event definition. #[derive(From)] pub struct EventDefinition<'a> { - event_def: &'a ir::InkEventDefinition<'a>, + event_def: &'a ir::InkEventDefinition, } impl GenerateCode for EventDefinition<'_> { @@ -49,8 +49,8 @@ impl GenerateCode for EventDefinition<'_> { impl<'a> EventDefinition<'a> { fn generate_event_enum(&'a self) -> TokenStream2 { - let span = self.event_def.structure.span(); - let event_enum = &self.event_def.structure.ast(); + let span = self.event_def.item.span(); + let event_enum = &self.event_def.item; quote_spanned!(span => #[derive(::scale::Encode, ::scale::Decode)] #event_enum @@ -72,8 +72,9 @@ impl<'a> EventDefinition<'a> { let event_ident = self.event_def.ident(); let impls = - self.event_def.structure.variants().iter().enumerate().map(|(index, ev)| { - let event_variant_ident = ev.ast().ident; + self.event_def.variants().map(|ev| { + let event_variant_ident = ev.ident(); + let index = ev.index(); quote_spanned!(span=> impl ::ink_lang::reflect::EventVariantInfo<#index> for #event_ident { const SIGNATURE: [u8: 32] = ::ink_lang::blake2x256!(::core::concat!( @@ -114,7 +115,9 @@ impl<'a> EventDefinition<'a> { } fn generate_topics_impl2(&self) -> TokenStream2 { - + let span = self.event_def.span(); + quote_spanned!(span => + ) } // /// Generates the `Topics` trait implementations for the user defined events. diff --git a/crates/lang/codegen/src/generator/metadata/event.rs b/crates/lang/codegen/src/generator/metadata/event.rs index b58530e4b5f..0b05f230fd7 100644 --- a/crates/lang/codegen/src/generator/metadata/event.rs +++ b/crates/lang/codegen/src/generator/metadata/event.rs @@ -35,25 +35,27 @@ impl GenerateCode for EventMetadata<'_> { .attrs() .iter() .filter_map(|attr| attr.extract_docs()); - let args = self.event_def.fields().map(|event_field| { - let span = event_field.span(); - let ident = event_field.ident(); - let is_topic = event_field.is_topic; - let docs = event_field - .attrs() - .into_iter() - .filter_map(|attr| attr.extract_docs()); - let ty = super::generate_type_spec(event_field.ty()); - quote_spanned!(span => - ::ink_metadata::EventParamSpec::new(::core::stringify!(#ident)) - .of_type(#ty) - .indexed(#is_topic) - .docs([ - #( #docs ),* - ]) - .done() - ) - }); + // let args = self.event_def.fields().map(|event_field| { + // let span = event_field.span(); + // let ident = event_field.ident(); + // let is_topic = event_field.is_topic; + // let docs = event_field + // .attrs() + // .into_iter() + // .filter_map(|attr| attr.extract_docs()); + // let ty = super::generate_type_spec(event_field.ty()); + // quote_spanned!(span => + // ::ink_metadata::EventParamSpec::new(::core::stringify!(#ident)) + // .of_type(#ty) + // .indexed(#is_topic) + // .docs([ + // #( #docs ),* + // ]) + // .done() + // ) + // }); + // todo generate event metadata + let args = Vec::::new(); quote_spanned!(span=> #[cfg(feature = "std")] #[cfg(not(feature = "ink-as-dependency"))] diff --git a/crates/lang/ir/Cargo.toml b/crates/lang/ir/Cargo.toml index 9b3ad764ab1..3e89ad57424 100644 --- a/crates/lang/ir/Cargo.toml +++ b/crates/lang/ir/Cargo.toml @@ -21,7 +21,6 @@ name = "ink_lang_ir" ink_storage_codegen = { version = "4.0.0-alpha.1", path = "../../storage/codegen" } quote = "1" syn = { version = "1.0", features = ["parsing", "full", "visit", "extra-traits"] } -synstructure = "0.12.6" proc-macro2 = "1.0" itertools = { version = "0.10", default-features = false } either = { version = "1.5", default-features = false } diff --git a/crates/lang/ir/src/ir/event_def.rs b/crates/lang/ir/src/ir/event_def.rs index 410f595a526..0aa30702d7c 100644 --- a/crates/lang/ir/src/ir/event_def.rs +++ b/crates/lang/ir/src/ir/event_def.rs @@ -29,91 +29,94 @@ use syn::{ /// A checked ink! event definition. #[derive(Debug, PartialEq, Eq)] -pub struct InkEventDefinition<'a> { - pub structure: synstructure::Structure<'a>, +pub struct InkEventDefinition { + pub item: syn::ItemEnum, pub anonymous: bool, } -// impl TryFrom for InkEventDefinition { -// type Error = syn::Error; -// -// fn try_from(item_enum: syn::ItemEnum) -> Result { -// let enum_span = item_enum.span(); -// let (ink_attrs, other_attrs) = ir::sanitize_attributes( -// enum_span, -// item_enum.attrs, -// &ir::AttributeArgKind::Event, -// |arg| { -// match arg.kind() { -// ir::AttributeArg::Event | ir::AttributeArg::Anonymous => Ok(()), -// _ => Err(None), -// } -// }, -// )?; -// let item_enum = syn::ItemEnum { -// attrs: other_attrs, -// ..item_enum -// }; -// Self::new(item_enum, ink_attrs.is_anonymous()) -// } -// } +impl TryFrom for InkEventDefinition { + type Error = syn::Error; + + fn try_from(item_enum: syn::ItemEnum) -> Result { + let enum_span = item_enum.span(); + let (ink_attrs, other_attrs) = ir::sanitize_attributes( + enum_span, + item_enum.attrs, + &ir::AttributeArgKind::Event, + |arg| { + match arg.kind() { + ir::AttributeArg::Event | ir::AttributeArg::Anonymous => Ok(()), + _ => Err(None), + } + }, + )?; + let item_enum = syn::ItemEnum { + attrs: other_attrs, + ..item_enum + }; + Self::new(item_enum, ink_attrs.is_anonymous()) + } +} impl quote::ToTokens for InkEventDefinition { /// We mainly implement this trait for this ink! type to have a derived /// [`Spanned`](`syn::spanned::Spanned`) implementation for it. fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { - self.structure.ast().to_tokens(tokens) + self.item.to_tokens(tokens) } } impl InkEventDefinition { /// Returns `Ok` if the input matches all requirements for an ink! event definition. - pub fn new(structure: synstructure::Structure, anonymous: bool) -> Result { - // for variant in structure.variants() { - // 'repeat: for field in variant.ast().fields { - // let field_span = field.span(); - // let (ink_attrs, _) = ir::partition_attributes(field.attrs.clone())?; - // if ink_attrs.is_empty() { - // continue 'repeat - // } - // let normalized = - // ir::InkAttribute::from_expanded(ink_attrs).map_err(|err| { - // err.into_combine(format_err!(field_span, "at this invocation",)) - // })?; - // if !matches!(normalized.first().kind(), ir::AttributeArg::Topic) { - // return Err(format_err!( - // field_span, - // "first optional ink! attribute of an event field must be #[ink(topic)]", - // )) - // } - // for arg in normalized.args() { - // if !matches!(arg.kind(), ir::AttributeArg::Topic) { - // return Err(format_err!( - // arg.span(), - // "encountered conflicting ink! attribute for event field", - // )) - // } - // } - // } - // } + pub fn new(item: syn::ItemEnum, anonymous: bool) -> Result { + for variant in item.variants.iter() { + 'repeat: for field in variant.fields.iter() { + let field_span = field.span(); + let (ink_attrs, _) = ir::partition_attributes(field.attrs.clone())?; + if ink_attrs.is_empty() { + continue 'repeat + } + let normalized = + ir::InkAttribute::from_expanded(ink_attrs).map_err(|err| { + err.into_combine(format_err!(field_span, "at this invocation",)) + })?; + if !matches!(normalized.first().kind(), ir::AttributeArg::Topic) { + return Err(format_err!( + field_span, + "first optional ink! attribute of an event field must be #[ink(topic)]", + )) + } + for arg in normalized.args() { + if !matches!(arg.kind(), ir::AttributeArg::Topic) { + return Err(format_err!( + arg.span(), + "encountered conflicting ink! attribute for event field", + )) + } + } + } + } Ok(Self { - structure, + item, anonymous, }) } - pub fn from_structure( - attr: TokenStream2, - structure: synstructure::Structure, + /// Returns `Ok` if the input matches all requirements for an ink! event definition. + pub fn from_event_def_tokens( + config: TokenStream2, + input: TokenStream2, ) -> Result { let _parsed_config = syn::parse2::(config)?; let anonymous = false; // todo parse this from attr config - Self::new(structure, anonymous) + let item = syn::parse2::(input)?; + // let item = InkItemTrait::new(&config, parsed_item)?; + Ok(Self { anonymous, item }) } /// Returns the identifier of the event struct. pub fn ident(&self) -> &Ident { - &self.structure.ast().ident + &self.item.ident } /// Returns all non-ink! attributes. @@ -129,9 +132,7 @@ impl InkEventDefinition { /// Returns the maximum number of topics of any event variant. pub fn max_len_topics(&self) -> usize { self - .structure .variants() - .iter() .map(|v| v.fields() .filter(|event| event.is_topic) .count()) @@ -147,6 +148,11 @@ pub struct EventVariant<'a> { } impl<'a> EventVariant<'a> { + /// The identifier of the event variant. + pub fn ident(&self) -> &Ident { + &self.item.ident + } + /// The index of the the event variant in the enum definition. pub fn index(&self) -> usize { self.index diff --git a/crates/lang/macro/Cargo.toml b/crates/lang/macro/Cargo.toml index a03a7ced945..891c4970e89 100644 --- a/crates/lang/macro/Cargo.toml +++ b/crates/lang/macro/Cargo.toml @@ -21,7 +21,6 @@ ink_primitives = { version = "4.0.0-alpha.1", path = "../../primitives/", defaul scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } syn = "1" -synstructure = "0.12.6" proc-macro2 = "1" [dev-dependencies] diff --git a/crates/lang/macro/src/event_def.rs b/crates/lang/macro/src/event_def.rs index 142ff933d92..3085f38503d 100644 --- a/crates/lang/macro/src/event_def.rs +++ b/crates/lang/macro/src/event_def.rs @@ -16,8 +16,8 @@ use ink_lang_codegen::generate_code; use proc_macro2::TokenStream as TokenStream2; use syn::Result; -pub fn generate(attr: TokenStream2, structure: synstructure::Structure) -> TokenStream2 { - match generate_or_err(attr, structure) { +pub fn generate(attr: TokenStream2, item: TokenStream2) -> TokenStream2 { + match generate_or_err(attr, item) { Ok(tokens) => tokens, Err(err) => err.to_compile_error(), } @@ -25,7 +25,7 @@ pub fn generate(attr: TokenStream2, structure: synstructure::Structure) -> Token pub fn generate_or_err( config: TokenStream2, - structure: synstructure::Structure, + input: TokenStream2, ) -> Result { let trait_definition = ink_lang_ir::InkEventDefinition::from_event_def_tokens(config, input)?; diff --git a/crates/lang/macro/src/lib.rs b/crates/lang/macro/src/lib.rs index d59e9c0a658..f2090cb2378 100644 --- a/crates/lang/macro/src/lib.rs +++ b/crates/lang/macro/src/lib.rs @@ -668,7 +668,10 @@ pub fn trait_definition(attr: TokenStream, item: TokenStream) -> TokenStream { } /// todo derive Event docs -synstructure::decl_attribute!([event_definition] => event_def::generate); +#[proc_macro_attribute] +pub fn event_definition(attr: TokenStream, item: TokenStream) -> TokenStream { + event_def::generate(attr.into(), item.into()).into() +} /// Prepares the type to be fully compatible and usable with the storage. /// It implements all necessary traits and calculates the storage key for types. diff --git a/crates/lang/tests/unique_topics.rs b/crates/lang/tests/unique_topics.rs index 2501ba46dd8..c4bf262393c 100644 --- a/crates/lang/tests/unique_topics.rs +++ b/crates/lang/tests/unique_topics.rs @@ -28,16 +28,18 @@ mod my_contract { pub struct MyContract {} /// Exemplary event - #[ink(event)] - pub struct MyEvent { - #[ink(topic)] - v0: Option, - #[ink(topic)] - v1: Balance, - #[ink(topic)] - v2: bool, - #[ink(topic)] - v3: bool, + #[ink::event_definition] + pub enum Event { + MyEvent { + #[ink(topic)] + v0: Option, + #[ink(topic)] + v1: Balance, + #[ink(topic)] + v2: bool, + #[ink(topic)] + v3: bool + } } impl MyContract { @@ -50,7 +52,7 @@ mod my_contract { /// Emits a `MyEvent`. #[ink(message)] pub fn emit_my_event(&self) { - self.env().emit_event(MyEvent { + self.env().emit_event(Event::MyEvent { v0: None, v1: 0, v2: false, From 65a8822fcef2ab05bde5f3b9be0b76b6cbdbf8a8 Mon Sep 17 00:00:00 2001 From: ascjones Date: Tue, 6 Sep 2022 17:30:49 +0100 Subject: [PATCH 035/122] Restore wiring for inline contract events --- crates/lang/ir/src/ir/item/mod.rs | 39 ++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/crates/lang/ir/src/ir/item/mod.rs b/crates/lang/ir/src/ir/item/mod.rs index b987050eb1e..5aaf3579c08 100644 --- a/crates/lang/ir/src/ir/item/mod.rs +++ b/crates/lang/ir/src/ir/item/mod.rs @@ -80,12 +80,25 @@ impl TryFrom for Item { } } syn::Item::Enum(item_enum) => { - todo!("recognise ink::event_definition or simply ink(event) still") - // ir::AttributeArg::Event => { - // >::try_from(item_struct) - // .map(Into::into) - // .map(Self::Ink) - // } + // todo: dedup this with similar struct code above + if !ir::contains_ink_attributes(&item_enum.attrs) { + return Ok(Self::Rust(item_enum.into())) + } + let attr = ir::first_ink_attribute(&item_enum.attrs)? + .expect("missing expected ink! attribute for struct"); + match attr.first().kind() { + ir::AttributeArg::Event => { + >::try_from(item_enum) + .map(Into::into) + .map(Self::Ink) + } + _invalid => { + Err(format_err!( + attr.span(), + "encountered unsupported ink! attribute argument an enum", + )) + } + } } syn::Item::Impl(item_impl) => { if !ir::ItemImpl::is_ink_impl_block(&item_impl)? { @@ -154,7 +167,7 @@ impl Item { #[derive(Debug, PartialEq, Eq)] pub enum InkItem { /// The ink! storage struct definition. - Storage(ir::Storage), + Storage(Storage), /// An ink! event definition. Event(InkEventDefinition), /// An ink! implementation block. @@ -221,18 +234,18 @@ impl From for InkItem { } } -impl From for InkItem { - fn from(event: InkEventDefinition) -> Self { - Self::Event(event) - } -} - impl From for InkItem { fn from(impl_block: ir::ItemImpl) -> Self { Self::ImplBlock(impl_block) } } +impl From for InkItem { + fn from(event_def: InkEventDefinition) -> Self { + Self::Event(event_def) + } +} + impl InkItem { /// Returns `Some` if `self` is the ink! storage struct definition. /// From 873597884bc14d90fd7c74925e6136b28316c467 Mon Sep 17 00:00:00 2001 From: ascjones Date: Tue, 6 Sep 2022 21:44:48 +0100 Subject: [PATCH 036/122] WIP generating event enum impls --- .../lang/codegen/src/generator/event_def.rs | 3 +- crates/lang/ir/src/ir/event_def.rs | 108 +++++++++--------- crates/lang/tests/unique_topics.rs | 2 +- examples/erc20/lib.rs | 35 +++--- 4 files changed, 76 insertions(+), 72 deletions(-) diff --git a/crates/lang/codegen/src/generator/event_def.rs b/crates/lang/codegen/src/generator/event_def.rs index 0864e05a082..9cc28449827 100644 --- a/crates/lang/codegen/src/generator/event_def.rs +++ b/crates/lang/codegen/src/generator/event_def.rs @@ -37,7 +37,6 @@ impl GenerateCode for EventDefinition<'_> { let topics_impl = self.generate_topics_impl2(); // let topics_guard = self.generate_topics_guard(); quote! { - #[derive(::scale::Encode, ::scale::Decode)] #event_enum // #event_info_impl // #event_metadata_impl @@ -49,7 +48,7 @@ impl GenerateCode for EventDefinition<'_> { impl<'a> EventDefinition<'a> { fn generate_event_enum(&'a self) -> TokenStream2 { - let span = self.event_def.item.span(); + let span = self.event_def.span(); let event_enum = &self.event_def.item; quote_spanned!(span => #[derive(::scale::Encode, ::scale::Decode)] diff --git a/crates/lang/ir/src/ir/event_def.rs b/crates/lang/ir/src/ir/event_def.rs index 0aa30702d7c..371db41b4cc 100644 --- a/crates/lang/ir/src/ir/event_def.rs +++ b/crates/lang/ir/src/ir/event_def.rs @@ -31,6 +31,7 @@ use syn::{ #[derive(Debug, PartialEq, Eq)] pub struct InkEventDefinition { pub item: syn::ItemEnum, + variants: Vec, pub anonymous: bool, } @@ -68,36 +69,40 @@ impl quote::ToTokens for InkEventDefinition { impl InkEventDefinition { /// Returns `Ok` if the input matches all requirements for an ink! event definition. - pub fn new(item: syn::ItemEnum, anonymous: bool) -> Result { - for variant in item.variants.iter() { - 'repeat: for field in variant.fields.iter() { - let field_span = field.span(); - let (ink_attrs, _) = ir::partition_attributes(field.attrs.clone())?; - if ink_attrs.is_empty() { - continue 'repeat - } - let normalized = - ir::InkAttribute::from_expanded(ink_attrs).map_err(|err| { - err.into_combine(format_err!(field_span, "at this invocation",)) - })?; - if !matches!(normalized.first().kind(), ir::AttributeArg::Topic) { - return Err(format_err!( - field_span, - "first optional ink! attribute of an event field must be #[ink(topic)]", - )) - } - for arg in normalized.args() { - if !matches!(arg.kind(), ir::AttributeArg::Topic) { - return Err(format_err!( - arg.span(), - "encountered conflicting ink! attribute for event field", - )) - } - } + pub fn new(mut item: syn::ItemEnum, anonymous: bool) -> Result { + let mut variants = Vec::new(); + for (index, variant) in item.variants.iter_mut().enumerate() { + let mut fields = Vec::new(); + for field in variant.fields.iter_mut() { + let (topic_attr, other_attrs) = ir::sanitize_optional_attributes( + field.span(), + field.attrs.clone(), + |arg| { + match arg.kind() { + ir::AttributeArg::Topic => Ok(()), + _ => Err(None), + } + }, + )?; + // strip out the `#[ink(topic)] attributes, since the item will be used to + // regenerate the event enum + field.attrs = other_attrs; + fields.push(EventField { + is_topic: topic_attr.is_some(), + field: field.clone(), + }) } + let named_fields = matches!(variant.fields, syn::Fields::Named(_)); + variants.push(EventVariant { + index, + ident: variant.ident.clone(), + named_fields, + fields + }) } Ok(Self { item, + variants, anonymous, }) } @@ -111,7 +116,7 @@ impl InkEventDefinition { let anonymous = false; // todo parse this from attr config let item = syn::parse2::(input)?; // let item = InkItemTrait::new(&config, parsed_item)?; - Ok(Self { anonymous, item }) + Self::new(item, anonymous) } /// Returns the identifier of the event struct. @@ -119,14 +124,18 @@ impl InkEventDefinition { &self.item.ident } + pub fn span(&self) -> Span { + self.item.span() + } + /// Returns all non-ink! attributes. pub fn attrs(&self) -> &[syn::Attribute] { &self.item.attrs } /// Returns all event variants. - pub fn variants(&self) -> impl Iterator> { - self.item.variants.iter().enumerate().map(|(i, v) | EventVariant { index: i, item: v}) + pub fn variants(&self) -> impl Iterator { + self.variants.iter() } /// Returns the maximum number of topics of any event variant. @@ -142,15 +151,18 @@ impl InkEventDefinition { } /// A variant of an event. -pub struct EventVariant<'a> { +#[derive(Debug, PartialEq, Eq)] +pub struct EventVariant { index: usize, - item: &'a syn::Variant, + ident: Ident, + named_fields: bool, + fields: Vec, } -impl<'a> EventVariant<'a> { +impl EventVariant { /// The identifier of the event variant. pub fn ident(&self) -> &Ident { - &self.item.ident + &self.ident } /// The index of the the event variant in the enum definition. @@ -160,53 +172,45 @@ impl<'a> EventVariant<'a> { /// Returns an iterator yielding all the `#[ink(topic)]` annotated fields /// of the event variant struct. - pub fn fields(&self) -> impl Iterator> { - self.item.fields - .iter() - .map(|field| { - let is_topic = ir::first_ink_attribute(&field.attrs) - .unwrap_or_default() - .map(|attr| matches!(attr.first().kind(), ir::AttributeArg::Topic)) - .unwrap_or_default(); - EventField { is_topic, field } - }) + pub fn fields(&self) -> impl Iterator { + self.fields.iter() } } /// An event field with a flag indicating if this field is an event topic. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct EventField<'a> { +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct EventField { /// The associated `field` is an event topic if this is `true`. pub is_topic: bool, /// The event field. - field: &'a syn::Field, + field: syn::Field, } -impl<'a> EventField<'a> { +impl EventField { /// Returns the span of the event field. - pub fn span(self) -> Span { + pub fn span(&self) -> Span { self.field.span() } /// Returns all non-ink! attributes of the event field. - pub fn attrs(self) -> Vec { + pub fn attrs(&self) -> Vec { let (_, non_ink_attrs) = ir::partition_attributes(self.field.attrs.clone()) .expect("encountered invalid event field attributes"); non_ink_attrs } /// Returns the visibility of the event field. - pub fn vis(self) -> &'a syn::Visibility { + pub fn vis(&self) -> &syn::Visibility { &self.field.vis } /// Returns the identifier of the event field if any. - pub fn ident(self) -> Option<&'a Ident> { + pub fn ident(&self) -> Option<&Ident> { self.field.ident.as_ref() } /// Returns the type of the event field. - pub fn ty(self) -> &'a syn::Type { + pub fn ty(&self) -> &syn::Type { &self.field.ty } } diff --git a/crates/lang/tests/unique_topics.rs b/crates/lang/tests/unique_topics.rs index c4bf262393c..45874d5c283 100644 --- a/crates/lang/tests/unique_topics.rs +++ b/crates/lang/tests/unique_topics.rs @@ -28,7 +28,7 @@ mod my_contract { pub struct MyContract {} /// Exemplary event - #[ink::event_definition] + #[ink(event)] pub enum Event { MyEvent { #[ink(topic)] diff --git a/examples/erc20/lib.rs b/examples/erc20/lib.rs index fc411ad57e3..cb4eb0d59e5 100644 --- a/examples/erc20/lib.rs +++ b/examples/erc20/lib.rs @@ -19,25 +19,26 @@ mod erc20 { allowances: Mapping<(AccountId, AccountId), Balance>, } - /// Event emitted when a token transfer occurs. - #[ink(event)] - pub struct Transfer { - #[ink(topic)] - from: Option, - #[ink(topic)] - to: Option, - value: Balance, - } - /// Event emitted when an approval occurs that `spender` is allowed to withdraw - /// up to the amount of `value` tokens from `owner`. #[ink(event)] - pub struct Approval { - #[ink(topic)] - owner: AccountId, - #[ink(topic)] - spender: AccountId, - value: Balance, + pub enum Event { + /// Event emitted when a token transfer occurs. + Transfer { + #[ink(topic)] + from: Option, + #[ink(topic)] + to: Option, + value: Balance, + }, + /// Event emitted when an approval occurs that `spender` is allowed to withdraw + /// up to the amount of `value` tokens from `owner`. + Approval { + #[ink(topic)] + owner: AccountId, + #[ink(topic)] + spender: AccountId, + value: Balance, + } } /// The ERC-20 error types. From 6663383e9ae0c6e4a438b4cee83f3817e3c5332d Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 28 Sep 2022 10:04:41 +0100 Subject: [PATCH 037/122] Fix event def after merge --- crates/ink/ir/src/ir/event_def.rs | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/crates/ink/ir/src/ir/event_def.rs b/crates/ink/ir/src/ir/event_def.rs index 31c5b6f2ec1..4d263263dfd 100644 --- a/crates/ink/ir/src/ir/event_def.rs +++ b/crates/ink/ir/src/ir/event_def.rs @@ -27,26 +27,7 @@ use syn::{ Result, }; -<<<<<<<< HEAD:crates/ink/ir/src/ir/event_def.rs -/// A checked ink! event definition. -======== -/// An ink! event struct definition. -/// -/// # Example -/// -/// ``` -/// # let event = >::try_from(syn::parse_quote! { -/// #[ink(event)] -/// pub struct Transaction { -/// #[ink(topic)] -/// from: AccountId, -/// #[ink(topic)] -/// to: AccountId, -/// value: Balance, -/// } -/// # }).unwrap(); -/// ``` ->>>>>>>> master:crates/ink/ir/src/ir/item/event.rs +/// An ink! event enum definition. #[derive(Debug, PartialEq, Eq)] pub struct InkEventDefinition { pub item: syn::ItemEnum, From 090219d39dccdc7586acbc72f5bb013c63e9775e Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 28 Sep 2022 10:10:11 +0100 Subject: [PATCH 038/122] Fmt --- crates/ink/ir/src/ir/event_def.rs | 9 +++------ crates/ink/ir/src/ir/mod.rs | 2 +- crates/ink/tests/unique_topics.rs | 4 ++-- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/crates/ink/ir/src/ir/event_def.rs b/crates/ink/ir/src/ir/event_def.rs index 4d263263dfd..9eb20b1bf5b 100644 --- a/crates/ink/ir/src/ir/event_def.rs +++ b/crates/ink/ir/src/ir/event_def.rs @@ -97,7 +97,7 @@ impl InkEventDefinition { index, ident: variant.ident.clone(), named_fields, - fields + fields, }) } Ok(Self { @@ -140,11 +140,8 @@ impl InkEventDefinition { /// Returns the maximum number of topics of any event variant. pub fn max_len_topics(&self) -> usize { - self - .variants() - .map(|v| v.fields() - .filter(|event| event.is_topic) - .count()) + self.variants() + .map(|v| v.fields().filter(|event| event.is_topic).count()) .max() .unwrap_or_default() } diff --git a/crates/ink/ir/src/ir/mod.rs b/crates/ink/ir/src/ir/mod.rs index 455a7b619db..b213a961a18 100644 --- a/crates/ink/ir/src/ir/mod.rs +++ b/crates/ink/ir/src/ir/mod.rs @@ -71,8 +71,8 @@ pub use self::{ config::Config, contract::Contract, e2e_config::E2EConfig, - ink_e2e_test::InkE2ETest, event_def::InkEventDefinition, + ink_e2e_test::InkE2ETest, ink_test::InkTest, item::{ InkItem, diff --git a/crates/ink/tests/unique_topics.rs b/crates/ink/tests/unique_topics.rs index e15447063af..2dbf7f4eddf 100644 --- a/crates/ink/tests/unique_topics.rs +++ b/crates/ink/tests/unique_topics.rs @@ -30,8 +30,8 @@ mod my_contract { #[ink(topic)] v2: bool, #[ink(topic)] - v3: bool - } + v3: bool, + }, } impl MyContract { From 21897194b2484c6366bdb2b8a342e5b3aa77e548 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 28 Sep 2022 11:06:51 +0100 Subject: [PATCH 039/122] Recover changes from master --- .../ink/codegen/src/generator/metadata/mod.rs | 40 +++---------------- 1 file changed, 5 insertions(+), 35 deletions(-) diff --git a/crates/ink/codegen/src/generator/metadata/mod.rs b/crates/ink/codegen/src/generator/metadata/mod.rs index 9a0ee47bc99..63e19b262dc 100644 --- a/crates/ink/codegen/src/generator/metadata/mod.rs +++ b/crates/ink/codegen/src/generator/metadata/mod.rs @@ -157,7 +157,7 @@ impl Metadata<'_> { syn::Pat::Ident(ident) => &ident.ident, _ => unreachable!("encountered ink! dispatch input with missing identifier"), }; - let type_spec = generate_type_spec(&pat_type.ty); + let type_spec = Self::generate_type_spec(&pat_type.ty); quote! { ::ink::metadata::MessageParamSpec::new(::core::stringify!(#ident)) .of_type(#type_spec) @@ -325,10 +325,9 @@ impl Metadata<'_> { self.contract.module().events().map(|event| { let span = event.span(); let ident = event.ident(); + let docs = event.attrs().iter().filter_map(|attr| attr.extract_docs()); + let args = Self::generate_event_args(event); quote_spanned!(span => -<<<<<<<< HEAD:crates/ink/codegen/src/generator/metadata/mod.rs - <#ident as ::ink_metadata::EventMetadata>::event_spec() -======== ::ink::metadata::EventSpec::new(::core::stringify!(#ident)) .args([ #( #args ),* @@ -337,36 +336,10 @@ impl Metadata<'_> { #( #docs ),* ]) .done() ->>>>>>>> master:crates/ink/codegen/src/generator/metadata.rs ) }) } -} -<<<<<<<< HEAD:crates/ink/codegen/src/generator/metadata/mod.rs -/// Generates the ink! metadata for the given type. -pub fn generate_type_spec(ty: &syn::Type) -> TokenStream2 { - fn without_display_name(ty: &syn::Type) -> TokenStream2 { - quote! { ::ink_metadata::TypeSpec::new::<#ty>() } - } - if let syn::Type::Path(type_path) = ty { - if type_path.qself.is_some() { - return without_display_name(ty) - } - let path = &type_path.path; - if path.segments.is_empty() { - return without_display_name(ty) - } - let segs = path - .segments - .iter() - .map(|seg| &seg.ident) - .collect::>(); - quote! { - ::ink_metadata::TypeSpec::with_name_segs::<#ty, _>( - ::core::iter::IntoIterator::into_iter([ #( ::core::stringify!(#segs) ),* ]) - .map(::core::convert::AsRef::as_ref) -======== /// Generate ink! metadata for a single argument of an ink! event definition. fn generate_event_args(event: &ir::Event) -> impl Iterator + '_ { event.fields().map(|event_field| { @@ -386,11 +359,8 @@ pub fn generate_type_spec(ty: &syn::Type) -> TokenStream2 { #( #docs ),* ]) .done() ->>>>>>>> master:crates/ink/codegen/src/generator/metadata.rs ) - } - } else { - without_display_name(ty) + }) } } @@ -431,7 +401,7 @@ mod tests { * may span many, * many lines " - .to_string()], + .to_string()], ); assert_eq!( extract_doc_attributes(&[ From 42dc29687894b5bd4e408567de21c10b04d581d7 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 28 Sep 2022 11:17:26 +0100 Subject: [PATCH 040/122] Fix up metadata compilation --- .../ink/codegen/src/generator/metadata/mod.rs | 48 +------------------ 1 file changed, 1 insertion(+), 47 deletions(-) diff --git a/crates/ink/codegen/src/generator/metadata/mod.rs b/crates/ink/codegen/src/generator/metadata/mod.rs index 63e19b262dc..750dc706eef 100644 --- a/crates/ink/codegen/src/generator/metadata/mod.rs +++ b/crates/ink/codegen/src/generator/metadata/mod.rs @@ -86,7 +86,7 @@ impl Metadata<'_> { fn generate_contract(&self) -> TokenStream2 { let constructors = self.generate_constructors(); let messages = self.generate_messages(); - let events = self.generate_events(); + // let events = self.generate_events(); let docs = self .contract .module() @@ -101,9 +101,6 @@ impl Metadata<'_> { .messages([ #( #messages ),* ]) - .events([ - #( #events ),* - ]) .docs([ #( #docs ),* ]) @@ -319,49 +316,6 @@ impl Metadata<'_> { } } } - - /// Generates ink! metadata for all user provided ink! event definitions. - fn generate_events(&self) -> impl Iterator + '_ { - self.contract.module().events().map(|event| { - let span = event.span(); - let ident = event.ident(); - let docs = event.attrs().iter().filter_map(|attr| attr.extract_docs()); - let args = Self::generate_event_args(event); - quote_spanned!(span => - ::ink::metadata::EventSpec::new(::core::stringify!(#ident)) - .args([ - #( #args ),* - ]) - .docs([ - #( #docs ),* - ]) - .done() - ) - }) - } - - /// Generate ink! metadata for a single argument of an ink! event definition. - fn generate_event_args(event: &ir::Event) -> impl Iterator + '_ { - event.fields().map(|event_field| { - let span = event_field.span(); - let ident = event_field.ident(); - let is_topic = event_field.is_topic; - let docs = event_field - .attrs() - .into_iter() - .filter_map(|attr| attr.extract_docs()); - let ty = Self::generate_type_spec(event_field.ty()); - quote_spanned!(span => - ::ink::metadata::EventParamSpec::new(::core::stringify!(#ident)) - .of_type(#ty) - .indexed(#is_topic) - .docs([ - #( #docs ),* - ]) - .done() - ) - }) - } } #[cfg(test)] From 3be3025698158f509498457c0265358def61f564 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 28 Sep 2022 11:21:58 +0100 Subject: [PATCH 041/122] Fmt --- crates/ink/codegen/src/generator/event_def.rs | 35 +++++++++---------- crates/ink/codegen/src/generator/events.rs | 4 +-- .../ink/codegen/src/generator/metadata/mod.rs | 2 +- 3 files changed, 18 insertions(+), 23 deletions(-) diff --git a/crates/ink/codegen/src/generator/event_def.rs b/crates/ink/codegen/src/generator/event_def.rs index 9cc28449827..f016c68d0f3 100644 --- a/crates/ink/codegen/src/generator/event_def.rs +++ b/crates/ink/codegen/src/generator/event_def.rs @@ -70,22 +70,21 @@ impl<'a> EventDefinition<'a> { let span = self.event_def.span(); let event_ident = self.event_def.ident(); - let impls = - self.event_def.variants().map(|ev| { - let event_variant_ident = ev.ident(); - let index = ev.index(); - quote_spanned!(span=> - impl ::ink_lang::reflect::EventVariantInfo<#index> for #event_ident { - const SIGNATURE: [u8: 32] = ::ink_lang::blake2x256!(::core::concat!( - ::core::module_path!(), - "::", - ::core::stringify!(#event_ident), - "::", - ::core::stringify!(#event_variant_ident) - )); - } - ) - }); + let impls = self.event_def.variants().map(|ev| { + let event_variant_ident = ev.ident(); + let index = ev.index(); + quote_spanned!(span=> + impl ::ink_lang::reflect::EventVariantInfo<#index> for #event_ident { + const SIGNATURE: [u8: 32] = ::ink_lang::blake2x256!(::core::concat!( + ::core::module_path!(), + "::", + ::core::stringify!(#event_ident), + "::", + ::core::stringify!(#event_variant_ident) + )); + } + ) + }); quote_spanned!(span=> #( #impls @@ -102,9 +101,7 @@ impl<'a> EventDefinition<'a> { fn generate_topics_guard(&self) -> TokenStream2 { let span = self.event_def.span(); let event_ident = self.event_def.ident(); - let len_topics = self - .event_def - .max_len_topics(); + let len_topics = self.event_def.max_len_topics(); quote_spanned!(span=> impl ::ink_lang::codegen::EventLenTopics for #event_ident { diff --git a/crates/ink/codegen/src/generator/events.rs b/crates/ink/codegen/src/generator/events.rs index 3ddbb52f6da..77dcf055757 100644 --- a/crates/ink/codegen/src/generator/events.rs +++ b/crates/ink/codegen/src/generator/events.rs @@ -18,9 +18,7 @@ use crate::{ }; use derive_more::From; use proc_macro2::TokenStream as TokenStream2; -use quote::{ - quote, -}; +use quote::quote; /// Generates code for the ink! event structs of the contract. #[derive(From)] diff --git a/crates/ink/codegen/src/generator/metadata/mod.rs b/crates/ink/codegen/src/generator/metadata/mod.rs index 750dc706eef..f1930cbeb4b 100644 --- a/crates/ink/codegen/src/generator/metadata/mod.rs +++ b/crates/ink/codegen/src/generator/metadata/mod.rs @@ -355,7 +355,7 @@ mod tests { * may span many, * many lines " - .to_string()], + .to_string()], ); assert_eq!( extract_doc_attributes(&[ From a1ac0b457334d6e6c34f6cf45867ebfbd1889328 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 29 Sep 2022 09:39:58 +0100 Subject: [PATCH 042/122] Convert more events to enums --- crates/ink/ir/src/ir/event_def.rs | 127 +++++++++++++++++------------- 1 file changed, 74 insertions(+), 53 deletions(-) diff --git a/crates/ink/ir/src/ir/event_def.rs b/crates/ink/ir/src/ir/event_def.rs index 9eb20b1bf5b..64793e62a1f 100644 --- a/crates/ink/ir/src/ir/event_def.rs +++ b/crates/ink/ir/src/ir/event_def.rs @@ -218,18 +218,20 @@ mod tests { #[test] fn simple_try_from_works() { - let item_struct: syn::ItemStruct = syn::parse_quote! { + let item_struct: syn::ItemEnum = syn::parse_quote! { #[ink(event)] - pub struct MyEvent { - #[ink(topic)] - field_1: i32, - field_2: bool, + pub enum MyEvent { + Event { + #[ink(topic)] + field_1: i32, + field_2: bool, + } } }; assert!(InkEventDefinition::try_from(item_struct).is_ok()); } - fn assert_try_from_fails(item_struct: syn::ItemStruct, expected: &str) { + fn assert_try_from_fails(item_struct: syn::ItemEnum, expected: &str) { assert_eq!( InkEventDefinition::try_from(item_struct).map_err(|err| err.to_string()), Err(expected.to_string()) @@ -242,10 +244,12 @@ mod tests { syn::parse_quote! { #[ink(event)] #[ink(storage)] - pub struct MyEvent { - #[ink(topic)] - field_1: i32, - field_2: bool, + pub enum MyEvent { + Event { + #[ink(topic)] + field_1: i32, + field_2: bool, + } } }, "encountered conflicting ink! attribute argument", @@ -257,11 +261,12 @@ mod tests { assert_try_from_fails( syn::parse_quote! { #[ink(event)] - #[ink(event)] - pub struct MyEvent { - #[ink(topic)] - field_1: i32, - field_2: bool, + pub enum MyEvent { + Event { + #[ink(topic)] + field_1: i32, + field_2: bool, + } } }, "encountered duplicate ink! attribute", @@ -274,10 +279,12 @@ mod tests { syn::parse_quote! { #[ink(storage)] #[ink(event)] - pub struct MyEvent { - #[ink(topic)] - field_1: i32, - field_2: bool, + pub enum MyEvent { + Event { + #[ink(topic)] + field_1: i32, + field_2: bool, + } } }, "unexpected first ink! attribute argument", @@ -285,13 +292,15 @@ mod tests { } #[test] - fn missing_storage_attribute_fails() { + fn missing_event_attribute_fails() { assert_try_from_fails( syn::parse_quote! { - pub struct MyEvent { - #[ink(topic)] - field_1: i32, - field_2: bool, + pub enum MyEvent { + Event { + #[ink(topic)] + field_1: i32, + field_2: bool, + } } }, "encountered unexpected empty expanded ink! attribute arguments", @@ -303,10 +312,12 @@ mod tests { assert_try_from_fails( syn::parse_quote! { #[ink(event)] - pub struct GenericEvent { - #[ink(topic)] - field_1: T, - field_2: bool, + pub enum GenericEvent { + Event { + #[ink(topic)] + field_1: T, + field_2: bool, + } } }, "generic ink! event structs are not supported", @@ -318,10 +329,12 @@ mod tests { assert_try_from_fails( syn::parse_quote! { #[ink(event)] - struct PrivateEvent { - #[ink(topic)] - field_1: i32, - field_2: bool, + enum PrivateEvent { + Event { + #[ink(topic)] + field_1: i32, + field_2: bool, + } } }, "non `pub` ink! event structs are not supported", @@ -333,11 +346,13 @@ mod tests { assert_try_from_fails( syn::parse_quote! { #[ink(event)] - pub struct MyEvent { - #[ink(topic)] - #[ink(topic)] - field_1: i32, - field_2: bool, + pub enum MyEvent { + Event { + #[ink(topic)] + #[ink(topic)] + field_1: i32, + field_2: bool, + } } }, "encountered duplicate ink! attribute", @@ -349,10 +364,12 @@ mod tests { assert_try_from_fails( syn::parse_quote! { #[ink(event)] - pub struct MyEvent { - #[ink(message)] - field_1: i32, - field_2: bool, + pub enum MyEvent { + Event { + #[ink(message)] + field_1: i32, + field_2: bool, + } } }, "first optional ink! attribute of an event field must be #[ink(topic)]", @@ -364,11 +381,13 @@ mod tests { assert_try_from_fails( syn::parse_quote! { #[ink(event)] - pub struct MyEvent { - #[ink(topic)] - #[ink(payable)] - field_1: i32, - field_2: bool, + pub enum MyEvent { + Event { + #[ink(topic)] + #[ink(payable)] + field_1: i32, + field_2: bool, + } } }, "encountered conflicting ink! attribute for event field", @@ -420,15 +439,17 @@ mod tests { }, ), ]; - let event_def = >::try_from( + let event_def = >::try_from( syn::parse_quote! { #[ink(event)] pub struct MyEvent { - #[ink(topic)] - field_1: i32, - field_2: u64, - #[ink(topic)] - field_3: [u8; 32], + Event { + #[ink(topic)] + field_1: i32, + field_2: u64, + #[ink(topic)] + field_3: [u8; 32], + } } }, ) @@ -444,7 +465,7 @@ mod tests { #[test] fn anonymous_event_works() { - fn assert_anonymous_event(event: syn::ItemStruct) { + fn assert_anonymous_event(event: syn::ItemEnum) { match InkEventDefinition::try_from(event) { Ok(event) => { assert!(event.anonymous); From 10ad8e5818dbc174bccb1f41dbd891656ac66e52 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 29 Sep 2022 09:40:46 +0100 Subject: [PATCH 043/122] Fix some crate paths --- crates/ink/macro/src/event_def.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ink/macro/src/event_def.rs b/crates/ink/macro/src/event_def.rs index 3085f38503d..045b50284b7 100644 --- a/crates/ink/macro/src/event_def.rs +++ b/crates/ink/macro/src/event_def.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use ink_lang_codegen::generate_code; +use ink_codegen::generate_code; use proc_macro2::TokenStream as TokenStream2; use syn::Result; @@ -28,6 +28,6 @@ pub fn generate_or_err( input: TokenStream2, ) -> Result { let trait_definition = - ink_lang_ir::InkEventDefinition::from_event_def_tokens(config, input)?; + ink_ir::InkEventDefinition::from_event_def_tokens(config, input)?; Ok(generate_code(&trait_definition)) } From 9383b40afa8c56122ed26383d1723e6289e4e4a9 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 29 Sep 2022 09:44:38 +0100 Subject: [PATCH 044/122] Fix event def tests --- crates/ink/ir/src/ir/event_def.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/ink/ir/src/ir/event_def.rs b/crates/ink/ir/src/ir/event_def.rs index 64793e62a1f..13722fabd73 100644 --- a/crates/ink/ir/src/ir/event_def.rs +++ b/crates/ink/ir/src/ir/event_def.rs @@ -442,7 +442,7 @@ mod tests { let event_def = >::try_from( syn::parse_quote! { #[ink(event)] - pub struct MyEvent { + pub enum MyEvent { Event { #[ink(topic)] field_1: i32, @@ -454,7 +454,8 @@ mod tests { }, ) .unwrap(); - let mut fields_iter = event_def.fields(); + let event_variant = event_def.variants().next().expect("Event variant"); + let mut fields_iter = event_variant.fields(); for (is_topic, expected_field) in expected_fields { let field = fields_iter.next().unwrap(); assert_eq!(field.is_topic, is_topic); From 5253a31dcadb09676844b14fdb623d577774a666 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 29 Sep 2022 11:18:27 +0100 Subject: [PATCH 045/122] Start to rebuild topics impl --- crates/ink/codegen/src/generator/event_def.rs | 45 +++++++++++++++++-- .../ui/contract/pass/event-shared-external.rs | 2 - 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/crates/ink/codegen/src/generator/event_def.rs b/crates/ink/codegen/src/generator/event_def.rs index f016c68d0f3..19defce66fc 100644 --- a/crates/ink/codegen/src/generator/event_def.rs +++ b/crates/ink/codegen/src/generator/event_def.rs @@ -34,13 +34,13 @@ impl GenerateCode for EventDefinition<'_> { // let event_info_impl = self.generate_event_info_impl(); // let event_metadata_impl = self.generate_event_metadata_impl(); let event_variants_impls = self.generate_event_variant_info_impls(); - let topics_impl = self.generate_topics_impl2(); + let topics_impl = self.generate_topics_impl(); // let topics_guard = self.generate_topics_guard(); quote! { #event_enum // #event_info_impl // #event_metadata_impl - // #topics_impl + #topics_impl // #topics_guard } } @@ -110,9 +110,48 @@ impl<'a> EventDefinition<'a> { ) } - fn generate_topics_impl2(&self) -> TokenStream2 { + fn generate_topics_impl(&self) -> TokenStream2 { let span = self.event_def.span(); + let event_ident = self.event_def.ident(); + let len_topics = self + .event_def + .max_len_topics(); + + // Anonymous events require 1 fewer topics since they do not include their signature. + let anonymous_topics_offset = if self.event_def.anonymous { 0 } else { 1 }; + let remaining_topics_ty = match len_topics + anonymous_topics_offset { + 0 => quote_spanned!(span=> ::ink::env::topics::state::NoRemainingTopics), + n => { + quote_spanned!(span=> [::ink::env::topics::state::HasRemainingTopics; #n]) + } + }; + quote_spanned!(span => + const _: () = { + impl ::ink_env::Topics for #event_ident { + type RemainingTopics = #remaining_topics_ty; + + fn topics( + &self, + builder: ::ink::env::topics::TopicsBuilder<::ink::env::topics::state::Uninit, E, B>, + ) -> >::Output + where + E: ::ink::env::Environment, + B: ::ink::env::topics::TopicsBuilderBackend, + { + todo!() + // const EVENT_SIGNATURE: &[u8] = <#event_ident as ::ink::reflect::EventInfo>::PATH.as_bytes(); + // + // builder + // .build::() + // #event_signature_topic + // #( + // #topic_impls + // )* + // .finish() + } + } + }; ) } diff --git a/crates/ink/tests/ui/contract/pass/event-shared-external.rs b/crates/ink/tests/ui/contract/pass/event-shared-external.rs index c4c2052917f..469b8a75241 100644 --- a/crates/ink/tests/ui/contract/pass/event-shared-external.rs +++ b/crates/ink/tests/ui/contract/pass/event-shared-external.rs @@ -1,5 +1,3 @@ -use ink_lang as ink; - // todo: add the wiring to detect the events metadata, and in cargo-contract merge together // todo: consider the possibility of enforcing shared events to be an enum, and tied to an ink! trait def // only a single event type per interface which encapsulates all the possible events From 8e8af63b99700d5e3d575030c6a774e6ab51e729 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 29 Sep 2022 12:17:12 +0100 Subject: [PATCH 046/122] Fix some IR tests --- crates/ink/ir/src/ir/item/tests.rs | 10 ++++++---- crates/ink/ir/src/ir/item_mod.rs | 6 ++++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/crates/ink/ir/src/ir/item/tests.rs b/crates/ink/ir/src/ir/item/tests.rs index 51bee26b475..11188e105cc 100644 --- a/crates/ink/ir/src/ir/item/tests.rs +++ b/crates/ink/ir/src/ir/item/tests.rs @@ -33,10 +33,12 @@ fn simple_storage_works() { fn simple_event_works() { let event_struct: syn::Item = syn::parse_quote! { #[ink(event)] - pub struct MyEvent { - #[ink(topic)] - param_1: bool, - param_2: i32, + pub enum MyEvent { + Event { + #[ink(topic)] + param_1: bool, + param_2: i32, + } } }; assert!(matches!( diff --git a/crates/ink/ir/src/ir/item_mod.rs b/crates/ink/ir/src/ir/item_mod.rs index ffd08df6583..8e54e28a19a 100644 --- a/crates/ink/ir/src/ir/item_mod.rs +++ b/crates/ink/ir/src/ir/item_mod.rs @@ -49,8 +49,10 @@ use syn::{ /// } /// /// #[ink(event)] -/// pub struct MyEvent { -/// /* event fields */ +/// pub enum MyEvent { +/// Event { +/// /* event fields */ +/// } /// } /// /// impl MyStorage { From d2ce784e5a15aa10ece12144178d51a9a0ab6c7f Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 29 Sep 2022 21:01:53 +0100 Subject: [PATCH 047/122] WIP impl variant topics --- crates/ink/codegen/src/generator/event_def.rs | 41 ++++++++++++++----- crates/ink/ir/src/ir/event_def.rs | 20 ++++++--- 2 files changed, 46 insertions(+), 15 deletions(-) diff --git a/crates/ink/codegen/src/generator/event_def.rs b/crates/ink/codegen/src/generator/event_def.rs index 19defce66fc..831747e4e64 100644 --- a/crates/ink/codegen/src/generator/event_def.rs +++ b/crates/ink/codegen/src/generator/event_def.rs @@ -117,6 +117,32 @@ impl<'a> EventDefinition<'a> { .event_def .max_len_topics(); + let variant_match_arms = self + .event_def + .variants() + .map(|variant| { + let span = variant.span(); + let variant_ident = variant.ident(); + let field_bindings = variant.fields() + .map(|field| { + let span = field.span(); + let field_ident = field.ident(); + quote_spanned!(span=> ref #field_ident) + }); + let field_topics = variant.fields() + .map(|field| { + + }); + + quote_spanned!(span=> + Self::#variant_ident { #( field_bindings, ) } => { + #( + field_topics + )* + } + ) + }); + // Anonymous events require 1 fewer topics since they do not include their signature. let anonymous_topics_offset = if self.event_def.anonymous { 0 } else { 1 }; let remaining_topics_ty = match len_topics + anonymous_topics_offset { @@ -139,16 +165,11 @@ impl<'a> EventDefinition<'a> { E: ::ink::env::Environment, B: ::ink::env::topics::TopicsBuilderBackend, { - todo!() - // const EVENT_SIGNATURE: &[u8] = <#event_ident as ::ink::reflect::EventInfo>::PATH.as_bytes(); - // - // builder - // .build::() - // #event_signature_topic - // #( - // #topic_impls - // )* - // .finish() + match self { + #( + variant_match_arms + )* + } } } }; diff --git a/crates/ink/ir/src/ir/event_def.rs b/crates/ink/ir/src/ir/event_def.rs index 13722fabd73..c1665de03af 100644 --- a/crates/ink/ir/src/ir/event_def.rs +++ b/crates/ink/ir/src/ir/event_def.rs @@ -87,15 +87,18 @@ impl InkEventDefinition { // strip out the `#[ink(topic)] attributes, since the item will be used to // regenerate the event enum field.attrs = other_attrs; + let ident = field.ident + .ok_or_else(|| format_err_spanned!(variant.span(), "event variants must have named fields"))?; fields.push(EventField { is_topic: topic_attr.is_some(), field: field.clone(), + ident, }) } let named_fields = matches!(variant.fields, syn::Fields::Named(_)); variants.push(EventVariant { index, - ident: variant.ident.clone(), + item: variant.clone(), named_fields, fields, }) @@ -151,15 +154,20 @@ impl InkEventDefinition { #[derive(Debug, PartialEq, Eq)] pub struct EventVariant { index: usize, - ident: Ident, + item: syn::Variant, named_fields: bool, fields: Vec, } impl EventVariant { + /// Returns the span of the event variant. + pub fn span(&self) -> Span { + self.item.span() + } + /// The identifier of the event variant. pub fn ident(&self) -> &Ident { - &self.ident + &self.item.ident } /// The index of the the event variant in the enum definition. @@ -181,6 +189,8 @@ pub struct EventField { pub is_topic: bool, /// The event field. field: syn::Field, + /// The event field ident. + ident: syn::Ident, } impl EventField { @@ -202,8 +212,8 @@ impl EventField { } /// Returns the identifier of the event field if any. - pub fn ident(&self) -> Option<&Ident> { - self.field.ident.as_ref() + pub fn ident(&self) -> &Ident { + &self.ident } /// Returns the type of the event field. From 504e1fedc7391fb29fb3ef01f1448b5b9b5a2907 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 5 Oct 2022 18:06:09 +0100 Subject: [PATCH 048/122] WIP building push_topics impl --- crates/ink/codegen/src/generator/event_def.rs | 89 ++++++++++++------- crates/ink/ir/src/ir/event_def.rs | 27 +++--- crates/ink/src/reflect/event.rs | 12 --- crates/ink/src/reflect/mod.rs | 2 +- 4 files changed, 71 insertions(+), 59 deletions(-) diff --git a/crates/ink/codegen/src/generator/event_def.rs b/crates/ink/codegen/src/generator/event_def.rs index 831747e4e64..b61c1ff6c2b 100644 --- a/crates/ink/codegen/src/generator/event_def.rs +++ b/crates/ink/codegen/src/generator/event_def.rs @@ -31,14 +31,13 @@ pub struct EventDefinition<'a> { impl GenerateCode for EventDefinition<'_> { fn generate_code(&self) -> TokenStream2 { let event_enum = self.generate_event_enum(); - // let event_info_impl = self.generate_event_info_impl(); // let event_metadata_impl = self.generate_event_metadata_impl(); - let event_variants_impls = self.generate_event_variant_info_impls(); + let event_info_impls = self.generate_event_variant_info_impls(); let topics_impl = self.generate_topics_impl(); // let topics_guard = self.generate_topics_guard(); quote! { #event_enum - // #event_info_impl + #event_info_impls // #event_metadata_impl #topics_impl // #topics_guard @@ -56,16 +55,6 @@ impl<'a> EventDefinition<'a> { ) } - fn generate_event_info_impl(&self) -> TokenStream2 { - let span = self.event_def.span(); - let event_ident = self.event_def.ident(); - quote_spanned!(span=> - impl ::ink_lang::reflect::EventInfo for #event_ident { - const PATH: &'static str = module_path!(); - } - ) - } - fn generate_event_variant_info_impls(&self) -> TokenStream2 { let span = self.event_def.span(); let event_ident = self.event_def.ident(); @@ -74,14 +63,14 @@ impl<'a> EventDefinition<'a> { let event_variant_ident = ev.ident(); let index = ev.index(); quote_spanned!(span=> - impl ::ink_lang::reflect::EventVariantInfo<#index> for #event_ident { - const SIGNATURE: [u8: 32] = ::ink_lang::blake2x256!(::core::concat!( - ::core::module_path!(), - "::", - ::core::stringify!(#event_ident), - "::", - ::core::stringify!(#event_variant_ident) - )); + impl ::ink::reflect::EventVariantInfo<#index> for #event_ident { + const NAME: &'static str = ::core::stringify!(#event_ident); + // const SIGNATURE: [u8; 32] = ::ink::blake2x256!(::core::concat!( + // ::core::module_path!(), "::", + // ::core::stringify!(#event_ident), "::", + // ::core::stringify!(#event_variant_ident)) + // ); + const SIGNATURE: [u8; 32] = ; } ) }); @@ -104,8 +93,8 @@ impl<'a> EventDefinition<'a> { let len_topics = self.event_def.max_len_topics(); quote_spanned!(span=> - impl ::ink_lang::codegen::EventLenTopics for #event_ident { - type LenTopics = ::ink_lang::codegen::EventTopics<#len_topics>; + impl ::ink::codegen::EventLenTopics for #event_ident { + type LenTopics = ::ink::codegen::EventTopics<#len_topics>; } ) } @@ -131,18 +120,47 @@ impl<'a> EventDefinition<'a> { }); let field_topics = variant.fields() .map(|field| { - + let field_type = field.ty(); + let field_ident = field.ident(); + quote_spanned!(span => + builder.push_topic::<::ink_env::topics::PrefixedValue<#field_type>>( + &::ink_env::topics::PrefixedValue { + // todo: deduplicate with EVENT_SIGNATURE + prefix: ::core::concat!( + ::core::module_path!(), + "::", + ::core::stringify!(#event_ident), + "::", + ::core::stringify!(#field_ident), + ).as_bytes(), + value: &self.#field_ident, + } + ); + ) }); quote_spanned!(span=> - Self::#variant_ident { #( field_bindings, ) } => { + Self::#variant_ident { #( #field_bindings, )* } => { #( - field_topics + #field_topics )* } ) }); + let event_signature_topic = match self.event_def.anonymous { + true => None, + false => { + Some(quote_spanned!(span=> + .push_topic::<::ink_env::topics::PrefixedValue<()>>( + &::ink_env::topics::PrefixedValue { + prefix: EVENT_SIGNATURE, value: &(), + } + ) + )) + } + }; + // Anonymous events require 1 fewer topics since they do not include their signature. let anonymous_topics_offset = if self.event_def.anonymous { 0 } else { 1 }; let remaining_topics_ty = match len_topics + anonymous_topics_offset { @@ -165,11 +183,18 @@ impl<'a> EventDefinition<'a> { E: ::ink::env::Environment, B: ::ink::env::topics::TopicsBuilderBackend, { - match self { - #( - variant_match_arms - )* - } + let builder = builder + .build::() + #event_signature_topic; + + // return type of match arms matching topics len? + let builder = + match self { + #( + #variant_match_arms + )* + }; + builder.finish() } } }; @@ -245,7 +270,7 @@ impl<'a> EventDefinition<'a> { // E: ::ink_env::Environment, // B: ::ink_env::topics::TopicsBuilderBackend, // { - // const EVENT_SIGNATURE: &[u8] = <#event_ident as ::ink_lang::reflect::EventInfo>::PATH.as_bytes(); + // const EVENT_SIGNATURE: &[u8] = <#event_ident as ::ink::reflect::EventInfo>::PATH.as_bytes(); // // builder // .build::() diff --git a/crates/ink/ir/src/ir/event_def.rs b/crates/ink/ir/src/ir/event_def.rs index c1665de03af..57f8c11d704 100644 --- a/crates/ink/ir/src/ir/event_def.rs +++ b/crates/ink/ir/src/ir/event_def.rs @@ -12,11 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{ - error::ExtError as _, - ir, - ir::utils, -}; +use crate::ir; use proc_macro2::{ Ident, Span, @@ -69,11 +65,11 @@ impl quote::ToTokens for InkEventDefinition { impl InkEventDefinition { /// Returns `Ok` if the input matches all requirements for an ink! event definition. - pub fn new(mut item: syn::ItemEnum, anonymous: bool) -> Result { + pub fn new(item: syn::ItemEnum, anonymous: bool) -> Result { let mut variants = Vec::new(); - for (index, variant) in item.variants.iter_mut().enumerate() { + for (index, variant) in item.variants.iter().enumerate() { let mut fields = Vec::new(); - for field in variant.fields.iter_mut() { + for field in variant.fields.iter() { let (topic_attr, other_attrs) = ir::sanitize_optional_attributes( field.span(), field.attrs.clone(), @@ -84,15 +80,18 @@ impl InkEventDefinition { } }, )?; + let ident = field.ident.as_ref() + .ok_or_else(|| format_err_spanned!(variant, "event variants must have named fields"))?; // strip out the `#[ink(topic)] attributes, since the item will be used to // regenerate the event enum - field.attrs = other_attrs; - let ident = field.ident - .ok_or_else(|| format_err_spanned!(variant.span(), "event variants must have named fields"))?; + let field = syn::Field { + attrs: other_attrs, + ..field.clone() + }; fields.push(EventField { is_topic: topic_attr.is_some(), - field: field.clone(), - ident, + field, + ident: ident.clone(), }) } let named_fields = matches!(variant.fields, syn::Fields::Named(_)); @@ -469,7 +468,7 @@ mod tests { for (is_topic, expected_field) in expected_fields { let field = fields_iter.next().unwrap(); assert_eq!(field.is_topic, is_topic); - assert_eq!(field.ident(), Some(expected_field.ident())); + assert_eq!(field.ident(), expected_field.ident()); assert_eq!(field.ty(), expected_field.ty()); } } diff --git a/crates/ink/src/reflect/event.rs b/crates/ink/src/reflect/event.rs index 3f650e7d61d..86d38aaad37 100644 --- a/crates/ink/src/reflect/event.rs +++ b/crates/ink/src/reflect/event.rs @@ -12,18 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -/// todo: docs -pub trait EventInfo { - /// The complete path of the ink! event definition. - /// - /// This is equivalent to Rust's builtin `module_path!` macro - /// invocation at the definition site of the ink! event, concatenated with - /// the event identifier. - /// - /// todo: rename? - const PATH: &'static str; -} - /// todo: docs /// The ID is the index of the event variant in the enum pub trait EventVariantInfo { diff --git a/crates/ink/src/reflect/mod.rs b/crates/ink/src/reflect/mod.rs index 29345d6a84a..dab634c8510 100644 --- a/crates/ink/src/reflect/mod.rs +++ b/crates/ink/src/reflect/mod.rs @@ -46,7 +46,7 @@ pub use self::{ DispatchableMessageInfo, ExecuteDispatchable, }, - event::EventInfo, + event::EventVariantInfo, trait_def::{ TraitDefinitionRegistry, TraitInfo, From 35561a7646e4f762d30569df70900955dc5c7ccd Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 6 Oct 2022 11:06:06 +0100 Subject: [PATCH 049/122] WIP use const fn to generate event_variant_signature --- crates/ink/codegen/src/generator/event_def.rs | 6 +++++- crates/ink/src/reflect/event.rs | 7 +++++++ crates/ink/src/reflect/mod.rs | 5 ++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/crates/ink/codegen/src/generator/event_def.rs b/crates/ink/codegen/src/generator/event_def.rs index b61c1ff6c2b..b6648dc4302 100644 --- a/crates/ink/codegen/src/generator/event_def.rs +++ b/crates/ink/codegen/src/generator/event_def.rs @@ -70,7 +70,11 @@ impl<'a> EventDefinition<'a> { // ::core::stringify!(#event_ident), "::", // ::core::stringify!(#event_variant_ident)) // ); - const SIGNATURE: [u8; 32] = ; + const SIGNATURE: [u8; 32] = ::ink::reflect::event_variant_signature( + ::core::module_path!(), + ::core::stringify!(#event_ident), + ::core::stringify!(#event_variant_ident), + ); } ) }); diff --git a/crates/ink/src/reflect/event.rs b/crates/ink/src/reflect/event.rs index 86d38aaad37..1e4bb323a0d 100644 --- a/crates/ink/src/reflect/event.rs +++ b/crates/ink/src/reflect/event.rs @@ -21,3 +21,10 @@ pub trait EventVariantInfo { /// Should be able to compute up front const SIGNATURE: [u8; 32]; } + +pub const fn event_variant_signature(path: &'static str, event_ident: &'static str, event_variant: &'static str) -> [u8; 32] { + let buf = [0u8; 32]; + // todo: use xxh3? + // let bytes = path.as_bytes() + buf +} diff --git a/crates/ink/src/reflect/mod.rs b/crates/ink/src/reflect/mod.rs index dab634c8510..fda82124b58 100644 --- a/crates/ink/src/reflect/mod.rs +++ b/crates/ink/src/reflect/mod.rs @@ -46,7 +46,10 @@ pub use self::{ DispatchableMessageInfo, ExecuteDispatchable, }, - event::EventVariantInfo, + event::{ + EventVariantInfo, + event_variant_signature + }, trait_def::{ TraitDefinitionRegistry, TraitInfo, From a9d05598668ebabfb3d57591f066431f0bbace42 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 6 Oct 2022 18:15:45 +0100 Subject: [PATCH 050/122] WIP generate event variant match arms with remaining topics --- crates/env/src/topics.rs | 11 +- crates/ink/codegen/src/generator/event_def.rs | 155 ++++-------------- crates/ink/ir/src/ir/event_def.rs | 47 +++--- crates/ink/src/reflect/event.rs | 1 + 4 files changed, 64 insertions(+), 150 deletions(-) diff --git a/crates/env/src/topics.rs b/crates/env/src/topics.rs index 16a862b6c9a..9b7e8ea9ee0 100644 --- a/crates/env/src/topics.rs +++ b/crates/env/src/topics.rs @@ -80,12 +80,12 @@ where { /// Initializes the topics builder and informs it about how many topics it must expect to serialize. /// - /// The number of expected topics is given implicitly by the `E` type parameter. - pub fn build( + /// The number of expected topics is given by the `TopicsAmount` type parameter. + pub fn build( mut self, - ) -> TopicsBuilder<::RemainingTopics, E, B> { + ) -> TopicsBuilder { self.backend - .expect(<::RemainingTopics as EventTopicsAmount>::AMOUNT); + .expect(::AMOUNT); TopicsBuilder { backend: self.backend, state: Default::default(), @@ -189,9 +189,6 @@ impl EventTopicsAmount for state::NoRemainingTopics { /// /// Normally this trait should be implemented automatically via the ink! codegen. pub trait Topics { - /// Type state indicating how many event topics are to be expected by the topics builder. - type RemainingTopics: EventTopicsAmount; - /// Guides event topic serialization using the given topics builder. fn topics( &self, diff --git a/crates/ink/codegen/src/generator/event_def.rs b/crates/ink/codegen/src/generator/event_def.rs index b6648dc4302..db8bd47a530 100644 --- a/crates/ink/codegen/src/generator/event_def.rs +++ b/crates/ink/codegen/src/generator/event_def.rs @@ -94,6 +94,7 @@ impl<'a> EventDefinition<'a> { fn generate_topics_guard(&self) -> TokenStream2 { let span = self.event_def.span(); let event_ident = self.event_def.ident(); + // todo: [AJ] check if event signature topic should be included here (it is now, wasn't before) let len_topics = self.event_def.max_len_topics(); quote_spanned!(span=> @@ -143,37 +144,40 @@ impl<'a> EventDefinition<'a> { ) }); + let event_signature_topic = match self.event_def.anonymous { + true => None, + false => { + Some(quote_spanned!(span=> + .push_topic::<::ink_env::topics::PrefixedValue<()>>( + &::ink_env::topics::PrefixedValue { + // todo: look up event signature topic via indexed trait impl + prefix: EVENT_SIGNATURE, value: &(), + } + ) + )) + } + }; + + let remaining_topics_ty = match len_topics { + 0 => quote_spanned!(span=> ::ink::env::topics::state::NoRemainingTopics), + n => { + quote_spanned!(span=> [::ink::env::topics::state::HasRemainingTopics; #n]) + } + }; + quote_spanned!(span=> Self::#variant_ident { #( #field_bindings, )* } => { - #( - #field_topics - )* + builder + .build::<#remaining_topics_ty>() + #event_signature_topic + #( + #field_topics + )* + .finish() } ) }); - let event_signature_topic = match self.event_def.anonymous { - true => None, - false => { - Some(quote_spanned!(span=> - .push_topic::<::ink_env::topics::PrefixedValue<()>>( - &::ink_env::topics::PrefixedValue { - prefix: EVENT_SIGNATURE, value: &(), - } - ) - )) - } - }; - - // Anonymous events require 1 fewer topics since they do not include their signature. - let anonymous_topics_offset = if self.event_def.anonymous { 0 } else { 1 }; - let remaining_topics_ty = match len_topics + anonymous_topics_offset { - 0 => quote_spanned!(span=> ::ink::env::topics::state::NoRemainingTopics), - n => { - quote_spanned!(span=> [::ink::env::topics::state::HasRemainingTopics; #n]) - } - }; - quote_spanned!(span => const _: () = { impl ::ink_env::Topics for #event_ident { @@ -187,105 +191,14 @@ impl<'a> EventDefinition<'a> { E: ::ink::env::Environment, B: ::ink::env::topics::TopicsBuilderBackend, { - let builder = builder - .build::() - #event_signature_topic; - - // return type of match arms matching topics len? - let builder = - match self { - #( - #variant_match_arms - )* - }; - builder.finish() + match self { + #( + #variant_match_arms + )* + }; } } }; ) } - - // /// Generates the `Topics` trait implementations for the user defined events. - // fn generate_topics_impl(&self) -> TokenStream2 { - // let span = self.event_def.span(); - // let event_ident = self.event_def.ident(); - // let len_topics = self - // .event_def - // .max_len_topics(); - // let topic_impls = self - // .event_def - // .fields() - // .enumerate() - // .filter(|(_, field)| field.is_topic) - // .map(|(n, topic_field)| { - // let span = topic_field.span(); - // let field_ident = topic_field - // .ident() - // .map(quote::ToTokens::into_token_stream) - // .unwrap_or_else(|| quote_spanned!(span => #n)); - // let field_type = topic_field.ty(); - // quote_spanned!(span => - // .push_topic::<::ink_env::topics::PrefixedValue<#field_type>>( - // &::ink_env::topics::PrefixedValue { - // // todo: deduplicate with EVENT_SIGNATURE - // prefix: ::core::concat!( - // ::core::module_path!(), - // "::", - // ::core::stringify!(#event_ident), - // "::", - // ::core::stringify!(#field_ident), - // ).as_bytes(), - // value: &self.#field_ident, - // } - // ) - // ) - // }); - // // Only include topic for event signature in case of non-anonymous event. - // let event_signature_topic = match self.event_def.anonymous { - // true => None, - // false => { - // Some(quote_spanned!(span=> - // .push_topic::<::ink_env::topics::PrefixedValue<()>>( - // &::ink_env::topics::PrefixedValue { - // prefix: EVENT_SIGNATURE, value: &(), - // } - // ) - // )) - // } - // }; - // // Anonymous events require 1 fewer topics since they do not include their signature. - // let anonymous_topics_offset = if self.event_def.anonymous { 0 } else { 1 }; - // let remaining_topics_ty = match len_topics + anonymous_topics_offset { - // 0 => quote_spanned!(span=> ::ink_env::topics::state::NoRemainingTopics), - // n => { - // quote_spanned!(span=> [::ink_env::topics::state::HasRemainingTopics; #n]) - // } - // }; - // quote_spanned!(span => - // const _: () = { - // impl ::ink_env::Topics for #event_ident { - // type RemainingTopics = #remaining_topics_ty; - // - // fn topics( - // &self, - // builder: ::ink_env::topics::TopicsBuilder<::ink_env::topics::state::Uninit, E, B>, - // ) -> >::Output - // where - // E: ::ink_env::Environment, - // B: ::ink_env::topics::TopicsBuilderBackend, - // { - // const EVENT_SIGNATURE: &[u8] = <#event_ident as ::ink::reflect::EventInfo>::PATH.as_bytes(); - // - // builder - // .build::() - // #event_signature_topic - // #( - // #topic_impls - // )* - // .finish() - // } - // } - // }; - // ) - // } } diff --git a/crates/ink/ir/src/ir/event_def.rs b/crates/ink/ir/src/ir/event_def.rs index 57f8c11d704..513b9f06354 100644 --- a/crates/ink/ir/src/ir/event_def.rs +++ b/crates/ink/ir/src/ir/event_def.rs @@ -28,7 +28,6 @@ use syn::{ pub struct InkEventDefinition { pub item: syn::ItemEnum, variants: Vec, - pub anonymous: bool, } impl TryFrom for InkEventDefinition { @@ -51,24 +50,10 @@ impl TryFrom for InkEventDefinition { attrs: other_attrs, ..item_enum }; - Self::new(item_enum, ink_attrs.is_anonymous()) - } -} - -impl quote::ToTokens for InkEventDefinition { - /// We mainly implement this trait for this ink! type to have a derived - /// [`Spanned`](`syn::spanned::Spanned`) implementation for it. - fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { - self.item.to_tokens(tokens) - } -} - -impl InkEventDefinition { - /// Returns `Ok` if the input matches all requirements for an ink! event definition. - pub fn new(item: syn::ItemEnum, anonymous: bool) -> Result { let mut variants = Vec::new(); - for (index, variant) in item.variants.iter().enumerate() { + for (index, variant) in item_enum.variants.iter().enumerate() { let mut fields = Vec::new(); + let anonymous = true; // todo: extract this value from a variant attribute: ink_attrs.is_anonymous()? for field in variant.fields.iter() { let (topic_attr, other_attrs) = ir::sanitize_optional_attributes( field.span(), @@ -100,25 +85,34 @@ impl InkEventDefinition { item: variant.clone(), named_fields, fields, + anonymous, }) } Ok(Self { - item, + item: item_enum, variants, - anonymous, }) } +} +impl quote::ToTokens for InkEventDefinition { + /// We mainly implement this trait for this ink! type to have a derived + /// [`Spanned`](`syn::spanned::Spanned`) implementation for it. + fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { + self.item.to_tokens(tokens) + } +} + +impl InkEventDefinition { /// Returns `Ok` if the input matches all requirements for an ink! event definition. pub fn from_event_def_tokens( config: TokenStream2, input: TokenStream2, ) -> Result { let _parsed_config = syn::parse2::(config)?; - let anonymous = false; // todo parse this from attr config let item = syn::parse2::(input)?; // let item = InkItemTrait::new(&config, parsed_item)?; - Self::new(item, anonymous) + Self::try_from(item) } /// Returns the identifier of the event struct. @@ -143,7 +137,10 @@ impl InkEventDefinition { /// Returns the maximum number of topics of any event variant. pub fn max_len_topics(&self) -> usize { self.variants() - .map(|v| v.fields().filter(|event| event.is_topic).count()) + .map(|v| { + let topics_len = v.fields().filter(|event| event.is_topic).count(); + if v.anonymous { topics_len } else { topics_len + 1usize } + }) .max() .unwrap_or_default() } @@ -156,6 +153,7 @@ pub struct EventVariant { item: syn::Variant, named_fields: bool, fields: Vec, + anonymous: bool, } impl EventVariant { @@ -179,6 +177,11 @@ impl EventVariant { pub fn fields(&self) -> impl Iterator { self.fields.iter() } + + /// Returns true if the signature of the event variant should *not* be indexed by a topic. + pub fn anonymous(&self) -> bool { + self.anonymous + } } /// An event field with a flag indicating if this field is an event topic. diff --git a/crates/ink/src/reflect/event.rs b/crates/ink/src/reflect/event.rs index 1e4bb323a0d..32e22041a80 100644 --- a/crates/ink/src/reflect/event.rs +++ b/crates/ink/src/reflect/event.rs @@ -22,6 +22,7 @@ pub trait EventVariantInfo { const SIGNATURE: [u8; 32]; } +// todo: move to primitives where xxh3 dependency is? pub const fn event_variant_signature(path: &'static str, event_ident: &'static str, event_variant: &'static str) -> [u8; 32] { let buf = [0u8; 32]; // todo: use xxh3? From 23fe12ebaddc28c6906509a65129d33ddeaaf050 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 7 Oct 2022 14:41:31 +0100 Subject: [PATCH 051/122] Fix some errors --- crates/env/src/topics.rs | 4 ++-- crates/ink/codegen/src/generator/event_def.rs | 10 ++++----- crates/ink/ir/src/ir/event_def.rs | 22 +++++++------------ 3 files changed, 14 insertions(+), 22 deletions(-) diff --git a/crates/env/src/topics.rs b/crates/env/src/topics.rs index 9b7e8ea9ee0..95d7addcc35 100644 --- a/crates/env/src/topics.rs +++ b/crates/env/src/topics.rs @@ -83,9 +83,9 @@ where /// The number of expected topics is given by the `TopicsAmount` type parameter. pub fn build( mut self, - ) -> TopicsBuilder { + ) -> TopicsBuilder { self.backend - .expect(::AMOUNT); + .expect(::AMOUNT); TopicsBuilder { backend: self.backend, state: Default::default(), diff --git a/crates/ink/codegen/src/generator/event_def.rs b/crates/ink/codegen/src/generator/event_def.rs index db8bd47a530..011156377f0 100644 --- a/crates/ink/codegen/src/generator/event_def.rs +++ b/crates/ink/codegen/src/generator/event_def.rs @@ -128,7 +128,7 @@ impl<'a> EventDefinition<'a> { let field_type = field.ty(); let field_ident = field.ident(); quote_spanned!(span => - builder.push_topic::<::ink_env::topics::PrefixedValue<#field_type>>( + .push_topic::<::ink_env::topics::PrefixedValue<#field_type>>( &::ink_env::topics::PrefixedValue { // todo: deduplicate with EVENT_SIGNATURE prefix: ::core::concat!( @@ -140,11 +140,11 @@ impl<'a> EventDefinition<'a> { ).as_bytes(), value: &self.#field_ident, } - ); + ) ) }); - let event_signature_topic = match self.event_def.anonymous { + let event_signature_topic = match variant.anonymous() { true => None, false => { Some(quote_spanned!(span=> @@ -181,8 +181,6 @@ impl<'a> EventDefinition<'a> { quote_spanned!(span => const _: () = { impl ::ink_env::Topics for #event_ident { - type RemainingTopics = #remaining_topics_ty; - fn topics( &self, builder: ::ink::env::topics::TopicsBuilder<::ink::env::topics::state::Uninit, E, B>, @@ -195,7 +193,7 @@ impl<'a> EventDefinition<'a> { #( #variant_match_arms )* - }; + } } } }; diff --git a/crates/ink/ir/src/ir/event_def.rs b/crates/ink/ir/src/ir/event_def.rs index 513b9f06354..91c8ae9b64a 100644 --- a/crates/ink/ir/src/ir/event_def.rs +++ b/crates/ink/ir/src/ir/event_def.rs @@ -481,26 +481,20 @@ mod tests { fn assert_anonymous_event(event: syn::ItemEnum) { match InkEventDefinition::try_from(event) { Ok(event) => { - assert!(event.anonymous); + assert!(event.variants[0].anonymous); } Err(_) => panic!("encountered unexpected invalid anonymous event"), } } assert_anonymous_event(syn::parse_quote! { #[ink(event)] - #[ink(anonymous)] - pub struct MyEvent { - #[ink(topic)] - field_1: i32, - field_2: bool, - } - }); - assert_anonymous_event(syn::parse_quote! { - #[ink(event, anonymous)] - pub struct MyEvent { - #[ink(topic)] - field_1: i32, - field_2: bool, + pub enum MyEvent { + #[ink(anonymous)] + Event { + #[ink(topic)] + field_1: i32, + field_2: bool, + } } }); } From 8db474f3932ce79f27cbf7fc0da46a25a5a18828 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 7 Oct 2022 14:50:38 +0100 Subject: [PATCH 052/122] Split InkEventDefinition constructors for inline and external events --- .../ink/codegen/src/generator/metadata/mod.rs | 1 + crates/ink/ir/src/ir/event_def.rs | 43 +++++++++++-------- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/crates/ink/codegen/src/generator/metadata/mod.rs b/crates/ink/codegen/src/generator/metadata/mod.rs index f1930cbeb4b..bf9a5baa9af 100644 --- a/crates/ink/codegen/src/generator/metadata/mod.rs +++ b/crates/ink/codegen/src/generator/metadata/mod.rs @@ -87,6 +87,7 @@ impl Metadata<'_> { let constructors = self.generate_constructors(); let messages = self.generate_messages(); // let events = self.generate_events(); + // todo: call into InkEventDefinition::from_inline_event for inlinne events let docs = self .contract .module() diff --git a/crates/ink/ir/src/ir/event_def.rs b/crates/ink/ir/src/ir/event_def.rs index 91c8ae9b64a..9ce8ad39a3c 100644 --- a/crates/ink/ir/src/ir/event_def.rs +++ b/crates/ink/ir/src/ir/event_def.rs @@ -34,22 +34,6 @@ impl TryFrom for InkEventDefinition { type Error = syn::Error; fn try_from(item_enum: syn::ItemEnum) -> Result { - let enum_span = item_enum.span(); - let (ink_attrs, other_attrs) = ir::sanitize_attributes( - enum_span, - item_enum.attrs, - &ir::AttributeArgKind::Event, - |arg| { - match arg.kind() { - ir::AttributeArg::Event | ir::AttributeArg::Anonymous => Ok(()), - _ => Err(None), - } - }, - )?; - let item_enum = syn::ItemEnum { - attrs: other_attrs, - ..item_enum - }; let mut variants = Vec::new(); for (index, variant) in item_enum.variants.iter().enumerate() { let mut fields = Vec::new(); @@ -104,7 +88,32 @@ impl quote::ToTokens for InkEventDefinition { } impl InkEventDefinition { - /// Returns `Ok` if the input matches all requirements for an ink! event definition. + /// Create an [`InkEventDefinition`] for a event defined as part of an `#[ink::contract]`. + /// + /// This will be an enum annotated with the `#[ink(event)]` attribute. + pub fn from_inline_event(item_enum: syn::ItemEnum) -> Result { + let enum_span = item_enum.span(); + let (ink_attrs, other_attrs) = ir::sanitize_attributes( + enum_span, + item_enum.attrs, + &ir::AttributeArgKind::Event, + |arg| { + match arg.kind() { + ir::AttributeArg::Event | ir::AttributeArg::Anonymous => Ok(()), + _ => Err(None), + } + }, + )?; + let item_enum = syn::ItemEnum { + attrs: other_attrs, + ..item_enum + }; + Self::try_from(item_enum) + } + + /// Create an [`InkEventDefinition`] for a event defined externally to a contract. + /// + /// This will be an enum annotated with the `#[ink::event_def]` attribute. pub fn from_event_def_tokens( config: TokenStream2, input: TokenStream2, From 5068804685b571ce42af4d3a6bf9396fcf89d186 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 7 Oct 2022 15:02:38 +0100 Subject: [PATCH 053/122] Read anonymous from variant attributs, also fmt --- crates/ink/codegen/src/generator/event_def.rs | 4 +- crates/ink/ir/src/ir/event_def.rs | 42 ++++++++++++++----- crates/ink/src/reflect/event.rs | 6 ++- crates/ink/src/reflect/mod.rs | 2 +- 4 files changed, 38 insertions(+), 16 deletions(-) diff --git a/crates/ink/codegen/src/generator/event_def.rs b/crates/ink/codegen/src/generator/event_def.rs index 011156377f0..3d28557c5f2 100644 --- a/crates/ink/codegen/src/generator/event_def.rs +++ b/crates/ink/codegen/src/generator/event_def.rs @@ -107,9 +107,7 @@ impl<'a> EventDefinition<'a> { fn generate_topics_impl(&self) -> TokenStream2 { let span = self.event_def.span(); let event_ident = self.event_def.ident(); - let len_topics = self - .event_def - .max_len_topics(); + let len_topics = self.event_def.max_len_topics(); let variant_match_arms = self .event_def diff --git a/crates/ink/ir/src/ir/event_def.rs b/crates/ink/ir/src/ir/event_def.rs index 9ce8ad39a3c..1fd0cc2fecd 100644 --- a/crates/ink/ir/src/ir/event_def.rs +++ b/crates/ink/ir/src/ir/event_def.rs @@ -37,7 +37,23 @@ impl TryFrom for InkEventDefinition { let mut variants = Vec::new(); for (index, variant) in item_enum.variants.iter().enumerate() { let mut fields = Vec::new(); - let anonymous = true; // todo: extract this value from a variant attribute: ink_attrs.is_anonymous()? + let (ink_attrs, other_attrs) = ir::sanitize_optional_attributes( + variant.span(), + variant.attrs.clone(), + |arg| { + match arg.kind() { + ir::AttributeArg::Anonymous => Ok(()), + _ => Err(None), + } + }, + )?; + // strip out the `#[ink(anonymous)] attributes, since the item will be used to + // regenerate the event enum + let variant = syn::Variant { + attrs: other_attrs, + ..variant.clone() + }; + let anonymous = ink_attrs.map_or(false, |attrs| attrs.is_anonymous()); for field in variant.fields.iter() { let (topic_attr, other_attrs) = ir::sanitize_optional_attributes( field.span(), @@ -49,8 +65,9 @@ impl TryFrom for InkEventDefinition { } }, )?; - let ident = field.ident.as_ref() - .ok_or_else(|| format_err_spanned!(variant, "event variants must have named fields"))?; + let ident = field.ident.as_ref().ok_or_else(|| { + format_err_spanned!(variant, "event variants must have named fields") + })?; // strip out the `#[ink(topic)] attributes, since the item will be used to // regenerate the event enum let field = syn::Field { @@ -93,13 +110,13 @@ impl InkEventDefinition { /// This will be an enum annotated with the `#[ink(event)]` attribute. pub fn from_inline_event(item_enum: syn::ItemEnum) -> Result { let enum_span = item_enum.span(); - let (ink_attrs, other_attrs) = ir::sanitize_attributes( + let (_, other_attrs) = ir::sanitize_attributes( enum_span, item_enum.attrs, &ir::AttributeArgKind::Event, |arg| { match arg.kind() { - ir::AttributeArg::Event | ir::AttributeArg::Anonymous => Ok(()), + ir::AttributeArg::Event => Ok(()), _ => Err(None), } }, @@ -148,7 +165,11 @@ impl InkEventDefinition { self.variants() .map(|v| { let topics_len = v.fields().filter(|event| event.is_topic).count(); - if v.anonymous { topics_len } else { topics_len + 1usize } + if v.anonymous { + topics_len + } else { + topics_len + 1usize + } }) .max() .unwrap_or_default() @@ -460,8 +481,8 @@ mod tests { }, ), ]; - let event_def = >::try_from( - syn::parse_quote! { + let event_def = + >::try_from(syn::parse_quote! { #[ink(event)] pub enum MyEvent { Event { @@ -472,9 +493,8 @@ mod tests { field_3: [u8; 32], } } - }, - ) - .unwrap(); + }) + .unwrap(); let event_variant = event_def.variants().next().expect("Event variant"); let mut fields_iter = event_variant.fields(); for (is_topic, expected_field) in expected_fields { diff --git a/crates/ink/src/reflect/event.rs b/crates/ink/src/reflect/event.rs index 32e22041a80..6e89ffd24ea 100644 --- a/crates/ink/src/reflect/event.rs +++ b/crates/ink/src/reflect/event.rs @@ -23,7 +23,11 @@ pub trait EventVariantInfo { } // todo: move to primitives where xxh3 dependency is? -pub const fn event_variant_signature(path: &'static str, event_ident: &'static str, event_variant: &'static str) -> [u8; 32] { +pub const fn event_variant_signature( + path: &'static str, + event_ident: &'static str, + event_variant: &'static str, +) -> [u8; 32] { let buf = [0u8; 32]; // todo: use xxh3? // let bytes = path.as_bytes() diff --git a/crates/ink/src/reflect/mod.rs b/crates/ink/src/reflect/mod.rs index fda82124b58..36ff261d422 100644 --- a/crates/ink/src/reflect/mod.rs +++ b/crates/ink/src/reflect/mod.rs @@ -47,8 +47,8 @@ pub use self::{ ExecuteDispatchable, }, event::{ + event_variant_signature, EventVariantInfo, - event_variant_signature }, trait_def::{ TraitDefinitionRegistry, From 9914bf4e13ad8f95e978898d108fc6e1a2b56c8e Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 7 Oct 2022 17:45:56 +0100 Subject: [PATCH 054/122] Just allow only ink::event_definition --- crates/ink/ir/src/ir/event_def.rs | 23 ----------------- crates/ink/tests/unique_topics.rs | 2 +- examples/trait-erc20/lib.rs | 42 +++++++++++++++---------------- 3 files changed, 22 insertions(+), 45 deletions(-) diff --git a/crates/ink/ir/src/ir/event_def.rs b/crates/ink/ir/src/ir/event_def.rs index 1fd0cc2fecd..963d79c73c1 100644 --- a/crates/ink/ir/src/ir/event_def.rs +++ b/crates/ink/ir/src/ir/event_def.rs @@ -105,29 +105,6 @@ impl quote::ToTokens for InkEventDefinition { } impl InkEventDefinition { - /// Create an [`InkEventDefinition`] for a event defined as part of an `#[ink::contract]`. - /// - /// This will be an enum annotated with the `#[ink(event)]` attribute. - pub fn from_inline_event(item_enum: syn::ItemEnum) -> Result { - let enum_span = item_enum.span(); - let (_, other_attrs) = ir::sanitize_attributes( - enum_span, - item_enum.attrs, - &ir::AttributeArgKind::Event, - |arg| { - match arg.kind() { - ir::AttributeArg::Event => Ok(()), - _ => Err(None), - } - }, - )?; - let item_enum = syn::ItemEnum { - attrs: other_attrs, - ..item_enum - }; - Self::try_from(item_enum) - } - /// Create an [`InkEventDefinition`] for a event defined externally to a contract. /// /// This will be an enum annotated with the `#[ink::event_def]` attribute. diff --git a/crates/ink/tests/unique_topics.rs b/crates/ink/tests/unique_topics.rs index 2dbf7f4eddf..57f0a0adec4 100644 --- a/crates/ink/tests/unique_topics.rs +++ b/crates/ink/tests/unique_topics.rs @@ -20,7 +20,7 @@ mod my_contract { pub struct MyContract {} /// Exemplary event - #[ink(event)] + #[ink::event_definition] pub enum Event { MyEvent { #[ink(topic)] diff --git a/examples/trait-erc20/lib.rs b/examples/trait-erc20/lib.rs index e48679cb74a..257e3b39995 100644 --- a/examples/trait-erc20/lib.rs +++ b/examples/trait-erc20/lib.rs @@ -64,27 +64,27 @@ mod erc20 { allowances: Mapping<(AccountId, AccountId), Balance>, } - /// Event emitted when a token transfer occurs. - #[ink(event)] - pub struct Transfer { - #[ink(topic)] - from: Option, - #[ink(topic)] - to: Option, - #[ink(topic)] - value: Balance, - } - - /// Event emitted when an approval occurs that `spender` is allowed to withdraw - /// up to the amount of `value` tokens from `owner`. - #[ink(event)] - pub struct Approval { - #[ink(topic)] - owner: AccountId, - #[ink(topic)] - spender: AccountId, - #[ink(topic)] - value: Balance, + #[ink::event_definition] + pub enum Event { + /// Event emitted when a token transfer occurs. + Transfer { + #[ink(topic)] + from: Option, + #[ink(topic)] + to: Option, + #[ink(topic)] + value: Balance, + }, + /// Event emitted when an approval occurs that `spender` is allowed to withdraw + /// up to the amount of `value` tokens from `owner`. + Approval { + #[ink(topic)] + owner: AccountId, + #[ink(topic)] + spender: AccountId, + #[ink(topic)] + value: Balance, + }, } impl Erc20 { From 3e83f6eeb5385a9a2a5ac8f4236f6b1b61323dde Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 7 Oct 2022 17:59:56 +0100 Subject: [PATCH 055/122] WIP attempt to make trait-erc20 compile --- crates/ink/ir/src/ir/event_def.rs | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/crates/ink/ir/src/ir/event_def.rs b/crates/ink/ir/src/ir/event_def.rs index 963d79c73c1..6b2e024055b 100644 --- a/crates/ink/ir/src/ir/event_def.rs +++ b/crates/ink/ir/src/ir/event_def.rs @@ -33,9 +33,9 @@ pub struct InkEventDefinition { impl TryFrom for InkEventDefinition { type Error = syn::Error; - fn try_from(item_enum: syn::ItemEnum) -> Result { + fn try_from(mut item_enum: syn::ItemEnum) -> Result { let mut variants = Vec::new(); - for (index, variant) in item_enum.variants.iter().enumerate() { + for (index, variant) in item_enum.variants.iter_mut().enumerate() { let mut fields = Vec::new(); let (ink_attrs, other_attrs) = ir::sanitize_optional_attributes( variant.span(), @@ -49,12 +49,9 @@ impl TryFrom for InkEventDefinition { )?; // strip out the `#[ink(anonymous)] attributes, since the item will be used to // regenerate the event enum - let variant = syn::Variant { - attrs: other_attrs, - ..variant.clone() - }; + variant.attrs = other_attrs; let anonymous = ink_attrs.map_or(false, |attrs| attrs.is_anonymous()); - for field in variant.fields.iter() { + for (index, field) in variant.fields.iter_mut().enumerate() { let (topic_attr, other_attrs) = ir::sanitize_optional_attributes( field.span(), field.attrs.clone(), @@ -65,18 +62,19 @@ impl TryFrom for InkEventDefinition { } }, )?; - let ident = field.ident.as_ref().ok_or_else(|| { - format_err_spanned!(variant, "event variants must have named fields") - })?; + let ident = field + .ident + .expect("field has no name"); + // todo: make this work + // .as_ref() + // .map(|ident| ident.clone()) + // .unwrap_or(quote::format_ident!("{}", index)); // strip out the `#[ink(topic)] attributes, since the item will be used to // regenerate the event enum - let field = syn::Field { - attrs: other_attrs, - ..field.clone() - }; + field.attrs = other_attrs; fields.push(EventField { is_topic: topic_attr.is_some(), - field, + field: field.clone(), ident: ident.clone(), }) } From a0768213b4da107ab2df857e52ee36decf4e6344 Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 17 Oct 2022 03:07:53 -0500 Subject: [PATCH 056/122] Fix up field def gen error --- crates/ink/ir/src/ir/event_def.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/crates/ink/ir/src/ir/event_def.rs b/crates/ink/ir/src/ir/event_def.rs index 6b2e024055b..64331c0a4e9 100644 --- a/crates/ink/ir/src/ir/event_def.rs +++ b/crates/ink/ir/src/ir/event_def.rs @@ -64,11 +64,9 @@ impl TryFrom for InkEventDefinition { )?; let ident = field .ident - .expect("field has no name"); - // todo: make this work - // .as_ref() - // .map(|ident| ident.clone()) - // .unwrap_or(quote::format_ident!("{}", index)); + .clone() + .unwrap_or_else(|| panic!("FIELDS SHOULD HAVE A NAME {:?}", field.ident)); + // .unwrap_or(quote::format_ident!("{}", index)); // todo: should it also handle tuple variants? This breaks // strip out the `#[ink(topic)] attributes, since the item will be used to // regenerate the event enum field.attrs = other_attrs; From 2f81f6752f8dc0e19a15e9f86b6fb31ad1c8d9fa Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 18 Oct 2022 17:29:51 +0100 Subject: [PATCH 057/122] Fix up trait-erc20 events emit --- examples/trait-erc20/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/trait-erc20/lib.rs b/examples/trait-erc20/lib.rs index 257e3b39995..c767f0b5b18 100644 --- a/examples/trait-erc20/lib.rs +++ b/examples/trait-erc20/lib.rs @@ -94,7 +94,7 @@ mod erc20 { let mut balances = Mapping::default(); let caller = Self::env().caller(); balances.insert(&caller, &total_supply); - Self::env().emit_event(Transfer { + Self::env().emit_event(Event::Transfer { from: None, to: Some(caller), value: total_supply, @@ -154,7 +154,7 @@ mod erc20 { fn approve(&mut self, spender: AccountId, value: Balance) -> Result<()> { let owner = self.env().caller(); self.allowances.insert((&owner, &spender), &value); - self.env().emit_event(Approval { + self.env().emit_event(Event::Approval { owner, spender, value, @@ -245,7 +245,7 @@ mod erc20 { self.balances.insert(from, &(from_balance - value)); let to_balance = self.balance_of_impl(to); self.balances.insert(to, &(to_balance + value)); - self.env().emit_event(Transfer { + self.env().emit_event(Event::Transfer { from: Some(*from), to: Some(*to), value, From 797ea95a2cdee268473c03bfd722606e459cfba9 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 18 Oct 2022 17:41:24 +0100 Subject: [PATCH 058/122] Fix up ink_env refs in event_definition --- crates/ink/codegen/src/generator/event_def.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/ink/codegen/src/generator/event_def.rs b/crates/ink/codegen/src/generator/event_def.rs index 3d28557c5f2..5cec92dbfea 100644 --- a/crates/ink/codegen/src/generator/event_def.rs +++ b/crates/ink/codegen/src/generator/event_def.rs @@ -126,8 +126,8 @@ impl<'a> EventDefinition<'a> { let field_type = field.ty(); let field_ident = field.ident(); quote_spanned!(span => - .push_topic::<::ink_env::topics::PrefixedValue<#field_type>>( - &::ink_env::topics::PrefixedValue { + .push_topic::<::ink::env::topics::PrefixedValue<#field_type>>( + &::ink::env::topics::PrefixedValue { // todo: deduplicate with EVENT_SIGNATURE prefix: ::core::concat!( ::core::module_path!(), @@ -146,8 +146,8 @@ impl<'a> EventDefinition<'a> { true => None, false => { Some(quote_spanned!(span=> - .push_topic::<::ink_env::topics::PrefixedValue<()>>( - &::ink_env::topics::PrefixedValue { + .push_topic::<::ink::env::topics::PrefixedValue<()>>( + &::ink::env::topics::PrefixedValue { // todo: look up event signature topic via indexed trait impl prefix: EVENT_SIGNATURE, value: &(), } @@ -178,7 +178,7 @@ impl<'a> EventDefinition<'a> { quote_spanned!(span => const _: () = { - impl ::ink_env::Topics for #event_ident { + impl ::ink::env::Topics for #event_ident { fn topics( &self, builder: ::ink::env::topics::TopicsBuilder<::ink::env::topics::state::Uninit, E, B>, From 2309dd3fab9c8de9ffb93b5a34fa622958077999 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 18 Oct 2022 18:10:36 +0100 Subject: [PATCH 059/122] Wire up event signature topic --- crates/ink/codegen/src/generator/event_def.rs | 5 +++-- crates/ink/src/reflect/event.rs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/ink/codegen/src/generator/event_def.rs b/crates/ink/codegen/src/generator/event_def.rs index 5cec92dbfea..24adbdac230 100644 --- a/crates/ink/codegen/src/generator/event_def.rs +++ b/crates/ink/codegen/src/generator/event_def.rs @@ -142,14 +142,15 @@ impl<'a> EventDefinition<'a> { ) }); + let index = variant.index(); let event_signature_topic = match variant.anonymous() { true => None, false => { Some(quote_spanned!(span=> .push_topic::<::ink::env::topics::PrefixedValue<()>>( &::ink::env::topics::PrefixedValue { - // todo: look up event signature topic via indexed trait impl - prefix: EVENT_SIGNATURE, value: &(), + prefix: &<#event_ident as ::ink::reflect::EventVariantInfo<#index>>::SIGNATURE, + value: &(), } ) )) diff --git a/crates/ink/src/reflect/event.rs b/crates/ink/src/reflect/event.rs index 6e89ffd24ea..6368207afd9 100644 --- a/crates/ink/src/reflect/event.rs +++ b/crates/ink/src/reflect/event.rs @@ -14,7 +14,7 @@ /// todo: docs /// The ID is the index of the event variant in the enum -pub trait EventVariantInfo { +pub trait EventVariantInfo { const NAME: &'static str; /// todo: docs /// Will be hashed unique path of Event -> Variant, used for topic of Event variant From d776c3f672f7ae902f03b57e231703d91e0b8b67 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 18 Oct 2022 20:41:10 +0100 Subject: [PATCH 060/122] Fix variant field bindings --- crates/ink/codegen/src/generator/event_def.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ink/codegen/src/generator/event_def.rs b/crates/ink/codegen/src/generator/event_def.rs index 24adbdac230..5dcc5d5c6b1 100644 --- a/crates/ink/codegen/src/generator/event_def.rs +++ b/crates/ink/codegen/src/generator/event_def.rs @@ -136,7 +136,7 @@ impl<'a> EventDefinition<'a> { "::", ::core::stringify!(#field_ident), ).as_bytes(), - value: &self.#field_ident, + value: #field_ident, } ) ) From a720d301c7715d94f90045c430068f791528dd7f Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 19 Oct 2022 10:41:17 +0100 Subject: [PATCH 061/122] Generate EventVariantInfo SIGNATURE --- crates/ink/codegen/src/generator/event_def.rs | 19 +++++++++---------- crates/ink/src/reflect/event.rs | 2 +- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/crates/ink/codegen/src/generator/event_def.rs b/crates/ink/codegen/src/generator/event_def.rs index 5dcc5d5c6b1..b78b7f78882 100644 --- a/crates/ink/codegen/src/generator/event_def.rs +++ b/crates/ink/codegen/src/generator/event_def.rs @@ -64,16 +64,15 @@ impl<'a> EventDefinition<'a> { let index = ev.index(); quote_spanned!(span=> impl ::ink::reflect::EventVariantInfo<#index> for #event_ident { - const NAME: &'static str = ::core::stringify!(#event_ident); - // const SIGNATURE: [u8; 32] = ::ink::blake2x256!(::core::concat!( - // ::core::module_path!(), "::", - // ::core::stringify!(#event_ident), "::", - // ::core::stringify!(#event_variant_ident)) - // ); - const SIGNATURE: [u8; 32] = ::ink::reflect::event_variant_signature( + const PATH: &'static str = ::core::concat!( ::core::module_path!(), - ::core::stringify!(#event_ident), - ::core::stringify!(#event_variant_ident), + "::", + ::core::stringify!(#event_ident) + ); + const NAME: &'static str = ::core::stringify!(#event_variant_ident); + const SIGNATURE: [u8; 32] = ::ink::reflect::event_variant_signature( + >::PATH, + >::NAME, ); } ) @@ -128,7 +127,7 @@ impl<'a> EventDefinition<'a> { quote_spanned!(span => .push_topic::<::ink::env::topics::PrefixedValue<#field_type>>( &::ink::env::topics::PrefixedValue { - // todo: deduplicate with EVENT_SIGNATURE + // todo: concat SIGNATURE + field name (possibly index by topic) prefix: ::core::concat!( ::core::module_path!(), "::", diff --git a/crates/ink/src/reflect/event.rs b/crates/ink/src/reflect/event.rs index 6368207afd9..3874b39f830 100644 --- a/crates/ink/src/reflect/event.rs +++ b/crates/ink/src/reflect/event.rs @@ -15,6 +15,7 @@ /// todo: docs /// The ID is the index of the event variant in the enum pub trait EventVariantInfo { + const PATH: &'static str; const NAME: &'static str; /// todo: docs /// Will be hashed unique path of Event -> Variant, used for topic of Event variant @@ -25,7 +26,6 @@ pub trait EventVariantInfo { // todo: move to primitives where xxh3 dependency is? pub const fn event_variant_signature( path: &'static str, - event_ident: &'static str, event_variant: &'static str, ) -> [u8; 32] { let buf = [0u8; 32]; From 9d2e334abeedc0cc9e5b0f23233fcf8a4f22bee5 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 19 Oct 2022 12:09:51 +0100 Subject: [PATCH 062/122] WIP impl compile time signature topic calculation --- crates/ink/codegen/src/generator/event_def.rs | 4 +- crates/ink/src/reflect/event.rs | 13 +----- crates/ink/src/reflect/mod.rs | 5 +-- crates/primitives/Cargo.toml | 2 +- crates/primitives/src/event.rs | 41 +++++++++++++++++++ crates/primitives/src/lib.rs | 2 + 6 files changed, 48 insertions(+), 19 deletions(-) create mode 100644 crates/primitives/src/event.rs diff --git a/crates/ink/codegen/src/generator/event_def.rs b/crates/ink/codegen/src/generator/event_def.rs index b78b7f78882..0dc847c226f 100644 --- a/crates/ink/codegen/src/generator/event_def.rs +++ b/crates/ink/codegen/src/generator/event_def.rs @@ -70,7 +70,7 @@ impl<'a> EventDefinition<'a> { ::core::stringify!(#event_ident) ); const NAME: &'static str = ::core::stringify!(#event_variant_ident); - const SIGNATURE: [u8; 32] = ::ink::reflect::event_variant_signature( + const SIGNATURE_TOPIC: [u8; 32] = ::ink::primitives::event_signature_topic( >::PATH, >::NAME, ); @@ -148,7 +148,7 @@ impl<'a> EventDefinition<'a> { Some(quote_spanned!(span=> .push_topic::<::ink::env::topics::PrefixedValue<()>>( &::ink::env::topics::PrefixedValue { - prefix: &<#event_ident as ::ink::reflect::EventVariantInfo<#index>>::SIGNATURE, + prefix: &<#event_ident as ::ink::reflect::EventVariantInfo<#index>>::SIGNATURE_TOPIC, value: &(), } ) diff --git a/crates/ink/src/reflect/event.rs b/crates/ink/src/reflect/event.rs index 3874b39f830..f040ef7c30c 100644 --- a/crates/ink/src/reflect/event.rs +++ b/crates/ink/src/reflect/event.rs @@ -20,16 +20,5 @@ pub trait EventVariantInfo { /// todo: docs /// Will be hashed unique path of Event -> Variant, used for topic of Event variant /// Should be able to compute up front - const SIGNATURE: [u8; 32]; -} - -// todo: move to primitives where xxh3 dependency is? -pub const fn event_variant_signature( - path: &'static str, - event_variant: &'static str, -) -> [u8; 32] { - let buf = [0u8; 32]; - // todo: use xxh3? - // let bytes = path.as_bytes() - buf + const SIGNATURE_TOPIC: [u8; 32]; } diff --git a/crates/ink/src/reflect/mod.rs b/crates/ink/src/reflect/mod.rs index 36ff261d422..dab634c8510 100644 --- a/crates/ink/src/reflect/mod.rs +++ b/crates/ink/src/reflect/mod.rs @@ -46,10 +46,7 @@ pub use self::{ DispatchableMessageInfo, ExecuteDispatchable, }, - event::{ - event_variant_signature, - EventVariantInfo, - }, + event::EventVariantInfo, trait_def::{ TraitDefinitionRegistry, TraitInfo, diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index e19ad86f6c9..a0743ab3360 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -19,7 +19,7 @@ derive_more = { version = "0.99", default-features = false, features = ["from", ink_prelude = { version = "4.0.0-alpha.3", path = "../prelude/", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive", "full"] } scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } -xxhash-rust = { version = "0.8", features = ["const_xxh32"] } +xxhash-rust = { version = "0.8", features = ["const_xxh32", "const_xxh3"] } [features] default = ["std"] diff --git a/crates/primitives/src/event.rs b/crates/primitives/src/event.rs new file mode 100644 index 00000000000..40a41de49e1 --- /dev/null +++ b/crates/primitives/src/event.rs @@ -0,0 +1,41 @@ +// Copyright 2018-2022 Parity Technologies (UK) Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use xxhash_rust::const_xxh3::xxh3_128; + +/// Generate the topic for the event signature. +/// +/// xxh3_128(path) ++ xxh3_128(event_variant) todo: + fields? +pub const fn event_signature_topic( + path: &'static str, + event_variant: &'static str, +) -> [u8; 32] { + let p = xxh3_128(path.as_bytes()).to_be_bytes(); + // todo: add fields to signature? + let s = xxh3_128(event_variant.as_bytes()).to_be_bytes(); + [ + p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], + p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15], + s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], + s[8], s[9], s[10], s[11], s[12], s[13], s[14], s[15], + ] +} + +// pub const fn event_field_topic_prefix( +// path: &'static str, +// event_variant: &'static str, +// ) -> [u8; 32] { +// let path = xxh3_128(path.as_bytes()); +// let signature = xxh3_128() +// } \ No newline at end of file diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index f5453da6081..2d57753f048 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -23,10 +23,12 @@ #![cfg_attr(not(feature = "std"), no_std)] +mod event; mod key; mod types; pub use self::{ + event::event_signature_topic, key::{ Key, KeyComposer, From 924666425182daa73a7cde93c1760f2a620e2d5a Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 19 Oct 2022 17:54:10 +0100 Subject: [PATCH 063/122] Remove field topic prefix --- crates/ink/codegen/src/generator/event_def.rs | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/crates/ink/codegen/src/generator/event_def.rs b/crates/ink/codegen/src/generator/event_def.rs index 0dc847c226f..17992112b9d 100644 --- a/crates/ink/codegen/src/generator/event_def.rs +++ b/crates/ink/codegen/src/generator/event_def.rs @@ -127,14 +127,18 @@ impl<'a> EventDefinition<'a> { quote_spanned!(span => .push_topic::<::ink::env::topics::PrefixedValue<#field_type>>( &::ink::env::topics::PrefixedValue { - // todo: concat SIGNATURE + field name (possibly index by topic) - prefix: ::core::concat!( - ::core::module_path!(), - "::", - ::core::stringify!(#event_ident), - "::", - ::core::stringify!(#field_ident), - ).as_bytes(), + // todo: figure out whether we even need to include a prefix here? + // Previously the prefix would be the full field path e.g. + // erc20::Event::Transfer::from + value. + // However the value on its own might be sufficient, albeit + // requiring combination with the signature topic and some + // metadata to determine whether a topic value belongs to a + // specific field of a given Event variant. The upside is that + // indexers can use the unhashed value for meaningful topics + // e.g. addresses < 32 bytes. If the prefix is included we + // will always require to hash the value so need any indexer + // would not be able to go from hash > address. + prefix: &[], value: #field_ident, } ) From 343ae04799d46ac4783e872424a42550140895c1 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 19 Oct 2022 17:56:27 +0100 Subject: [PATCH 064/122] Resolve some warnings --- crates/ink/codegen/src/generator/event_def.rs | 1 - crates/ink/codegen/src/generator/metadata/event.rs | 1 - crates/ink/ir/src/ir/event_def.rs | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/ink/codegen/src/generator/event_def.rs b/crates/ink/codegen/src/generator/event_def.rs index 17992112b9d..fe6d7682b2d 100644 --- a/crates/ink/codegen/src/generator/event_def.rs +++ b/crates/ink/codegen/src/generator/event_def.rs @@ -20,7 +20,6 @@ use quote::{ quote, quote_spanned, }; -use syn::spanned::Spanned as _; /// Generates code for an event definition. #[derive(From)] diff --git a/crates/ink/codegen/src/generator/metadata/event.rs b/crates/ink/codegen/src/generator/metadata/event.rs index 0b05f230fd7..59149181958 100644 --- a/crates/ink/codegen/src/generator/metadata/event.rs +++ b/crates/ink/codegen/src/generator/metadata/event.rs @@ -18,7 +18,6 @@ use derive_more::From; use ir::IsDocAttribute; use proc_macro2::TokenStream as TokenStream2; use quote::quote_spanned; -use syn::spanned::Spanned as _; /// Generates code for an event definition. #[derive(From)] diff --git a/crates/ink/ir/src/ir/event_def.rs b/crates/ink/ir/src/ir/event_def.rs index 64331c0a4e9..9016a8a7b6d 100644 --- a/crates/ink/ir/src/ir/event_def.rs +++ b/crates/ink/ir/src/ir/event_def.rs @@ -51,7 +51,7 @@ impl TryFrom for InkEventDefinition { // regenerate the event enum variant.attrs = other_attrs; let anonymous = ink_attrs.map_or(false, |attrs| attrs.is_anonymous()); - for (index, field) in variant.fields.iter_mut().enumerate() { + for (_index, field) in variant.fields.iter_mut().enumerate() { let (topic_attr, other_attrs) = ir::sanitize_optional_attributes( field.span(), field.attrs.clone(), From 4238fbd56598aea92bf5668031403130aec0a07e Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 20 Oct 2022 08:45:05 +0100 Subject: [PATCH 065/122] Restore topics guard --- crates/ink/codegen/src/generator/event_def.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ink/codegen/src/generator/event_def.rs b/crates/ink/codegen/src/generator/event_def.rs index fe6d7682b2d..920896dbb45 100644 --- a/crates/ink/codegen/src/generator/event_def.rs +++ b/crates/ink/codegen/src/generator/event_def.rs @@ -33,13 +33,13 @@ impl GenerateCode for EventDefinition<'_> { // let event_metadata_impl = self.generate_event_metadata_impl(); let event_info_impls = self.generate_event_variant_info_impls(); let topics_impl = self.generate_topics_impl(); - // let topics_guard = self.generate_topics_guard(); + let topics_guard = self.generate_topics_guard(); quote! { #event_enum #event_info_impls // #event_metadata_impl #topics_impl - // #topics_guard + #topics_guard } } } From 87ac91c21ffdcecc4c7f685a450f99de7f3a905b Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 20 Oct 2022 11:04:22 +0100 Subject: [PATCH 066/122] WIP generate event metadata, introduce EventInfo trait --- crates/ink/codegen/src/generator/event_def.rs | 26 ++- crates/ink/src/reflect/event.rs | 6 +- crates/ink/src/reflect/mod.rs | 5 +- crates/metadata/src/lib.rs | 2 +- crates/metadata/src/specs.rs | 150 +++++++++++++++--- 5 files changed, 158 insertions(+), 31 deletions(-) diff --git a/crates/ink/codegen/src/generator/event_def.rs b/crates/ink/codegen/src/generator/event_def.rs index 920896dbb45..be989a7cadb 100644 --- a/crates/ink/codegen/src/generator/event_def.rs +++ b/crates/ink/codegen/src/generator/event_def.rs @@ -31,12 +31,14 @@ impl GenerateCode for EventDefinition<'_> { fn generate_code(&self) -> TokenStream2 { let event_enum = self.generate_event_enum(); // let event_metadata_impl = self.generate_event_metadata_impl(); - let event_info_impls = self.generate_event_variant_info_impls(); + let event_info_impls = self.generate_event_info_impl(); + let event_variant_info_impls = self.generate_event_variant_info_impls(); let topics_impl = self.generate_topics_impl(); let topics_guard = self.generate_topics_guard(); quote! { #event_enum #event_info_impls + #event_variant_info_impls // #event_metadata_impl #topics_impl #topics_guard @@ -54,6 +56,21 @@ impl<'a> EventDefinition<'a> { ) } + fn generate_event_info_impl(&self) -> TokenStream2 { + let span = self.event_def.span(); + let event_ident = self.event_def.ident(); + + quote_spanned!(span=> + impl ::ink::reflect::EventInfo for #event_ident { + const PATH: &'static str = ::core::concat!( + ::core::module_path!(), + "::", + ::core::stringify!(#event_ident) + ); + } + ) + } + fn generate_event_variant_info_impls(&self) -> TokenStream2 { let span = self.event_def.span(); let event_ident = self.event_def.ident(); @@ -63,14 +80,9 @@ impl<'a> EventDefinition<'a> { let index = ev.index(); quote_spanned!(span=> impl ::ink::reflect::EventVariantInfo<#index> for #event_ident { - const PATH: &'static str = ::core::concat!( - ::core::module_path!(), - "::", - ::core::stringify!(#event_ident) - ); const NAME: &'static str = ::core::stringify!(#event_variant_ident); const SIGNATURE_TOPIC: [u8; 32] = ::ink::primitives::event_signature_topic( - >::PATH, + ::PATH, >::NAME, ); } diff --git a/crates/ink/src/reflect/event.rs b/crates/ink/src/reflect/event.rs index f040ef7c30c..9fe643e9128 100644 --- a/crates/ink/src/reflect/event.rs +++ b/crates/ink/src/reflect/event.rs @@ -12,10 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. +/// todo: docs +pub trait EventInfo { + const PATH: &'static str; +} + /// todo: docs /// The ID is the index of the event variant in the enum pub trait EventVariantInfo { - const PATH: &'static str; const NAME: &'static str; /// todo: docs /// Will be hashed unique path of Event -> Variant, used for topic of Event variant diff --git a/crates/ink/src/reflect/mod.rs b/crates/ink/src/reflect/mod.rs index dab634c8510..1c651843331 100644 --- a/crates/ink/src/reflect/mod.rs +++ b/crates/ink/src/reflect/mod.rs @@ -46,7 +46,10 @@ pub use self::{ DispatchableMessageInfo, ExecuteDispatchable, }, - event::EventVariantInfo, + event::{ + EventInfo, + EventVariantInfo, + }, trait_def::{ TraitDefinitionRegistry, TraitInfo, diff --git a/crates/metadata/src/lib.rs b/crates/metadata/src/lib.rs index d50a9ab0aa5..ea6ae03641c 100644 --- a/crates/metadata/src/lib.rs +++ b/crates/metadata/src/lib.rs @@ -37,7 +37,7 @@ pub use self::specs::{ EventParamSpec, EventParamSpecBuilder, EventSpec, - EventSpecBuilder, + EventVariantSpecBuilder, MessageParamSpec, MessageParamSpecBuilder, MessageSpec, diff --git a/crates/metadata/src/specs.rs b/crates/metadata/src/specs.rs index ad599de8c47..d8ed3eb9aa3 100644 --- a/crates/metadata/src/specs.rs +++ b/crates/metadata/src/specs.rs @@ -632,26 +632,134 @@ impl IntoPortable for MessageSpec { /// Describes an event definition. #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(bound( - serialize = "F::Type: Serialize, F::String: Serialize", - deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned" +serialize = "F::Type: Serialize, F::String: Serialize", +deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned" ))] pub struct EventSpec { - /// The label of the event. - label: F::String, - /// The event arguments. - args: Vec>, + /// The fully qualified path of the event. + path: F::String, + /// The event variants. + variants: Vec>, /// The event documentation. docs: Vec, } -/// An event specification builder. +/// An event variant specification builder. #[must_use] pub struct EventSpecBuilder { spec: EventSpec, } impl EventSpecBuilder { - /// Sets the input arguments of the event specification. + /// Sets the fully qualified path of the event. + pub fn path(self, path: &'static str) -> Self { + let mut this = self; + this.spec.path = path; + this + } + + /// Sets the variants of the event specification. + pub fn variants(self, variants: A) -> Self + where + A: IntoIterator, + { + let mut this = self; + debug_assert!(this.spec.variants.is_empty()); + this.spec.variants = variants.into_iter().collect::>(); + this + } + + /// Sets the documentation of the event specification. + pub fn docs(self, docs: D) -> Self + where + D: IntoIterator, + { + let mut this = self; + debug_assert!(this.spec.docs.is_empty()); + this.spec.docs = docs.into_iter().collect::>(); + this + } + + /// Finalizes building the event specification. + pub fn done(self) -> EventSpec { + self.spec + } +} + +impl IntoPortable for EventSpec { + type Output = EventSpec; + + fn into_portable(self, registry: &mut Registry) -> Self::Output { + EventSpec { + path: self.path.into_portable(registry), + variants: self + .variants + .into_iter() + .map(|arg| arg.into_portable(registry)) + .collect::>(), + docs: registry.map_into_portable(self.docs), + } + } +} + +impl EventSpec { + /// Creates a new event specification builder. + pub fn new(path: &'static str) -> EventSpecBuilder { + EventSpecBuilder { + spec: Self { + path, + variants: Vec::new(), + docs: Vec::new(), + }, + } + } +} + +impl EventSpec + where + F: Form, +{ + /// Returns the fully qualified path of the event. + pub fn path(&self) -> &F::String { + &self.path + } + + /// The event variants. + pub fn variants(&self) -> &[EventVariantSpec] { + &self.variants + } + + /// The event variant documentation. + pub fn docs(&self) -> &[F::String] { + &self.docs + } +} + +/// Describes an event variant. +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(bound( + serialize = "F::Type: Serialize, F::String: Serialize", + deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned" +))] +pub struct EventVariantSpec { + /// The label of the event variant. + label: F::String, + /// todo: The unique event signature for event topics. + // signature: F::String, + /// The event variant arguments. + args: Vec>, + /// The event variant documentation. + docs: Vec, +} + +/// An event variant specification builder. +#[must_use] +pub struct EventVariantSpecBuilder { + spec: EventVariantSpec, +} + +impl EventVariantSpecBuilder { + /// Sets the input arguments of the event variant specification. pub fn args(self, args: A) -> Self where A: IntoIterator, @@ -662,7 +770,7 @@ impl EventSpecBuilder { this } - /// Sets the input arguments of the event specification. + /// Sets the documentation of the event variant specification. pub fn docs(self, docs: D) -> Self where D: IntoIterator, @@ -674,16 +782,16 @@ impl EventSpecBuilder { } /// Finalizes building the event specification. - pub fn done(self) -> EventSpec { + pub fn done(self) -> EventVariantSpec { self.spec } } -impl IntoPortable for EventSpec { - type Output = EventSpec; +impl IntoPortable for EventVariantSpec { + type Output = EventVariantSpec; fn into_portable(self, registry: &mut Registry) -> Self::Output { - EventSpec { + EventVariantSpec { label: self.label.into_portable(registry), args: self .args @@ -695,10 +803,10 @@ impl IntoPortable for EventSpec { } } -impl EventSpec { - /// Creates a new event specification builder. - pub fn new(label: &'static str) -> EventSpecBuilder { - EventSpecBuilder { +impl EventVariantSpec { + /// Creates a new event variant specification builder. + pub fn new(label: &'static str) -> EventVariantSpecBuilder { + EventVariantSpecBuilder { spec: Self { label, args: Vec::new(), @@ -708,21 +816,21 @@ impl EventSpec { } } -impl EventSpec +impl EventVariantSpec where F: Form, { - /// Returns the label of the event. + /// Returns the label of the event variant. pub fn label(&self) -> &F::String { &self.label } - /// The event arguments. + /// The event variant arguments. pub fn args(&self) -> &[EventParamSpec] { &self.args } - /// The event documentation. + /// The event variant documentation. pub fn docs(&self) -> &[F::String] { &self.docs } From ec01087322f170f21c3e176faab9a4efcb274412 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 20 Oct 2022 11:41:03 +0100 Subject: [PATCH 067/122] Generate event variants metadata, wire it up --- crates/ink/codegen/src/generator/event_def.rs | 4 +- .../codegen/src/generator/metadata/event.rs | 74 ++++++++++++------- .../ink/codegen/src/generator/metadata/mod.rs | 62 ++++++++-------- crates/ink/ir/src/ir/event_def.rs | 16 ++-- crates/metadata/src/lib.rs | 2 + crates/metadata/src/specs.rs | 16 ++-- crates/primitives/src/event.rs | 9 +-- 7 files changed, 105 insertions(+), 78 deletions(-) diff --git a/crates/ink/codegen/src/generator/event_def.rs b/crates/ink/codegen/src/generator/event_def.rs index be989a7cadb..e9c460bc187 100644 --- a/crates/ink/codegen/src/generator/event_def.rs +++ b/crates/ink/codegen/src/generator/event_def.rs @@ -30,16 +30,16 @@ pub struct EventDefinition<'a> { impl GenerateCode for EventDefinition<'_> { fn generate_code(&self) -> TokenStream2 { let event_enum = self.generate_event_enum(); - // let event_metadata_impl = self.generate_event_metadata_impl(); let event_info_impls = self.generate_event_info_impl(); let event_variant_info_impls = self.generate_event_variant_info_impls(); + let event_metadata_impl = self.generate_event_metadata_impl(); let topics_impl = self.generate_topics_impl(); let topics_guard = self.generate_topics_guard(); quote! { #event_enum #event_info_impls #event_variant_info_impls - // #event_metadata_impl + #event_metadata_impl #topics_impl #topics_guard } diff --git a/crates/ink/codegen/src/generator/metadata/event.rs b/crates/ink/codegen/src/generator/metadata/event.rs index 59149181958..055a2c77b99 100644 --- a/crates/ink/codegen/src/generator/metadata/event.rs +++ b/crates/ink/codegen/src/generator/metadata/event.rs @@ -34,37 +34,57 @@ impl GenerateCode for EventMetadata<'_> { .attrs() .iter() .filter_map(|attr| attr.extract_docs()); - // let args = self.event_def.fields().map(|event_field| { - // let span = event_field.span(); - // let ident = event_field.ident(); - // let is_topic = event_field.is_topic; - // let docs = event_field - // .attrs() - // .into_iter() - // .filter_map(|attr| attr.extract_docs()); - // let ty = super::generate_type_spec(event_field.ty()); - // quote_spanned!(span => - // ::ink_metadata::EventParamSpec::new(::core::stringify!(#ident)) - // .of_type(#ty) - // .indexed(#is_topic) - // .docs([ - // #( #docs ),* - // ]) - // .done() - // ) - // }); - // todo generate event metadata - let args = Vec::::new(); + let variants = self.event_def.variants().map(|ev| { + let span = ev.span(); + let label = ev.ident(); + + let args = ev.fields().map(|event_field| { + let span = event_field.span(); + let ident = event_field.ident(); + let is_topic = event_field.is_topic; + let docs = event_field + .attrs() + .into_iter() + .filter_map(|attr| attr.extract_docs()); + let ty = super::generate_type_spec(event_field.ty()); + quote_spanned!(span => + ::ink::metadata::EventParamSpec::new(::core::stringify!(#ident)) + .of_type(#ty) + .indexed(#is_topic) + .docs([ + #( #docs ),* + ]) + .done() + ) + }); + + let docs = ev + .attrs() + .iter() + .filter_map(|attr| attr.extract_docs()) + .collect::>(); + + quote_spanned!(span=> + ::ink::metadata::EventVariantSpec::new(::core::stringify!(#label)) + .args([ + #( #args ),* + ]) + .docs([ + #( #docs ),* + ]) + .done() + ) + }); + quote_spanned!(span=> #[cfg(feature = "std")] #[cfg(not(feature = "ink-as-dependency"))] const _: () = { - impl ::ink_metadata::EventMetadata for #event_ident { - fn event_spec() -> ::ink_metadata::EventSpec { - // todo: insert event ident - ::ink_metadata::EventSpec::new(::core::stringify!(#event_ident)) - .args([ - #( #args ),* + impl ::ink::metadata::EventMetadata for #event_ident { + fn event_spec() -> ::ink::metadata::EventSpec { + ::ink::metadata::EventSpec::new(<#event_ident as ::ink::reflect::EventInfo>::PATH) + .variants([ + #( #variants ),* ]) .docs([ #( #docs ),* diff --git a/crates/ink/codegen/src/generator/metadata/mod.rs b/crates/ink/codegen/src/generator/metadata/mod.rs index bf9a5baa9af..c88ac452385 100644 --- a/crates/ink/codegen/src/generator/metadata/mod.rs +++ b/crates/ink/codegen/src/generator/metadata/mod.rs @@ -155,7 +155,7 @@ impl Metadata<'_> { syn::Pat::Ident(ident) => &ident.ident, _ => unreachable!("encountered ink! dispatch input with missing identifier"), }; - let type_spec = Self::generate_type_spec(&pat_type.ty); + let type_spec = generate_type_spec(&pat_type.ty); quote! { ::ink::metadata::MessageParamSpec::new(::core::stringify!(#ident)) .of_type(#type_spec) @@ -163,35 +163,6 @@ impl Metadata<'_> { } } - /// Generates the ink! metadata for the given type. - fn generate_type_spec(ty: &syn::Type) -> TokenStream2 { - fn without_display_name(ty: &syn::Type) -> TokenStream2 { - quote! { ::ink::metadata::TypeSpec::new::<#ty>() } - } - if let syn::Type::Path(type_path) = ty { - if type_path.qself.is_some() { - return without_display_name(ty) - } - let path = &type_path.path; - if path.segments.is_empty() { - return without_display_name(ty) - } - let segs = path - .segments - .iter() - .map(|seg| &seg.ident) - .collect::>(); - quote! { - ::ink::metadata::TypeSpec::with_name_segs::<#ty, _>( - ::core::iter::IntoIterator::into_iter([ #( ::core::stringify!(#segs) ),* ]) - .map(::core::convert::AsRef::as_ref) - ) - } - } else { - without_display_name(ty) - } - } - /// Generates the ink! metadata for all ink! smart contract messages. fn generate_messages(&self) -> Vec { let mut messages = Vec::new(); @@ -310,7 +281,7 @@ impl Metadata<'_> { } } Some(ty) => { - let type_spec = Self::generate_type_spec(ty); + let type_spec = generate_type_spec(ty); quote! { ::ink::metadata::ReturnTypeSpec::new(#type_spec) } @@ -319,6 +290,35 @@ impl Metadata<'_> { } } +/// Generates the ink! metadata for the given type. +fn generate_type_spec(ty: &syn::Type) -> TokenStream2 { + fn without_display_name(ty: &syn::Type) -> TokenStream2 { + quote! { ::ink::metadata::TypeSpec::new::<#ty>() } + } + if let syn::Type::Path(type_path) = ty { + if type_path.qself.is_some() { + return without_display_name(ty) + } + let path = &type_path.path; + if path.segments.is_empty() { + return without_display_name(ty) + } + let segs = path + .segments + .iter() + .map(|seg| &seg.ident) + .collect::>(); + quote! { + ::ink::metadata::TypeSpec::with_name_segs::<#ty, _>( + ::core::iter::IntoIterator::into_iter([ #( ::core::stringify!(#segs) ),* ]) + .map(::core::convert::AsRef::as_ref) + ) + } + } else { + without_display_name(ty) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/ink/ir/src/ir/event_def.rs b/crates/ink/ir/src/ir/event_def.rs index 9016a8a7b6d..56b2eabd8e4 100644 --- a/crates/ink/ir/src/ir/event_def.rs +++ b/crates/ink/ir/src/ir/event_def.rs @@ -62,11 +62,10 @@ impl TryFrom for InkEventDefinition { } }, )?; - let ident = field - .ident - .clone() - .unwrap_or_else(|| panic!("FIELDS SHOULD HAVE A NAME {:?}", field.ident)); - // .unwrap_or(quote::format_ident!("{}", index)); // todo: should it also handle tuple variants? This breaks + let ident = field.ident.clone().unwrap_or_else(|| { + panic!("FIELDS SHOULD HAVE A NAME {:?}", field.ident) + }); + // .unwrap_or(quote::format_ident!("{}", index)); // todo: should it also handle tuple variants? This breaks // strip out the `#[ink(topic)] attributes, since the item will be used to // regenerate the event enum field.attrs = other_attrs; @@ -165,6 +164,13 @@ impl EventVariant { self.item.span() } + /// Returns all non-ink! attributes of the event variant. + pub fn attrs(&self) -> Vec { + let (_, non_ink_attrs) = ir::partition_attributes(self.item.attrs.clone()) + .expect("encountered invalid event field attributes"); + non_ink_attrs + } + /// The identifier of the event variant. pub fn ident(&self) -> &Ident { &self.item.ident diff --git a/crates/metadata/src/lib.rs b/crates/metadata/src/lib.rs index ea6ae03641c..85c1461a0b6 100644 --- a/crates/metadata/src/lib.rs +++ b/crates/metadata/src/lib.rs @@ -37,6 +37,8 @@ pub use self::specs::{ EventParamSpec, EventParamSpecBuilder, EventSpec, + EventSpecBuilder, + EventVariantSpec, EventVariantSpecBuilder, MessageParamSpec, MessageParamSpecBuilder, diff --git a/crates/metadata/src/specs.rs b/crates/metadata/src/specs.rs index d8ed3eb9aa3..7d46a7f7529 100644 --- a/crates/metadata/src/specs.rs +++ b/crates/metadata/src/specs.rs @@ -632,8 +632,8 @@ impl IntoPortable for MessageSpec { /// Describes an event definition. #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(bound( -serialize = "F::Type: Serialize, F::String: Serialize", -deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned" + serialize = "F::Type: Serialize, F::String: Serialize", + deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned" ))] pub struct EventSpec { /// The fully qualified path of the event. @@ -660,8 +660,8 @@ impl EventSpecBuilder { /// Sets the variants of the event specification. pub fn variants(self, variants: A) -> Self - where - A: IntoIterator, + where + A: IntoIterator, { let mut this = self; debug_assert!(this.spec.variants.is_empty()); @@ -671,8 +671,8 @@ impl EventSpecBuilder { /// Sets the documentation of the event specification. pub fn docs(self, docs: D) -> Self - where - D: IntoIterator, + where + D: IntoIterator, { let mut this = self; debug_assert!(this.spec.docs.is_empty()); @@ -716,8 +716,8 @@ impl EventSpec { } impl EventSpec - where - F: Form, +where + F: Form, { /// Returns the fully qualified path of the event. pub fn path(&self) -> &F::String { diff --git a/crates/primitives/src/event.rs b/crates/primitives/src/event.rs index 40a41de49e1..8041d4a8251 100644 --- a/crates/primitives/src/event.rs +++ b/crates/primitives/src/event.rs @@ -25,10 +25,9 @@ pub const fn event_signature_topic( // todo: add fields to signature? let s = xxh3_128(event_variant.as_bytes()).to_be_bytes(); [ - p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], - p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15], - s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], - s[8], s[9], s[10], s[11], s[12], s[13], s[14], s[15], + p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], + p[13], p[14], p[15], s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], + s[10], s[11], s[12], s[13], s[14], s[15], ] } @@ -38,4 +37,4 @@ pub const fn event_signature_topic( // ) -> [u8; 32] { // let path = xxh3_128(path.as_bytes()); // let signature = xxh3_128() -// } \ No newline at end of file +// } From 97cd76538535082874651e0854b83a2160beec17 Mon Sep 17 00:00:00 2001 From: andrew Date: Tue, 25 Oct 2022 15:52:26 +0100 Subject: [PATCH 068/122] Allow passing in of event metadata vec --- .../ink/codegen/src/generator/metadata/mod.rs | 57 +++++++++---------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/crates/ink/codegen/src/generator/metadata/mod.rs b/crates/ink/codegen/src/generator/metadata/mod.rs index c88ac452385..def62dacf0c 100644 --- a/crates/ink/codegen/src/generator/metadata/mod.rs +++ b/crates/ink/codegen/src/generator/metadata/mod.rs @@ -41,7 +41,15 @@ impl_as_ref_for_generator!(Metadata); impl GenerateCode for Metadata<'_> { fn generate_code(&self) -> TokenStream2 { - let contract = self.generate_contract(); + let constructors = self.generate_constructors(); + let messages = self.generate_messages(); + let docs = self + .contract + .module() + .attrs() + .iter() + .filter_map(|attr| attr.extract_docs()); + let layout = self.generate_layout(); quote! { @@ -49,12 +57,29 @@ impl GenerateCode for Metadata<'_> { #[cfg(not(feature = "ink-as-dependency"))] const _: () = { #[no_mangle] - pub fn __ink_generate_metadata() -> ::ink::metadata::InkProject { + pub fn __ink_generate_metadata( + events: ::ink::prelude::vec::Vec<::ink::metadata::EventSpec> + ) -> ::ink::metadata::InkProject { let layout = #layout; ::ink::metadata::layout::ValidateLayout::validate(&layout).unwrap_or_else(|error| { ::core::panic!("metadata ink! generation failed: {}", error) }); - ::ink::metadata::InkProject::new(layout, #contract) + let contract = + ::ink::metadata::ContractSpec::new() + .constructors([ + #( #constructors ),* + ]) + .messages([ + #( #messages ),* + ]) + .events( + events + ) + .docs([ + #( #docs ),* + ]) + .done(); + ::ink::metadata::InkProject::new(layout, contract) } }; } @@ -83,32 +108,6 @@ impl Metadata<'_> { ) } - fn generate_contract(&self) -> TokenStream2 { - let constructors = self.generate_constructors(); - let messages = self.generate_messages(); - // let events = self.generate_events(); - // todo: call into InkEventDefinition::from_inline_event for inlinne events - let docs = self - .contract - .module() - .attrs() - .iter() - .filter_map(|attr| attr.extract_docs()); - quote! { - ::ink::metadata::ContractSpec::new() - .constructors([ - #( #constructors ),* - ]) - .messages([ - #( #messages ),* - ]) - .docs([ - #( #docs ),* - ]) - .done() - } - } - /// Generates ink! metadata for all ink! smart contract constructors. #[allow(clippy::redundant_closure)] // We are getting arcane lifetime errors otherwise. fn generate_constructors(&self) -> impl Iterator + '_ { From 354f81d563f8d3fc69dc920d1581489bbccf18ca Mon Sep 17 00:00:00 2001 From: andrew Date: Wed, 26 Oct 2022 15:39:45 +0100 Subject: [PATCH 069/122] Generate event metadata custom sections and externs --- .../codegen/src/generator/metadata/event.rs | 18 ++++++++++++++++++ crates/ink/ir/src/ir/event_def.rs | 17 ++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/crates/ink/codegen/src/generator/metadata/event.rs b/crates/ink/codegen/src/generator/metadata/event.rs index 055a2c77b99..70e0e627626 100644 --- a/crates/ink/codegen/src/generator/metadata/event.rs +++ b/crates/ink/codegen/src/generator/metadata/event.rs @@ -76,10 +76,28 @@ impl GenerateCode for EventMetadata<'_> { ) }); + let unique_id = self.event_def.unique_identifier(); + let hex = impl_serde::serialize::to_hex(&unique_id, true); + let event_metadata_fn = quote::format_ident!("__ink_event_metadata_{}", hex); + quote_spanned!(span=> + #[cfg(not(feature = "std"))] + const _: () = { + /// This adds a custom section to the unoptimized Wasm, the name of which + /// is used by `cargo-contract` to discover the extern function to get this + /// events metadata. + #[link_section = stringify!(#event_metadata_fn)] + pub static __INK_EVENT_METADATA: u32 = 0; + }; + #[cfg(feature = "std")] #[cfg(not(feature = "ink-as-dependency"))] const _: () = { + #[no_mangle] + pub fn #event_metadata_fn () -> ::ink::metadata::EventSpec { + < #event_ident as ::ink::metadata::EventMetadata >::event_spec() + } + impl ::ink::metadata::EventMetadata for #event_ident { fn event_spec() -> ::ink::metadata::EventSpec { ::ink::metadata::EventSpec::new(<#event_ident as ::ink::reflect::EventInfo>::PATH) diff --git a/crates/ink/ir/src/ir/event_def.rs b/crates/ink/ir/src/ir/event_def.rs index 56b2eabd8e4..b28b6a712e6 100644 --- a/crates/ink/ir/src/ir/event_def.rs +++ b/crates/ink/ir/src/ir/event_def.rs @@ -12,7 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::ir; +use crate::{ + blake2b_256, + ir, +}; use proc_macro2::{ Ident, Span, @@ -146,6 +149,18 @@ impl InkEventDefinition { .max() .unwrap_or_default() } + + /// Unique identifier for the event definition. + /// + /// **Note:** This needs only to be unique within the set of events imported by an individual + /// contract. + pub fn unique_identifier(&self) -> [u8; 32] { + let event_enum = &self.item; + let event_toks = quote::quote!( #event_enum ).to_string(); + let mut output = [0u8; 32]; + blake2b_256(event_toks.as_bytes(), &mut output); + output + } } /// A variant of an event. From ff3b2ed0f2c94ec42e0d84cb9ac4b78779f90129 Mon Sep 17 00:00:00 2001 From: andrew Date: Wed, 26 Oct 2022 15:46:31 +0100 Subject: [PATCH 070/122] Remove todo comment from event-shared-external.rs --- .../ink/tests/ui/contract/pass/event-shared-external.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/crates/ink/tests/ui/contract/pass/event-shared-external.rs b/crates/ink/tests/ui/contract/pass/event-shared-external.rs index 469b8a75241..dd8fa36caa0 100644 --- a/crates/ink/tests/ui/contract/pass/event-shared-external.rs +++ b/crates/ink/tests/ui/contract/pass/event-shared-external.rs @@ -1,11 +1,3 @@ -// todo: add the wiring to detect the events metadata, and in cargo-contract merge together -// todo: consider the possibility of enforcing shared events to be an enum, and tied to an ink! trait def -// only a single event type per interface which encapsulates all the possible events -// inside an impl the emit_event is restricted to that trait impl type. -// in libs there is no such restriction, can just ink_env::emit_event? -// either way still need to do the metadata scanning -// also with cross-contract call even those events will not be included in the metadata. - #[ink::event_definition] pub enum SharedEvent { Event1 { From 6c94cb0dd3390d9798b04f5e6cd142284a3a2dd4 Mon Sep 17 00:00:00 2001 From: andrew Date: Wed, 26 Oct 2022 17:54:03 +0100 Subject: [PATCH 071/122] Filter topic fields and combine bindings --- crates/ink/codegen/src/generator/event_def.rs | 55 +++++++++---------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/crates/ink/codegen/src/generator/event_def.rs b/crates/ink/codegen/src/generator/event_def.rs index e9c460bc187..7f4a8512fc1 100644 --- a/crates/ink/codegen/src/generator/event_def.rs +++ b/crates/ink/codegen/src/generator/event_def.rs @@ -125,36 +125,35 @@ impl<'a> EventDefinition<'a> { .map(|variant| { let span = variant.span(); let variant_ident = variant.ident(); - let field_bindings = variant.fields() - .map(|field| { - let span = field.span(); - let field_ident = field.ident(); - quote_spanned!(span=> ref #field_ident) - }); - let field_topics = variant.fields() + let (field_bindings, field_topics): (Vec<_>, Vec<_>) = variant.fields() + .filter(|field| field.is_topic) .map(|field| { let field_type = field.ty(); let field_ident = field.ident(); - quote_spanned!(span => - .push_topic::<::ink::env::topics::PrefixedValue<#field_type>>( - &::ink::env::topics::PrefixedValue { - // todo: figure out whether we even need to include a prefix here? - // Previously the prefix would be the full field path e.g. - // erc20::Event::Transfer::from + value. - // However the value on its own might be sufficient, albeit - // requiring combination with the signature topic and some - // metadata to determine whether a topic value belongs to a - // specific field of a given Event variant. The upside is that - // indexers can use the unhashed value for meaningful topics - // e.g. addresses < 32 bytes. If the prefix is included we - // will always require to hash the value so need any indexer - // would not be able to go from hash > address. - prefix: &[], - value: #field_ident, - } - ) - ) - }); + let push_topic = + quote_spanned!(span => + .push_topic::<::ink::env::topics::PrefixedValue<#field_type>>( + &::ink::env::topics::PrefixedValue { + // todo: figure out whether we even need to include a prefix here? + // Previously the prefix would be the full field path e.g. + // erc20::Event::Transfer::from + value. + // However the value on its own might be sufficient, albeit + // requiring combination with the signature topic and some + // metadata to determine whether a topic value belongs to a + // specific field of a given Event variant. The upside is that + // indexers can use the unhashed value for meaningful topics + // e.g. addresses < 32 bytes. If the prefix is included we + // will always require to hash the value so need any indexer + // would not be able to go from hash > address. + prefix: &[], + value: #field_ident, + } + ) + ); + let binding = quote_spanned!(span=> ref #field_ident); + (binding, push_topic) + }) + .unzip(); let index = variant.index(); let event_signature_topic = match variant.anonymous() { @@ -179,7 +178,7 @@ impl<'a> EventDefinition<'a> { }; quote_spanned!(span=> - Self::#variant_ident { #( #field_bindings, )* } => { + Self::#variant_ident { #( #field_bindings, )* .. } => { builder .build::<#remaining_topics_ty>() #event_signature_topic From 3beb5a7acb1beda69c3b7b38a4a338d476724c71 Mon Sep 17 00:00:00 2001 From: andrew Date: Sat, 29 Oct 2022 10:59:26 +0200 Subject: [PATCH 072/122] Migrating erc721 to new event def --- examples/erc721/lib.rs | 72 ++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/examples/erc721/lib.rs b/examples/erc721/lib.rs index e85be4fa587..0f8b0f737df 100644 --- a/examples/erc721/lib.rs +++ b/examples/erc721/lib.rs @@ -87,39 +87,37 @@ mod erc721 { NotAllowed, } - /// Event emitted when a token transfer occurs. - #[ink(event)] - pub struct Transfer { - #[ink(topic)] - from: Option, - #[ink(topic)] - to: Option, - #[ink(topic)] - id: TokenId, - } - - /// Event emitted when a token approve occurs. - #[ink(event)] - pub struct Approval { - #[ink(topic)] - from: AccountId, - #[ink(topic)] - to: AccountId, - #[ink(topic)] - id: TokenId, - } - - /// Event emitted when an operator is enabled or disabled for an owner. - /// The operator can manage all NFTs of the owner. - #[ink(event)] - pub struct ApprovalForAll { - #[ink(topic)] - owner: AccountId, - #[ink(topic)] - operator: AccountId, - approved: bool, + #[ink::event_definition] + pub enum Event { + /// Event emitted when a token transfer occurs. + Transfer { + #[ink(topic)] + from: Option, + #[ink(topic)] + to: Option, + #[ink(topic)] + id: TokenId, + }, + /// Event emitted when a token approve occurs. + Approval { + #[ink(topic)] + from: AccountId, + #[ink(topic)] + to: AccountId, + #[ink(topic)] + id: TokenId, + }, + /// Event emitted when an operator is enabled or disabled for an owner. + /// The operator can manage all NFTs of the owner. + ApprovalForAll { + #[ink(topic)] + owner: AccountId, + #[ink(topic)] + operator: AccountId, + approved: bool, + } } - + impl Erc721 { /// Creates a new ERC-721 token contract. #[ink(constructor)] @@ -200,7 +198,7 @@ mod erc721 { pub fn mint(&mut self, id: TokenId) -> Result<(), Error> { let caller = self.env().caller(); self.add_token_to(&caller, id)?; - self.env().emit_event(Transfer { + self.env().emit_event(Event::Transfer { from: Some(AccountId::from([0x0; 32])), to: Some(caller), id, @@ -230,7 +228,7 @@ mod erc721 { owned_tokens_count.insert(&caller, &count); token_owner.remove(&id); - self.env().emit_event(Transfer { + self.env().emit_event(Event::Transfer { from: Some(caller), to: Some(AccountId::from([0x0; 32])), id, @@ -256,7 +254,7 @@ mod erc721 { self.clear_approval(id); self.remove_token_from(from, id)?; self.add_token_to(to, id)?; - self.env().emit_event(Transfer { + self.env().emit_event(Event::Transfer { from: Some(*from), to: Some(*to), id, @@ -324,7 +322,7 @@ mod erc721 { if to == caller { return Err(Error::NotAllowed) } - self.env().emit_event(ApprovalForAll { + self.env().emit_event(Event::ApprovalForAll { owner: caller, operator: to, approved, @@ -359,7 +357,7 @@ mod erc721 { self.token_approvals.insert(&id, to); } - self.env().emit_event(Approval { + self.env().emit_event(Event::Approval { from: caller, to: *to, id, From 06bf240fb2ef8f38012f69a5725a83b49a2e7c7a Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 20 Oct 2022 13:41:47 +0100 Subject: [PATCH 073/122] Put event definition to the top of the contract file --- crates/ink/tests/unique_topics.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/ink/tests/unique_topics.rs b/crates/ink/tests/unique_topics.rs index 57f0a0adec4..cdccd06fba4 100644 --- a/crates/ink/tests/unique_topics.rs +++ b/crates/ink/tests/unique_topics.rs @@ -16,9 +16,6 @@ #[ink::contract] mod my_contract { - #[ink(storage)] - pub struct MyContract {} - /// Exemplary event #[ink::event_definition] pub enum Event { @@ -34,6 +31,9 @@ mod my_contract { }, } + #[ink(storage)] + pub struct MyContract {} + impl MyContract { /// Creates a new `MyContract` instance. #[ink(constructor)] From e1c97de458a8fcab91f60f9f436a72e217a2a1ab Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 31 Oct 2022 09:25:50 +0000 Subject: [PATCH 074/122] Add ink event metadata custom section marker --- crates/ink/codegen/src/generator/metadata/event.rs | 12 +++++------- crates/ink/ir/src/ir/event_def.rs | 13 ++++++------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/crates/ink/codegen/src/generator/metadata/event.rs b/crates/ink/codegen/src/generator/metadata/event.rs index 70e0e627626..9b1127d2e28 100644 --- a/crates/ink/codegen/src/generator/metadata/event.rs +++ b/crates/ink/codegen/src/generator/metadata/event.rs @@ -82,13 +82,11 @@ impl GenerateCode for EventMetadata<'_> { quote_spanned!(span=> #[cfg(not(feature = "std"))] - const _: () = { - /// This adds a custom section to the unoptimized Wasm, the name of which - /// is used by `cargo-contract` to discover the extern function to get this - /// events metadata. - #[link_section = stringify!(#event_metadata_fn)] - pub static __INK_EVENT_METADATA: u32 = 0; - }; + #[link_section = stringify!(#event_metadata_extern)] + /// This adds a custom section to the unoptimized Wasm, the name of which + /// is used by `cargo-contract` to discover the extern function to get this + /// events metadata. + pub static __INK_EVENT_METADATA: u32 = 0; #[cfg(feature = "std")] #[cfg(not(feature = "ink-as-dependency"))] diff --git a/crates/ink/ir/src/ir/event_def.rs b/crates/ink/ir/src/ir/event_def.rs index b28b6a712e6..0a90b3f86f3 100644 --- a/crates/ink/ir/src/ir/event_def.rs +++ b/crates/ink/ir/src/ir/event_def.rs @@ -150,15 +150,14 @@ impl InkEventDefinition { .unwrap_or_default() } - /// Unique identifier for the event definition. + /// Returns a unique identifier for this event definition. /// - /// **Note:** This needs only to be unique within the set of events imported by an individual - /// contract. - pub fn unique_identifier(&self) -> [u8; 32] { - let event_enum = &self.item; - let event_toks = quote::quote!( #event_enum ).to_string(); + /// **Note:** this only needs to be unique within the context of a contract binary. + pub fn unique_id(&self) -> [u8; 32] { + let item_enum = &self.item; + let event_def_str = quote::quote!( #item_enum ).to_string(); let mut output = [0u8; 32]; - blake2b_256(event_toks.as_bytes(), &mut output); + blake2b_256(event_def_str.as_bytes(), &mut output); output } } From 2356ffae7f8f9da83539ecf6758249d07ba163de Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 31 Oct 2022 09:34:24 +0000 Subject: [PATCH 075/122] Fix errors after merge --- crates/ink/codegen/src/generator/metadata/event.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ink/codegen/src/generator/metadata/event.rs b/crates/ink/codegen/src/generator/metadata/event.rs index 9b1127d2e28..487efdcea5c 100644 --- a/crates/ink/codegen/src/generator/metadata/event.rs +++ b/crates/ink/codegen/src/generator/metadata/event.rs @@ -76,13 +76,13 @@ impl GenerateCode for EventMetadata<'_> { ) }); - let unique_id = self.event_def.unique_identifier(); + let unique_id = self.event_def.unique_id(); let hex = impl_serde::serialize::to_hex(&unique_id, true); let event_metadata_fn = quote::format_ident!("__ink_event_metadata_{}", hex); quote_spanned!(span=> #[cfg(not(feature = "std"))] - #[link_section = stringify!(#event_metadata_extern)] + #[link_section = stringify!(#event_metadata_fn)] /// This adds a custom section to the unoptimized Wasm, the name of which /// is used by `cargo-contract` to discover the extern function to get this /// events metadata. From 53189d58b9831f8dcd7a6b0aefa579f7104c2650 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 31 Oct 2022 10:04:51 +0000 Subject: [PATCH 076/122] Number of topics builder per variant --- crates/ink/codegen/src/generator/event_def.rs | 3 +-- crates/ink/ir/src/ir/event_def.rs | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/crates/ink/codegen/src/generator/event_def.rs b/crates/ink/codegen/src/generator/event_def.rs index 7f4a8512fc1..c443d4abc21 100644 --- a/crates/ink/codegen/src/generator/event_def.rs +++ b/crates/ink/codegen/src/generator/event_def.rs @@ -117,7 +117,6 @@ impl<'a> EventDefinition<'a> { fn generate_topics_impl(&self) -> TokenStream2 { let span = self.event_def.span(); let event_ident = self.event_def.ident(); - let len_topics = self.event_def.max_len_topics(); let variant_match_arms = self .event_def @@ -170,7 +169,7 @@ impl<'a> EventDefinition<'a> { } }; - let remaining_topics_ty = match len_topics { + let remaining_topics_ty = match variant.len_topics() { 0 => quote_spanned!(span=> ::ink::env::topics::state::NoRemainingTopics), n => { quote_spanned!(span=> [::ink::env::topics::state::HasRemainingTopics; #n]) diff --git a/crates/ink/ir/src/ir/event_def.rs b/crates/ink/ir/src/ir/event_def.rs index 0a90b3f86f3..b0d47c1fae8 100644 --- a/crates/ink/ir/src/ir/event_def.rs +++ b/crates/ink/ir/src/ir/event_def.rs @@ -138,14 +138,7 @@ impl InkEventDefinition { /// Returns the maximum number of topics of any event variant. pub fn max_len_topics(&self) -> usize { self.variants() - .map(|v| { - let topics_len = v.fields().filter(|event| event.is_topic).count(); - if v.anonymous { - topics_len - } else { - topics_len + 1usize - } - }) + .map(|v| v.len_topics()) .max() .unwrap_or_default() } @@ -205,6 +198,16 @@ impl EventVariant { pub fn anonymous(&self) -> bool { self.anonymous } + + /// The number of topics of this event variant. + pub fn len_topics(&self) -> usize { + let topics_len = self.fields().filter(|event| event.is_topic).count(); + if self.anonymous { + topics_len + } else { + topics_len + 1usize + } + } } /// An event field with a flag indicating if this field is an event topic. From 3a23e066e33a616b790ae615d0fb98d1201792b7 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 31 Oct 2022 10:16:57 +0000 Subject: [PATCH 077/122] Fmt erc721 --- examples/erc721/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/erc721/lib.rs b/examples/erc721/lib.rs index 0f8b0f737df..805ba57e15d 100644 --- a/examples/erc721/lib.rs +++ b/examples/erc721/lib.rs @@ -115,9 +115,9 @@ mod erc721 { #[ink(topic)] operator: AccountId, approved: bool, - } + }, } - + impl Erc721 { /// Creates a new ERC-721 token contract. #[ink(constructor)] From ca6822392b9345fffe5aec8e1be9b89af32d3b7e Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 31 Oct 2022 10:17:34 +0000 Subject: [PATCH 078/122] Convert dns to event_definition enum --- examples/dns/lib.rs | 67 ++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/examples/dns/lib.rs b/examples/dns/lib.rs index 63743863044..aeb0bdbe7da 100644 --- a/examples/dns/lib.rs +++ b/examples/dns/lib.rs @@ -4,37 +4,35 @@ mod dns { use ink::storage::Mapping; - /// Emitted whenever a new name is being registered. - #[ink(event)] - pub struct Register { - #[ink(topic)] - name: Hash, - #[ink(topic)] - from: AccountId, - } - - /// Emitted whenever an address changes. - #[ink(event)] - pub struct SetAddress { - #[ink(topic)] - name: Hash, - from: AccountId, - #[ink(topic)] - old_address: Option, - #[ink(topic)] - new_address: AccountId, - } - - /// Emitted whenever a name is being transferred. - #[ink(event)] - pub struct Transfer { - #[ink(topic)] - name: Hash, - from: AccountId, - #[ink(topic)] - old_owner: Option, - #[ink(topic)] - new_owner: AccountId, + #[ink::event_definition] + pub enum Event { + /// Emitted whenever a new name is being registered. + Register { + #[ink(topic)] + name: Hash, + #[ink(topic)] + from: AccountId, + }, + /// Emitted whenever an address changes. + SetAddress { + #[ink(topic)] + name: Hash, + from: AccountId, + #[ink(topic)] + old_address: Option, + #[ink(topic)] + new_address: AccountId, + }, + /// Emitted whenever a name is being transferred. + Transfer { + #[ink(topic)] + name: Hash, + from: AccountId, + #[ink(topic)] + old_owner: Option, + #[ink(topic)] + new_owner: AccountId, + }, } /// Domain name service contract inspired by @@ -92,7 +90,8 @@ mod dns { } self.name_to_owner.insert(&name, &caller); - self.env().emit_event(Register { name, from: caller }); + self.env() + .emit_event(Event::Register { name, from: caller }); Ok(()) } @@ -109,7 +108,7 @@ mod dns { let old_address = self.name_to_address.get(&name); self.name_to_address.insert(&name, &new_address); - self.env().emit_event(SetAddress { + self.env().emit_event(Event::SetAddress { name, from: caller, old_address, @@ -130,7 +129,7 @@ mod dns { let old_owner = self.name_to_owner.get(&name); self.name_to_owner.insert(&name, &to); - self.env().emit_event(Transfer { + self.env().emit_event(Event::Transfer { name, from: caller, old_owner, From d922172b0a49c3ae40790e07660881d6835d220b Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 31 Oct 2022 10:38:29 +0000 Subject: [PATCH 079/122] Fix up erc20 events --- examples/erc20/lib.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/examples/erc20/lib.rs b/examples/erc20/lib.rs index 6beef8f56d6..4a33f2b213e 100644 --- a/examples/erc20/lib.rs +++ b/examples/erc20/lib.rs @@ -17,8 +17,7 @@ mod erc20 { allowances: Mapping<(AccountId, AccountId), Balance>, } - - #[ink(event)] + #[ink::event_definition] pub enum Event { /// Event emitted when a token transfer occurs. Transfer { @@ -36,7 +35,7 @@ mod erc20 { #[ink(topic)] spender: AccountId, value: Balance, - } + }, } /// The ERC-20 error types. @@ -59,7 +58,7 @@ mod erc20 { let mut balances = Mapping::default(); let caller = Self::env().caller(); balances.insert(&caller, &total_supply); - Self::env().emit_event(Transfer { + Self::env().emit_event(Event::Transfer { from: None, to: Some(caller), value: total_supply, @@ -143,7 +142,7 @@ mod erc20 { pub fn approve(&mut self, spender: AccountId, value: Balance) -> Result<()> { let owner = self.env().caller(); self.allowances.insert((&owner, &spender), &value); - self.env().emit_event(Approval { + self.env().emit_event(Event::Approval { owner, spender, value, @@ -205,7 +204,7 @@ mod erc20 { self.balances.insert(from, &(from_balance - value)); let to_balance = self.balance_of_impl(to); self.balances.insert(to, &(to_balance + value)); - self.env().emit_event(Transfer { + self.env().emit_event(Event::Transfer { from: Some(*from), to: Some(*to), value, @@ -220,8 +219,6 @@ mod erc20 { use ink::primitives::Clear; - type Event = ::Type; - fn assert_transfer_event( event: &ink::env::test::EmittedEvent, expected_from: Option, @@ -230,7 +227,7 @@ mod erc20 { ) { let decoded_event = ::decode(&mut &event.data[..]) .expect("encountered invalid contract event data buffer"); - if let Event::Transfer(Transfer { from, to, value }) = decoded_event { + if let Event::Transfer { from, to, value } = decoded_event { assert_eq!(from, expected_from, "encountered invalid Transfer.from"); assert_eq!(to, expected_to, "encountered invalid Transfer.to"); assert_eq!(value, expected_value, "encountered invalid Trasfer.value"); From 16aa6151fedfa17cc250dc34015d88577b2c4b66 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 31 Oct 2022 10:42:09 +0000 Subject: [PATCH 080/122] Migrate rand-extension example --- examples/rand-extension/lib.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/examples/rand-extension/lib.rs b/examples/rand-extension/lib.rs index 5dc4f0a3318..4c27497f177 100755 --- a/examples/rand-extension/lib.rs +++ b/examples/rand-extension/lib.rs @@ -63,10 +63,12 @@ mod rand_extension { value: [u8; 32], } - #[ink(event)] - pub struct RandomUpdated { - #[ink(topic)] - new: [u8; 32], + #[ink::event_definition] + pub enum Event { + RandomUpdated { + #[ink(topic)] + new: [u8; 32], + }, } impl RandExtension { @@ -94,7 +96,8 @@ mod rand_extension { self.value = new_random; // Emit the `RandomUpdated` event when the random seed // is successfully fetched. - self.env().emit_event(RandomUpdated { new: new_random }); + self.env() + .emit_event(Event::RandomUpdated { new: new_random }); Ok(()) } From 2ba841ea0e562a0f83aa174d253b9bbb58b4b822 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 31 Oct 2022 10:45:27 +0000 Subject: [PATCH 081/122] Migrate erc1155 example --- examples/erc1155/lib.rs | 68 ++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/examples/erc1155/lib.rs b/examples/erc1155/lib.rs index 50379d964b8..58f7446e844 100644 --- a/examples/erc1155/lib.rs +++ b/examples/erc1155/lib.rs @@ -193,37 +193,35 @@ mod erc1155 { type Owner = AccountId; type Operator = AccountId; - /// Indicate that a token transfer has occured. - /// - /// This must be emitted even if a zero value transfer occurs. - #[ink(event)] - pub struct TransferSingle { - #[ink(topic)] - operator: Option, - #[ink(topic)] - from: Option, - #[ink(topic)] - to: Option, - token_id: TokenId, - value: Balance, - } - - /// Indicate that an approval event has happened. - #[ink(event)] - pub struct ApprovalForAll { - #[ink(topic)] - owner: AccountId, - #[ink(topic)] - operator: AccountId, - approved: bool, - } - - /// Indicate that a token's URI has been updated. - #[ink(event)] - pub struct Uri { - value: ink::prelude::string::String, - #[ink(topic)] - token_id: TokenId, + #[ink::event_definition] + pub enum Event { + /// Indicate that a token transfer has occured. + /// + /// This must be emitted even if a zero value transfer occurs. + TransferSingle { + #[ink(topic)] + operator: Option, + #[ink(topic)] + from: Option, + #[ink(topic)] + to: Option, + token_id: TokenId, + value: Balance, + }, + /// Indicate that an approval event has happened. + ApprovalForAll { + #[ink(topic)] + owner: AccountId, + #[ink(topic)] + operator: AccountId, + approved: bool, + }, + /// Indicate that a token's URI has been updated. + Uri { + value: ink::prelude::string::String, + #[ink(topic)] + token_id: TokenId, + }, } /// An ERC-1155 contract. @@ -263,7 +261,7 @@ mod erc1155 { self.balances.insert(&(caller, self.token_id_nonce), &value); // Emit transfer event but with mint semantics - self.env().emit_event(TransferSingle { + self.env().emit_event(Event::TransferSingle { operator: Some(caller), from: None, to: if value == 0 { None } else { Some(caller) }, @@ -290,7 +288,7 @@ mod erc1155 { self.balances.insert(&(caller, token_id), &value); // Emit transfer event but with mint semantics - self.env().emit_event(TransferSingle { + self.env().emit_event(Event::TransferSingle { operator: Some(caller), from: None, to: Some(caller), @@ -328,7 +326,7 @@ mod erc1155 { self.balances.insert(&(to, token_id), &recipient_balance); let caller = self.env().caller(); - self.env().emit_event(TransferSingle { + self.env().emit_event(Event::TransferSingle { operator: Some(caller), from: Some(from), to: Some(from), @@ -522,7 +520,7 @@ mod erc1155 { self.approvals.remove((&caller, &operator)); } - self.env().emit_event(ApprovalForAll { + self.env().emit_event(Event::ApprovalForAll { owner: caller, operator, approved, From 55884db206f1d9c19c7cee09db99ebab4ef491ee Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 31 Oct 2022 11:13:18 +0000 Subject: [PATCH 082/122] Migrate payment-channel example --- examples/payment-channel/lib.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/examples/payment-channel/lib.rs b/examples/payment-channel/lib.rs index 6742cde5898..b44a66063b3 100755 --- a/examples/payment-channel/lib.rs +++ b/examples/payment-channel/lib.rs @@ -87,11 +87,13 @@ mod payment_channel { /// Type alias for the contract's `Result` type. pub type Result = core::result::Result; - /// Emitted when the sender starts closing the channel. - #[ink(event)] - pub struct SenderCloseStarted { - expiration: Timestamp, - close_duration: Timestamp, + #[ink::event_definition] + pub enum Event { + /// Emitted when the sender starts closing the channel. + SenderCloseStarted { + expiration: Timestamp, + close_duration: Timestamp, + }, } impl PaymentChannel { @@ -159,7 +161,7 @@ mod payment_channel { let now = self.env().block_timestamp(); let expiration = now + self.close_duration; - self.env().emit_event(SenderCloseStarted { + self.env().emit_event(Event::SenderCloseStarted { expiration, close_duration: self.close_duration, }); From 7d42db0c3aa47cf862e47fb4b2fa85a67926a0ff Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 31 Oct 2022 11:16:18 +0000 Subject: [PATCH 083/122] Migrate mother example --- examples/mother/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/mother/lib.rs b/examples/mother/lib.rs index bfb90698a25..0113313e839 100755 --- a/examples/mother/lib.rs +++ b/examples/mother/lib.rs @@ -122,10 +122,10 @@ mod mother { Panic, } - /// Event emitted when an auction being echoed. - #[ink(event)] - pub struct AuctionEchoed { - auction: Auction, + #[ink::event_definition] + pub enum Event { + /// Event emitted when an auction being echoed. + AuctionEchoed { auction: Auction }, } /// Storage of the contract. @@ -163,7 +163,7 @@ mod mother { /// Takes an auction data struct as input and returns it back. #[ink(message)] pub fn echo_auction(&mut self, auction: Auction) -> Auction { - self.env().emit_event(AuctionEchoed { + self.env().emit_event(Event::AuctionEchoed { auction: auction.clone(), }); auction From c91171a76d3d9c38cedee86c2f35b0ec559df2ae Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 31 Oct 2022 11:36:52 +0000 Subject: [PATCH 084/122] Migrate multisig example --- examples/multisig/lib.rs | 160 ++++++++++++++++++--------------------- 1 file changed, 74 insertions(+), 86 deletions(-) diff --git a/examples/multisig/lib.rs b/examples/multisig/lib.rs index 4b9ac0bb8e2..d9b04110973 100755 --- a/examples/multisig/lib.rs +++ b/examples/multisig/lib.rs @@ -167,81 +167,69 @@ mod multisig { next_id: TransactionId, } - /// Emitted when an owner confirms a transaction. - #[ink(event)] - pub struct Confirmation { - /// The transaction that was confirmed. - #[ink(topic)] - transaction: TransactionId, - /// The owner that sent the confirmation. - #[ink(topic)] - from: AccountId, - /// The confirmation status after this confirmation was applied. - #[ink(topic)] - status: ConfirmationStatus, - } - - /// Emitted when an owner revoked a confirmation. - #[ink(event)] - pub struct Revocation { - /// The transaction that was revoked. - #[ink(topic)] - transaction: TransactionId, - /// The owner that sent the revocation. - #[ink(topic)] - from: AccountId, - } - - /// Emitted when an owner submits a transaction. - #[ink(event)] - pub struct Submission { - /// The transaction that was submitted. - #[ink(topic)] - transaction: TransactionId, - } - - /// Emitted when a transaction was canceled. - #[ink(event)] - pub struct Cancellation { - /// The transaction that was canceled. - #[ink(topic)] - transaction: TransactionId, - } - - /// Emitted when a transaction was executed. - #[ink(event)] - pub struct Execution { - /// The transaction that was executed. - #[ink(topic)] - transaction: TransactionId, - /// Indicates whether the transaction executed successfully. If so the `Ok` value holds - /// the output in bytes. The Option is `None` when the transaction was executed through - /// `invoke_transaction` rather than `evaluate_transaction`. - #[ink(topic)] - result: Result>, Error>, - } - - /// Emitted when an owner is added to the wallet. - #[ink(event)] - pub struct OwnerAddition { - /// The owner that was added. - #[ink(topic)] - owner: AccountId, - } - - /// Emitted when an owner is removed from the wallet. - #[ink(event)] - pub struct OwnerRemoval { - /// The owner that was removed. - #[ink(topic)] - owner: AccountId, - } - - /// Emitted when the requirement changed. - #[ink(event)] - pub struct RequirementChange { - /// The new requirement value. - new_requirement: u32, + #[ink::event_definition] + pub enum Event { + /// Emitted when an owner confirms a transaction. + Confirmation { + /// The transaction that was confirmed. + #[ink(topic)] + transaction: TransactionId, + /// The owner that sent the confirmation. + #[ink(topic)] + from: AccountId, + /// The confirmation status after this confirmation was applied. + #[ink(topic)] + status: ConfirmationStatus, + }, + /// Emitted when an owner revoked a confirmation. + Revocation { + /// The transaction that was revoked. + #[ink(topic)] + transaction: TransactionId, + /// The owner that sent the revocation. + #[ink(topic)] + from: AccountId, + }, + /// Emitted when an owner submits a transaction. + Submission { + /// The transaction that was submitted. + #[ink(topic)] + transaction: TransactionId, + }, + /// Emitted when a transaction was canceled. + Cancellation { + /// The transaction that was canceled. + #[ink(topic)] + transaction: TransactionId, + }, + /// Emitted when a transaction was executed. + Execution { + /// The transaction that was executed. + #[ink(topic)] + transaction: TransactionId, + /// Indicates whether the transaction executed successfully. If so the `Ok` value holds + /// the output in bytes. The Option is `None` when the transaction was executed through + /// `invoke_transaction` rather than `evaluate_transaction`. + #[ink(topic)] + result: Result>, Error>, + }, + /// Emitted when an owner is added to the wallet. + OwnerAddition { + /// The owner that was added. + #[ink(topic)] + owner: AccountId, + }, + /// Emitted when an owner is removed from the wallet. + OwnerRemoval { + /// The owner that was removed. + #[ink(topic)] + owner: AccountId, + }, + /// Emitted when the requirement changed. + RequirementChange { + /// The new requirement value. + new_requirement: u32, + }, } #[ink(storage)] @@ -372,7 +360,7 @@ mod multisig { ensure_requirement_is_valid(self.owners.len() as u32 + 1, self.requirement); self.is_owner.insert(new_owner, &()); self.owners.push(new_owner); - self.env().emit_event(OwnerAddition { owner: new_owner }); + self.env().emit_event(Event::OwnerAddition { owner: new_owner }); } /// Remove an owner from the contract. @@ -396,7 +384,7 @@ mod multisig { self.is_owner.remove(&owner); self.requirement = requirement; self.clean_owner_confirmations(&owner); - self.env().emit_event(OwnerRemoval { owner }); + self.env().emit_event(Event::OwnerRemoval { owner }); } /// Replace an owner from the contract with a new one. @@ -416,8 +404,8 @@ mod multisig { self.is_owner.remove(&old_owner); self.is_owner.insert(new_owner, &()); self.clean_owner_confirmations(&old_owner); - self.env().emit_event(OwnerRemoval { owner: old_owner }); - self.env().emit_event(OwnerAddition { owner: new_owner }); + self.env().emit_event(Event::OwnerRemoval { owner: old_owner }); + self.env().emit_event(Event::OwnerAddition { owner: new_owner }); } /// Change the requirement to a new value. @@ -432,7 +420,7 @@ mod multisig { self.ensure_from_wallet(); ensure_requirement_is_valid(self.owners.len() as u32, new_requirement); self.requirement = new_requirement; - self.env().emit_event(RequirementChange { new_requirement }); + self.env().emit_event(Event::RequirementChange { new_requirement }); } /// Add a new transaction candidate to the contract. @@ -449,7 +437,7 @@ mod multisig { trans_id.checked_add(1).expect("Transaction ids exhausted."); self.transactions.insert(trans_id, &transaction); self.transaction_list.transactions.push(trans_id); - self.env().emit_event(Submission { + self.env().emit_event(Event::Submission { transaction: trans_id, }); ( @@ -468,7 +456,7 @@ mod multisig { pub fn cancel_transaction(&mut self, trans_id: TransactionId) { self.ensure_from_wallet(); if self.take_transaction(trans_id).is_some() { - self.env().emit_event(Cancellation { + self.env().emit_event(Event::Cancellation { transaction: trans_id, }); } @@ -514,7 +502,7 @@ mod multisig { confirmation_count -= 1; self.confirmation_count .insert(&trans_id, &confirmation_count); - self.env().emit_event(Revocation { + self.env().emit_event(Event::Revocation { transaction: trans_id, from: caller, }); @@ -551,7 +539,7 @@ mod multisig { .returns::<()>() .fire() .map_err(|_| Error::TransactionFailed); - self.env().emit_event(Execution { + self.env().emit_event(Event::Execution { transaction: trans_id, result: result.map(|_| None), }); @@ -584,7 +572,7 @@ mod multisig { .returns::>() .fire() .map_err(|_| Error::TransactionFailed); - self.env().emit_event(Execution { + self.env().emit_event(Event::Execution { transaction: trans_id, result: result.clone().map(Some), }); @@ -615,7 +603,7 @@ mod multisig { } }; if new_confirmation { - self.env().emit_event(Confirmation { + self.env().emit_event(Event::Confirmation { transaction, from: confirmer, status, From b4ddcac6d18a2b97910c962dab77c5cb4e028f0b Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 31 Oct 2022 15:37:29 +0000 Subject: [PATCH 085/122] WIP fixing topic attr validation --- crates/ink/ir/src/ir/event_def.rs | 120 +++++++++++------------------- 1 file changed, 45 insertions(+), 75 deletions(-) diff --git a/crates/ink/ir/src/ir/event_def.rs b/crates/ink/ir/src/ir/event_def.rs index b0d47c1fae8..4ac91f37a17 100644 --- a/crates/ink/ir/src/ir/event_def.rs +++ b/crates/ink/ir/src/ir/event_def.rs @@ -14,6 +14,7 @@ use crate::{ blake2b_256, + error::ExtError as _, ir, }; use proc_macro2::{ @@ -55,16 +56,37 @@ impl TryFrom for InkEventDefinition { variant.attrs = other_attrs; let anonymous = ink_attrs.map_or(false, |attrs| attrs.is_anonymous()); for (_index, field) in variant.fields.iter_mut().enumerate() { - let (topic_attr, other_attrs) = ir::sanitize_optional_attributes( - field.span(), - field.attrs.clone(), - |arg| { - match arg.kind() { - ir::AttributeArg::Topic => Ok(()), - _ => Err(None), + let field_span = field.span(); + let (ink_attrs, other_attrs) = + ir::partition_attributes(field.attrs.clone())?; + + let is_topic = if ink_attrs.is_empty() { + false + } else { + let normalized = + ir::InkAttribute::from_expanded(ink_attrs).map_err(|err| { + err.into_combine(format_err!(field_span, "at this invocation",)) + })?; + match normalized.first().kind() { + ir::AttributeArg::Topic => { + + }, + _ => return Err(format_err!( + field_span, + "first optional ink! attribute of an event field must be #[ink(topic)]", + )) + } + + for arg in normalized.args() { + if !matches!(arg.kind(), ir::AttributeArg::Topic) { + return Err(format_err!( + arg.span(), + "encountered conflicting ink! attribute for event field", + )) } - }, - )?; + } + }; + let ident = field.ident.clone().unwrap_or_else(|| { panic!("FIELDS SHOULD HAVE A NAME {:?}", field.ident) }); @@ -73,7 +95,7 @@ impl TryFrom for InkEventDefinition { // regenerate the event enum field.attrs = other_attrs; fields.push(EventField { - is_topic: topic_attr.is_some(), + is_topic, field: field.clone(), ident: ident.clone(), }) @@ -256,8 +278,8 @@ mod tests { #[test] fn simple_try_from_works() { - let item_struct: syn::ItemEnum = syn::parse_quote! { - #[ink(event)] + let item_enum: syn::ItemEnum = syn::parse_quote! { + #[ink::event_definition] pub enum MyEvent { Event { #[ink(topic)] @@ -266,57 +288,22 @@ mod tests { } } }; - assert!(InkEventDefinition::try_from(item_struct).is_ok()); + assert!(InkEventDefinition::try_from(item_enum).is_ok()); } - fn assert_try_from_fails(item_struct: syn::ItemEnum, expected: &str) { + fn assert_try_from_fails(item_enum: syn::ItemEnum, expected: &str) { assert_eq!( - InkEventDefinition::try_from(item_struct).map_err(|err| err.to_string()), + InkEventDefinition::try_from(item_enum).map_err(|err| err.to_string()), Err(expected.to_string()) ) } - #[test] - fn conflicting_struct_attributes_fails() { - assert_try_from_fails( - syn::parse_quote! { - #[ink(event)] - #[ink(storage)] - pub enum MyEvent { - Event { - #[ink(topic)] - field_1: i32, - field_2: bool, - } - } - }, - "encountered conflicting ink! attribute argument", - ) - } - - #[test] - fn duplicate_struct_attributes_fails() { - assert_try_from_fails( - syn::parse_quote! { - #[ink(event)] - pub enum MyEvent { - Event { - #[ink(topic)] - field_1: i32, - field_2: bool, - } - } - }, - "encountered duplicate ink! attribute", - ) - } - #[test] fn wrong_first_struct_attribute_fails() { assert_try_from_fails( syn::parse_quote! { #[ink(storage)] - #[ink(event)] + #[ink::event_definition] pub enum MyEvent { Event { #[ink(topic)] @@ -345,28 +332,11 @@ mod tests { ) } - #[test] - fn generic_event_fails() { - assert_try_from_fails( - syn::parse_quote! { - #[ink(event)] - pub enum GenericEvent { - Event { - #[ink(topic)] - field_1: T, - field_2: bool, - } - } - }, - "generic ink! event structs are not supported", - ) - } - #[test] fn non_pub_event_struct() { assert_try_from_fails( syn::parse_quote! { - #[ink(event)] + #[ink::event_definition] enum PrivateEvent { Event { #[ink(topic)] @@ -383,7 +353,7 @@ mod tests { fn duplicate_field_attributes_fails() { assert_try_from_fails( syn::parse_quote! { - #[ink(event)] + #[ink::event_definition] pub enum MyEvent { Event { #[ink(topic)] @@ -401,7 +371,7 @@ mod tests { fn invalid_field_attributes_fails() { assert_try_from_fails( syn::parse_quote! { - #[ink(event)] + #[ink::event_definition] pub enum MyEvent { Event { #[ink(message)] @@ -418,7 +388,7 @@ mod tests { fn conflicting_field_attributes_fails() { assert_try_from_fails( syn::parse_quote! { - #[ink(event)] + #[ink::event_definition] pub enum MyEvent { Event { #[ink(topic)] @@ -428,7 +398,7 @@ mod tests { } } }, - "encountered conflicting ink! attribute for event field", + "encountered conflicting ink! attribute argument", ) } @@ -479,7 +449,7 @@ mod tests { ]; let event_def = >::try_from(syn::parse_quote! { - #[ink(event)] + #[ink::event_definition] pub enum MyEvent { Event { #[ink(topic)] @@ -512,7 +482,7 @@ mod tests { } } assert_anonymous_event(syn::parse_quote! { - #[ink(event)] + #[ink::event_definition] pub enum MyEvent { #[ink(anonymous)] Event { From 9af23c6cb2237c2dcdc18b58a6910823519df1df Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 1 Nov 2022 17:33:43 +0000 Subject: [PATCH 086/122] WIP use event def ids to call into metadata --- .../codegen/src/generator/metadata/event.rs | 21 ++++++++++++------- crates/ink/src/reflect/event.rs | 10 +++++++++ crates/ink/src/reflect/mod.rs | 2 ++ crates/primitives/src/event.rs | 16 +++++++++++++- crates/primitives/src/lib.rs | 5 ++++- 5 files changed, 44 insertions(+), 10 deletions(-) diff --git a/crates/ink/codegen/src/generator/metadata/event.rs b/crates/ink/codegen/src/generator/metadata/event.rs index 487efdcea5c..95888cac280 100644 --- a/crates/ink/codegen/src/generator/metadata/event.rs +++ b/crates/ink/codegen/src/generator/metadata/event.rs @@ -81,19 +81,24 @@ impl GenerateCode for EventMetadata<'_> { let event_metadata_fn = quote::format_ident!("__ink_event_metadata_{}", hex); quote_spanned!(span=> + /// This adds the unique id of the event definition into a custom section, which can + /// be used by `cargo-contract` to identify and extract metadata for all imported event + /// definitions in the Wasm binary. #[cfg(not(feature = "std"))] - #[link_section = stringify!(#event_metadata_fn)] - /// This adds a custom section to the unoptimized Wasm, the name of which - /// is used by `cargo-contract` to discover the extern function to get this - /// events metadata. - pub static __INK_EVENT_METADATA: u32 = 0; + #[link_section = "__ink_event_definition_ids"] + pub static __INK_EVENT_METADATA: u128 = ::ink::primitives::path_unique_id( + <#event_ident as ::ink::reflect::EventInfo>::PATH + ); #[cfg(feature = "std")] #[cfg(not(feature = "ink-as-dependency"))] const _: () = { - #[no_mangle] - pub fn #event_metadata_fn () -> ::ink::metadata::EventSpec { - < #event_ident as ::ink::metadata::EventMetadata >::event_spec() + const EVENT_DEF_ID: u128 = ::ink::primitives::path_unique_id( + <#event_ident as ::ink::reflect::EventInfo>::PATH + ); + + impl ::ink::reflect::EventDefinition<{ EVENT_DEF_ID }> for ::ink::reflect::EventDefinitionRegistry { + type Type = #event_ident; } impl ::ink::metadata::EventMetadata for #event_ident { diff --git a/crates/ink/src/reflect/event.rs b/crates/ink/src/reflect/event.rs index 9fe643e9128..3c7f748bf49 100644 --- a/crates/ink/src/reflect/event.rs +++ b/crates/ink/src/reflect/event.rs @@ -26,3 +26,13 @@ pub trait EventVariantInfo { /// Should be able to compute up front const SIGNATURE_TOPIC: [u8; 32]; } + +/// todo: docs +pub trait EventDefinition { + type Type: EventInfo; +} + +/// todo: docs +pub enum EventDefinitionRegistry; + + diff --git a/crates/ink/src/reflect/mod.rs b/crates/ink/src/reflect/mod.rs index 1c651843331..dade1bdbafa 100644 --- a/crates/ink/src/reflect/mod.rs +++ b/crates/ink/src/reflect/mod.rs @@ -47,6 +47,8 @@ pub use self::{ ExecuteDispatchable, }, event::{ + EventDefinition, + EventDefinitionRegistry, EventInfo, EventVariantInfo, }, diff --git a/crates/primitives/src/event.rs b/crates/primitives/src/event.rs index 8041d4a8251..59fa6a23f1c 100644 --- a/crates/primitives/src/event.rs +++ b/crates/primitives/src/event.rs @@ -14,6 +14,20 @@ use xxhash_rust::const_xxh3::xxh3_128; +// todo: docs +pub const fn path_unique_bytes( + path: &'static str, +) -> [u8; 16] { + xxh3_128(path.as_bytes()).to_be_bytes() +} + +// todo: docs +pub const fn path_unique_id( + path: &'static str, +) -> u128 { + u128::from_be_bytes(path_unique_bytes(path)) +} + /// Generate the topic for the event signature. /// /// xxh3_128(path) ++ xxh3_128(event_variant) todo: + fields? @@ -21,7 +35,7 @@ pub const fn event_signature_topic( path: &'static str, event_variant: &'static str, ) -> [u8; 32] { - let p = xxh3_128(path.as_bytes()).to_be_bytes(); + let p = path_unique_bytes(path); // todo: add fields to signature? let s = xxh3_128(event_variant.as_bytes()).to_be_bytes(); [ diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index f8a02bb2ff8..9876c7b95b0 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -32,7 +32,10 @@ mod key; mod types; pub use self::{ - event::event_signature_topic, + event::{ + event_signature_topic, + path_unique_id, + }, key::{ Key, KeyComposer, From 82cff3d91a0edea1d56997a774a32fc073e07b0f Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 1 Nov 2022 18:13:40 +0000 Subject: [PATCH 087/122] Fix up topic field attribute validation, fix warnings --- .../codegen/src/generator/metadata/event.rs | 4 --- crates/ink/ir/src/ir/event_def.rs | 31 ++++++++++--------- crates/ink/src/reflect/event.rs | 4 +-- crates/primitives/src/event.rs | 8 ++--- 4 files changed, 19 insertions(+), 28 deletions(-) diff --git a/crates/ink/codegen/src/generator/metadata/event.rs b/crates/ink/codegen/src/generator/metadata/event.rs index 95888cac280..f48eb4d3e5c 100644 --- a/crates/ink/codegen/src/generator/metadata/event.rs +++ b/crates/ink/codegen/src/generator/metadata/event.rs @@ -76,10 +76,6 @@ impl GenerateCode for EventMetadata<'_> { ) }); - let unique_id = self.event_def.unique_id(); - let hex = impl_serde::serialize::to_hex(&unique_id, true); - let event_metadata_fn = quote::format_ident!("__ink_event_metadata_{}", hex); - quote_spanned!(span=> /// This adds the unique id of the event definition into a custom section, which can /// be used by `cargo-contract` to identify and extract metadata for all imported event diff --git a/crates/ink/ir/src/ir/event_def.rs b/crates/ink/ir/src/ir/event_def.rs index 4ac91f37a17..f863fcb6f9a 100644 --- a/crates/ink/ir/src/ir/event_def.rs +++ b/crates/ink/ir/src/ir/event_def.rs @@ -65,26 +65,27 @@ impl TryFrom for InkEventDefinition { } else { let normalized = ir::InkAttribute::from_expanded(ink_attrs).map_err(|err| { - err.into_combine(format_err!(field_span, "at this invocation",)) + err.into_combine(format_err!( + field_span, + "at this invocation", + )) })?; - match normalized.first().kind() { - ir::AttributeArg::Topic => { - - }, - _ => return Err(format_err!( - field_span, - "first optional ink! attribute of an event field must be #[ink(topic)]", - )) - } + let mut topic_attr = false; for arg in normalized.args() { - if !matches!(arg.kind(), ir::AttributeArg::Topic) { - return Err(format_err!( - arg.span(), - "encountered conflicting ink! attribute for event field", - )) + match (topic_attr, arg.kind()) { + (false, ir::AttributeArg::Topic) => topic_attr = true, + (true, ir::AttributeArg::Topic) => return Err(format_err!( + arg.span(), + "encountered conflicting ink! attribute for event field", + )), + (_, _) => return Err(format_err!( + field_span, + "only the #[ink(topic)] attribute is supported for event fields", + )), } } + topic_attr }; let ident = field.ident.clone().unwrap_or_else(|| { diff --git a/crates/ink/src/reflect/event.rs b/crates/ink/src/reflect/event.rs index 3c7f748bf49..6ca70fe8e13 100644 --- a/crates/ink/src/reflect/event.rs +++ b/crates/ink/src/reflect/event.rs @@ -33,6 +33,4 @@ pub trait EventDefinition { } /// todo: docs -pub enum EventDefinitionRegistry; - - +pub enum EventDefinitionRegistry {} diff --git a/crates/primitives/src/event.rs b/crates/primitives/src/event.rs index 59fa6a23f1c..06ba30d76ee 100644 --- a/crates/primitives/src/event.rs +++ b/crates/primitives/src/event.rs @@ -15,16 +15,12 @@ use xxhash_rust::const_xxh3::xxh3_128; // todo: docs -pub const fn path_unique_bytes( - path: &'static str, -) -> [u8; 16] { +pub const fn path_unique_bytes(path: &'static str) -> [u8; 16] { xxh3_128(path.as_bytes()).to_be_bytes() } // todo: docs -pub const fn path_unique_id( - path: &'static str, -) -> u128 { +pub const fn path_unique_id(path: &'static str) -> u128 { u128::from_be_bytes(path_unique_bytes(path)) } From 2261e9d4017997432908e19aa0c18ca6376bc3cd Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 2 Nov 2022 10:30:41 +0000 Subject: [PATCH 088/122] Revert using event definition ids in custom section --- .../codegen/src/generator/metadata/event.rs | 25 +++++++++---------- crates/ink/src/reflect/event.rs | 8 ------ crates/ink/src/reflect/mod.rs | 2 -- crates/primitives/src/event.rs | 12 +-------- crates/primitives/src/lib.rs | 5 +--- 5 files changed, 14 insertions(+), 38 deletions(-) diff --git a/crates/ink/codegen/src/generator/metadata/event.rs b/crates/ink/codegen/src/generator/metadata/event.rs index f48eb4d3e5c..487efdcea5c 100644 --- a/crates/ink/codegen/src/generator/metadata/event.rs +++ b/crates/ink/codegen/src/generator/metadata/event.rs @@ -76,25 +76,24 @@ impl GenerateCode for EventMetadata<'_> { ) }); + let unique_id = self.event_def.unique_id(); + let hex = impl_serde::serialize::to_hex(&unique_id, true); + let event_metadata_fn = quote::format_ident!("__ink_event_metadata_{}", hex); + quote_spanned!(span=> - /// This adds the unique id of the event definition into a custom section, which can - /// be used by `cargo-contract` to identify and extract metadata for all imported event - /// definitions in the Wasm binary. #[cfg(not(feature = "std"))] - #[link_section = "__ink_event_definition_ids"] - pub static __INK_EVENT_METADATA: u128 = ::ink::primitives::path_unique_id( - <#event_ident as ::ink::reflect::EventInfo>::PATH - ); + #[link_section = stringify!(#event_metadata_fn)] + /// This adds a custom section to the unoptimized Wasm, the name of which + /// is used by `cargo-contract` to discover the extern function to get this + /// events metadata. + pub static __INK_EVENT_METADATA: u32 = 0; #[cfg(feature = "std")] #[cfg(not(feature = "ink-as-dependency"))] const _: () = { - const EVENT_DEF_ID: u128 = ::ink::primitives::path_unique_id( - <#event_ident as ::ink::reflect::EventInfo>::PATH - ); - - impl ::ink::reflect::EventDefinition<{ EVENT_DEF_ID }> for ::ink::reflect::EventDefinitionRegistry { - type Type = #event_ident; + #[no_mangle] + pub fn #event_metadata_fn () -> ::ink::metadata::EventSpec { + < #event_ident as ::ink::metadata::EventMetadata >::event_spec() } impl ::ink::metadata::EventMetadata for #event_ident { diff --git a/crates/ink/src/reflect/event.rs b/crates/ink/src/reflect/event.rs index 6ca70fe8e13..9fe643e9128 100644 --- a/crates/ink/src/reflect/event.rs +++ b/crates/ink/src/reflect/event.rs @@ -26,11 +26,3 @@ pub trait EventVariantInfo { /// Should be able to compute up front const SIGNATURE_TOPIC: [u8; 32]; } - -/// todo: docs -pub trait EventDefinition { - type Type: EventInfo; -} - -/// todo: docs -pub enum EventDefinitionRegistry {} diff --git a/crates/ink/src/reflect/mod.rs b/crates/ink/src/reflect/mod.rs index dade1bdbafa..1c651843331 100644 --- a/crates/ink/src/reflect/mod.rs +++ b/crates/ink/src/reflect/mod.rs @@ -47,8 +47,6 @@ pub use self::{ ExecuteDispatchable, }, event::{ - EventDefinition, - EventDefinitionRegistry, EventInfo, EventVariantInfo, }, diff --git a/crates/primitives/src/event.rs b/crates/primitives/src/event.rs index 06ba30d76ee..8041d4a8251 100644 --- a/crates/primitives/src/event.rs +++ b/crates/primitives/src/event.rs @@ -14,16 +14,6 @@ use xxhash_rust::const_xxh3::xxh3_128; -// todo: docs -pub const fn path_unique_bytes(path: &'static str) -> [u8; 16] { - xxh3_128(path.as_bytes()).to_be_bytes() -} - -// todo: docs -pub const fn path_unique_id(path: &'static str) -> u128 { - u128::from_be_bytes(path_unique_bytes(path)) -} - /// Generate the topic for the event signature. /// /// xxh3_128(path) ++ xxh3_128(event_variant) todo: + fields? @@ -31,7 +21,7 @@ pub const fn event_signature_topic( path: &'static str, event_variant: &'static str, ) -> [u8; 32] { - let p = path_unique_bytes(path); + let p = xxh3_128(path.as_bytes()).to_be_bytes(); // todo: add fields to signature? let s = xxh3_128(event_variant.as_bytes()).to_be_bytes(); [ diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index 9876c7b95b0..f8a02bb2ff8 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -32,10 +32,7 @@ mod key; mod types; pub use self::{ - event::{ - event_signature_topic, - path_unique_id, - }, + event::event_signature_topic, key::{ Key, KeyComposer, From a25b76315a3c8432c7aeef115dedbb2e853e98ab Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 3 Nov 2022 17:07:04 +0000 Subject: [PATCH 089/122] Fix compilation errors after merge --- crates/metadata/src/specs.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/metadata/src/specs.rs b/crates/metadata/src/specs.rs index a8559561c9c..8a31cf5db98 100644 --- a/crates/metadata/src/specs.rs +++ b/crates/metadata/src/specs.rs @@ -719,7 +719,7 @@ where F: Form, { /// Sets the fully qualified path of the event. - pub fn path(self, path: &'static str) -> Self { + pub fn path(self, path: F::String) -> Self { let mut this = self; this.spec.path = path; this @@ -728,7 +728,7 @@ where /// Sets the variants of the event specification. pub fn variants(self, variants: A) -> Self where - A: IntoIterator, + A: IntoIterator>, { let mut this = self; debug_assert!(this.spec.variants.is_empty()); @@ -774,7 +774,7 @@ where F: Form, { /// Creates a new event specification builder. - pub fn new(label: ::String) -> EventSpecBuilder { + pub fn new(path: ::String) -> EventSpecBuilder { EventSpecBuilder { spec: Self { path, From 87a014a9aa68874d74463d6a3eb33901d59a12bc Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 3 Nov 2022 17:07:31 +0000 Subject: [PATCH 090/122] Comment out TypeSpec::default for now --- crates/metadata/src/specs.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/metadata/src/specs.rs b/crates/metadata/src/specs.rs index 8a31cf5db98..82e051a0aab 100644 --- a/crates/metadata/src/specs.rs +++ b/crates/metadata/src/specs.rs @@ -1001,14 +1001,14 @@ impl Default for TypeSpec { } } -impl Default for TypeSpec { - fn default() -> Self { - Self { - ty: u32::default().into(), - display_name: Default::default(), - } - } -} +// impl Default for TypeSpec { +// fn default() -> Self { +// Self { +// ty: u32::default().into(), +// display_name: Default::default(), +// } +// } +// } impl IntoPortable for TypeSpec { type Output = TypeSpec; From abdb624474352ed82cd34e69bde8979e9c813f4b Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 4 Nov 2022 09:23:19 +0000 Subject: [PATCH 091/122] Fix clippy errors --- crates/e2e/src/utils.rs | 2 +- crates/storage/src/lazy/mapping.rs | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/crates/e2e/src/utils.rs b/crates/e2e/src/utils.rs index ad5e9cb6284..9a60afa8858 100644 --- a/crates/e2e/src/utils.rs +++ b/crates/e2e/src/utils.rs @@ -17,7 +17,7 @@ use super::log_info; /// Extracts the Wasm blob from a contract bundle. pub fn extract_wasm(contract_path: &str) -> Vec { log_info(&format!("opening {:?}", contract_path)); - let reader = std::fs::File::open(&contract_path).unwrap_or_else(|err| { + let reader = std::fs::File::open(contract_path).unwrap_or_else(|err| { panic!("contract path cannot be opened: {:?}", err); }); let contract: contract_metadata::ContractMetadata = serde_json::from_reader(reader) diff --git a/crates/storage/src/lazy/mapping.rs b/crates/storage/src/lazy/mapping.rs index dadbe51c9c0..25be0b80ebe 100644 --- a/crates/storage/src/lazy/mapping.rs +++ b/crates/storage/src/lazy/mapping.rs @@ -261,8 +261,8 @@ mod tests { fn insert_and_get_work() { ink_env::test::run_test::(|_| { let mut mapping: Mapping = Mapping::new(); - mapping.insert(&1, &2); - assert_eq!(mapping.get(&1), Some(2)); + mapping.insert(1, &2); + assert_eq!(mapping.get(1), Some(2)); Ok(()) }) @@ -273,10 +273,10 @@ mod tests { fn insert_and_get_work_for_two_mapping_with_same_manual_key() { ink_env::test::run_test::(|_| { let mut mapping: Mapping> = Mapping::new(); - mapping.insert(&1, &2); + mapping.insert(1, &2); let mapping2: Mapping> = Mapping::new(); - assert_eq!(mapping2.get(&1), Some(2)); + assert_eq!(mapping2.get(1), Some(2)); Ok(()) }) @@ -287,7 +287,7 @@ mod tests { fn gets_default_if_no_key_set() { ink_env::test::run_test::(|_| { let mapping: Mapping = Mapping::new(); - assert_eq!(mapping.get(&1), None); + assert_eq!(mapping.get(1), None); Ok(()) }) @@ -300,14 +300,14 @@ mod tests { // Given let mut mapping: Mapping = Mapping::new(); - mapping.insert(&1, &2); - assert_eq!(mapping.get(&1), Some(2)); + mapping.insert(1, &2); + assert_eq!(mapping.get(1), Some(2)); // When - mapping.remove(&1); + mapping.remove(1); // Then - assert_eq!(mapping.get(&1), None); + assert_eq!(mapping.get(1), None); Ok(()) }) @@ -321,10 +321,10 @@ mod tests { let mapping: Mapping = Mapping::new(); // When - mapping.remove(&1); + mapping.remove(1); // Then - assert_eq!(mapping.get(&1), None); + assert_eq!(mapping.get(1), None); Ok(()) }) From 1d6fbafaeb56561191d481721517aa75940f6427 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 4 Nov 2022 09:44:33 +0000 Subject: [PATCH 092/122] Update `scale-info` requirement to 2.3 --- crates/env/Cargo.toml | 2 +- crates/ink/Cargo.toml | 2 +- crates/ink/macro/Cargo.toml | 2 +- crates/metadata/Cargo.toml | 2 +- crates/primitives/Cargo.toml | 2 +- crates/storage/Cargo.toml | 2 +- crates/storage/traits/Cargo.toml | 2 +- examples/contract-terminate/Cargo.toml | 2 +- examples/contract-transfer/Cargo.toml | 2 +- examples/delegator/Cargo.toml | 2 +- examples/delegator/accumulator/Cargo.toml | 2 +- examples/delegator/adder/Cargo.toml | 2 +- examples/delegator/subber/Cargo.toml | 2 +- examples/dns/Cargo.toml | 2 +- examples/erc1155/Cargo.toml | 2 +- examples/erc20/Cargo.toml | 2 +- examples/erc721/Cargo.toml | 2 +- examples/flipper/Cargo.toml | 2 +- examples/incrementer/Cargo.toml | 2 +- examples/mother/Cargo.toml | 2 +- examples/multisig/Cargo.toml | 2 +- examples/payment-channel/Cargo.toml | 2 +- examples/psp22-extension/Cargo.toml | 2 +- examples/rand-extension/Cargo.toml | 2 +- examples/trait-erc20/Cargo.toml | 2 +- examples/trait-flipper/Cargo.toml | 2 +- examples/trait-incrementer/Cargo.toml | 2 +- examples/trait-incrementer/traits/Cargo.toml | 2 +- examples/upgradeable-contracts/forward-calls/Cargo.toml | 2 +- examples/upgradeable-contracts/set-code-hash/Cargo.toml | 2 +- .../set-code-hash/updated-incrementer/Cargo.toml | 2 +- linting/Cargo.toml | 2 +- 32 files changed, 32 insertions(+), 32 deletions(-) diff --git a/crates/env/Cargo.toml b/crates/env/Cargo.toml index 81d5e0965e9..ba0806f1e91 100644 --- a/crates/env/Cargo.toml +++ b/crates/env/Cargo.toml @@ -47,7 +47,7 @@ secp256k1 = { version = "0.24", features = ["recovery", "global-context"], optio # # Sadly couldn't be marked as dev-dependency. # Never use this crate outside the off-chain environment! -scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } +scale-info = { version = "2.3", default-features = false, features = ["derive"], optional = true } [features] default = ["std"] diff --git a/crates/ink/Cargo.toml b/crates/ink/Cargo.toml index fcad926de33..65334979e1a 100644 --- a/crates/ink/Cargo.toml +++ b/crates/ink/Cargo.toml @@ -31,7 +31,7 @@ ink_metadata = { path = "../metadata", default-features = false } trybuild = { version = "1.0.60", features = ["diff"] } # Required for the doctest of `env_access::EnvAccess::instantiate_contract` -scale-info = { version = "2", default-features = false, features = ["derive"] } +scale-info = { version = "2.3", default-features = false, features = ["derive"] } [features] default = ["std"] diff --git a/crates/ink/macro/Cargo.toml b/crates/ink/macro/Cargo.toml index a7c9145d1d3..5e753675c93 100644 --- a/crates/ink/macro/Cargo.toml +++ b/crates/ink/macro/Cargo.toml @@ -31,7 +31,7 @@ ink = { path = ".." } ink_metadata = { path = "../../metadata" } ink_prelude = { path = "../../prelude" } ink_storage = { path = "../../storage" } -scale-info = { version = "2", default-features = false, features = ["derive"] } +scale-info = { version = "2.3", default-features = false, features = ["derive"] } [lib] name = "ink_macro" diff --git a/crates/metadata/Cargo.toml b/crates/metadata/Cargo.toml index b3e02f5804a..b67e6ffd354 100644 --- a/crates/metadata/Cargo.toml +++ b/crates/metadata/Cargo.toml @@ -21,7 +21,7 @@ ink_primitives = { version = "4.0.0-alpha.3", path = "../primitives/", default-f serde = { version = "1.0", default-features = false, features = ["derive", "alloc"] } impl-serde = "0.4.0" derive_more = { version = "0.99", default-features = false, features = ["from"] } -scale-info = { version = "2", default-features = false, features = ["derive", "serde", "decode"] } +scale-info = { version = "2.3", default-features = false, features = ["derive", "serde", "decode"] } [dev-dependencies] pretty_assertions = "1" diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index e19ad86f6c9..ef91e255553 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -18,7 +18,7 @@ include = ["/Cargo.toml", "src/**/*.rs", "/README.md", "/LICENSE"] derive_more = { version = "0.99", default-features = false, features = ["from", "display"] } ink_prelude = { version = "4.0.0-alpha.3", path = "../prelude/", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive", "full"] } -scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } +scale-info = { version = "2.3", default-features = false, features = ["derive"], optional = true } xxhash-rust = { version = "0.8", features = ["const_xxh32"] } [features] diff --git a/crates/storage/Cargo.toml b/crates/storage/Cargo.toml index 8fadb83d785..bec90fea904 100644 --- a/crates/storage/Cargo.toml +++ b/crates/storage/Cargo.toml @@ -23,7 +23,7 @@ ink_prelude = { version = "4.0.0-alpha.3", path = "../prelude/", default-feature scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive", "full"] } derive_more = { version = "0.99", default-features = false, features = ["from", "display"] } -scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } +scale-info = { version = "2.3", default-features = false, features = ["derive"], optional = true } cfg-if = "1.0" array-init = { version = "2.0", default-features = false } diff --git a/crates/storage/traits/Cargo.toml b/crates/storage/traits/Cargo.toml index dc3c6a4966a..9c6e7583abe 100644 --- a/crates/storage/traits/Cargo.toml +++ b/crates/storage/traits/Cargo.toml @@ -19,7 +19,7 @@ ink_metadata = { version = "4.0.0-alpha.3", path = "../../metadata", default-fea ink_primitives = { version = "4.0.0-alpha.3", path = "../../primitives", default-features = false } ink_prelude = { version = "4.0.0-alpha.3", path = "../../prelude", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive", "full"] } -scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } +scale-info = { version = "2.3", default-features = false, features = ["derive"], optional = true } syn = { version = "1", features = ["full"] } [dev-dependencies] diff --git a/examples/contract-terminate/Cargo.toml b/examples/contract-terminate/Cargo.toml index f0983b52e23..9d21de7b33c 100644 --- a/examples/contract-terminate/Cargo.toml +++ b/examples/contract-terminate/Cargo.toml @@ -9,7 +9,7 @@ publish = false ink = { path = "../../crates/ink", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } +scale-info = { version = "2.3", default-features = false, features = ["derive"], optional = true } [lib] name = "contract_terminate" diff --git a/examples/contract-transfer/Cargo.toml b/examples/contract-transfer/Cargo.toml index 21074243253..8a4f98ecd3f 100644 --- a/examples/contract-transfer/Cargo.toml +++ b/examples/contract-transfer/Cargo.toml @@ -9,7 +9,7 @@ publish = false ink = { path = "../../crates/ink", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } +scale-info = { version = "2.3", default-features = false, features = ["derive"], optional = true } [dev-dependencies] ink_e2e = { path = "../../crates/e2e" } diff --git a/examples/delegator/Cargo.toml b/examples/delegator/Cargo.toml index 563948931a6..1d6047ae946 100644 --- a/examples/delegator/Cargo.toml +++ b/examples/delegator/Cargo.toml @@ -9,7 +9,7 @@ publish = false ink = { path = "../../crates/ink", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } +scale-info = { version = "2.3", default-features = false, features = ["derive"], optional = true } adder = { path = "adder", default-features = false, features = ["ink-as-dependency"] } subber = { path = "subber", default-features = false, features = ["ink-as-dependency"] } diff --git a/examples/delegator/accumulator/Cargo.toml b/examples/delegator/accumulator/Cargo.toml index c4beec77898..2f2076a098e 100644 --- a/examples/delegator/accumulator/Cargo.toml +++ b/examples/delegator/accumulator/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] ink = { path = "../../../crates/ink", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } +scale-info = { version = "2.3", default-features = false, features = ["derive"], optional = true } [lib] name = "accumulator" diff --git a/examples/delegator/adder/Cargo.toml b/examples/delegator/adder/Cargo.toml index 527fe6d0a46..e91fcd0b0ef 100644 --- a/examples/delegator/adder/Cargo.toml +++ b/examples/delegator/adder/Cargo.toml @@ -10,7 +10,7 @@ ink = { path = "../../../crates/ink", default-features = false } accumulator = { path = "../accumulator", default-features = false, features = ["ink-as-dependency"] } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } +scale-info = { version = "2.3", default-features = false, features = ["derive"], optional = true } [lib] name = "adder" diff --git a/examples/delegator/subber/Cargo.toml b/examples/delegator/subber/Cargo.toml index 59c93e4613f..0f2a60f7eeb 100644 --- a/examples/delegator/subber/Cargo.toml +++ b/examples/delegator/subber/Cargo.toml @@ -10,7 +10,7 @@ ink = { path = "../../../crates/ink", default-features = false } accumulator = { path = "../accumulator", default-features = false, features = ["ink-as-dependency"] } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } +scale-info = { version = "2.3", default-features = false, features = ["derive"], optional = true } [lib] name = "subber" diff --git a/examples/dns/Cargo.toml b/examples/dns/Cargo.toml index 29c26cb0f4a..9d60fd74d25 100644 --- a/examples/dns/Cargo.toml +++ b/examples/dns/Cargo.toml @@ -9,7 +9,7 @@ publish = false ink = { path = "../../crates/ink", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } +scale-info = { version = "2.3", default-features = false, features = ["derive"], optional = true } [lib] name = "dns" diff --git a/examples/erc1155/Cargo.toml b/examples/erc1155/Cargo.toml index f67ad1c705c..3387a93aba3 100644 --- a/examples/erc1155/Cargo.toml +++ b/examples/erc1155/Cargo.toml @@ -9,7 +9,7 @@ publish = false ink = { path = "../../crates/ink", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } +scale-info = { version = "2.3", default-features = false, features = ["derive"], optional = true } [lib] name = "erc1155" diff --git a/examples/erc20/Cargo.toml b/examples/erc20/Cargo.toml index c210b868b3d..7af8d294814 100644 --- a/examples/erc20/Cargo.toml +++ b/examples/erc20/Cargo.toml @@ -9,7 +9,7 @@ publish = false ink = { path = "../../crates/ink", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } +scale-info = { version = "2.3", default-features = false, features = ["derive"], optional = true } [lib] name = "erc20" diff --git a/examples/erc721/Cargo.toml b/examples/erc721/Cargo.toml index 1238b7d5ddc..3db33e5bda1 100644 --- a/examples/erc721/Cargo.toml +++ b/examples/erc721/Cargo.toml @@ -9,7 +9,7 @@ publish = false ink = { path = "../../crates/ink", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } +scale-info = { version = "2.3", default-features = false, features = ["derive"], optional = true } [lib] name = "erc721" diff --git a/examples/flipper/Cargo.toml b/examples/flipper/Cargo.toml index b84c8679960..ec8865dcb56 100644 --- a/examples/flipper/Cargo.toml +++ b/examples/flipper/Cargo.toml @@ -9,7 +9,7 @@ publish = false ink = { path = "../../crates/ink", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } +scale-info = { version = "2.3", default-features = false, features = ["derive"], optional = true } [lib] name = "flipper" diff --git a/examples/incrementer/Cargo.toml b/examples/incrementer/Cargo.toml index 84ae3095e15..c21681b48f2 100644 --- a/examples/incrementer/Cargo.toml +++ b/examples/incrementer/Cargo.toml @@ -9,7 +9,7 @@ publish = false ink = { path = "../../crates/ink", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } +scale-info = { version = "2.3", default-features = false, features = ["derive"], optional = true } [lib] name = "incrementer" diff --git a/examples/mother/Cargo.toml b/examples/mother/Cargo.toml index 337b0703496..a81f834229f 100755 --- a/examples/mother/Cargo.toml +++ b/examples/mother/Cargo.toml @@ -10,7 +10,7 @@ publish = false ink = { path = "../../crates/ink", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } +scale-info = { version = "2.3", default-features = false, features = ["derive"], optional = true } [lib] name = "mother" diff --git a/examples/multisig/Cargo.toml b/examples/multisig/Cargo.toml index 9c21d02b140..ffe0345e025 100755 --- a/examples/multisig/Cargo.toml +++ b/examples/multisig/Cargo.toml @@ -9,7 +9,7 @@ publish = false ink = { path = "../../crates/ink", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } +scale-info = { version = "2.3", default-features = false, features = ["derive"], optional = true } [lib] name = "multisig" diff --git a/examples/payment-channel/Cargo.toml b/examples/payment-channel/Cargo.toml index 1a16473d881..d69d8ecf73d 100755 --- a/examples/payment-channel/Cargo.toml +++ b/examples/payment-channel/Cargo.toml @@ -9,7 +9,7 @@ publish = false ink = { path = "../../crates/ink", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -scale-info = { version = "2", default-features = false, features = ["derive"] } +scale-info = { version = "2.3", default-features = false, features = ["derive"] } [dev-dependencies] hex-literal = { version = "0.3" } diff --git a/examples/psp22-extension/Cargo.toml b/examples/psp22-extension/Cargo.toml index 5ced859fcae..bc538e15238 100755 --- a/examples/psp22-extension/Cargo.toml +++ b/examples/psp22-extension/Cargo.toml @@ -9,7 +9,7 @@ publish = false ink = { path = "../../crates/ink", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } +scale-info = { version = "2.3", default-features = false, features = ["derive"], optional = true } [lib] name = "psp22_extension" diff --git a/examples/rand-extension/Cargo.toml b/examples/rand-extension/Cargo.toml index c644e5dcd1a..ce5a0e2c8e6 100755 --- a/examples/rand-extension/Cargo.toml +++ b/examples/rand-extension/Cargo.toml @@ -9,7 +9,7 @@ publish = false ink = { path = "../../crates/ink", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } +scale-info = { version = "2.3", default-features = false, features = ["derive"], optional = true } [lib] name = "rand_extension" diff --git a/examples/trait-erc20/Cargo.toml b/examples/trait-erc20/Cargo.toml index 021e842adf1..29f1b99f105 100644 --- a/examples/trait-erc20/Cargo.toml +++ b/examples/trait-erc20/Cargo.toml @@ -9,7 +9,7 @@ publish = false ink = { path = "../../crates/ink", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } +scale-info = { version = "2.3", default-features = false, features = ["derive"], optional = true } [lib] name = "trait_erc20" diff --git a/examples/trait-flipper/Cargo.toml b/examples/trait-flipper/Cargo.toml index 4fdda79764e..326f75e9e5c 100644 --- a/examples/trait-flipper/Cargo.toml +++ b/examples/trait-flipper/Cargo.toml @@ -9,7 +9,7 @@ publish = false ink = { path = "../../crates/ink", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } +scale-info = { version = "2.3", default-features = false, features = ["derive"], optional = true } [lib] name = "trait_flipper" diff --git a/examples/trait-incrementer/Cargo.toml b/examples/trait-incrementer/Cargo.toml index a77d9fd51c8..521a7c8ce45 100644 --- a/examples/trait-incrementer/Cargo.toml +++ b/examples/trait-incrementer/Cargo.toml @@ -9,7 +9,7 @@ publish = false ink = { path = "../../crates/ink", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } +scale-info = { version = "2.3", default-features = false, features = ["derive"], optional = true } traits = { path = "./traits", default-features = false } [lib] diff --git a/examples/trait-incrementer/traits/Cargo.toml b/examples/trait-incrementer/traits/Cargo.toml index aa8b9fe38bb..97cbb67ec1b 100644 --- a/examples/trait-incrementer/traits/Cargo.toml +++ b/examples/trait-incrementer/traits/Cargo.toml @@ -9,7 +9,7 @@ publish = false ink = { path = "../../../crates/ink", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } +scale-info = { version = "2.3", default-features = false, features = ["derive"], optional = true } [lib] name = "traits" diff --git a/examples/upgradeable-contracts/forward-calls/Cargo.toml b/examples/upgradeable-contracts/forward-calls/Cargo.toml index 1d837cfc903..4b5fdea8f66 100644 --- a/examples/upgradeable-contracts/forward-calls/Cargo.toml +++ b/examples/upgradeable-contracts/forward-calls/Cargo.toml @@ -9,7 +9,7 @@ publish = false ink = { path = "../../../crates/ink", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } +scale-info = { version = "2.3", default-features = false, features = ["derive"], optional = true } [lib] name = "forward_calls" diff --git a/examples/upgradeable-contracts/set-code-hash/Cargo.toml b/examples/upgradeable-contracts/set-code-hash/Cargo.toml index 5fda147c7f9..dc80904e6ce 100644 --- a/examples/upgradeable-contracts/set-code-hash/Cargo.toml +++ b/examples/upgradeable-contracts/set-code-hash/Cargo.toml @@ -11,7 +11,7 @@ publish = false ink = { path = "../../../crates/ink", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } +scale-info = { version = "2.3", default-features = false, features = ["derive"], optional = true } [lib] name = "incrementer" diff --git a/examples/upgradeable-contracts/set-code-hash/updated-incrementer/Cargo.toml b/examples/upgradeable-contracts/set-code-hash/updated-incrementer/Cargo.toml index 065528e49eb..2dfc635c9c5 100644 --- a/examples/upgradeable-contracts/set-code-hash/updated-incrementer/Cargo.toml +++ b/examples/upgradeable-contracts/set-code-hash/updated-incrementer/Cargo.toml @@ -11,7 +11,7 @@ publish = false ink = { path = "../../../../crates/ink", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } +scale-info = { version = "2.3", default-features = false, features = ["derive"], optional = true } [lib] name = "updated_incrementer" diff --git a/linting/Cargo.toml b/linting/Cargo.toml index 822c212a43d..6e9f403fb14 100644 --- a/linting/Cargo.toml +++ b/linting/Cargo.toml @@ -34,7 +34,7 @@ ink_metadata = { path = "../crates/metadata", default-features = false } ink_primitives = { path = "../crates/primitives", default-features = false } ink_storage = { path = "../crates/storage", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -scale-info = { version = "2", default-features = false, features = ["derive"] } +scale-info = { version = "2.3", default-features = false, features = ["derive"] } # For the moment we have to include the tests as examples and # then use `dylint_testing::ui_test_examples`. From 22739eba7ecb0fb306de350da6002734be128a41 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 7 Nov 2022 12:13:16 +0000 Subject: [PATCH 093/122] Fix up erc20 ui test --- .../ui/contract/pass/example-erc20-works.rs | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/crates/ink/tests/ui/contract/pass/example-erc20-works.rs b/crates/ink/tests/ui/contract/pass/example-erc20-works.rs index 6ef1b98e10f..4adce05d5bd 100644 --- a/crates/ink/tests/ui/contract/pass/example-erc20-works.rs +++ b/crates/ink/tests/ui/contract/pass/example-erc20-works.rs @@ -15,25 +15,25 @@ mod erc20 { allowances: Mapping<(AccountId, AccountId), Balance>, } - /// Event emitted when a token transfer occurs. - #[ink(event)] - pub struct Transfer { - #[ink(topic)] - from: Option, - #[ink(topic)] - to: Option, - value: Balance, - } - - /// Event emitted when an approval occurs that `spender` is allowed to withdraw - /// up to the amount of `value` tokens from `owner`. - #[ink(event)] - pub struct Approval { - #[ink(topic)] - owner: AccountId, - #[ink(topic)] - spender: AccountId, - value: Balance, + #[ink::event_definition] + pub enum Event { + /// Event emitted when a token transfer occurs. + Transfer { + #[ink(topic)] + from: Option, + #[ink(topic)] + to: Option, + value: Balance, + }, + /// Event emitted when an approval occurs that `spender` is allowed to withdraw + /// up to the amount of `value` tokens from `owner`. + Approval { + #[ink(topic)] + owner: AccountId, + #[ink(topic)] + spender: AccountId, + value: Balance, + }, } /// The ERC-20 error types. From 39da2d7248fcb4378d3d43e5f1f12ff31a9d105b Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 7 Nov 2022 12:27:04 +0000 Subject: [PATCH 094/122] Fix and remove some tests --- crates/ink/ir/src/ir/event_def.rs | 38 ++----------------------------- 1 file changed, 2 insertions(+), 36 deletions(-) diff --git a/crates/ink/ir/src/ir/event_def.rs b/crates/ink/ir/src/ir/event_def.rs index f863fcb6f9a..71026d33058 100644 --- a/crates/ink/ir/src/ir/event_def.rs +++ b/crates/ink/ir/src/ir/event_def.rs @@ -299,40 +299,6 @@ mod tests { ) } - #[test] - fn wrong_first_struct_attribute_fails() { - assert_try_from_fails( - syn::parse_quote! { - #[ink(storage)] - #[ink::event_definition] - pub enum MyEvent { - Event { - #[ink(topic)] - field_1: i32, - field_2: bool, - } - } - }, - "unexpected first ink! attribute argument", - ) - } - - #[test] - fn missing_event_attribute_fails() { - assert_try_from_fails( - syn::parse_quote! { - pub enum MyEvent { - Event { - #[ink(topic)] - field_1: i32, - field_2: bool, - } - } - }, - "encountered unexpected empty expanded ink! attribute arguments", - ) - } - #[test] fn non_pub_event_struct() { assert_try_from_fails( @@ -381,7 +347,7 @@ mod tests { } } }, - "first optional ink! attribute of an event field must be #[ink(topic)]", + "only the #[ink(topic)] attribute is supported for event fields", ) } @@ -399,7 +365,7 @@ mod tests { } } }, - "encountered conflicting ink! attribute argument", + "only the #[ink(topic)] attribute is supported for event fields", ) } From 2aef9d5509d812b33643a94844d80e575d1e411a Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 7 Nov 2022 12:34:16 +0000 Subject: [PATCH 095/122] Fix non pub test --- crates/ink/ir/src/ir/event_def.rs | 9 ++++++++- crates/metadata/src/specs.rs | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/crates/ink/ir/src/ir/event_def.rs b/crates/ink/ir/src/ir/event_def.rs index 71026d33058..8eb0ec535c8 100644 --- a/crates/ink/ir/src/ir/event_def.rs +++ b/crates/ink/ir/src/ir/event_def.rs @@ -38,6 +38,13 @@ impl TryFrom for InkEventDefinition { type Error = syn::Error; fn try_from(mut item_enum: syn::ItemEnum) -> Result { + if !matches!(item_enum.vis, syn::Visibility::Public(_)) { + return Err(format_err_spanned!( + item_enum.vis, + "ink! event enum definitions must be declared as `pub`" + )) + } + let mut variants = Vec::new(); for (index, variant) in item_enum.variants.iter_mut().enumerate() { let mut fields = Vec::new(); @@ -312,7 +319,7 @@ mod tests { } } }, - "non `pub` ink! event structs are not supported", + "ink! event enum definitions must be declared as `pub`", ) } diff --git a/crates/metadata/src/specs.rs b/crates/metadata/src/specs.rs index 82e051a0aab..d346940c5ae 100644 --- a/crates/metadata/src/specs.rs +++ b/crates/metadata/src/specs.rs @@ -727,8 +727,8 @@ where /// Sets the variants of the event specification. pub fn variants(self, variants: A) -> Self - where - A: IntoIterator>, + where + A: IntoIterator>, { let mut this = self; debug_assert!(this.spec.variants.is_empty()); From 2d16ec1011f4540bd75726076a2368c50a22c565 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 7 Nov 2022 17:33:08 +0000 Subject: [PATCH 096/122] Fix up metadata specs --- crates/metadata/src/specs.rs | 51 ++++++++++++++++++++---------------- crates/metadata/src/tests.rs | 5 +++- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/crates/metadata/src/specs.rs b/crates/metadata/src/specs.rs index d346940c5ae..75e9bb7c32f 100644 --- a/crates/metadata/src/specs.rs +++ b/crates/metadata/src/specs.rs @@ -824,15 +824,18 @@ pub struct EventVariantSpec { /// An event variant specification builder. #[must_use] -pub struct EventVariantSpecBuilder { - spec: EventVariantSpec, +pub struct EventVariantSpecBuilder { + spec: EventVariantSpec, } -impl EventVariantSpecBuilder { +impl EventVariantSpecBuilder +where + F: Form, +{ /// Sets the input arguments of the event variant specification. pub fn args(self, args: A) -> Self where - A: IntoIterator, + A: IntoIterator>, { let mut this = self; debug_assert!(this.spec.args.is_empty()); @@ -841,18 +844,22 @@ impl EventVariantSpecBuilder { } /// Sets the documentation of the event variant specification. - pub fn docs(self, docs: D) -> Self + pub fn docs<'a, D>(self, docs: D) -> Self where - D: IntoIterator, + D: IntoIterator, + F::String: From<&'a str>, { let mut this = self; debug_assert!(this.spec.docs.is_empty()); - this.spec.docs = docs.into_iter().collect::>(); + this.spec.docs = docs + .into_iter() + .map(|s| trim_extra_whitespace(s).into()) + .collect::>(); this } /// Finalizes building the event specification. - pub fn done(self) -> EventVariantSpec { + pub fn done(self) -> EventVariantSpec { self.spec } } @@ -873,9 +880,12 @@ impl IntoPortable for EventVariantSpec { } } -impl EventVariantSpec { +impl EventVariantSpec +where + F: Form, +{ /// Creates a new event variant specification builder. - pub fn new(label: &'static str) -> EventVariantSpecBuilder { + pub fn new(label: F::String) -> EventVariantSpecBuilder { EventVariantSpecBuilder { spec: Self { label, @@ -884,12 +894,7 @@ impl EventVariantSpec { }, } } -} -impl EventVariantSpec -where - F: Form, -{ /// Returns the label of the event variant. pub fn label(&self) -> &F::String { &self.label @@ -1001,14 +1006,14 @@ impl Default for TypeSpec { } } -// impl Default for TypeSpec { -// fn default() -> Self { -// Self { -// ty: u32::default().into(), -// display_name: Default::default(), -// } -// } -// } +impl Default for TypeSpec { + fn default() -> Self { + Self { + ty: u32::default().into(), + display_name: Default::default(), + } + } +} impl IntoPortable for TypeSpec { type Output = TypeSpec; diff --git a/crates/metadata/src/tests.rs b/crates/metadata/src/tests.rs index 8d1f4e7f21b..bca0da06b0c 100644 --- a/crates/metadata/src/tests.rs +++ b/crates/metadata/src/tests.rs @@ -292,8 +292,11 @@ fn runtime_event_spec() -> EventSpec { .indexed(true) .docs(vec![]) .done()]; - EventSpec::new("foobar".into()) + let variants = [EventVariantSpec::new("EventVariant".to_string()) .args(args) + .done()]; + EventSpec::new("foobar".into()) + .variants(variants) .docs(["foobar event".into()]) .done() } From cdee107ed895f754acfe3ac54be05581272727a2 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 28 Nov 2022 18:12:25 +0000 Subject: [PATCH 097/122] Remove method after merge --- .../ink/codegen/src/generator/metadata/mod.rs | 35 ------------------- 1 file changed, 35 deletions(-) diff --git a/crates/ink/codegen/src/generator/metadata/mod.rs b/crates/ink/codegen/src/generator/metadata/mod.rs index 529047b5a0f..35bbc38a697 100644 --- a/crates/ink/codegen/src/generator/metadata/mod.rs +++ b/crates/ink/codegen/src/generator/metadata/mod.rs @@ -116,41 +116,6 @@ impl Metadata<'_> { ) } - fn generate_contract(&self) -> TokenStream2 { - let constructors = self.generate_constructors(); - let messages = self.generate_messages(); - let events = self.generate_events(); - let docs = self - .contract - .module() - .attrs() - .iter() - .filter_map(|attr| attr.extract_docs()); - let error_ty = syn::parse_quote! { - ::ink::LangError - }; - let error = Self::generate_type_spec(&error_ty); - quote! { - ::ink::metadata::ContractSpec::new() - .constructors([ - #( #constructors ),* - ]) - .messages([ - #( #messages ),* - ]) - .events([ - #( #events ),* - ]) - .docs([ - #( #docs ),* - ]) - .lang_error( - #error - ) - .done() - } - } - /// Generates ink! metadata for all ink! smart contract constructors. #[allow(clippy::redundant_closure)] // We are getting arcane lifetime errors otherwise. fn generate_constructors(&self) -> impl Iterator + '_ { From 148f43f67336601aca79102b6697377a9681d76f Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 29 Nov 2022 10:16:17 +0000 Subject: [PATCH 098/122] E2E: utilize `contract-build` crate --- crates/e2e/Cargo.toml | 2 +- crates/e2e/macro/Cargo.toml | 4 +- crates/e2e/macro/src/codegen.rs | 79 ++++++++++++++++----------------- 3 files changed, 42 insertions(+), 43 deletions(-) diff --git a/crates/e2e/Cargo.toml b/crates/e2e/Cargo.toml index abca4c34268..78931bc58c6 100644 --- a/crates/e2e/Cargo.toml +++ b/crates/e2e/Cargo.toml @@ -19,7 +19,7 @@ include = ["/Cargo.toml", "src/**/*.rs", "/README.md", "/LICENSE"] ink_e2e_macro = { version = "4.0.0-beta", path = "./macro" } ink_env = { version = "4.0.0-beta", path = "../env" } -contract-metadata = { version = "2.0.0-alpha.4" } +contract-metadata = { version = "2.0.0-beta" } impl-serde = { version = "0.3.1", default-features = false } jsonrpsee = { version = "0.16.0", features = ["ws-client"] } serde = { version = "1.0.137", default-features = false, features = ["derive"] } diff --git a/crates/e2e/macro/Cargo.toml b/crates/e2e/macro/Cargo.toml index d1f7a941471..57e45ecac0f 100644 --- a/crates/e2e/macro/Cargo.toml +++ b/crates/e2e/macro/Cargo.toml @@ -21,10 +21,12 @@ proc-macro = true [dependencies] ink_ir = { version = "4.0.0-beta", path = "../../ink/ir" } +# todo: switch to crates.io package once released +contract-build = { version = "2.0.0-beta", git = "https://github.com/paritytech/cargo-contract", branch = "aj/build-lib", package = "contract-build" } derive_more = "0.99.17" env_logger = "0.10.0" log = "0.4.17" -serde_json = "1.0.85" +serde_json = "1.0.89" syn = "1" proc-macro2 = "1" quote = "1" diff --git a/crates/e2e/macro/src/codegen.rs b/crates/e2e/macro/src/codegen.rs index 271e8ba0625..72eb473ad9c 100644 --- a/crates/e2e/macro/src/codegen.rs +++ b/crates/e2e/macro/src/codegen.rs @@ -176,47 +176,44 @@ impl InkE2ETest { /// Builds the contract at `manifest_path`, returns the path to the contract /// bundle build artifact. -fn build_contract(manifest_path: &str) -> String { - use std::process::{ - Command, - Stdio, +fn build_contract(path_to_cargo_toml: &str) -> String { + use contract_build::{ + BuildArtifacts, + BuildMode, + ExecuteArgs, + ManifestPath, + Verbosity, + }; + + let manifest_path = + ManifestPath::new(path_to_cargo_toml).expect("Invalid manifest path"); + let args = ExecuteArgs { + manifest_path, + verbosity: Verbosity::Default, + build_mode: BuildMode::Release, + network: Default::default(), + build_artifact: BuildArtifacts::All, + unstable_flags: Default::default(), + optimization_passes: Default::default(), + keep_debug_symbols: false, + lint: false, + output_type: Default::default(), }; - let output = Command::new("cargo") - .args([ - "+stable", - "contract", - "build", - "--output-json", - &format!("--manifest-path={}", manifest_path), - ]) - .env("RUST_LOG", "") - .stderr(Stdio::inherit()) - .output() - .unwrap_or_else(|err| { - panic!("failed to execute `cargo-contract` build process: {}", err) - }); - - log::info!("`cargo-contract` returned status: {}", output.status); - log::info!( - "`cargo-contract` stdout: {}", - String::from_utf8_lossy(&output.stdout) - ); - if !output.status.success() { - log::error!( - "`cargo-contract` stderr: {}", - String::from_utf8_lossy(&output.stderr) - ); - } - assert!( - output.status.success(), - "contract build for {} failed", - manifest_path - ); - - let json = String::from_utf8_lossy(&output.stdout); - let metadata: serde_json::Value = serde_json::from_str(&json) - .unwrap_or_else(|err| panic!("cannot convert json to utf8: {}", err)); - let dest_metadata = metadata["metadata_result"]["dest_bundle"].to_string(); - dest_metadata.trim_matches('"').to_string() + match contract_build::execute(args) { + Ok(build_result) => { + let metadata_result = build_result + .metadata_result + .expect("Metadata artifacts not generated"); + metadata_result + .dest_bundle + .canonicalize() + .expect("Invalid dest bundle path") + .to_string_lossy() + .into() + } + Err(err) => { + panic!("contract build for {} failed: {}", path_to_cargo_toml, err) + } + } } From 52f2024ced267a7be976c11fef540ed351b26bd0 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 29 Nov 2022 12:52:43 +0000 Subject: [PATCH 099/122] Build as debug so we can see the debug messages --- crates/e2e/macro/src/codegen.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/e2e/macro/src/codegen.rs b/crates/e2e/macro/src/codegen.rs index 72eb473ad9c..0df6839222b 100644 --- a/crates/e2e/macro/src/codegen.rs +++ b/crates/e2e/macro/src/codegen.rs @@ -190,7 +190,7 @@ fn build_contract(path_to_cargo_toml: &str) -> String { let args = ExecuteArgs { manifest_path, verbosity: Verbosity::Default, - build_mode: BuildMode::Release, + build_mode: BuildMode::Debug, network: Default::default(), build_artifact: BuildArtifacts::All, unstable_flags: Default::default(), From 963cfeeaa4c4a5f0e906ca9785775a93cd967542 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 1 Dec 2022 12:52:26 +0000 Subject: [PATCH 100/122] Switch to using `contract-build` master branch --- crates/e2e/macro/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/e2e/macro/Cargo.toml b/crates/e2e/macro/Cargo.toml index 57e45ecac0f..94578b7a1b8 100644 --- a/crates/e2e/macro/Cargo.toml +++ b/crates/e2e/macro/Cargo.toml @@ -22,7 +22,7 @@ proc-macro = true [dependencies] ink_ir = { version = "4.0.0-beta", path = "../../ink/ir" } # todo: switch to crates.io package once released -contract-build = { version = "2.0.0-beta", git = "https://github.com/paritytech/cargo-contract", branch = "aj/build-lib", package = "contract-build" } +contract-build = { version = "2.0.0-beta", git = "https://github.com/paritytech/cargo-contract", package = "contract-build" } derive_more = "0.99.17" env_logger = "0.10.0" log = "0.4.17" From e9701ea165e498bc467635efbb0ff52df101278e Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 1 Dec 2022 12:54:18 +0000 Subject: [PATCH 101/122] Add missing flag --- crates/e2e/macro/src/codegen.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/e2e/macro/src/codegen.rs b/crates/e2e/macro/src/codegen.rs index f8ed95b937e..d9b5f5e1125 100644 --- a/crates/e2e/macro/src/codegen.rs +++ b/crates/e2e/macro/src/codegen.rs @@ -196,6 +196,7 @@ fn build_contract(path_to_cargo_toml: &str) -> String { keep_debug_symbols: false, lint: false, output_type: Default::default(), + skip_wasm_validation: false, }; match contract_build::execute(args) { From cdbcbe0ca87dce9a646fbaa6da78ef9eaed92bb7 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 1 Dec 2022 13:27:53 +0000 Subject: [PATCH 102/122] Use released `contract-build` crate --- crates/e2e/macro/Cargo.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/e2e/macro/Cargo.toml b/crates/e2e/macro/Cargo.toml index 94578b7a1b8..4cf5d332ce7 100644 --- a/crates/e2e/macro/Cargo.toml +++ b/crates/e2e/macro/Cargo.toml @@ -21,8 +21,7 @@ proc-macro = true [dependencies] ink_ir = { version = "4.0.0-beta", path = "../../ink/ir" } -# todo: switch to crates.io package once released -contract-build = { version = "2.0.0-beta", git = "https://github.com/paritytech/cargo-contract", package = "contract-build" } +contract-build = "2.0.0-beta" derive_more = "0.99.17" env_logger = "0.10.0" log = "0.4.17" From 4775cf36adbbee35651219c8cb5c4b22ad1548c0 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 1 Dec 2022 16:04:03 +0000 Subject: [PATCH 103/122] Use custom `contract-build` branch --- crates/e2e/macro/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/e2e/macro/Cargo.toml b/crates/e2e/macro/Cargo.toml index 4cf5d332ce7..4d7bc3877e3 100644 --- a/crates/e2e/macro/Cargo.toml +++ b/crates/e2e/macro/Cargo.toml @@ -21,7 +21,7 @@ proc-macro = true [dependencies] ink_ir = { version = "4.0.0-beta", path = "../../ink/ir" } -contract-build = "2.0.0-beta" +contract-build = { git = "https://github.com/paritytech/cargo-contract", branch = "aj/shared-events-metadata", package = "contract-build" } derive_more = "0.99.17" env_logger = "0.10.0" log = "0.4.17" From 3777274bc9038d2208c58eef4484014a9637cd51 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 1 Dec 2022 18:07:36 +0000 Subject: [PATCH 104/122] Remove duplicate generate_type_spec method --- .../ink/codegen/src/generator/metadata/mod.rs | 45 ++++--------------- 1 file changed, 8 insertions(+), 37 deletions(-) diff --git a/crates/ink/codegen/src/generator/metadata/mod.rs b/crates/ink/codegen/src/generator/metadata/mod.rs index 35bbc38a697..1061d9b6739 100644 --- a/crates/ink/codegen/src/generator/metadata/mod.rs +++ b/crates/ink/codegen/src/generator/metadata/mod.rs @@ -53,7 +53,7 @@ impl GenerateCode for Metadata<'_> { .iter() .filter_map(|attr| attr.extract_docs()); let error_ty = syn::parse_quote! { ::ink::LangError }; - let error = Self::generate_type_spec(&error_ty); + let error = generate_type_spec(&error_ty); let layout = self.generate_layout(); @@ -175,38 +175,6 @@ impl Metadata<'_> { } } - /// Generates the ink! metadata for the given type. - fn generate_type_spec(ty: &syn::Type) -> TokenStream2 { - fn without_display_name(ty: &syn::Type) -> TokenStream2 { - quote! { ::ink::metadata::TypeSpec::of_type::<#ty>() } - } - - if let syn::Type::Path(type_path) = ty { - if type_path.qself.is_some() { - return without_display_name(ty) - } - let path = &type_path.path; - if path.segments.is_empty() { - return without_display_name(ty) - } - let segs = path - .segments - .iter() - .map(|seg| &seg.ident) - .collect::>(); - quote! { - ::ink::metadata::TypeSpec::with_name_segs::<#ty, _>( - ::core::iter::Iterator::map( - ::core::iter::IntoIterator::into_iter([ #( ::core::stringify!(#segs) ),* ]), - ::core::convert::AsRef::as_ref - ) - ) - } - } else { - without_display_name(ty) - } - } - /// Generates the ink! metadata for all ink! smart contract messages. fn generate_messages(&self) -> Vec { let mut messages = Vec::new(); @@ -362,6 +330,7 @@ fn generate_type_spec(ty: &syn::Type) -> TokenStream2 { fn without_display_name(ty: &syn::Type) -> TokenStream2 { quote! { ::ink::metadata::TypeSpec::of_type::<#ty>() } } + if let syn::Type::Path(type_path) = ty { if type_path.qself.is_some() { return without_display_name(ty) @@ -376,11 +345,13 @@ fn generate_type_spec(ty: &syn::Type) -> TokenStream2 { .map(|seg| &seg.ident) .collect::>(); quote! { - ::ink::metadata::TypeSpec::with_name_segs::<#ty, _>( - ::core::iter::IntoIterator::into_iter([ #( ::core::stringify!(#segs) ),* ]) - .map(::core::convert::AsRef::as_ref) + ::ink::metadata::TypeSpec::with_name_segs::<#ty, _>( + ::core::iter::Iterator::map( + ::core::iter::IntoIterator::into_iter([ #( ::core::stringify!(#segs) ),* ]), + ::core::convert::AsRef::as_ref ) - } + ) + } } else { without_display_name(ty) } From e9fe3e10f7f0bdf82ea3f3d282c8bd6f1669c67b Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 2 Dec 2022 13:18:59 +0000 Subject: [PATCH 105/122] Update generate_metadata signature in ui test --- .../ui/contract/pass/constructor-return-result-alias.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/crates/ink/tests/ui/contract/pass/constructor-return-result-alias.rs b/crates/ink/tests/ui/contract/pass/constructor-return-result-alias.rs index 4fe4f90f794..6a4fd1a58e0 100644 --- a/crates/ink/tests/ui/contract/pass/constructor-return-result-alias.rs +++ b/crates/ink/tests/ui/contract/pass/constructor-return-result-alias.rs @@ -22,14 +22,17 @@ mod contract { } } -use ink::metadata::InkProject; +use ink::metadata::{ + EventSpec, + InkProject, +}; fn generate_metadata() -> InkProject { extern "Rust" { - fn __ink_generate_metadata() -> InkProject; + fn __ink_generate_metadata(events: Vec) -> InkProject; } - unsafe { __ink_generate_metadata() } + unsafe { __ink_generate_metadata(vec![]) } } fn main() { From 9d9ef5e7a2e1cb4e7143fcf14bd8d2963852ac3e Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 2 Dec 2022 17:25:17 +0000 Subject: [PATCH 106/122] Fix anonymous event ui test --- .../tests/ui/contract/pass/event-anonymous.rs | 124 +++++++++--------- 1 file changed, 61 insertions(+), 63 deletions(-) diff --git a/crates/ink/tests/ui/contract/pass/event-anonymous.rs b/crates/ink/tests/ui/contract/pass/event-anonymous.rs index 371d10e595e..7397dafb41d 100644 --- a/crates/ink/tests/ui/contract/pass/event-anonymous.rs +++ b/crates/ink/tests/ui/contract/pass/event-anonymous.rs @@ -3,77 +3,75 @@ mod contract { #[ink(storage)] pub struct Contract {} - #[ink(event, anonymous)] - pub struct Event0 {} - - #[ink(event, anonymous)] - pub struct Event1 { - #[ink(topic)] - arg_1: i8, - } - - #[ink(event, anonymous)] - pub struct Event2 { - #[ink(topic)] - arg_1: i8, - #[ink(topic)] - arg_2: i16, - } - - #[ink(event, anonymous)] - pub struct Event3 { - #[ink(topic)] - arg_1: i8, - #[ink(topic)] - arg_2: i16, - #[ink(topic)] - arg_3: i32, - } - - #[ink(event, anonymous)] - pub struct Event4 { - #[ink(topic)] - arg_1: i8, - #[ink(topic)] - arg_2: i16, - #[ink(topic)] - arg_3: i32, - #[ink(topic)] - arg_4: i64, - } - - #[ink(event, anonymous)] - pub struct Event5 { - #[ink(topic)] - arg_1: i8, - #[ink(topic)] - arg_2: i16, - #[ink(topic)] - arg_3: i32, - #[ink(topic)] - arg_4: i64, - // #[ink(topic)] <- Cannot have more than 4 topics by default. - arg_5: i128, + #[ink::event_definition] + pub enum Event { + #[ink(anonymous)] + Event0 {}, + #[ink(anonymous)] + Event1 { + #[ink(topic)] + arg_1: i8, + }, + #[ink(anonymous)] + Event2 { + #[ink(topic)] + arg_1: i8, + #[ink(topic)] + arg_2: i16, + }, + #[ink(anonymous)] + Event3 { + #[ink(topic)] + arg_1: i8, + #[ink(topic)] + arg_2: i16, + #[ink(topic)] + arg_3: i32, + }, + #[ink(anonymous)] + Event4 { + #[ink(topic)] + arg_1: i8, + #[ink(topic)] + arg_2: i16, + #[ink(topic)] + arg_3: i32, + #[ink(topic)] + arg_4: i64, + }, + #[ink(anonymous)] + Event5 { + #[ink(topic)] + arg_1: i8, + #[ink(topic)] + arg_2: i16, + #[ink(topic)] + arg_3: i32, + #[ink(topic)] + arg_4: i64, + // #[ink(topic)] <- Cannot have more than 4 topics by default. + arg_5: i128, + } } impl Contract { #[ink(constructor)] pub fn constructor() -> Self { - Self::env().emit_event(Event0 {}); - Self::env().emit_event(Event1 { arg_1: 1 }); - Self::env().emit_event(Event2 { arg_1: 1, arg_2: 2 }); - Self::env().emit_event(Event3 { + Self::env().emit_event(Event::Event0 {}); + Self::env().emit_event(Event::Event1 { arg_1: 1 }); + Self::env().emit_event(Event::Event2 { arg_1: 1, arg_2: 2 }); + Self::env().emit_event(Event::Event3 { arg_1: 1, arg_2: 2, arg_3: 3, }); - Self::env().emit_event(Event4 { + Self::env().emit_event(Event::Event4 { arg_1: 1, arg_2: 2, arg_3: 3, arg_4: 4, }); - Self::env().emit_event(Event5 { + Self::env().emit_event(Event::Event5 { arg_1: 1, arg_2: 2, arg_3: 3, @@ -85,21 +83,21 @@ mod contract { #[ink(message)] pub fn message(&self) { - self.env().emit_event(Event0 {}); - self.env().emit_event(Event1 { arg_1: 1 }); - self.env().emit_event(Event2 { arg_1: 1, arg_2: 2 }); - self.env().emit_event(Event3 { + self.env().emit_event(Event::Event0 {}); + self.env().emit_event(Event::Event1 { arg_1: 1 }); + self.env().emit_event(Event::Event2 { arg_1: 1, arg_2: 2 }); + self.env().emit_event(Event::Event3 { arg_1: 1, arg_2: 2, arg_3: 3, }); - self.env().emit_event(Event4 { + self.env().emit_event(Event::Event4 { arg_1: 1, arg_2: 2, arg_3: 3, arg_4: 4, }); - self.env().emit_event(Event5 { + self.env().emit_event(Event::Event5 { arg_1: 1, arg_2: 2, arg_3: 3, From 5ef3525179d15dd3746871b2d6f5e4552c66c048 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 2 Dec 2022 17:57:57 +0000 Subject: [PATCH 107/122] Update event defs in some UI tests --- .../fail/event-too-many-topics-anonymous.rs | 27 +++--- .../contract/pass/event-many-definitions.rs | 88 +++++++++---------- 2 files changed, 55 insertions(+), 60 deletions(-) diff --git a/crates/ink/tests/ui/contract/fail/event-too-many-topics-anonymous.rs b/crates/ink/tests/ui/contract/fail/event-too-many-topics-anonymous.rs index 440ba81c419..c4bfa8339c4 100644 --- a/crates/ink/tests/ui/contract/fail/event-too-many-topics-anonymous.rs +++ b/crates/ink/tests/ui/contract/fail/event-too-many-topics-anonymous.rs @@ -21,22 +21,25 @@ mod contract { #[ink(storage)] pub struct Contract {} - #[ink(event, anonymous)] - pub struct Event { - #[ink(topic)] - arg_1: i8, - #[ink(topic)] - arg_2: i16, - #[ink(topic)] - arg_3: i32, - #[ink(topic)] - arg_4: i32, + #[ink::event_definition] + pub enum Event { + #[ink(anonymous)] + Event { + #[ink(topic)] + arg_1: i8, + #[ink(topic)] + arg_2: i16, + #[ink(topic)] + arg_3: i32, + #[ink(topic)] + arg_4: i32, + } } impl Contract { #[ink(constructor)] pub fn constructor() -> Self { - Self::env().emit_event(Event { + Self::env().emit_event(Event::Event { arg_1: 1, arg_2: 2, arg_3: 3, @@ -47,7 +50,7 @@ mod contract { #[ink(message)] pub fn message(&self) { - self.env().emit_event(Event { + self.env().emit_event(Event::Event { arg_1: 1, arg_2: 2, arg_3: 3, diff --git a/crates/ink/tests/ui/contract/pass/event-many-definitions.rs b/crates/ink/tests/ui/contract/pass/event-many-definitions.rs index 00f9400dbe9..17ac6ce3b3a 100644 --- a/crates/ink/tests/ui/contract/pass/event-many-definitions.rs +++ b/crates/ink/tests/ui/contract/pass/event-many-definitions.rs @@ -3,62 +3,54 @@ mod contract { #[ink(storage)] pub struct Contract {} - #[ink(event)] - pub struct Event0 {} - - #[ink(event)] - pub struct Event1 { - arg_1: i8, - } - - #[ink(event)] - pub struct Event2 { - arg_1: i8, - arg_2: i16, - } - - #[ink(event)] - pub struct Event3 { - arg_1: i8, - arg_2: i16, - arg_3: i32, - } - - #[ink(event)] - pub struct Event4 { - arg_1: i8, - arg_2: i16, - arg_3: i32, - arg_4: i64, - } - - #[ink(event)] - pub struct Event5 { - arg_1: i8, - arg_2: i16, - arg_3: i32, - arg_4: i64, - arg_5: i128, + #[ink::event_definition] + pub enum Event { + Event0 {}, + Event1 { + arg_1: i8, + }, + Event2 { + arg_1: i8, + arg_2: i16, + }, + Event3 { + arg_1: i8, + arg_2: i16, + arg_3: i32, + }, + Event4 { + arg_1: i8, + arg_2: i16, + arg_3: i32, + arg_4: i64, + }, + Event5 { + arg_1: i8, + arg_2: i16, + arg_3: i32, + arg_4: i64, + arg_5: i128, + } } impl Contract { #[ink(constructor)] pub fn constructor() -> Self { - Self::env().emit_event(Event0 {}); - Self::env().emit_event(Event1 { arg_1: 1 }); - Self::env().emit_event(Event2 { arg_1: 1, arg_2: 2 }); - Self::env().emit_event(Event3 { + Self::env().emit_event(Event::Event0 {}); + Self::env().emit_event(Event::Event1 { arg_1: 1 }); + Self::env().emit_event(Event::Event2 { arg_1: 1, arg_2: 2 }); + Self::env().emit_event(Event::Event3 { arg_1: 1, arg_2: 2, arg_3: 3, }); - Self::env().emit_event(Event4 { + Self::env().emit_event(Event::Event4 { arg_1: 1, arg_2: 2, arg_3: 3, arg_4: 4, }); - Self::env().emit_event(Event5 { + Self::env().emit_event(Event::Event5 { arg_1: 1, arg_2: 2, arg_3: 3, @@ -70,21 +62,21 @@ mod contract { #[ink(message)] pub fn message(&self) { - self.env().emit_event(Event0 {}); - self.env().emit_event(Event1 { arg_1: 1 }); - self.env().emit_event(Event2 { arg_1: 1, arg_2: 2 }); - self.env().emit_event(Event3 { + self.env().emit_event(Event::Event0 {}); + self.env().emit_event(Event::Event1 { arg_1: 1 }); + self.env().emit_event(Event::Event2 { arg_1: 1, arg_2: 2 }); + self.env().emit_event(Event::Event3 { arg_1: 1, arg_2: 2, arg_3: 3, }); - self.env().emit_event(Event4 { + self.env().emit_event(Event::Event4 { arg_1: 1, arg_2: 2, arg_3: 3, arg_4: 4, }); - self.env().emit_event(Event5 { + self.env().emit_event(Event::Event5 { arg_1: 1, arg_2: 2, arg_3: 3, From ddd35593d22b997b0ebc75a7d9b2030fd7ae6a57 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 5 Dec 2022 11:45:39 +0000 Subject: [PATCH 108/122] More UI tests migration --- .../contract/pass/event-config-more-topics.rs | 51 ++++---- .../contract/pass/event-single-definition.rs | 4 +- .../tests/ui/contract/pass/event-topics.rs | 118 ++++++++---------- .../ui/contract/pass/example-erc20-works.rs | 6 +- .../ui/contract/pass/example-erc721-works.rs | 70 +++++------ 5 files changed, 121 insertions(+), 128 deletions(-) diff --git a/crates/ink/tests/ui/contract/pass/event-config-more-topics.rs b/crates/ink/tests/ui/contract/pass/event-config-more-topics.rs index 5628749fb75..53c47cd3e1d 100644 --- a/crates/ink/tests/ui/contract/pass/event-config-more-topics.rs +++ b/crates/ink/tests/ui/contract/pass/event-config-more-topics.rs @@ -21,34 +21,37 @@ mod contract { #[ink(storage)] pub struct Contract {} - #[ink(event, anonymous)] - pub struct EventWithManyTopics { - #[ink(topic)] - arg_1: i8, - #[ink(topic)] - arg_2: i16, - #[ink(topic)] - arg_3: i32, - #[ink(topic)] - arg_4: i64, - #[ink(topic)] - arg_5: i128, - #[ink(topic)] - arg_6: u8, - #[ink(topic)] - arg_7: u16, - #[ink(topic)] - arg_8: u32, - #[ink(topic)] - arg_9: u64, - #[ink(topic)] - arg_10: u128, + #[ink::event_definition] + pub enum Event { + #[ink(anonymous)] + EventWithManyTopics { + #[ink(topic)] + arg_1: i8, + #[ink(topic)] + arg_2: i16, + #[ink(topic)] + arg_3: i32, + #[ink(topic)] + arg_4: i64, + #[ink(topic)] + arg_5: i128, + #[ink(topic)] + arg_6: u8, + #[ink(topic)] + arg_7: u16, + #[ink(topic)] + arg_8: u32, + #[ink(topic)] + arg_9: u64, + #[ink(topic)] + arg_10: u128, + } } impl Contract { #[ink(constructor)] pub fn constructor() -> Self { - Self::env().emit_event(EventWithManyTopics { + Self::env().emit_event(Event::EventWithManyTopics { arg_1: 1, arg_2: 2, arg_3: 3, @@ -65,7 +68,7 @@ mod contract { #[ink(message)] pub fn message(&self) { - self.env().emit_event(EventWithManyTopics { + self.env().emit_event(Event::EventWithManyTopics { arg_1: 1, arg_2: 2, arg_3: 3, diff --git a/crates/ink/tests/ui/contract/pass/event-single-definition.rs b/crates/ink/tests/ui/contract/pass/event-single-definition.rs index 6932d4dc3f6..241ced43d24 100644 --- a/crates/ink/tests/ui/contract/pass/event-single-definition.rs +++ b/crates/ink/tests/ui/contract/pass/event-single-definition.rs @@ -3,8 +3,8 @@ mod contract { #[ink(storage)] pub struct Contract {} - #[ink(event)] - pub struct Event0 {} + #[ink::event_definition] + pub enum Event0 {} impl Contract { #[ink(constructor)] diff --git a/crates/ink/tests/ui/contract/pass/event-topics.rs b/crates/ink/tests/ui/contract/pass/event-topics.rs index 236e63a0c7f..e6df91d61a5 100644 --- a/crates/ink/tests/ui/contract/pass/event-topics.rs +++ b/crates/ink/tests/ui/contract/pass/event-topics.rs @@ -3,77 +3,69 @@ mod contract { #[ink(storage)] pub struct Contract {} - #[ink(event)] - pub struct Event0 {} - - #[ink(event)] - pub struct Event1 { - #[ink(topic)] - arg_1: i8, - } - - #[ink(event)] - pub struct Event2 { - #[ink(topic)] - arg_1: i8, - #[ink(topic)] - arg_2: i16, - } - - #[ink(event)] - pub struct Event3 { - #[ink(topic)] - arg_1: i8, - #[ink(topic)] - arg_2: i16, - #[ink(topic)] - arg_3: i32, - } - - #[ink(event)] - pub struct Event4 { - #[ink(topic)] - arg_1: i8, - #[ink(topic)] - arg_2: i16, - #[ink(topic)] - arg_3: i32, - #[ink(topic)] - arg_4: i64, - } - - #[ink(event)] - pub struct Event5 { - #[ink(topic)] - arg_1: i8, - #[ink(topic)] - arg_2: i16, - #[ink(topic)] - arg_3: i32, - #[ink(topic)] - arg_4: i64, - // #[ink(topic)] <- Cannot have more than 4 topics by default. - arg_5: i128, + #[ink::event_definition] + pub enum Event { + Event0 {}, + Event1 { + #[ink(topic)] + arg_1: i8, + }, + Event2 { + #[ink(topic)] + arg_1: i8, + #[ink(topic)] + arg_2: i16, + }, + Event3 { + #[ink(topic)] + arg_1: i8, + #[ink(topic)] + arg_2: i16, + #[ink(topic)] + arg_3: i32, + }, + Event4 { + #[ink(topic)] + arg_1: i8, + #[ink(topic)] + arg_2: i16, + #[ink(topic)] + arg_3: i32, + #[ink(topic)] + arg_4: i64, + }, + Event5 { + #[ink(topic)] + arg_1: i8, + #[ink(topic)] + arg_2: i16, + #[ink(topic)] + arg_3: i32, + #[ink(topic)] + arg_4: i64, + // #[ink(topic)] <- Cannot have more than 4 topics by default. + arg_5: i128, + } } impl Contract { #[ink(constructor)] pub fn constructor() -> Self { - Self::env().emit_event(Event0 {}); - Self::env().emit_event(Event1 { arg_1: 1 }); - Self::env().emit_event(Event2 { arg_1: 1, arg_2: 2 }); - Self::env().emit_event(Event3 { + Self::env().emit_event(Event::Event0 {}); + Self::env().emit_event(Event::Event1 { arg_1: 1 }); + Self::env().emit_event(Event::Event2 { arg_1: 1, arg_2: 2 }); + Self::env().emit_event(Event::Event3 { arg_1: 1, arg_2: 2, arg_3: 3, }); - Self::env().emit_event(Event4 { + Self::env().emit_event(Event::Event4 { arg_1: 1, arg_2: 2, arg_3: 3, arg_4: 4, }); - Self::env().emit_event(Event5 { + Self::env().emit_event(Event::Event5 { arg_1: 1, arg_2: 2, arg_3: 3, @@ -85,21 +77,21 @@ mod contract { #[ink(message)] pub fn message(&self) { - self.env().emit_event(Event0 {}); - self.env().emit_event(Event1 { arg_1: 1 }); - self.env().emit_event(Event2 { arg_1: 1, arg_2: 2 }); - self.env().emit_event(Event3 { + self.env().emit_event(Event::Event0 {}); + self.env().emit_event(Event::Event1 { arg_1: 1 }); + self.env().emit_event(Event::Event2 { arg_1: 1, arg_2: 2 }); + self.env().emit_event(Event::Event3 { arg_1: 1, arg_2: 2, arg_3: 3, }); - self.env().emit_event(Event4 { + self.env().emit_event(Event::Event4 { arg_1: 1, arg_2: 2, arg_3: 3, arg_4: 4, }); - self.env().emit_event(Event5 { + self.env().emit_event(Event::Event5 { arg_1: 1, arg_2: 2, arg_3: 3, diff --git a/crates/ink/tests/ui/contract/pass/example-erc20-works.rs b/crates/ink/tests/ui/contract/pass/example-erc20-works.rs index 4adce05d5bd..865e83b65a6 100644 --- a/crates/ink/tests/ui/contract/pass/example-erc20-works.rs +++ b/crates/ink/tests/ui/contract/pass/example-erc20-works.rs @@ -56,7 +56,7 @@ mod erc20 { let mut balances = Mapping::default(); let caller = Self::env().caller(); balances.insert(&caller, &total_supply); - Self::env().emit_event(Transfer { + Self::env().emit_event(Event::Transfer { from: None, to: Some(caller), value: total_supply, @@ -140,7 +140,7 @@ mod erc20 { pub fn approve(&mut self, spender: AccountId, value: Balance) -> Result<()> { let owner = self.env().caller(); self.allowances.insert((&owner, &spender), &value); - self.env().emit_event(Approval { + self.env().emit_event(Event::Approval { owner, spender, value, @@ -202,7 +202,7 @@ mod erc20 { self.balances.insert(from, &(from_balance - value)); let to_balance = self.balance_of_impl(to); self.balances.insert(to, &(to_balance + value)); - self.env().emit_event(Transfer { + self.env().emit_event(Event::Transfer { from: Some(*from), to: Some(*to), value, diff --git a/crates/ink/tests/ui/contract/pass/example-erc721-works.rs b/crates/ink/tests/ui/contract/pass/example-erc721-works.rs index e5b250bf0d9..5dff9aed9b2 100644 --- a/crates/ink/tests/ui/contract/pass/example-erc721-works.rs +++ b/crates/ink/tests/ui/contract/pass/example-erc721-works.rs @@ -35,37 +35,35 @@ mod erc721 { NotAllowed, } - /// Event emitted when a token transfer occurs. - #[ink(event)] - pub struct Transfer { - #[ink(topic)] - from: Option, - #[ink(topic)] - to: Option, - #[ink(topic)] - id: TokenId, - } - - /// Event emitted when a token approve occurs. - #[ink(event)] - pub struct Approval { - #[ink(topic)] - from: AccountId, - #[ink(topic)] - to: AccountId, - #[ink(topic)] - id: TokenId, - } - - /// Event emitted when an operator is enabled or disabled for an owner. - /// The operator can manage all NFTs of the owner. - #[ink(event)] - pub struct ApprovalForAll { - #[ink(topic)] - owner: AccountId, - #[ink(topic)] - operator: AccountId, - approved: bool, + #[ink::event_definition] + pub enum Event { + /// Event emitted when a token transfer occurs. + Transfer { + #[ink(topic)] + from: Option, + #[ink(topic)] + to: Option, + #[ink(topic)] + id: TokenId, + }, + /// Event emitted when a token approve occurs. + Approval { + #[ink(topic)] + from: AccountId, + #[ink(topic)] + to: AccountId, + #[ink(topic)] + id: TokenId, + }, + /// Event emitted when an operator is enabled or disabled for an owner. + /// The operator can manage all NFTs of the owner. + ApprovalForAll { + #[ink(topic)] + owner: AccountId, + #[ink(topic)] + operator: AccountId, + approved: bool, + } } impl Erc721 { @@ -148,7 +146,7 @@ mod erc721 { pub fn mint(&mut self, id: TokenId) -> Result<(), Error> { let caller = self.env().caller(); self.add_token_to(&caller, id)?; - self.env().emit_event(Transfer { + self.env().emit_event(Event::Transfer { from: Some(AccountId::from([0x0; 32])), to: Some(caller), id, @@ -178,7 +176,7 @@ mod erc721 { owned_tokens_count.insert(&caller, &count); token_owner.remove(&id); - self.env().emit_event(Transfer { + self.env().emit_event(Event::Transfer { from: Some(caller), to: Some(AccountId::from([0x0; 32])), id, @@ -204,7 +202,7 @@ mod erc721 { self.clear_approval(id); self.remove_token_from(from, id)?; self.add_token_to(to, id)?; - self.env().emit_event(Transfer { + self.env().emit_event(Event::Transfer { from: Some(*from), to: Some(*to), id, @@ -272,7 +270,7 @@ mod erc721 { if to == caller { return Err(Error::NotAllowed) } - self.env().emit_event(ApprovalForAll { + self.env().emit_event(Event::ApprovalForAll { owner: caller, operator: to, approved, @@ -307,7 +305,7 @@ mod erc721 { self.token_approvals.insert(&id, to); } - self.env().emit_event(Approval { + self.env().emit_event(Event::Approval { from: caller, to: *to, id, From e5d81636dc55240b9e7077ad1c3596ec191eee94 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 5 Dec 2022 17:14:08 +0000 Subject: [PATCH 109/122] Check for event definitions with no variants --- crates/ink/ir/src/ir/event_def.rs | 6 ++++++ crates/ink/tests/ui/contract/fail/event-no-variants.rs | 4 ++++ crates/ink/tests/ui/contract/fail/event-no-variants.stderr | 5 +++++ 3 files changed, 15 insertions(+) create mode 100644 crates/ink/tests/ui/contract/fail/event-no-variants.rs create mode 100644 crates/ink/tests/ui/contract/fail/event-no-variants.stderr diff --git a/crates/ink/ir/src/ir/event_def.rs b/crates/ink/ir/src/ir/event_def.rs index 8eb0ec535c8..639150e458f 100644 --- a/crates/ink/ir/src/ir/event_def.rs +++ b/crates/ink/ir/src/ir/event_def.rs @@ -44,6 +44,12 @@ impl TryFrom for InkEventDefinition { "ink! event enum definitions must be declared as `pub`" )) } + if item_enum.variants.is_empty() { + return Err(format_err_spanned!( + item_enum, + "ink! event enum definitions must have at least one variant" + )) + } let mut variants = Vec::new(); for (index, variant) in item_enum.variants.iter_mut().enumerate() { diff --git a/crates/ink/tests/ui/contract/fail/event-no-variants.rs b/crates/ink/tests/ui/contract/fail/event-no-variants.rs new file mode 100644 index 00000000000..14de0555d52 --- /dev/null +++ b/crates/ink/tests/ui/contract/fail/event-no-variants.rs @@ -0,0 +1,4 @@ +#[ink::event_definition] +pub enum Event {} + +fn main() {} diff --git a/crates/ink/tests/ui/contract/fail/event-no-variants.stderr b/crates/ink/tests/ui/contract/fail/event-no-variants.stderr new file mode 100644 index 00000000000..4b6dce8e465 --- /dev/null +++ b/crates/ink/tests/ui/contract/fail/event-no-variants.stderr @@ -0,0 +1,5 @@ +error: ink! event enum definitions must have at least one variant + --> tests/ui/contract/fail/event-no-variants.rs:2:1 + | +2 | pub enum Event {} + | ^^^^^^^^^^^^^^^^^ From b5a961ae717c2d3e6d766469723e85095afb7fae Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 5 Dec 2022 17:28:28 +0000 Subject: [PATCH 110/122] Check for event definitions are not structs --- crates/ink/ir/src/ir/event_def.rs | 10 ++++++---- crates/ink/tests/ui/contract/fail/event-struct.rs | 4 ++++ .../ink/tests/ui/contract/fail/event-struct.stderr | 13 +++++++++++++ 3 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 crates/ink/tests/ui/contract/fail/event-struct.rs create mode 100644 crates/ink/tests/ui/contract/fail/event-struct.stderr diff --git a/crates/ink/ir/src/ir/event_def.rs b/crates/ink/ir/src/ir/event_def.rs index 639150e458f..94d74e05ae2 100644 --- a/crates/ink/ir/src/ir/event_def.rs +++ b/crates/ink/ir/src/ir/event_def.rs @@ -141,14 +141,16 @@ impl quote::ToTokens for InkEventDefinition { impl InkEventDefinition { /// Create an [`InkEventDefinition`] for a event defined externally to a contract. /// - /// This will be an enum annotated with the `#[ink::event_def]` attribute. + /// This will be an enum annotated with the `#[ink::event_definition]` attribute. pub fn from_event_def_tokens( config: TokenStream2, input: TokenStream2, ) -> Result { - let _parsed_config = syn::parse2::(config)?; - let item = syn::parse2::(input)?; - // let item = InkItemTrait::new(&config, parsed_item)?; + let attr_span = config.span(); + // todo: remove this, or do we need config attrs? + // let _parsed_config = syn::parse2::(config)?; + let item = syn::parse2::(input) + .map_err(|err| err.into_combine(format_err!(attr_span, "ink! event definitions must be enums")))?; Self::try_from(item) } diff --git a/crates/ink/tests/ui/contract/fail/event-struct.rs b/crates/ink/tests/ui/contract/fail/event-struct.rs new file mode 100644 index 00000000000..3769396d9d0 --- /dev/null +++ b/crates/ink/tests/ui/contract/fail/event-struct.rs @@ -0,0 +1,4 @@ +#[ink::event_definition] +pub struct Event {} + +fn main() {} diff --git a/crates/ink/tests/ui/contract/fail/event-struct.stderr b/crates/ink/tests/ui/contract/fail/event-struct.stderr new file mode 100644 index 00000000000..c0c7289200e --- /dev/null +++ b/crates/ink/tests/ui/contract/fail/event-struct.stderr @@ -0,0 +1,13 @@ +error: expected `enum` + --> tests/ui/contract/fail/event-struct.rs:2:5 + | +2 | pub struct Event {} + | ^^^^^^ + +error: ink! event definitions must be enums + --> tests/ui/contract/fail/event-struct.rs:1:1 + | +1 | #[ink::event_definition] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the attribute macro `ink::event_definition` (in Nightly builds, run with -Z macro-backtrace for more info) From 38d74f9e4982ea05d142dbe48c32c82fb06d2fee Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 5 Dec 2022 17:31:13 +0000 Subject: [PATCH 111/122] Fix up single definition event UI test --- crates/ink/tests/ui/contract/pass/event-single-definition.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/ink/tests/ui/contract/pass/event-single-definition.rs b/crates/ink/tests/ui/contract/pass/event-single-definition.rs index 241ced43d24..301f4d3c3ba 100644 --- a/crates/ink/tests/ui/contract/pass/event-single-definition.rs +++ b/crates/ink/tests/ui/contract/pass/event-single-definition.rs @@ -4,7 +4,9 @@ mod contract { pub struct Contract {} #[ink::event_definition] - pub enum Event0 {} + pub enum Event { + Event0 {} + } impl Contract { #[ink(constructor)] From f849e8e4aec6a7c3e7ba7022c786ebc08ce9748b Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 5 Dec 2022 17:44:06 +0000 Subject: [PATCH 112/122] Fix up too-many-topics UI test, succeeds but should fail... --- .../ui/contract/fail/event-too-many-topics.rs | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/crates/ink/tests/ui/contract/fail/event-too-many-topics.rs b/crates/ink/tests/ui/contract/fail/event-too-many-topics.rs index 4b7be584017..a167462409d 100644 --- a/crates/ink/tests/ui/contract/fail/event-too-many-topics.rs +++ b/crates/ink/tests/ui/contract/fail/event-too-many-topics.rs @@ -21,20 +21,22 @@ mod contract { #[ink(storage)] pub struct Contract {} - #[ink(event)] - pub struct Event { - #[ink(topic)] - arg_1: i8, - #[ink(topic)] - arg_2: i16, - #[ink(topic)] - arg_3: i32, + #[ink::event_definition] + pub enum Event { + Event { + #[ink(topic)] + arg_1: i8, + #[ink(topic)] + arg_2: i16, + #[ink(topic)] + arg_3: i32, + } } impl Contract { #[ink(constructor)] pub fn constructor() -> Self { - Self::env().emit_event(Event { + Self::env().emit_event(Event::Event { arg_1: 1, arg_2: 2, arg_3: 3, @@ -44,7 +46,7 @@ mod contract { #[ink(message)] pub fn message(&self) { - self.env().emit_event(Event { + self.env().emit_event(Event::Event { arg_1: 1, arg_2: 2, arg_3: 3, From 5d806911b21fd5b809562854f0b62d958f51f21b Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 9 Dec 2022 10:30:20 +0000 Subject: [PATCH 113/122] Fix up generate_metadata extern in test --- crates/ink/tests/return_type_metadata.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/crates/ink/tests/return_type_metadata.rs b/crates/ink/tests/return_type_metadata.rs index bf64663f606..cff7af413e4 100644 --- a/crates/ink/tests/return_type_metadata.rs +++ b/crates/ink/tests/return_type_metadata.rs @@ -41,6 +41,10 @@ mod contract { #[cfg(test)] mod tests { + use ink::metadata::{ + EventSpec, + InkProject, + }; use scale_info::{ form::PortableForm, Type, @@ -49,19 +53,19 @@ mod tests { TypeDefTuple, }; - fn generate_metadata() -> ink_metadata::InkProject { + fn generate_metadata() -> InkProject { extern "Rust" { - fn __ink_generate_metadata() -> ink_metadata::InkProject; + fn __ink_generate_metadata(events: Vec) -> InkProject; } - unsafe { __ink_generate_metadata() } + unsafe { __ink_generate_metadata(vec![]) } } /// Extract the type defs of the `Ok` and `Error` variants of a `Result` type. /// /// Panics if the type def is not a valid result fn extract_result<'a>( - metadata: &'a ink_metadata::InkProject, + metadata: &'a InkProject, ty: &'a Type, ) -> (&'a Type, &'a Type) { assert_eq!( @@ -90,7 +94,7 @@ mod tests { /// Resolve a type with the given id from the type registry fn resolve_type( - metadata: &ink_metadata::InkProject, + metadata: &InkProject, type_id: u32, ) -> &Type { metadata From 55813c6339ea6d8e993c6f8f1ee07744ad61f789 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 9 Dec 2022 17:20:51 +0000 Subject: [PATCH 114/122] Restore max topics len guard for environment --- crates/env/src/engine/off_chain/impls.rs | 2 +- crates/env/src/topics.rs | 90 +++++++++++++++++-- crates/ink/codegen/src/generator/event_def.rs | 23 +++-- crates/ink/ir/src/ir/event_def.rs | 8 +- crates/ink/tests/return_type_metadata.rs | 5 +- 5 files changed, 110 insertions(+), 18 deletions(-) diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index 6954942e69c..7ff6496ca27 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -432,7 +432,7 @@ impl TypedEnvBackend for EnvInstance { Event: Topics + scale::Encode, { let builder = TopicsBuilder::default(); - let enc_topics = event.topics::(builder.into()); + let enc_topics = event.topics(builder.into()); let enc_data = &scale::Encode::encode(&event)[..]; self.engine.deposit_event(&enc_topics[..], enc_data); } diff --git a/crates/env/src/topics.rs b/crates/env/src/topics.rs index 95d7addcc35..ddcfa8c5e22 100644 --- a/crates/env/src/topics.rs +++ b/crates/env/src/topics.rs @@ -189,14 +189,16 @@ impl EventTopicsAmount for state::NoRemainingTopics { /// /// Normally this trait should be implemented automatically via the ink! codegen. pub trait Topics { + /// The environment type. + type Env: Environment; + /// Guides event topic serialization using the given topics builder. - fn topics( + fn topics( &self, - builder: TopicsBuilder, - ) -> >::Output + builder: TopicsBuilder, + ) -> >::Output where - E: Environment, - B: TopicsBuilderBackend; + B: TopicsBuilderBackend; } /// For each topic a hash is generated. This hash must be unique @@ -231,3 +233,81 @@ where self.value.encode_to(dest); } } + +use core::marker::PhantomData; + +/// Guards that an ink! event definitions respects the topic limit. +/// +/// # Usage +/// +/// ``` +/// // #[ink(event)] +/// pub struct ExampleEvent {} +/// +/// /// The amount of the topics of the example event struct. +/// const LEN_TOPICS: usize = 3; +/// +/// /// The limit for the amount of topics per ink! event definition. +/// const TOPICS_LIMIT: usize = 4; +/// +/// impl ::ink::codegen::EventLenTopics for ExampleEvent { +/// type LenTopics = ::ink::codegen::EventTopics; +/// } +/// +/// // The below code only compiles successfully if the example ink! event +/// // definitions respects the topic limitation: it must have an amount of +/// // topics less than or equal to the topic limit. +/// const _: () = ::ink::codegen::utils::consume_type::< +/// ::ink::codegen::EventRespectsTopicLimit< +/// ExampleEvent, +/// TOPICS_LIMIT, +/// > +/// >(); +/// ``` +pub struct EventRespectsTopicLimit +where + Event: EventLenTopics, + ::LenTopics: RespectTopicLimit, +{ + marker: PhantomData Event>, +} + +/// Guards that an amount of event topics respects the event topic limit. +/// +/// # Note +/// +/// Implemented by `EventTopics` if M is less or equal to N. +/// Automatically implemented for up to 12 event topics. +pub trait RespectTopicLimit {} + +/// Represents an the amount of topics for an ink! event definition. +pub struct EventTopics; + +macro_rules! impl_is_smaller_or_equals { + ( $first:literal $( , $rest:literal )* $(,)? ) => { + impl RespectTopicLimit<$first> for EventTopics<$first> {} + $( + impl RespectTopicLimit<$rest> for EventTopics<$first> {} + )* + + impl_is_smaller_or_equals! { $( $rest ),* } + }; + ( ) => {}; +} +impl_is_smaller_or_equals! { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 +} + +/// Stores the number of event topics of the ink! event definition. +pub trait EventLenTopics { + /// Type denoting the number of event topics. + /// + /// # Note + /// + /// We use an associated type instead of an associated constant here + /// because Rust does not yet allow for generics in constant parameter + /// position which would be required in the `EventRespectsTopicLimit` + /// trait definition. + /// As soon as this is possible in Rust we might change this to a constant. + type LenTopics; +} diff --git a/crates/ink/codegen/src/generator/event_def.rs b/crates/ink/codegen/src/generator/event_def.rs index c443d4abc21..949ec0b6331 100644 --- a/crates/ink/codegen/src/generator/event_def.rs +++ b/crates/ink/codegen/src/generator/event_def.rs @@ -106,11 +106,21 @@ impl<'a> EventDefinition<'a> { let event_ident = self.event_def.ident(); // todo: [AJ] check if event signature topic should be included here (it is now, wasn't before) let len_topics = self.event_def.max_len_topics(); - + let max_len_topics = quote_spanned!(span=> + <<#event_ident as ::ink::env::Topics>::Env + as ::ink::env::Environment>::MAX_EVENT_TOPICS + ); quote_spanned!(span=> impl ::ink::codegen::EventLenTopics for #event_ident { type LenTopics = ::ink::codegen::EventTopics<#len_topics>; } + + const _: () = ::ink::codegen::utils::consume_type::< + ::ink::codegen::EventRespectsTopicLimit< + #event_ident, + { #max_len_topics }, + > + >(); ) } @@ -192,13 +202,14 @@ impl<'a> EventDefinition<'a> { quote_spanned!(span => const _: () = { impl ::ink::env::Topics for #event_ident { - fn topics( + type Env = ::ink::env::DefaultEnvironment; // todo: configure environment? + + fn topics( &self, - builder: ::ink::env::topics::TopicsBuilder<::ink::env::topics::state::Uninit, E, B>, - ) -> >::Output + builder: ::ink::env::topics::TopicsBuilder<::ink::env::topics::state::Uninit, Self::Env, B>, + ) -> >::Output where - E: ::ink::env::Environment, - B: ::ink::env::topics::TopicsBuilderBackend, + B: ::ink::env::topics::TopicsBuilderBackend, { match self { #( diff --git a/crates/ink/ir/src/ir/event_def.rs b/crates/ink/ir/src/ir/event_def.rs index 94d74e05ae2..c8085d5c6ec 100644 --- a/crates/ink/ir/src/ir/event_def.rs +++ b/crates/ink/ir/src/ir/event_def.rs @@ -149,8 +149,12 @@ impl InkEventDefinition { let attr_span = config.span(); // todo: remove this, or do we need config attrs? // let _parsed_config = syn::parse2::(config)?; - let item = syn::parse2::(input) - .map_err(|err| err.into_combine(format_err!(attr_span, "ink! event definitions must be enums")))?; + let item = syn::parse2::(input).map_err(|err| { + err.into_combine(format_err!( + attr_span, + "ink! event definitions must be enums" + )) + })?; Self::try_from(item) } diff --git a/crates/ink/tests/return_type_metadata.rs b/crates/ink/tests/return_type_metadata.rs index cff7af413e4..c7c700cc049 100644 --- a/crates/ink/tests/return_type_metadata.rs +++ b/crates/ink/tests/return_type_metadata.rs @@ -93,10 +93,7 @@ mod tests { } /// Resolve a type with the given id from the type registry - fn resolve_type( - metadata: &InkProject, - type_id: u32, - ) -> &Type { + fn resolve_type(metadata: &InkProject, type_id: u32) -> &Type { metadata .registry() .resolve(type_id) From e96f9d6a12c885790e43d72512cf39e653a10187 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 9 Dec 2022 17:22:27 +0000 Subject: [PATCH 115/122] Remove extra topic, max topics now includes signature topic --- crates/ink/tests/unique_topics.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/crates/ink/tests/unique_topics.rs b/crates/ink/tests/unique_topics.rs index cdccd06fba4..be9643a94b7 100644 --- a/crates/ink/tests/unique_topics.rs +++ b/crates/ink/tests/unique_topics.rs @@ -26,8 +26,6 @@ mod my_contract { v1: Balance, #[ink(topic)] v2: bool, - #[ink(topic)] - v3: bool, }, } @@ -48,7 +46,6 @@ mod my_contract { v0: None, v1: 0, v2: false, - v3: false, }); } } From bba0e88cc804f2fe3b62b10586fca5b38cc46144 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 9 Dec 2022 17:35:36 +0000 Subject: [PATCH 116/122] Update event-conflicting-storage.rs for event_definition --- .../ink/tests/ui/contract/fail/event-conflicting-storage.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/ink/tests/ui/contract/fail/event-conflicting-storage.rs b/crates/ink/tests/ui/contract/fail/event-conflicting-storage.rs index 647d8ec8ce0..a0e5ada72bc 100644 --- a/crates/ink/tests/ui/contract/fail/event-conflicting-storage.rs +++ b/crates/ink/tests/ui/contract/fail/event-conflicting-storage.rs @@ -3,9 +3,11 @@ mod contract { #[ink(storage)] pub struct Contract {} - #[ink(event)] + #[ink::event_definition] #[ink(storage)] - pub struct Event {} + pub enum Event { + Event {} + } impl Contract { #[ink(constructor)] From c999880b02504d2ec83f9b52b43e6b76a714acbb Mon Sep 17 00:00:00 2001 From: Green Baneling Date: Mon, 12 Dec 2022 10:35:38 +0000 Subject: [PATCH 117/122] Fixed compilation errors events (#1533) * Update README.md (#1521) * Fixed compilation errors * Make CI happy * Make CI happy * Return clippy changes back to minimize conflicts Co-authored-by: German --- CHANGELOG.md | 8 ++++---- MONTHLY_UPDATE.md | 2 +- README.md | 9 ++++----- crates/env/src/api.rs | 5 ++--- crates/env/src/backend.rs | 3 +-- crates/env/src/engine/off_chain/impls.rs | 3 +-- crates/env/src/engine/on_chain/impls.rs | 8 ++++---- crates/env/src/lib.rs | 1 - crates/ink/src/env_access.rs | 2 +- .../ui/contract/fail/event-conflicting-storage.rs | 2 +- .../contract/fail/event-too-many-topics-anonymous.rs | 2 +- .../tests/ui/contract/fail/event-too-many-topics.rs | 2 +- crates/ink/tests/ui/contract/pass/event-anonymous.rs | 2 +- .../ui/contract/pass/event-config-more-topics.rs | 2 +- .../tests/ui/contract/pass/event-many-definitions.rs | 2 +- .../tests/ui/contract/pass/event-shared-external.rs | 5 +++-- .../ui/contract/pass/event-single-definition.rs | 2 +- crates/ink/tests/ui/contract/pass/event-topics.rs | 2 +- .../tests/ui/contract/pass/example-erc721-works.rs | 2 +- crates/storage/src/lib.rs | 1 - examples/delegator/README.md | 2 +- examples/multisig/lib.rs | 12 ++++++++---- examples/rand-extension/README.md | 2 +- 23 files changed, 40 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57198bfd2d8..fa15d233235 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -690,9 +690,9 @@ ink! 3.0-rc4 is compatible with - [`substrate-contracts-node`](https://github.com/paritytech/substrate-contracts-node) version `0.1.0` or newer. - Install the newest version using `cargo install contracts-node --git https://github.com/paritytech/substrate-contracts-node.git --force`. -The documentation on our [Documentation Portal](https://ink.substrate.io) +The documentation on our [Documentation Portal](https://use.ink) is up-to-date with this release candidate. Since the last release candidate we notably -added a number of [Frequently Asked Questions](https://ink.substrate.io/faq) +added a number of [Frequently Asked Questions](https://use.ink/faq) there. ### Quality Assurance @@ -721,7 +721,7 @@ of key improvements to our testing setup: - Implemented the (unstable) `seal_rent_status` API ‒ [#798](https://github.com/paritytech/ink/pull/798). - Implemented the (unstable) `seal_debug_message` API ‒ [#792](https://github.com/paritytech/ink/pull/792). - Printing debug messages can now be achieved via `ink_env::debug_println!(…)`. - - See [our documentation](https://ink.substrate.io/faq#how-do-i-print-something-to-the-console-from-the-runtime) + - See [our documentation](https://use.ink/faq#how-do-i-print-something-to-the-console-from-the-runtime) for more information. - The examples have been updated to reflect this new way of printing debug messages. - Added usage comments with code examples to the `ink_env` API ‒ [#797](https://github.com/paritytech/ink/pull/797). @@ -782,7 +782,7 @@ ink! 3.0-rc3 is compatible with ### Added - Implemented chain extensions feature for ink!. -- ink!'s official documentation portal: https://ink.substrate.io/ +- ink!'s official documentation portal: https://use.ink/ - It is now possible to pass a `salt` argument to contract instantiations. - Implemented fuzz testing for the ink! codebase. diff --git a/MONTHLY_UPDATE.md b/MONTHLY_UPDATE.md index 14bbe244cc2..12ac19381ee 100644 --- a/MONTHLY_UPDATE.md +++ b/MONTHLY_UPDATE.md @@ -1,3 +1,3 @@ # Monthly Update: Parity Smart Contracts -The monthly update has been moved to [https://ink.substrate.io/monthly-update](https://ink.substrate.io/monthly-update)! +The monthly update has been moved to [https://use.ink/monthly-update](https://use.ink/monthly-update)! diff --git a/README.md b/README.md index c9357d9f1b6..cf04ca722d7 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@
[Guided Tutorial for Beginners](https://docs.substrate.io/tutorials/smart-contracts/)  •   -[ink! Documentation Portal](https://ink.substrate.io)  •   +[ink! Documentation Portal](https://use.ink)  •   [Developer Documentation](https://paritytech.github.io/ink/ink) @@ -72,11 +72,10 @@ More relevant links: If you want to have a local setup you can use our [`substrate-contracts-node`](https://github.com/paritytech/substrate-contracts-node) for a quickstart. It's a simple Substrate blockchain which includes the Substrate module for smart contract functionality ‒ the `contracts` pallet (see [How it Works](#how-it-works) for more). -We also have a live testnet on [Rococo](https://github.com/paritytech/cumulus/#rococo-) -called [Canvas](https://ink.substrate.io/canvas). Canvas is a Substrate based +We also have a live testnet on [Rococo](https://github.com/paritytech/cumulus/#rococo-). Rococo is a Substrate based parachain which supports ink! smart contracts. For further instructions on using this testnet, follow the instructions in the -[our documentation](https://ink.substrate.io/canvas#rococo-deployment). +[our documentation](https://use.ink/testnet). For both types of chains the [Contracts UI](https://contracts-ui.substrate.io/) can be used to instantiate your contract to a chain and interact with it. @@ -245,7 +244,7 @@ The `#[ink::test]` procedural macro enables off-chain testing. See e.g. the [`ex ## Developer Documentation -We have [a very comprehensive documentation portal](https://ink.substrate.io), +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: diff --git a/crates/env/src/api.rs b/crates/env/src/api.rs index e4821480a67..d7f2624afc1 100644 --- a/crates/env/src/api.rs +++ b/crates/env/src/api.rs @@ -173,13 +173,12 @@ where } /// Emits an event with the given event data. -pub fn emit_event(event: Event) +pub fn emit_event(event: Event) where - E: Environment, Event: Topics + scale::Encode, { ::on_instance(|instance| { - TypedEnvBackend::emit_event::(instance, event) + TypedEnvBackend::emit_event::(instance, event) }) } diff --git a/crates/env/src/backend.rs b/crates/env/src/backend.rs index dc3a8832b0e..e8a35bc585d 100644 --- a/crates/env/src/backend.rs +++ b/crates/env/src/backend.rs @@ -401,9 +401,8 @@ pub trait TypedEnvBackend: EnvBackend { /// # Note /// /// For more details visit: [`emit_event`][`crate::emit_event`] - fn emit_event(&mut self, event: Event) + fn emit_event(&mut self, event: Event) where - E: Environment, Event: Topics + scale::Encode; /// Invokes a contract message and returns its result. diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index 7ff6496ca27..053cdf98060 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -426,9 +426,8 @@ impl TypedEnvBackend for EnvInstance { }) } - fn emit_event(&mut self, event: Event) + fn emit_event(&mut self, event: Event) where - E: Environment, Event: Topics + scale::Encode, { let builder = TopicsBuilder::default(); diff --git a/crates/env/src/engine/on_chain/impls.rs b/crates/env/src/engine/on_chain/impls.rs index 036bb16d877..4de6183179f 100644 --- a/crates/env/src/engine/on_chain/impls.rs +++ b/crates/env/src/engine/on_chain/impls.rs @@ -401,13 +401,13 @@ impl TypedEnvBackend for EnvInstance { self.get_property_little_endian::(ext::minimum_balance) } - fn emit_event(&mut self, event: Event) + fn emit_event(&mut self, event: Event) where - E: Environment, Event: Topics + scale::Encode, { - let (mut scope, enc_topics) = - event.topics::(TopicsBuilder::from(self.scoped_buffer()).into()); + let (mut scope, enc_topics) = event.topics( + TopicsBuilder::<::Env>::from(self.scoped_buffer()).into(), + ); let enc_data = scope.take_encoded(&event); ext::deposit_event(enc_topics, enc_data); } diff --git a/crates/env/src/lib.rs b/crates/env/src/lib.rs index f04a61306f9..e9d9be7dcf1 100644 --- a/crates/env/src/lib.rs +++ b/crates/env/src/lib.rs @@ -29,7 +29,6 @@ missing_docs, bad_style, bare_trait_objects, - const_err, improper_ctypes, non_shorthand_field_patterns, no_mangle_generic_items, diff --git a/crates/ink/src/env_access.rs b/crates/ink/src/env_access.rs index 04eb77a5c32..0d3410a170b 100644 --- a/crates/ink/src/env_access.rs +++ b/crates/ink/src/env_access.rs @@ -414,7 +414,7 @@ where where Event: ink_env::Topics + scale::Encode, { - ink_env::emit_event::(event) + ink_env::emit_event::(event) } /// Instantiates another contract. diff --git a/crates/ink/tests/ui/contract/fail/event-conflicting-storage.rs b/crates/ink/tests/ui/contract/fail/event-conflicting-storage.rs index a0e5ada72bc..078fc6dac78 100644 --- a/crates/ink/tests/ui/contract/fail/event-conflicting-storage.rs +++ b/crates/ink/tests/ui/contract/fail/event-conflicting-storage.rs @@ -6,7 +6,7 @@ mod contract { #[ink::event_definition] #[ink(storage)] pub enum Event { - Event {} + Event {}, } impl Contract { diff --git a/crates/ink/tests/ui/contract/fail/event-too-many-topics-anonymous.rs b/crates/ink/tests/ui/contract/fail/event-too-many-topics-anonymous.rs index c4bfa8339c4..3eccf36565b 100644 --- a/crates/ink/tests/ui/contract/fail/event-too-many-topics-anonymous.rs +++ b/crates/ink/tests/ui/contract/fail/event-too-many-topics-anonymous.rs @@ -33,7 +33,7 @@ mod contract { arg_3: i32, #[ink(topic)] arg_4: i32, - } + }, } impl Contract { diff --git a/crates/ink/tests/ui/contract/fail/event-too-many-topics.rs b/crates/ink/tests/ui/contract/fail/event-too-many-topics.rs index a167462409d..a084886337b 100644 --- a/crates/ink/tests/ui/contract/fail/event-too-many-topics.rs +++ b/crates/ink/tests/ui/contract/fail/event-too-many-topics.rs @@ -30,7 +30,7 @@ mod contract { arg_2: i16, #[ink(topic)] arg_3: i32, - } + }, } impl Contract { diff --git a/crates/ink/tests/ui/contract/pass/event-anonymous.rs b/crates/ink/tests/ui/contract/pass/event-anonymous.rs index 7397dafb41d..1b9aa5a9294 100644 --- a/crates/ink/tests/ui/contract/pass/event-anonymous.rs +++ b/crates/ink/tests/ui/contract/pass/event-anonymous.rs @@ -51,7 +51,7 @@ mod contract { arg_4: i64, // #[ink(topic)] <- Cannot have more than 4 topics by default. arg_5: i128, - } + }, } impl Contract { diff --git a/crates/ink/tests/ui/contract/pass/event-config-more-topics.rs b/crates/ink/tests/ui/contract/pass/event-config-more-topics.rs index 53c47cd3e1d..40aec920799 100644 --- a/crates/ink/tests/ui/contract/pass/event-config-more-topics.rs +++ b/crates/ink/tests/ui/contract/pass/event-config-more-topics.rs @@ -45,7 +45,7 @@ mod contract { arg_9: u64, #[ink(topic)] arg_10: u128, - } + }, } impl Contract { diff --git a/crates/ink/tests/ui/contract/pass/event-many-definitions.rs b/crates/ink/tests/ui/contract/pass/event-many-definitions.rs index 17ac6ce3b3a..82a11ac3d63 100644 --- a/crates/ink/tests/ui/contract/pass/event-many-definitions.rs +++ b/crates/ink/tests/ui/contract/pass/event-many-definitions.rs @@ -30,7 +30,7 @@ mod contract { arg_3: i32, arg_4: i64, arg_5: i128, - } + }, } impl Contract { diff --git a/crates/ink/tests/ui/contract/pass/event-shared-external.rs b/crates/ink/tests/ui/contract/pass/event-shared-external.rs index dd8fa36caa0..8d06c61de55 100644 --- a/crates/ink/tests/ui/contract/pass/event-shared-external.rs +++ b/crates/ink/tests/ui/contract/pass/event-shared-external.rs @@ -4,7 +4,7 @@ pub enum SharedEvent { arg_1: u8, #[ink(topic)] arg_2: u16, - } + }, } #[ink::contract] @@ -20,7 +20,8 @@ mod contract { #[ink(message)] pub fn message(&self) { - self.env().emit_event(super::SharedEvent::Event1 { arg_1: 1, arg_2: 2 }); + self.env() + .emit_event(super::SharedEvent::Event1 { arg_1: 1, arg_2: 2 }); } } } diff --git a/crates/ink/tests/ui/contract/pass/event-single-definition.rs b/crates/ink/tests/ui/contract/pass/event-single-definition.rs index 301f4d3c3ba..731b29785b3 100644 --- a/crates/ink/tests/ui/contract/pass/event-single-definition.rs +++ b/crates/ink/tests/ui/contract/pass/event-single-definition.rs @@ -5,7 +5,7 @@ mod contract { #[ink::event_definition] pub enum Event { - Event0 {} + Event0 {}, } impl Contract { diff --git a/crates/ink/tests/ui/contract/pass/event-topics.rs b/crates/ink/tests/ui/contract/pass/event-topics.rs index e6df91d61a5..6c3331cbdf6 100644 --- a/crates/ink/tests/ui/contract/pass/event-topics.rs +++ b/crates/ink/tests/ui/contract/pass/event-topics.rs @@ -45,7 +45,7 @@ mod contract { arg_4: i64, // #[ink(topic)] <- Cannot have more than 4 topics by default. arg_5: i128, - } + }, } impl Contract { diff --git a/crates/ink/tests/ui/contract/pass/example-erc721-works.rs b/crates/ink/tests/ui/contract/pass/example-erc721-works.rs index 5dff9aed9b2..90e3bd1997d 100644 --- a/crates/ink/tests/ui/contract/pass/example-erc721-works.rs +++ b/crates/ink/tests/ui/contract/pass/example-erc721-works.rs @@ -63,7 +63,7 @@ mod erc721 { #[ink(topic)] operator: AccountId, approved: bool, - } + }, } impl Erc721 { diff --git a/crates/storage/src/lib.rs b/crates/storage/src/lib.rs index d9971535a3a..38a417cca5b 100644 --- a/crates/storage/src/lib.rs +++ b/crates/storage/src/lib.rs @@ -29,7 +29,6 @@ missing_docs, bad_style, bare_trait_objects, - const_err, improper_ctypes, non_shorthand_field_patterns, no_mangle_generic_items, diff --git a/examples/delegator/README.md b/examples/delegator/README.md index 8c3b0b6a5e2..449c3b30c46 100644 --- a/examples/delegator/README.md +++ b/examples/delegator/README.md @@ -13,7 +13,7 @@ In order to test this bundle of smart contracts you need to execute the following steps. You can upload the contracts using our [Contracts UI](https://contracts-ui.substrate.io/). -If you want to test it locally, our [`substrate-contracts-node`](https://ink.substrate.io/getting-started/setup/#installing-the-substrate-smart-contracts-node) +If you want to test it locally, our [`substrate-contracts-node`](https://use.ink/getting-started/setup/#installing-the-substrate-smart-contracts-node) is an easy way to get a local smart contract chain running. 1. Compile all contracts using the `./build-all.sh` script. diff --git a/examples/multisig/lib.rs b/examples/multisig/lib.rs index d1f43a736c3..a42a5011be2 100755 --- a/examples/multisig/lib.rs +++ b/examples/multisig/lib.rs @@ -360,7 +360,8 @@ mod multisig { ensure_requirement_is_valid(self.owners.len() as u32 + 1, self.requirement); self.is_owner.insert(new_owner, &()); self.owners.push(new_owner); - self.env().emit_event(Event::OwnerAddition { owner: new_owner }); + self.env() + .emit_event(Event::OwnerAddition { owner: new_owner }); } /// Remove an owner from the contract. @@ -404,8 +405,10 @@ mod multisig { self.is_owner.remove(old_owner); self.is_owner.insert(new_owner, &()); self.clean_owner_confirmations(&old_owner); - self.env().emit_event(Event::OwnerRemoval { owner: old_owner }); - self.env().emit_event(Event::OwnerAddition { owner: new_owner }); + self.env() + .emit_event(Event::OwnerRemoval { owner: old_owner }); + self.env() + .emit_event(Event::OwnerAddition { owner: new_owner }); } /// Change the requirement to a new value. @@ -420,7 +423,8 @@ mod multisig { self.ensure_from_wallet(); ensure_requirement_is_valid(self.owners.len() as u32, new_requirement); self.requirement = new_requirement; - self.env().emit_event(Event::RequirementChange { new_requirement }); + self.env() + .emit_event(Event::RequirementChange { new_requirement }); } /// Add a new transaction candidate to the contract. diff --git a/examples/rand-extension/README.md b/examples/rand-extension/README.md index 61b949cca17..19d4cc48c7a 100644 --- a/examples/rand-extension/README.md +++ b/examples/rand-extension/README.md @@ -4,7 +4,7 @@ It demonstrates how to call a custom Substrate function from ink!. -See [this chapter](https://ink.substrate.io/macros-attributes/chain-extension) +See [this chapter](https://use.ink/macros-attributes/chain-extension) in our ink! documentation for more details. There are two parts to this example: From 706c6001773ef8f49a46ab738fe31fa7d6c2bb28 Mon Sep 17 00:00:00 2001 From: andrew Date: Thu, 12 Jan 2023 14:33:22 +0000 Subject: [PATCH 118/122] Constrain emit_event environment --- crates/env/src/api.rs | 7 +++-- crates/env/src/backend.rs | 5 ++-- crates/env/src/engine/off_chain/impls.rs | 5 ++-- crates/env/src/engine/on_chain/impls.rs | 5 ++-- crates/ink/src/env_access.rs | 5 ++-- .../ui/contract/fail/event-too-many-topics.rs | 30 +++++++++++-------- 6 files changed, 33 insertions(+), 24 deletions(-) diff --git a/crates/env/src/api.rs b/crates/env/src/api.rs index d7f2624afc1..ee31f7c0627 100644 --- a/crates/env/src/api.rs +++ b/crates/env/src/api.rs @@ -173,12 +173,13 @@ where } /// Emits an event with the given event data. -pub fn emit_event(event: Event) +pub fn emit_event(event: Event) where - Event: Topics + scale::Encode, + E: Environment, + Event: Topics + scale::Encode, { ::on_instance(|instance| { - TypedEnvBackend::emit_event::(instance, event) + TypedEnvBackend::emit_event::(instance, event) }) } diff --git a/crates/env/src/backend.rs b/crates/env/src/backend.rs index e8a35bc585d..851f5fff240 100644 --- a/crates/env/src/backend.rs +++ b/crates/env/src/backend.rs @@ -401,9 +401,10 @@ pub trait TypedEnvBackend: EnvBackend { /// # Note /// /// For more details visit: [`emit_event`][`crate::emit_event`] - fn emit_event(&mut self, event: Event) + fn emit_event(&mut self, event: Event) where - Event: Topics + scale::Encode; + E: Environment, + Event: Topics + scale::Encode; /// Invokes a contract message and returns its result. /// diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index ae67e39d9fd..5128d0b3942 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -426,9 +426,10 @@ impl TypedEnvBackend for EnvInstance { }) } - fn emit_event(&mut self, event: Event) + fn emit_event(&mut self, event: Event) where - Event: Topics + scale::Encode, + E: Environment, + Event: Topics + scale::Encode, { let builder = TopicsBuilder::default(); let enc_topics = event.topics(builder.into()); diff --git a/crates/env/src/engine/on_chain/impls.rs b/crates/env/src/engine/on_chain/impls.rs index 39a01fd9961..344f0ebad9b 100644 --- a/crates/env/src/engine/on_chain/impls.rs +++ b/crates/env/src/engine/on_chain/impls.rs @@ -401,9 +401,10 @@ impl TypedEnvBackend for EnvInstance { self.get_property_little_endian::(ext::minimum_balance) } - fn emit_event(&mut self, event: Event) + fn emit_event(&mut self, event: Event) where - Event: Topics + scale::Encode, + E: Environment, + Event: Topics + scale::Encode, { let (mut scope, enc_topics) = event.topics( TopicsBuilder::<::Env>::from(self.scoped_buffer()).into(), diff --git a/crates/ink/src/env_access.rs b/crates/ink/src/env_access.rs index 00a09551445..3b802c3ccf3 100644 --- a/crates/ink/src/env_access.rs +++ b/crates/ink/src/env_access.rs @@ -412,9 +412,10 @@ where /// todo: [AJ] docs pub fn emit_event(self, event: Event) where - Event: ink_env::Topics + scale::Encode, + E: Environment, + Event: ink_env::Topics + scale::Encode, { - ink_env::emit_event::(event) + ink_env::emit_event::(event) } /// Instantiates another contract. diff --git a/crates/ink/tests/ui/contract/fail/event-too-many-topics.rs b/crates/ink/tests/ui/contract/fail/event-too-many-topics.rs index a084886337b..8153477a152 100644 --- a/crates/ink/tests/ui/contract/fail/event-too-many-topics.rs +++ b/crates/ink/tests/ui/contract/fail/event-too-many-topics.rs @@ -16,23 +16,27 @@ impl ink_env::Environment for EnvironmentMoreTopics { type ChainExtension = (); } -#[ink::contract(env = super::EnvironmentMoreTopics)] +#[ink::event_definition] +// #[ink::event_definition(env = super::EnvironmentMoreTopics)] +pub enum Event { + Event { + #[ink(topic)] + arg_1: i8, + #[ink(topic)] + arg_2: i16, + #[ink(topic)] + arg_3: i32, + }, +} + +#[ink::contract] +// #[ink::contract(env = super::EnvironmentMoreTopics)] mod contract { + use super::Event; + #[ink(storage)] pub struct Contract {} - #[ink::event_definition] - pub enum Event { - Event { - #[ink(topic)] - arg_1: i8, - #[ink(topic)] - arg_2: i16, - #[ink(topic)] - arg_3: i32, - }, - } - impl Contract { #[ink(constructor)] pub fn constructor() -> Self { From 468b2262b06536d0101f50a319e3a0549a2f55e7 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 21 Apr 2023 12:35:38 +0100 Subject: [PATCH 119/122] Calculate signature topic in macro --- crates/env/src/topics.rs | 5 +- crates/ink/codegen/src/generator/event_def.rs | 4 +- crates/ink/ir/src/ir/event_def.rs | 75 +++++++++++++++++-- crates/ink/ir/src/ir/item_mod.rs | 2 +- crates/primitives/src/event.rs | 36 ++++----- 5 files changed, 93 insertions(+), 29 deletions(-) diff --git a/crates/env/src/topics.rs b/crates/env/src/topics.rs index f463947e99d..a9716f2debb 100644 --- a/crates/env/src/topics.rs +++ b/crates/env/src/topics.rs @@ -260,10 +260,7 @@ use core::marker::PhantomData; /// // definitions respects the topic limitation: it must have an amount of /// // topics less than or equal to the topic limit. /// const _: () = ::ink::codegen::utils::consume_type::< -/// ::ink::codegen::EventRespectsTopicLimit< -/// ExampleEvent, -/// TOPICS_LIMIT, -/// > +/// ::ink::codegen::EventRespectsTopicLimit, /// >(); /// ``` pub struct EventRespectsTopicLimit diff --git a/crates/ink/codegen/src/generator/event_def.rs b/crates/ink/codegen/src/generator/event_def.rs index 949ec0b6331..23a9c5a5621 100644 --- a/crates/ink/codegen/src/generator/event_def.rs +++ b/crates/ink/codegen/src/generator/event_def.rs @@ -77,6 +77,7 @@ impl<'a> EventDefinition<'a> { let impls = self.event_def.variants().map(|ev| { let event_variant_ident = ev.ident(); + let signature_topic = ev.signature_topic(event_ident); let index = ev.index(); quote_spanned!(span=> impl ::ink::reflect::EventVariantInfo<#index> for #event_ident { @@ -104,7 +105,8 @@ impl<'a> EventDefinition<'a> { fn generate_topics_guard(&self) -> TokenStream2 { let span = self.event_def.span(); let event_ident = self.event_def.ident(); - // todo: [AJ] check if event signature topic should be included here (it is now, wasn't before) + // todo: [AJ] check if event signature topic should be included here (it is now, + // wasn't before) let len_topics = self.event_def.max_len_topics(); let max_len_topics = quote_spanned!(span=> <<#event_ident as ::ink::env::Topics>::Env diff --git a/crates/ink/ir/src/ir/event_def.rs b/crates/ink/ir/src/ir/event_def.rs index c8085d5c6ec..f01ec40074f 100644 --- a/crates/ink/ir/src/ir/event_def.rs +++ b/crates/ink/ir/src/ir/event_def.rs @@ -22,6 +22,7 @@ use proc_macro2::{ Span, TokenStream as TokenStream2, }; +use quote::ToTokens; use syn::{ spanned::Spanned as _, Result, @@ -104,8 +105,9 @@ impl TryFrom for InkEventDefinition { let ident = field.ident.clone().unwrap_or_else(|| { panic!("FIELDS SHOULD HAVE A NAME {:?}", field.ident) }); - // .unwrap_or(quote::format_ident!("{}", index)); // todo: should it also handle tuple variants? This breaks - // strip out the `#[ink(topic)] attributes, since the item will be used to + // .unwrap_or(quote::format_ident!("{}", index)); // todo: should it also + // handle tuple variants? This breaks strip out the + // `#[ink(topic)] attributes, since the item will be used to // regenerate the event enum field.attrs = other_attrs; fields.push(EventField { @@ -230,13 +232,13 @@ impl EventVariant { self.index } - /// Returns an iterator yielding all the `#[ink(topic)]` annotated fields - /// of the event variant struct. + /// Returns an iterator yielding all the fields of the event variant struct. pub fn fields(&self) -> impl Iterator { self.fields.iter() } - /// Returns true if the signature of the event variant should *not* be indexed by a topic. + /// Returns true if the signature of the event variant should *not* be indexed by a + /// topic. pub fn anonymous(&self) -> bool { self.anonymous } @@ -250,6 +252,23 @@ impl EventVariant { topics_len + 1usize } } + + /// The signature topic of an event variant. + /// + /// Calculated with `blake2b("EventEnum::EventVariant(field1_type,field2_type)")`. + pub fn signature_topic(&self, event_ident: &Ident) -> [u8; 32] { + let fields = self + .fields() + .map(|event_field| event_field.field.ty.to_token_stream().to_string().replace(" ", "")) + .collect::>() + .join(","); + let topic_str = format!("{}::{}({fields})", event_ident, self.ident()); + println!("topic_str: {}", topic_str); + let input = topic_str.as_bytes(); + let mut output = [0; 32]; + blake2b_256(&input, &mut output); + output + } } /// An event field with a flag indicating if this field is an event topic. @@ -479,4 +498,50 @@ mod tests { } }); } + + #[test] + fn event_variant_signature_topics() { + let event_def = + >::try_from(syn::parse_quote! { + #[ink::event_definition] + pub enum MyEvent { + EventA { + field_1: i32, + field_2: u64, + field_3: [u8; 32], + }, + EventB {}, + EventC { + field_1: (i32, u64), + } + } + }) + .unwrap(); + + let mut variants = event_def.variants(); + + fn signature_topic(input: &str) -> [u8; 32] { + let mut output = [0; 32]; + blake2b_256(input.as_bytes(), &mut output); + output + } + + let event_variant = variants.next().expect("EventA variant"); + assert_eq!( + event_variant.signature_topic(event_def.ident()), + signature_topic("MyEvent::EventA(i32,u64,[u8;32])") + ); + + let event_variant = variants.next().expect("EventB variant"); + assert_eq!( + event_variant.signature_topic(event_def.ident()), + signature_topic("MyEvent::EventB()") + ); + + let event_variant = variants.next().expect("EventC variant"); + assert_eq!( + event_variant.signature_topic(event_def.ident()), + signature_topic("MyEvent::EventC((i32,u64))") + ); + } } diff --git a/crates/ink/ir/src/ir/item_mod.rs b/crates/ink/ir/src/ir/item_mod.rs index 67e3835ea70..37b205c416a 100644 --- a/crates/ink/ir/src/ir/item_mod.rs +++ b/crates/ink/ir/src/ir/item_mod.rs @@ -53,7 +53,7 @@ use syn::{ /// pub enum MyEvent { /// Event { /// // event fields -/// } +/// }, /// } /// /// impl MyStorage { diff --git a/crates/primitives/src/event.rs b/crates/primitives/src/event.rs index 8041d4a8251..011aaeb6327 100644 --- a/crates/primitives/src/event.rs +++ b/crates/primitives/src/event.rs @@ -12,24 +12,24 @@ // See the License for the specific language governing permissions and // limitations under the License. -use xxhash_rust::const_xxh3::xxh3_128; - -/// Generate the topic for the event signature. -/// -/// xxh3_128(path) ++ xxh3_128(event_variant) todo: + fields? -pub const fn event_signature_topic( - path: &'static str, - event_variant: &'static str, -) -> [u8; 32] { - let p = xxh3_128(path.as_bytes()).to_be_bytes(); - // todo: add fields to signature? - let s = xxh3_128(event_variant.as_bytes()).to_be_bytes(); - [ - p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], - p[13], p[14], p[15], s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], - s[10], s[11], s[12], s[13], s[14], s[15], - ] -} +// use xxhash_rust::const_xxh3::xxh3_128; +// +// /// Generate the topic for the event signature. +// /// +// /// xxh3_128(path) ++ xxh3_128(event_variant) todo: + fields? +// pub const fn event_signature_topic( +// path: &'static str, +// event_variant: &'static str, +// ) -> [u8; 32] { +// let p = xxh3_128(path.as_bytes()).to_be_bytes(); +// // todo: add fields to signature? +// let s = xxh3_128(event_variant.as_bytes()).to_be_bytes(); +// [ +// p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], +// p[12], p[13], p[14], p[15], s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], +// s[8], s[9], s[10], s[11], s[12], s[13], s[14], s[15], +// ] +// } // pub const fn event_field_topic_prefix( // path: &'static str, From 203fe8b202ee48cadeb22b4940b3692bf516be29 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 21 Apr 2023 16:37:49 +0100 Subject: [PATCH 120/122] Fix lifetime from merge --- crates/metadata/src/specs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/metadata/src/specs.rs b/crates/metadata/src/specs.rs index 697f95a6b4e..a26aa99c48c 100644 --- a/crates/metadata/src/specs.rs +++ b/crates/metadata/src/specs.rs @@ -883,7 +883,7 @@ where } /// Sets the documentation of the event specification. - pub fn docs(self, docs: D) -> Self + pub fn docs<'a, D>(self, docs: D) -> Self where D: IntoIterator, F::String: From<&'a str>, From 3854c490d4b40d087c13ee345882841cb4ac4d5f Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 21 Apr 2023 16:48:52 +0100 Subject: [PATCH 121/122] Generate signature topic --- crates/ink/codegen/src/generator/event_def.rs | 7 ++----- crates/ink/ir/src/ir/event_def.rs | 19 +++++++++++++++++-- crates/primitives/src/lib.rs | 1 - 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/crates/ink/codegen/src/generator/event_def.rs b/crates/ink/codegen/src/generator/event_def.rs index 23a9c5a5621..5e78318e73d 100644 --- a/crates/ink/codegen/src/generator/event_def.rs +++ b/crates/ink/codegen/src/generator/event_def.rs @@ -77,15 +77,12 @@ impl<'a> EventDefinition<'a> { let impls = self.event_def.variants().map(|ev| { let event_variant_ident = ev.ident(); - let signature_topic = ev.signature_topic(event_ident); + let signature_topic = ev.signature_topic_hex_lits(event_ident); let index = ev.index(); quote_spanned!(span=> impl ::ink::reflect::EventVariantInfo<#index> for #event_ident { const NAME: &'static str = ::core::stringify!(#event_variant_ident); - const SIGNATURE_TOPIC: [u8; 32] = ::ink::primitives::event_signature_topic( - ::PATH, - >::NAME, - ); + const SIGNATURE_TOPIC: [u8; 32] = [ #( #signature_topic ),* ]; } ) }); diff --git a/crates/ink/ir/src/ir/event_def.rs b/crates/ink/ir/src/ir/event_def.rs index f01ec40074f..1ce0d085650 100644 --- a/crates/ink/ir/src/ir/event_def.rs +++ b/crates/ink/ir/src/ir/event_def.rs @@ -16,6 +16,7 @@ use crate::{ blake2b_256, error::ExtError as _, ir, + literal::HexLiteral, }; use proc_macro2::{ Ident, @@ -259,16 +260,30 @@ impl EventVariant { pub fn signature_topic(&self, event_ident: &Ident) -> [u8; 32] { let fields = self .fields() - .map(|event_field| event_field.field.ty.to_token_stream().to_string().replace(" ", "")) + .map(|event_field| { + event_field + .field + .ty + .to_token_stream() + .to_string() + .replace(" ", "") + }) .collect::>() .join(","); let topic_str = format!("{}::{}({fields})", event_ident, self.ident()); - println!("topic_str: {}", topic_str); let input = topic_str.as_bytes(); let mut output = [0; 32]; blake2b_256(&input, &mut output); output } + + /// The signature topic literal of an event variant. + /// + /// Calculated with `blake2b("EventEnum::EventVariant(field1_type,field2_type)")`. + pub fn signature_topic_hex_lits(&self, event_ident: &Ident) -> [syn::LitInt; 32] { + self.signature_topic(event_ident) + .map(::hex_padded_suffixed) + } } /// An event field with a flag indicating if this field is an event topic. diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index 21d560e22b8..05eb9a69abf 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -33,7 +33,6 @@ mod key; mod types; pub use self::{ - event::event_signature_topic, key::{ Key, KeyComposer, From 06c793375854b78284930034e52296a8a8f72394 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 21 Apr 2023 17:01:44 +0100 Subject: [PATCH 122/122] Add back method lost in merge --- .../ink/codegen/src/generator/metadata/mod.rs | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/crates/ink/codegen/src/generator/metadata/mod.rs b/crates/ink/codegen/src/generator/metadata/mod.rs index c8498de237c..d8beeebeaa2 100644 --- a/crates/ink/codegen/src/generator/metadata/mod.rs +++ b/crates/ink/codegen/src/generator/metadata/mod.rs @@ -186,6 +186,39 @@ impl Metadata<'_> { } } + /// Generates the ink! metadata for the given type. + fn generate_type_spec(ty: &syn::Type) -> TokenStream2 { + fn without_display_name(ty: &syn::Type) -> TokenStream2 { + quote! { ::ink::metadata::TypeSpec::of_type::<#ty>() } + } + + if let syn::Type::Path(type_path) = ty { + if type_path.qself.is_some() { + return without_display_name(ty) + } + let path = &type_path.path; + if path.segments.is_empty() { + return without_display_name(ty) + } + let segs = path + .segments + .iter() + .map(|seg| &seg.ident) + .collect::>(); + quote! { + ::ink::metadata::TypeSpec::with_name_segs::<#ty, _>( + ::core::iter::Iterator::map( + ::core::iter::IntoIterator::into_iter([ #( ::core::stringify!(#segs) ),* ]), + ::core::convert::AsRef::as_ref + ) + ) + } + } else { + without_display_name(ty) + } + } + + /// Generates the ink! metadata for all ink! smart contract messages. fn generate_messages(&self) -> Vec { let mut messages = Vec::new();