Skip to content

Commit 9445ba3

Browse files
Refactor events for pallet-revive and multiple ABI support (#2580)
* primitives: Implement Solidity ABI topic encoding * tests: Event topic encoding * primitives: Add `SolEncode::encode_topic` * primitives: Solidity params encoding optimizations, docs and ergonomics * primitives: Fix `PhantomData` decoding * primitives: Add `AbiEncodeWith::encode_topic` and `AbiEncodeWith::encode_with` * env: Refactor on-chain Solidity bytes encoding utilities * env: Refactor events abstractions and utilities for `pallet-revive` and multiple ABI support * tests: Update `Event` and `EventMetadata` macro tests * tests: Update `TopicBuilder` tests * doc: Update `Event` docs * tests: Update events UI tests * tests: Add events UI tests * tests: Update events integration test * Update changelog * chore: Add `TODO` for removing `Environment::MAX_EVENT_TOPICS` * chore: Fix linting UI test * linting: Fix `primitive_topic` lint * chore: Appease clippy in CI * env: Emit events in both ABIs in "all" ABI mode * tests: Add "all" ABI integration test for events * macro: Add Solidity signature topic by ref * doc: Update `Event` doc * chore: Appease clippy in CI * chore: Remove unused `ScopedBuffer::append_encoded` * optimization: Ensure compile-time computation of selector when calling Blake2x256 precompile
1 parent 1469168 commit 9445ba3

File tree

78 files changed

+3136
-626
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+3136
-626
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3737
- Solidity ABI compatibility metadata improvements - [#2511](https://github.com/use-ink/ink/pull/2511)
3838
- Share intermediate build artifacts across all contract builds in e2e tests - [#2531](https://github.com/use-ink/ink/pull/2531)
3939
- Refactor Solidity bytes wrapper(s) - [#2569](https://github.com/use-ink/ink/pull/2569)
40+
- Refactor events for `pallet-revive` and multiple ABI support - [#2580](https://github.com/use-ink/ink/pull/2580)
4041

4142
### Fixed
4243
- Update metadata version to version 6 ‒ [#2507](https://github.com/use-ink/ink/pull/2507)

crates/engine/src/ext.rs

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -123,29 +123,9 @@ impl Engine {
123123
}
124124

125125
/// Deposits an event identified by the supplied topics and data.
126-
#[allow(clippy::arithmetic_side_effects)] // todo
127-
pub fn deposit_event(&mut self, topics: &[u8], data: &[u8]) {
128-
// The first byte contains the number of topics in the slice
129-
let topics_count: scale::Compact<u32> = scale::Decode::decode(&mut &topics[0..1])
130-
.unwrap_or_else(|err| panic!("decoding number of topics failed: {err}"));
131-
let topics_count = topics_count.0 as usize;
132-
133-
let topics_vec = if topics_count > 0 {
134-
// The rest of the slice contains the topics
135-
let topics = &topics[1..];
136-
let bytes_per_topic = topics.len() / topics_count;
137-
let topics_vec: Vec<Vec<u8>> = topics
138-
.chunks(bytes_per_topic)
139-
.map(|chunk| chunk.to_vec())
140-
.collect();
141-
assert_eq!(topics_count, topics_vec.len());
142-
topics_vec
143-
} else {
144-
Vec::new()
145-
};
146-
126+
pub fn deposit_event(&mut self, topics: &[[u8; 32]], data: &[u8]) {
147127
self.debug_info.record_event(EmittedEvent {
148-
topics: topics_vec,
128+
topics: topics.to_vec(),
149129
data: data.to_vec(),
150130
});
151131
}

crates/engine/src/test_api.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use std::collections::HashMap;
3333
#[derive(Debug, Clone)]
3434
pub struct EmittedEvent {
3535
/// Recorded topics of the emitted event.
36-
pub topics: Vec<Vec<u8>>,
36+
pub topics: Vec<[u8; 32]>,
3737
/// Recorded encoding of the emitted event.
3838
pub data: Vec<u8>,
3939
}

crates/engine/src/tests.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -129,18 +129,19 @@ fn transfer() {
129129
fn events() {
130130
// given
131131
let mut engine = Engine::new();
132-
let topics_count: scale::Compact<u32> = scale::Compact(2u32);
133-
let mut enc_topics_count = scale::Encode::encode(&topics_count);
134-
let topic1 = vec![12u8, 13];
135-
let topic2 = vec![14u8, 15];
132+
let topic1 = [
133+
12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
134+
0, 0, 0, 0, 0, 0,
135+
];
136+
let topic2 = [
137+
14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
138+
0, 0, 0, 0, 0, 0,
139+
];
136140
let data = &vec![21, 22, 23];
137141

138142
// when
139-
let mut enc_topics_info: Vec<u8> = Vec::new();
140-
enc_topics_info.append(&mut enc_topics_count);
141-
enc_topics_info.append(&mut topic1.clone());
142-
enc_topics_info.append(&mut topic2.clone());
143-
engine.deposit_event(&enc_topics_info, data);
143+
let enc_topics = vec![topic1, topic2];
144+
engine.deposit_event(&enc_topics, data);
144145

145146
// then
146147
let mut events = engine.get_emitted_events();

crates/env/src/api.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,10 @@ use crate::{
4646
EnvInstance,
4747
OnInstance,
4848
},
49-
event::Event,
49+
event::{
50+
Event,
51+
TopicEncoder,
52+
},
5053
hash::{
5154
CryptoHash,
5255
HashOutput,
@@ -180,13 +183,14 @@ where
180183
}
181184

182185
/// Emits an event with the given event data.
183-
pub fn emit_event<E, Evt>(event: Evt)
186+
pub fn emit_event<E, Evt, Abi>(event: &Evt)
184187
where
185188
E: Environment,
186-
Evt: Event,
189+
Evt: Event<Abi>,
190+
Abi: TopicEncoder,
187191
{
188192
<EnvInstance as OnInstance>::on_instance(|instance| {
189-
TypedEnvBackend::emit_event::<E, Evt>(instance, event)
193+
TypedEnvBackend::emit_event::<E, Evt, Abi>(instance, event)
190194
})
191195
}
192196

crates/env/src/backend.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@ use crate::{
3737
CallParams,
3838
DelegateCall,
3939
},
40-
event::Event,
40+
event::{
41+
Event,
42+
TopicEncoder,
43+
},
4144
hash::{
4245
CryptoHash,
4346
HashOutput,
@@ -319,10 +322,11 @@ pub trait TypedEnvBackend: EnvBackend {
319322
/// # Note
320323
///
321324
/// For more details visit: [`emit_event`][`crate::emit_event`]
322-
fn emit_event<E, Evt>(&mut self, event: Evt)
325+
fn emit_event<E, Evt, Abi>(&mut self, event: &Evt)
323326
where
324327
E: Environment,
325-
Evt: Event;
328+
Evt: Event<Abi>,
329+
Abi: TopicEncoder;
326330

327331
/// Invokes a contract message and returns its result.
328332
///

crates/env/src/engine/off_chain/impls.rs

Lines changed: 60 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@ use ink_engine::ext::Engine;
1616
#[cfg(feature = "unstable-hostfn")]
1717
use ink_primitives::types::AccountIdMapper;
1818
use ink_primitives::{
19-
abi::AbiEncodeWith,
19+
abi::{
20+
AbiEncodeWith,
21+
Ink,
22+
Sol,
23+
},
2024
types::Environment,
2125
Address,
2226
SolEncode,
@@ -47,6 +51,7 @@ use crate::{
4751
},
4852
event::{
4953
Event,
54+
TopicEncoder,
5055
TopicsBuilderBackend,
5156
},
5257
hash::{
@@ -56,7 +61,6 @@ use crate::{
5661
Keccak256,
5762
Sha2x256,
5863
},
59-
Clear,
6064
DecodeDispatch,
6165
DispatchError,
6266
EnvBackend,
@@ -247,46 +251,68 @@ impl CryptoHash for Keccak256 {
247251

248252
#[derive(Default)]
249253
pub struct TopicsBuilder {
250-
pub topics: Vec<Vec<u8>>,
254+
pub topics: Vec<[u8; 32]>,
251255
}
252256

253-
impl<E> TopicsBuilderBackend<E> for TopicsBuilder
257+
impl<E, Abi> TopicsBuilderBackend<E, Abi> for TopicsBuilder
254258
where
255259
E: Environment,
260+
Abi: TopicEncoder,
256261
{
257-
type Output = Vec<u8>;
262+
type Output = Vec<[u8; 32]>;
258263

259264
fn push_topic<T>(&mut self, topic_value: &T)
260265
where
261-
T: scale::Encode,
266+
T: AbiEncodeWith<Abi>,
262267
{
263-
// todo
264-
let encoded = topic_value.encode();
265-
let len_encoded = encoded.len();
266-
let mut result = <E as Environment>::Hash::CLEAR_HASH;
267-
let len_result = result.as_ref().len();
268-
if len_encoded <= len_result {
269-
result.as_mut()[..len_encoded].copy_from_slice(&encoded[..]);
270-
} else {
271-
let mut hash_output = <Blake2x256 as HashOutput>::Type::default();
272-
<Blake2x256 as CryptoHash>::hash(&encoded[..], &mut hash_output);
273-
let copy_len = core::cmp::min(hash_output.len(), len_result);
274-
result.as_mut()[0..copy_len].copy_from_slice(&hash_output[0..copy_len]);
275-
}
276-
let off_hash = result.as_ref();
277-
let off_hash = off_hash.to_vec();
278-
self.topics.push(off_hash);
268+
let output = <Abi as TopicEncoder>::encode_topic(topic_value);
269+
self.topics.push(output);
279270
}
280271

281272
fn output(self) -> Self::Output {
282-
let mut all: Vec<u8> = Vec::new();
273+
self.topics
274+
}
275+
}
283276

284-
let topics_len_compact = &scale::Compact(self.topics.len() as u32);
285-
let topics_encoded = &scale::Encode::encode(&topics_len_compact)[..];
286-
all.append(&mut topics_encoded.to_vec());
277+
impl TopicEncoder for Ink {
278+
const REQUIRES_BUFFER: bool = false;
287279

288-
self.topics.into_iter().for_each(|mut v| all.append(&mut v));
289-
all
280+
fn encode_topic<T>(value: &T) -> [u8; 32]
281+
where
282+
T: AbiEncodeWith<Self>,
283+
{
284+
value.encode_topic(<Blake2x256 as CryptoHash>::hash)
285+
}
286+
287+
fn encode_topic_with_hash_buffer<T>(
288+
_value: &T,
289+
_output: &mut [u8; 32],
290+
_buffer: &mut [u8],
291+
) where
292+
T: AbiEncodeWith<Self>,
293+
{
294+
unreachable!("not required, `encode_topic` has been implemented.");
295+
}
296+
}
297+
298+
impl TopicEncoder for Sol {
299+
const REQUIRES_BUFFER: bool = false;
300+
301+
fn encode_topic<T>(value: &T) -> [u8; 32]
302+
where
303+
T: AbiEncodeWith<Self>,
304+
{
305+
value.encode_topic(<Keccak256 as CryptoHash>::hash)
306+
}
307+
308+
fn encode_topic_with_hash_buffer<T>(
309+
_value: &T,
310+
_output: &mut [u8; 32],
311+
_buffer: &mut [u8],
312+
) where
313+
T: AbiEncodeWith<Self>,
314+
{
315+
unreachable!("not required, `encode_topic` has been implemented.");
290316
}
291317
}
292318

@@ -607,15 +633,17 @@ impl TypedEnvBackend for EnvInstance {
607633
})
608634
}
609635

610-
fn emit_event<E, Evt>(&mut self, event: Evt)
636+
fn emit_event<E, Evt, Abi>(&mut self, event: &Evt)
611637
where
612638
E: Environment,
613-
Evt: Event,
639+
Evt: Event<Abi>,
640+
Abi: TopicEncoder,
614641
{
615642
let builder = TopicsBuilder::default();
616643
let enc_topics = event.topics::<E, _>(builder.into());
617-
let enc_data = &scale::Encode::encode(&event)[..];
618-
self.engine.deposit_event(&enc_topics[..], enc_data);
644+
let enc_data = event.encode_data();
645+
self.engine
646+
.deposit_event(&enc_topics[..], enc_data.as_slice());
619647
}
620648

621649
fn invoke_contract<E, Args, R, Abi>(

crates/env/src/engine/off_chain/test_api.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ use ink_primitives::{
4141
#[derive(Clone)]
4242
pub struct EmittedEvent {
4343
/// Recorded topics of the emitted event.
44-
pub topics: Vec<Vec<u8>>,
44+
pub topics: Vec<[u8; 32]>,
4545
/// Recorded encoding of the emitted event.
4646
pub data: Vec<u8>,
4747
}

crates/env/src/engine/off_chain/tests.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,13 @@ fn topics_builder() -> Result<()> {
3939
// then
4040
assert_eq!(builder.topics.len(), 2);
4141

42-
let topics_len_compact = &scale::Compact(2u32);
43-
let topics_len_encoded = scale::Encode::encode(&topics_len_compact);
4442
let output = TopicsBuilderBackend::<crate::DefaultEnvironment>::output(builder);
4543
#[rustfmt::skip]
46-
let expected = vec![topics_len_encoded[0], 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
44+
let expected = vec![
45+
[13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
46+
[17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
47+
];
4748
assert_eq!(output, expected);
48-
4949
Ok(())
5050
})
5151
}

crates/env/src/engine/on_chain/buffer.rs

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -202,23 +202,18 @@ impl<'a> ScopedBuffer<'a> {
202202
self.take(encode_len)
203203
}
204204

205-
/// Appends the encoding of `value` to the scoped buffer.
205+
/// Appends the given bytes to the scoped buffer.
206206
///
207207
/// Does not return the buffer immediately so that other values can be appended
208208
/// afterwards. The [`take_appended`] method shall be used to return the buffer
209209
/// that includes all appended encodings as a single buffer.
210210
#[inline(always)]
211-
pub fn append_encoded<T>(&mut self, value: &T)
212-
where
213-
T: scale::Encode,
214-
{
211+
pub fn append_bytes(&mut self, bytes: &[u8]) {
215212
let offset = self.offset;
216-
let buffer = core::mem::take(&mut self.buffer);
217-
let mut encode_scope = EncodeScope::from(&mut buffer[offset..]);
218-
scale::Encode::encode_to(&value, &mut encode_scope);
219-
let encode_len = encode_scope.len();
220-
self.offset = self.offset.checked_add(encode_len).unwrap();
221-
let _ = core::mem::replace(&mut self.buffer, buffer);
213+
let len = bytes.len();
214+
let end_offset = offset.checked_add(len).unwrap();
215+
self.buffer[offset..end_offset].copy_from_slice(bytes);
216+
self.offset = end_offset;
222217
}
223218

224219
/// Returns the buffer containing all encodings appended via [`append_encoded`]

0 commit comments

Comments
 (0)