Skip to content

Commit

Permalink
Events 2.0 (#1827)
Browse files Browse the repository at this point in the history
* WIP derive Event

* Move tests to top level

* Add failing Event derive test

* Test compiles, now fails

* Passing test, now impl

* Passing test with no fields

* Add events integration-tests example

* Expose Event derive macro at the top level ::ink::Event

* Remove println!

* Remove ContractEventBase

* WIP rewiring event codegen for use with derive.

* Direct impl of emit_event

* Use bound_impl

* WIP impl derive EventMetadata

* WIP add event metadata derive

* Add some metadata derive todos

* WIP Collect metadata from linked events

* Refactor event metadata collection

* Add metadata test

* Check for external and Inline events

* Add todo for inline events

* WIP adding compile time topics check to emit_event.

* fmt

* Refactor EventRespectsTopicsLimit to use const assertion

* Fmt

* Remove unused code from legacy events generation

* test and generate SIGNATURE topic

* use built in ink macro for generating signature topic

* Remove all warnings

* Implement anonymous event

* Remove PrefixedValue

* Implement field topics

* Use TOPICS_LEN for topics remaining

* WIP don't push Option::None topics

* Fix only publishing if not `Option::None`

* Fix only publishing if not `Option::None`

* Only publish value of `Some` topic, not none.

* Fix event derive codegen tests

* Add test for None topic

* Rename Topics trait to Event

* Fmt

* Remove println

* Remove EmitEvent imports

* WIP adding E2E test for topics

* Clippy

* Unnused imports

* E2E test contract events emitted

* WIP e2e testing topics

* Add e2e test which checks topics

* Add signature topic to event spec metadata

* Use Result in EventMetadata derive

* Tests for generating events metadata

* Remove max topics len compile time check

* Add failing test for topics len validation at metadata generation time

* Check for max topics limit breach in metadata generation

* Add extra event with no signature topic

* Remove checks for generics and pub visibility

* Fix anonymous attr

* Move topics attr validation to derive macro

* Fmt and remove remaining MAX_TOPICS check

* Remove event spec field type name

* Clippy

* WIP add `#[ink::event]` which expands to derives

* Check for signature topics collisions when building metadata

* Commentl

* Remove EventRespectsTopicLimits

* Remove cfg attr test

* Remove unused topics attr test

* Fmt

* Fix trait erc20 tests

* Fix erc20 tests and fmt

* Fix duplicate inline attrs. Remove offchain duplicate topics check.

* Fmt

* Clippy

* clippy

* events clippy

* Push 0 topic if `None`

* Expose signature_topic

* Change SignatureTopic to expose as_bytes

* Add test for None topic value

* Fix erc20 topic tests

* Add module_path

* Fix max topics in tests

* Fix event docs test

* Clippy

* Use path dependency for ink_env

* Remove ink_env dependency

* RUSTFLAGS for test to fix linking issue

* RUSTFLAGS for test to fix linking issue

* Fix custom environment, remove extra topic

* Use ink::event syntax

* Add ui test for cfg attributes

* Add success ui tests for ink::event

* UI test for `enum` should fail

* Refactor topic attribute fn to accept BindingInfo

* Fmt

* Remove commented out code

* Event docs

* Add event field docs

* Fix event param spec doc tests

* Fix metadata codegen tests

* Implement docs for `Event` derive macro

* Spellcheck

* Check for multiple ink attributes

* Spellcheck

* Ink attribute validation

* Remove Topic

* Oops

* Oops again

* Test for events in different crates being used in the metadata.

* Test for unused event not included in metadata

* Add test for inline event definition metadata.

* Add test for emitting inline event

* Fmt

* Remove todo, duplicate attributes are checked in the derive impls

* Add docs

* Fix examples-test

* Add docs for `#[ink::event]`

* Add docs for `EventMetadata` trait

* Update Event trait comments

* Docs

* SIGNATURE_TOPIC docs

* Fix docs

* fmt

* Try setting lto = "thin" for metadata crate to fix met

* Add lto to test profile of unit test

* Add test to check disallow generics for Event derive

* Fmt

* Change to `#[ink::event(anonymous = true)]` syntax

* Fix test

* Annotate derived event struct with anon

* UI test

* Document limitation of signature topic derive

* Fix doctest

* Fix up errors after merge

* Usage of the crate includes defined there events (#1842)

* Usage of the crate includes defined there events

* Inclusion of the event from `event_def_unused` is expected

* Update anonymous syntax

* Anonymous comment

* Move haashing macro inline signature topic gen fn

* Fix signature_topic return type

---------

Co-authored-by: Green Baneling <[email protected]>
  • Loading branch information
ascjones and xgreenx authored Jul 24, 2023
1 parent 8383828 commit 9bbeffd
Show file tree
Hide file tree
Showing 82 changed files with 2,574 additions and 1,625 deletions.
8 changes: 8 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,8 @@ test:
- job: check-std
artifacts: false
variables:
# Fix for linking of `linkme` for `cargo test`: https://github.com/dtolnay/linkme/issues/49
RUSTFLAGS: "-Clink-arg=-z -Clink-arg=nostart-stop-gc"
# Since we run the tests with `--all-features` this implies the feature
# `ink-fuzz-tests` as well -- i.e. the fuzz tests are run.
# There's no way to disable a single feature while enabling all features
Expand Down Expand Up @@ -370,6 +372,9 @@ examples-test:
needs:
- job: clippy-std
artifacts: false
variables:
# Fix linking of `linkme`: https://github.com/dtolnay/linkme/issues/49
RUSTFLAGS: "-Clink-arg=-z -Clink-arg=nostart-stop-gc"
script:
- for example in integration-tests/*/; do
if [ "$example" = "integration-tests/lang-err-integration-tests/" ]; then continue; fi;
Expand Down Expand Up @@ -399,6 +404,9 @@ examples-contract-build:
stage: examples
<<: *docker-env
<<: *test-refs
variables:
# Fix for linking of `linkme` for `cargo contract build`: https://github.com/dtolnay/linkme/issues/49
RUSTFLAGS: "-Clink-arg=-z -Clink-arg=nostart-stop-gc"
script:
- rustup component add rust-src --toolchain stable
- cargo contract -V
Expand Down
87 changes: 31 additions & 56 deletions crates/e2e/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ use super::{
constructor_exec_input,
CreateBuilderPartial,
},
events::{
CodeStoredEvent,
ContractInstantiatedEvent,
EventWithTopics,
},
log_error,
log_info,
sr25519,
Expand Down Expand Up @@ -49,18 +54,15 @@ use std::{
path::PathBuf,
};

use crate::events;
use subxt::{
blocks::ExtrinsicEvents,
config::ExtrinsicParams,
events::EventDetails,
ext::{
scale_decode,
scale_encode,
scale_value::{
Composite,
Value,
ValueDef,
},
ext::scale_value::{
Composite,
Value,
ValueDef,
},
tx::PairSigner,
};
Expand All @@ -80,54 +82,6 @@ pub type CallBuilderFinal<E, Args, RetType> = ink_env::call::CallBuilder<
Set<ReturnType<RetType>>,
>;

/// A contract was successfully instantiated.
#[derive(
Debug,
scale::Decode,
scale::Encode,
scale_decode::DecodeAsType,
scale_encode::EncodeAsType,
)]
#[decode_as_type(trait_bounds = "", crate_path = "subxt::ext::scale_decode")]
#[encode_as_type(crate_path = "subxt::ext::scale_encode")]
struct ContractInstantiatedEvent<E: Environment> {
/// Account id of the deployer.
pub deployer: E::AccountId,
/// Account id where the contract was instantiated to.
pub contract: E::AccountId,
}

impl<E> subxt::events::StaticEvent for ContractInstantiatedEvent<E>
where
E: Environment,
{
const PALLET: &'static str = "Contracts";
const EVENT: &'static str = "Instantiated";
}

/// Code with the specified hash has been stored.
#[derive(
Debug,
scale::Decode,
scale::Encode,
scale_decode::DecodeAsType,
scale_encode::EncodeAsType,
)]
#[decode_as_type(trait_bounds = "", crate_path = "subxt::ext::scale_decode")]
#[encode_as_type(crate_path = "subxt::ext::scale_encode")]
struct CodeStoredEvent<E: Environment> {
/// Hash under which the contract code was stored.
pub code_hash: E::Hash,
}

impl<E> subxt::events::StaticEvent for CodeStoredEvent<E>
where
E: Environment,
{
const PALLET: &'static str = "Contracts";
const EVENT: &'static str = "CodeStored";
}

/// The `Client` takes care of communicating with the node.
///
/// This node's RPC interface will be used for instantiating the contract
Expand Down Expand Up @@ -726,4 +680,25 @@ impl<E: Environment, V, C: subxt::Config> CallResult<E, V, ExtrinsicEvents<C>> {
event.pallet_name() == pallet_name && event.variant_name() == variant_name
})
}

/// Returns all the `ContractEmitted` events emitted by the contract.
pub fn contract_emitted_events(
&self,
) -> Result<Vec<EventWithTopics<events::ContractEmitted<E>>>, subxt::Error>
where
C::Hash: Into<sp_core::H256>,
{
let mut events_with_topics = Vec::new();
for event in self.events.iter() {
let event = event?;
if let Some(decoded_event) = event.as_event::<events::ContractEmitted<E>>()? {
let event_with_topics = EventWithTopics {
event: decoded_event,
topics: event.topics().iter().cloned().map(Into::into).collect(),
};
events_with_topics.push(event_with_topics);
}
}
Ok(events_with_topics)
}
}
102 changes: 102 additions & 0 deletions crates/e2e/src/events.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// 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_env::Environment;
#[cfg(feature = "std")]
use std::fmt::Debug;

use subxt::{
events::StaticEvent,
ext::{
scale_decode,
scale_encode,
},
};

/// A contract was successfully instantiated.
#[derive(
Debug,
scale::Decode,
scale::Encode,
scale_decode::DecodeAsType,
scale_encode::EncodeAsType,
)]
#[decode_as_type(trait_bounds = "", crate_path = "subxt::ext::scale_decode")]
#[encode_as_type(crate_path = "subxt::ext::scale_encode")]
pub struct ContractInstantiatedEvent<E: Environment> {
/// Account id of the deployer.
pub deployer: E::AccountId,
/// Account id where the contract was instantiated to.
pub contract: E::AccountId,
}

impl<E> StaticEvent for ContractInstantiatedEvent<E>
where
E: Environment,
{
const PALLET: &'static str = "Contracts";
const EVENT: &'static str = "Instantiated";
}

/// Code with the specified hash has been stored.
#[derive(
Debug,
scale::Decode,
scale::Encode,
scale_decode::DecodeAsType,
scale_encode::EncodeAsType,
)]
#[decode_as_type(trait_bounds = "", crate_path = "subxt::ext::scale_decode")]
#[encode_as_type(crate_path = "subxt::ext::scale_encode")]
pub struct CodeStoredEvent<E: Environment> {
/// Hash under which the contract code was stored.
pub code_hash: E::Hash,
}

impl<E> StaticEvent for CodeStoredEvent<E>
where
E: Environment,
{
const PALLET: &'static str = "Contracts";
const EVENT: &'static str = "CodeStored";
}

#[derive(
scale::Decode,
scale::Encode,
scale_decode::DecodeAsType,
scale_encode::EncodeAsType,
Debug,
)]
#[decode_as_type(trait_bounds = "", crate_path = "subxt::ext::scale_decode")]
#[encode_as_type(crate_path = "subxt::ext::scale_encode")]
/// A custom event emitted by the contract.
pub struct ContractEmitted<E: Environment> {
pub contract: E::AccountId,
pub data: Vec<u8>,
}

impl<E> StaticEvent for ContractEmitted<E>
where
E: Environment,
{
const PALLET: &'static str = "Contracts";
const EVENT: &'static str = "ContractEmitted";
}

/// A decoded event with its associated topics.
pub struct EventWithTopics<T> {
pub topics: Vec<sp_core::H256>,
pub event: T,
}
1 change: 1 addition & 0 deletions crates/e2e/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ mod client;
mod contract_results;
mod default_accounts;
mod error;
pub mod events;
mod node_proc;
mod xts;

Expand Down
8 changes: 4 additions & 4 deletions crates/env/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ use crate::{
EnvInstance,
OnInstance,
},
event::Event,
hash::{
CryptoHash,
HashOutput,
},
topics::Topics,
types::Gas,
Environment,
Result,
Expand Down Expand Up @@ -175,13 +175,13 @@ where
}

/// Emits an event with the given event data.
pub fn emit_event<E, Event>(event: Event)
pub fn emit_event<E, Evt>(event: Evt)
where
E: Environment,
Event: Topics + scale::Encode,
Evt: Event,
{
<EnvInstance as OnInstance>::on_instance(|instance| {
TypedEnvBackend::emit_event::<E, Event>(instance, event)
TypedEnvBackend::emit_event::<E, Evt>(instance, event)
})
}

Expand Down
6 changes: 3 additions & 3 deletions crates/env/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ use crate::{
DelegateCall,
FromAccountId,
},
event::Event,
hash::{
CryptoHash,
HashOutput,
},
topics::Topics,
Environment,
Result,
};
Expand Down Expand Up @@ -405,10 +405,10 @@ pub trait TypedEnvBackend: EnvBackend {
/// # Note
///
/// For more details visit: [`emit_event`][`crate::emit_event`]
fn emit_event<E, Event>(&mut self, event: Event)
fn emit_event<E, Evt>(&mut self, event: Evt)
where
E: Environment,
Event: Topics + scale::Encode;
Evt: Event;

/// Invokes a contract message and returns its result.
///
Expand Down
16 changes: 6 additions & 10 deletions crates/env/src/engine/off_chain/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ use crate::{
DelegateCall,
FromAccountId,
},
event::{
Event,
TopicsBuilderBackend,
},
hash::{
Blake2x128,
Blake2x256,
Expand All @@ -30,10 +34,6 @@ use crate::{
Keccak256,
Sha2x256,
},
topics::{
Topics,
TopicsBuilderBackend,
},
Clear,
EnvBackend,
Environment,
Expand Down Expand Up @@ -150,10 +150,6 @@ where
}
let off_hash = result.as_ref();
let off_hash = off_hash.to_vec();
debug_assert!(
!self.topics.contains(&off_hash),
"duplicate topic hash discovered!"
);
self.topics.push(off_hash);
}

Expand Down Expand Up @@ -422,10 +418,10 @@ impl TypedEnvBackend for EnvInstance {
})
}

fn emit_event<E, Event>(&mut self, event: Event)
fn emit_event<E, Evt>(&mut self, event: Evt)
where
E: Environment,
Event: Topics + scale::Encode,
Evt: Event,
{
let builder = TopicsBuilder::default();
let enc_topics = event.topics::<E, _>(builder.into());
Expand Down
2 changes: 1 addition & 1 deletion crates/env/src/engine/off_chain/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

use crate::{
engine::off_chain::impls::TopicsBuilder,
topics::TopicsBuilderBackend,
event::TopicsBuilderBackend,
Result,
};

Expand Down
Loading

0 comments on commit 9bbeffd

Please sign in to comment.