Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shared external event definitions #1243

Closed
wants to merge 163 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
163 commits
Select commit Hold shift + click to select a range
2c42a21
Add ui test for shared event
ascjones Mar 31, 2022
21fd910
WIP adding ink::event_definition
ascjones Apr 1, 2022
27948f1
Merge branch 'master' into aj/shared-events
ascjones Apr 1, 2022
ba6734d
More event definition wiring
ascjones Apr 1, 2022
54fbe58
WIP building shared event def
ascjones Apr 4, 2022
400ea92
Merge branch 'master' into aj/shared-events
ascjones Apr 11, 2022
88f3722
Make event_definition attribute compile
ascjones Apr 11, 2022
63a30c6
Parse ink(event) attribute on type alias
ascjones Apr 12, 2022
90c2eb5
Combining IR for external and inline event definitions
ascjones Apr 13, 2022
ee9e74b
WIP generating Topics impls for inline events
ascjones Apr 13, 2022
0edba13
Remove duplicate topics impls
ascjones Apr 14, 2022
c1f7d30
Merge branch 'master' into aj/shared-events
ascjones Apr 14, 2022
2d2541d
WIP implementing event spec metadata generation
ascjones Apr 14, 2022
05d35b5
Add missing semicolon
ascjones Apr 14, 2022
e73e17c
Remove unused fields iterator
ascjones Apr 14, 2022
a1a04f0
Fix imported event ident
ascjones Apr 14, 2022
98c7f49
Update trybuild to run ui tests in parallel (#1220)
ascjones Apr 21, 2022
c931a38
Fix test errors
ascjones Apr 21, 2022
a2c60ea
Add todo
ascjones Apr 25, 2022
f5882ed
Merge branch 'master' into aj/shared-events
ascjones May 3, 2022
3f1978a
Fix test errors
ascjones May 3, 2022
8b393f3
Merge remote-tracking branch 'origin/aj/shared-events' into aj/shared…
ascjones May 3, 2022
0081544
Test out new interface api
ascjones May 5, 2022
13a1e62
Merge branch 'master' into aj/shared-events
ascjones Aug 1, 2022
7f35189
Revert "Test out new interface api"
ascjones Aug 1, 2022
5f3f2f0
Update example to latest syntax
ascjones Aug 4, 2022
35d8184
Fmt
ascjones Aug 4, 2022
6763b74
Remove EmitEvent impl
ascjones Aug 4, 2022
7063bd3
Remove EmitEvent impl and ContractBaseEvent
ascjones Aug 4, 2022
7e115ec
Add args to shared event test
ascjones Aug 5, 2022
100e53b
Convert inline event to use event_def codegen
ascjones Aug 5, 2022
71db312
Remove ink item Event
ascjones Aug 5, 2022
c73ea8d
Fmt
ascjones Aug 5, 2022
7628786
Merge branch 'master' into aj/shared-events
ascjones Aug 25, 2022
7e59e74
Rewire contract internal event definitions
ascjones Aug 25, 2022
c6a8cec
add todos
ascjones Aug 30, 2022
fd8fef2
Merge branch 'master' into aj/shared-events
ascjones Sep 2, 2022
0dfc495
WIP changing event def to be an enum
ascjones Sep 5, 2022
34da8a6
WIP adding EventVariantInfo trait for EVENT_SIGNATURE
ascjones Sep 6, 2022
14d6e30
WIP adapting to synstructure
ascjones Sep 6, 2022
babda7d
Merge branch 'master' into aj/shared-events
ascjones Sep 6, 2022
99bb6bd
WIP generating event signature topics impls
ascjones Sep 6, 2022
1e5dae3
Revert previous work attempting to use synstructure
ascjones Sep 6, 2022
65a8822
Restore wiring for inline contract events
ascjones Sep 6, 2022
8735978
WIP generating event enum impls
ascjones Sep 6, 2022
17609fe
Merge branch 'master' into aj/shared-events
ascjones Sep 28, 2022
6663383
Fix event def after merge
ascjones Sep 28, 2022
ca6247e
Merge branch 'master' into aj/shared-events
ascjones Sep 28, 2022
090219d
Fmt
ascjones Sep 28, 2022
2189719
Recover changes from master
ascjones Sep 28, 2022
42dc296
Fix up metadata compilation
ascjones Sep 28, 2022
3be3025
Fmt
ascjones Sep 28, 2022
a1ac0b4
Convert more events to enums
ascjones Sep 29, 2022
10ad8e5
Fix some crate paths
ascjones Sep 29, 2022
9383b40
Fix event def tests
ascjones Sep 29, 2022
5253a31
Start to rebuild topics impl
ascjones Sep 29, 2022
8e8af63
Fix some IR tests
ascjones Sep 29, 2022
d2ce784
WIP impl variant topics
ascjones Sep 29, 2022
dd2c398
Merge branch 'master' into aj/shared-events
ascjones Oct 5, 2022
504e1fe
WIP building push_topics impl
ascjones Oct 5, 2022
35561a7
WIP use const fn to generate event_variant_signature
ascjones Oct 6, 2022
a9d0559
WIP generate event variant match arms with remaining topics
ascjones Oct 6, 2022
23fe12e
Fix some errors
ascjones Oct 7, 2022
8db474f
Split InkEventDefinition constructors for inline and external events
ascjones Oct 7, 2022
1c4d382
Merge branch 'master' into aj/shared-events
ascjones Oct 7, 2022
5068804
Read anonymous from variant attributs, also fmt
ascjones Oct 7, 2022
9914bf4
Just allow only ink::event_definition
ascjones Oct 7, 2022
3e83f6e
WIP attempt to make trait-erc20 compile
ascjones Oct 7, 2022
a076821
Fix up field def gen error
ascjones Oct 17, 2022
2f81f67
Fix up trait-erc20 events emit
ascjones Oct 18, 2022
797ea95
Fix up ink_env refs in event_definition
ascjones Oct 18, 2022
2309dd3
Wire up event signature topic
ascjones Oct 18, 2022
d776c3f
Fix variant field bindings
ascjones Oct 18, 2022
a720d30
Generate EventVariantInfo SIGNATURE
ascjones Oct 19, 2022
9d2e334
WIP impl compile time signature topic calculation
ascjones Oct 19, 2022
9246664
Remove field topic prefix
ascjones Oct 19, 2022
343ae04
Resolve some warnings
ascjones Oct 19, 2022
4238fbd
Restore topics guard
ascjones Oct 20, 2022
216d684
Merge branch 'master' into aj/shared-events
ascjones Oct 20, 2022
87ac91c
WIP generate event metadata, introduce EventInfo trait
ascjones Oct 20, 2022
ec01087
Generate event variants metadata, wire it up
ascjones Oct 20, 2022
97cd765
Allow passing in of event metadata vec
ascjones Oct 25, 2022
354f81d
Generate event metadata custom sections and externs
ascjones Oct 26, 2022
ff3b2ed
Remove todo comment from event-shared-external.rs
ascjones Oct 26, 2022
6c94cb0
Filter topic fields and combine bindings
ascjones Oct 26, 2022
dbe237e
Merge branch 'master' into aj/shared-events
ascjones Oct 28, 2022
3beb5a7
Migrating erc721 to new event def
ascjones Oct 29, 2022
06bf240
Put event definition to the top of the contract file
ascjones Oct 20, 2022
e1c97de
Add ink event metadata custom section marker
ascjones Oct 31, 2022
2356ffa
Fix errors after merge
ascjones Oct 31, 2022
53189d5
Number of topics builder per variant
ascjones Oct 31, 2022
3a23e06
Fmt erc721
ascjones Oct 31, 2022
ca68223
Convert dns to event_definition enum
ascjones Oct 31, 2022
d922172
Fix up erc20 events
ascjones Oct 31, 2022
16aa615
Migrate rand-extension example
ascjones Oct 31, 2022
2ba841e
Migrate erc1155 example
ascjones Oct 31, 2022
55884db
Migrate payment-channel example
ascjones Oct 31, 2022
7d42db0
Migrate mother example
ascjones Oct 31, 2022
c91171a
Migrate multisig example
ascjones Oct 31, 2022
b4ddcac
WIP fixing topic attr validation
ascjones Oct 31, 2022
0343989
Merge branch 'master' into aj/shared-events
ascjones Nov 1, 2022
9af23c6
WIP use event def ids to call into metadata
ascjones Nov 1, 2022
82cff3d
Fix up topic field attribute validation, fix warnings
ascjones Nov 1, 2022
2261e9d
Revert using event definition ids in custom section
ascjones Nov 2, 2022
e8a74c2
Merge branch 'master' into aj/shared-events
ascjones Nov 3, 2022
a25b763
Fix compilation errors after merge
ascjones Nov 3, 2022
87a014a
Comment out TypeSpec::default for now
ascjones Nov 3, 2022
ce28c3c
Merge branch 'master' into aj/shared-events
ascjones Nov 3, 2022
abdb624
Fix clippy errors
ascjones Nov 4, 2022
1d6fbaf
Update `scale-info` requirement to 2.3
ascjones Nov 4, 2022
1e89578
Merge branch 'master' into aj/upgrade-scale-info-requirement
ascjones Nov 4, 2022
905b943
Merge branch 'aj/upgrade-scale-info-requirement' into aj/shared-events
ascjones Nov 4, 2022
495e830
Merge branch 'master' into aj/shared-events
ascjones Nov 4, 2022
22739eb
Fix up erc20 ui test
ascjones Nov 7, 2022
39da2d7
Fix and remove some tests
ascjones Nov 7, 2022
2aef9d5
Fix non pub test
ascjones Nov 7, 2022
2d16ec1
Fix up metadata specs
ascjones Nov 7, 2022
5862d55
Merge branch 'master' into aj/shared-events
ascjones Nov 8, 2022
64915ad
Merge branch 'master' into aj/shared-events
ascjones Nov 28, 2022
cdee107
Remove method after merge
ascjones Nov 28, 2022
148f43f
E2E: utilize `contract-build` crate
ascjones Nov 29, 2022
50e88c1
Merge branch 'master' into aj/contract-build-lib
ascjones Nov 29, 2022
52f2024
Build as debug so we can see the debug messages
ascjones Nov 29, 2022
8481f8b
Merge branch 'master' into aj/shared-events
ascjones Nov 29, 2022
8aebcf2
Merge branch 'master' into aj/shared-events
ascjones Nov 30, 2022
21c37f5
Merge branch 'master' into aj/contract-build-lib
ascjones Nov 30, 2022
9d84bbe
Merge branch 'master' into aj/shared-events
ascjones Nov 30, 2022
963cfee
Switch to using `contract-build` master branch
ascjones Dec 1, 2022
e9701ea
Add missing flag
ascjones Dec 1, 2022
cdbcbe0
Use released `contract-build` crate
ascjones Dec 1, 2022
98dfb4a
Merge branch 'aj/contract-build-lib' into aj/shared-events
ascjones Dec 1, 2022
4775cf3
Use custom `contract-build` branch
ascjones Dec 1, 2022
3777274
Remove duplicate generate_type_spec method
ascjones Dec 1, 2022
e9fe3e1
Update generate_metadata signature in ui test
ascjones Dec 2, 2022
9d9ef5e
Fix anonymous event ui test
ascjones Dec 2, 2022
5ef3525
Update event defs in some UI tests
ascjones Dec 2, 2022
ddd3559
More UI tests migration
ascjones Dec 5, 2022
e5d8163
Check for event definitions with no variants
ascjones Dec 5, 2022
b5a961a
Check for event definitions are not structs
ascjones Dec 5, 2022
38d74f9
Fix up single definition event UI test
ascjones Dec 5, 2022
f849e8e
Fix up too-many-topics UI test, succeeds but should fail...
ascjones Dec 5, 2022
7cb6c74
Merge branch 'master' into aj/shared-events
ascjones Dec 9, 2022
5d80691
Fix up generate_metadata extern in test
ascjones Dec 9, 2022
55813c6
Restore max topics len guard for environment
ascjones Dec 9, 2022
e96f9d6
Remove extra topic, max topics now includes signature topic
ascjones Dec 9, 2022
bba0e88
Update event-conflicting-storage.rs for event_definition
ascjones Dec 9, 2022
c999880
Fixed compilation errors events (#1533)
xgreenx Dec 12, 2022
dc32a9c
Merge branch 'master' into aj/shared-events
ascjones Jan 4, 2023
9155178
Merge branch 'master' into aj/shared-events
ascjones Jan 11, 2023
b883634
Merge branch 'master' into aj/shared-events
ascjones Jan 11, 2023
aae9fcb
Merge branch 'master' into aj/shared-events
ascjones Jan 11, 2023
706c600
Constrain emit_event environment
ascjones Jan 12, 2023
dc5d2eb
Merge branch 'master' into aj/shared-events
ascjones Jan 25, 2023
482b610
Merge branch 'master' into aj/shared-events
ascjones Feb 3, 2023
ea73683
Merge branch 'master' into aj/shared-events
ascjones Feb 13, 2023
7a95e98
Merge branch 'master' into aj/shared-events
ascjones Feb 20, 2023
e1674a9
Merge branch 'master' into aj/shared-events
ascjones Feb 27, 2023
d9ec19b
Merge branch 'master' into aj/shared-events
ascjones Apr 14, 2023
7ae9b85
Merge branch 'master' into aj/shared-events
ascjones Apr 20, 2023
468b226
Calculate signature topic in macro
ascjones Apr 21, 2023
203fe8b
Fix lifetime from merge
ascjones Apr 21, 2023
3854c49
Generate signature topic
ascjones Apr 21, 2023
06c7933
Add back method lost in merge
ascjones Apr 21, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/e2e/macro/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ proc-macro = true
[dependencies]
ink_ir = { version = "4.2.0", path = "../../ink/ir" }
cargo_metadata = "0.15.3"
contract-build = "2.0.2"
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"
Expand Down
2 changes: 1 addition & 1 deletion crates/env/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ where
pub fn emit_event<E, Event>(event: Event)
where
E: Environment,
Event: Topics + scale::Encode,
Event: Topics<Env = E> + scale::Encode,
{
<EnvInstance as OnInstance>::on_instance(|instance| {
TypedEnvBackend::emit_event::<E, Event>(instance, event)
Expand Down
2 changes: 1 addition & 1 deletion crates/env/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ pub trait TypedEnvBackend: EnvBackend {
fn emit_event<E, Event>(&mut self, event: Event)
where
E: Environment,
Event: Topics + scale::Encode;
Event: Topics<Env = E> + scale::Encode;

/// Invokes a contract message and returns its result.
///
Expand Down
4 changes: 2 additions & 2 deletions crates/env/src/engine/off_chain/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,10 +425,10 @@ impl TypedEnvBackend for EnvInstance {
fn emit_event<E, Event>(&mut self, event: Event)
where
E: Environment,
Event: Topics + scale::Encode,
Event: Topics<Env = E> + scale::Encode,
{
let builder = TopicsBuilder::default();
let enc_topics = event.topics::<E, _>(builder.into());
let enc_topics = event.topics(builder.into());
let enc_data = &scale::Encode::encode(&event)[..];
self.engine.deposit_event(&enc_topics[..], enc_data);
}
Expand Down
7 changes: 4 additions & 3 deletions crates/env/src/engine/on_chain/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,10 +395,11 @@ impl TypedEnvBackend for EnvInstance {
fn emit_event<E, Event>(&mut self, event: Event)
where
E: Environment,
Event: Topics + scale::Encode,
Event: Topics<Env = E> + scale::Encode,
{
let (mut scope, enc_topics) =
event.topics::<E, _>(TopicsBuilder::from(self.scoped_buffer()).into());
let (mut scope, enc_topics) = event.topics(
TopicsBuilder::<<Event as Topics>::Env>::from(self.scoped_buffer()).into(),
);
let enc_data = scope.take_encoded(&event);
ext::deposit_event(enc_topics, enc_data);
}
Expand Down
97 changes: 85 additions & 12 deletions crates/env/src/topics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,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<Event: Topics>(
/// The number of expected topics is given by the `TopicsAmount` type parameter.
pub fn build<TopicsAmount: EventTopicsAmount>(
mut self,
) -> TopicsBuilder<<Event as Topics>::RemainingTopics, E, B> {
) -> TopicsBuilder<TopicsAmount, E, B> {
self.backend
.expect(<<Event as Topics>::RemainingTopics as EventTopicsAmount>::AMOUNT);
.expect(<TopicsAmount as EventTopicsAmount>::AMOUNT);
TopicsBuilder {
backend: self.backend,
state: Default::default(),
Expand Down Expand Up @@ -191,18 +191,16 @@ 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;
/// The environment type.
type Env: Environment;

/// Guides event topic serialization using the given topics builder.
fn topics<E, B>(
fn topics<B>(
&self,
builder: TopicsBuilder<state::Uninit, E, B>,
) -> <B as TopicsBuilderBackend<E>>::Output
builder: TopicsBuilder<state::Uninit, Self::Env, B>,
) -> <B as TopicsBuilderBackend<Self::Env>>::Output
where
E: Environment,
B: TopicsBuilderBackend<E>;
B: TopicsBuilderBackend<Self::Env>;
}

/// For each topic a hash is generated. This hash must be unique
Expand Down Expand Up @@ -237,3 +235,78 @@ 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<LEN_TOPICS>;
/// }
///
/// // 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<Event, const LEN_MAX_TOPICS: usize>
where
Event: EventLenTopics,
<Event as EventLenTopics>::LenTopics: RespectTopicLimit<LEN_MAX_TOPICS>,
{
marker: PhantomData<fn() -> Event>,
}

/// Guards that an amount of event topics respects the event topic limit.
///
/// # Note
///
/// Implemented by `EventTopics<M>` if M is less or equal to N.
/// Automatically implemented for up to 12 event topics.
pub trait RespectTopicLimit<const N: usize> {}

/// Represents an the amount of topics for an ink! event definition.
pub struct EventTopics<const N: usize>;

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;
}
223 changes: 223 additions & 0 deletions crates/ink/codegen/src/generator/event_def.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
// 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 proc_macro2::TokenStream as TokenStream2;
use quote::{
quote,
quote_spanned,
};

/// 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 {
let event_enum = self.generate_event_enum();
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
#topics_impl
#topics_guard
}
}
}

impl<'a> EventDefinition<'a> {
fn generate_event_enum(&'a self) -> TokenStream2 {
let span = self.event_def.span();
let event_enum = &self.event_def.item;
quote_spanned!(span =>
#[derive(::scale::Encode, ::scale::Decode)]
#event_enum
)
}

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();

let impls = self.event_def.variants().map(|ev| {
let event_variant_ident = ev.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] = [ #( #signature_topic ),* ];
}
)
});
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()
}

/// 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();
// 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 },
>
>();
)
}

fn generate_topics_impl(&self) -> TokenStream2 {
let span = self.event_def.span();
let event_ident = self.event_def.ident();

let variant_match_arms = self
.event_def
.variants()
.map(|variant| {
let span = variant.span();
let variant_ident = variant.ident();
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();
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?
Copy link
Collaborator

@xgreenx xgreenx Dec 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With #1533, tests fail because of the same topics.

image

The caller and from accounts are the same. It is clearly a problem with the test because the caller and from should be different, but it raises discussion about this part.

In the ethereum, the first topic is almost always a signature of the event(except manual LOG* opcode). And you highlighted it here. So the first topic is affected by the event's name and used types. But other topics are not prefixed and contain raw/hashed(if the value is more than 32 bytes) values.

I think we need to follow the same pattern. The first topic helps to subscribe to a specific event of contracts. With raw/hashed values, we can do searches across all events, only knowing value without knowing the event structure. It is also very helpful.

Prefixing each topic with the field's name allows us not to mix different events or fields with the same type. And for that, we need to know the definition of the event to do searches. But, we can achieve the same by filtering supported by ethereum nodes(we can do the same). We can use the event's signature if we need only specific events. If we need a specific field, we can use the (null, null, 0x...) format where we want the third topic.

So comparing those two options, the Ethereum approach looks more flexible and performant(we don't need to hash prefixes and values each time).

It seems you follow the same thoughts(based on your comment), so I only highlighted conclusions here(if not, let's discuss =) ).
I also created a discussion here because following the Ethereum approach creates several issues we need to solve:

  1. How do we want to calculate a unique signature of the event? It should be documented to be clear for developers of tools. We discussed it in this PR before but didn't finalize it. My approach was to use the hash({Name of the enum}::{Name of the variant}) or hash({Name of the enum}::{Name of the variant}::{Number of fields}). It is a bad idea to use types names because, in Rust, we can create a wrapper that behaves as an original type but has a new definition=( We can use only names, as we do for traits. The number of fields is only an idea that we can discuss or maybe that can give you more ideas=) Also we need to define which hash algorithm we want to use. Because we can calculate the hash during event definition, we are not limited.

  2. How do we want to process two same topics? Based on the Ethereum approach, we need to allow them, but on the contract-pallet side, we don't let it(and it is an error that I got in the tests).

image

  1. Right now, we sort topics, but it breaks the filtering strategy because the expected topic can be in an unexpected position.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are on the same page regarding the event topics, I am also leaning towards using non-prefixed field topics. Clients would then need to filter on both the signature topic and the field topic if they wanted only a specific field. It also opens up the possibility to susbscribe to all events with a topic of a given account id, which would be very useful for explorers.

// 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() {
true => None,
false => {
Some(quote_spanned!(span=>
.push_topic::<::ink::env::topics::PrefixedValue<()>>(
&::ink::env::topics::PrefixedValue {
prefix: &<#event_ident as ::ink::reflect::EventVariantInfo<#index>>::SIGNATURE_TOPIC,
value: &(),
}
)
))
}
};

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])
}
};

quote_spanned!(span=>
Self::#variant_ident { #( #field_bindings, )* .. } => {
builder
.build::<#remaining_topics_ty>()
#event_signature_topic
#(
#field_topics
)*
.finish()
}
)
});

quote_spanned!(span =>
const _: () = {
impl ::ink::env::Topics for #event_ident {
type Env = ::ink::env::DefaultEnvironment; // todo: configure environment?

fn topics<B>(
&self,
builder: ::ink::env::topics::TopicsBuilder<::ink::env::topics::state::Uninit, Self::Env, B>,
) -> <B as ::ink::env::topics::TopicsBuilderBackend<Self::Env>>::Output
where
B: ::ink::env::topics::TopicsBuilderBackend<Self::Env>,
{
match self {
#(
#variant_match_arms
)*
}
}
}
};
)
}
}
Loading