ac_node_api/events/
mod.rs

1// This file was taken from subxt (Parity Technologies (UK))
2// https://github.com/paritytech/subxt/
3// And was adapted by Supercomputing Systems AG and Integritee AG.
4//
5// Copyright 2019-2022 Parity Technologies (UK) Ltd, Supercomputing Systems AG and Integritee AG.
6// This file is licensed as Apache-2.0
7// see LICENSE for license details.
8
9//! A representation of a block of events.
10//! This file bases on https://github.com/paritytech/subxt/blob/8413c4d2dd625335b9200dc2289670accdf3391a/subxt/src/events/events_type.rs#L19-L196
11
12use crate::{error::Error, metadata::PalletMetadata, Metadata, StaticEvent};
13use alloc::{sync::Arc, vec::Vec};
14use codec::{Compact, Decode, Encode};
15
16mod event_details;
17mod raw_event_details;
18pub use event_details::EventDetails;
19pub use raw_event_details::RawEventDetails;
20
21/// A collection of events obtained from a block, bundled with the necessary
22/// information needed to decode and iterate over them.
23#[derive(Clone)]
24pub struct Events<Hash> {
25	metadata: Metadata,
26	block_hash: Hash,
27	// Note; raw event bytes are prefixed with a Compact<u32> containing
28	// the number of events to be decoded. The start_idx reflects that, so
29	// that we can skip over those bytes when decoding them
30	event_bytes: Arc<[u8]>,
31	start_idx: usize,
32	num_events: u32,
33}
34
35// Ignore the Metadata when debug-logging events; it's big and distracting.
36impl<Hash: core::fmt::Debug> core::fmt::Debug for Events<Hash> {
37	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
38		f.debug_struct("Events")
39			.field("block_hash", &self.block_hash)
40			.field("event_bytes", &self.event_bytes)
41			.field("start_idx", &self.start_idx)
42			.field("num_events", &self.num_events)
43			.finish()
44	}
45}
46
47impl<Hash: Copy + Encode + Decode> Events<Hash> {
48	pub fn new(metadata: Metadata, block_hash: Hash, event_bytes: Vec<u8>) -> Self {
49		// event_bytes is a SCALE encoded vector of events. So, pluck the
50		// compact encoded length from the front, leaving the remaining bytes
51		// for our iterating to decode.
52		//
53		// Note: if we get no bytes back, avoid an error reading vec length
54		// and default to 0 events.
55		let cursor = &mut &*event_bytes;
56		let num_events = <Compact<u32>>::decode(cursor).unwrap_or(Compact(0)).0;
57
58		// Start decoding after the compact encoded bytes.
59		let start_idx = event_bytes.len() - cursor.len();
60
61		Self { metadata, block_hash, event_bytes: event_bytes.into(), start_idx, num_events }
62	}
63
64	/// The number of events.
65	pub fn len(&self) -> u32 {
66		self.num_events
67	}
68
69	/// Are there no events in this block?
70	// Note: mainly here to satisfy clippy.
71	pub fn is_empty(&self) -> bool {
72		self.num_events == 0
73	}
74
75	/// Return the block hash that these events are from.
76	pub fn block_hash(&self) -> Hash {
77		self.block_hash
78	}
79
80	/// Return the encoded bytes of the Events.
81	pub fn event_bytes(&self) -> Arc<[u8]> {
82		self.event_bytes.clone()
83	}
84
85	/// Iterate over all of the events, using metadata to dynamically
86	/// decode them as we go, and returning the raw bytes and other associated
87	/// details. If an error occurs, all subsequent iterations return `None`.
88	// Dev note: The returned iterator is 'static + Send so that we can box it up and make
89	// use of it with our `FilterEvents` stuff.
90	pub fn iter(
91		&self,
92	) -> impl Iterator<Item = Result<EventDetails<Hash>, Error>> + Send + Sync + 'static {
93		// The event bytes ignoring the compact encoded length on the front:
94		let event_bytes = self.event_bytes.clone();
95		let metadata = self.metadata.clone();
96		let num_events = self.num_events;
97
98		let mut pos = self.start_idx;
99		let mut index = 0;
100		core::iter::from_fn(move || {
101			if event_bytes.len() <= pos || num_events == index {
102				None
103			} else {
104				match EventDetails::decode_from(metadata.clone(), event_bytes.clone(), pos, index) {
105					Ok(event_details) => {
106						// Skip over decoded bytes in next iteration:
107						pos += event_details.bytes().len();
108						// Increment the index:
109						index += 1;
110						// Return the event details:
111						Some(Ok(event_details))
112					},
113					Err(e) => {
114						// By setting the position to the "end" of the event bytes,
115						// the cursor len will become 0 and the iterator will return `None`
116						// from now on:
117						pos = event_bytes.len();
118						Some(Err(e))
119					},
120				}
121			}
122		})
123	}
124
125	/// Iterate through the events using metadata to dynamically decode and skip
126	/// them, and return only those which should decode to the provided `Ev` type.
127	/// If an error occurs, all subsequent iterations return `None`.
128	pub fn find<Ev: StaticEvent>(&self) -> impl Iterator<Item = Result<Ev, Error>> + '_ {
129		self.iter().filter_map(|ev| ev.and_then(|ev| ev.as_event::<Ev>()).transpose())
130	}
131
132	/// Iterate through the events using metadata to dynamically decode and skip
133	/// them, and return the first event found which decodes to the provided `Ev` type.
134	pub fn find_first<Ev: StaticEvent>(&self) -> Result<Option<Ev>, Error> {
135		self.find::<Ev>().next().transpose()
136	}
137
138	/// Iterate through the events using metadata to dynamically decode and skip
139	/// them, and return the last event found which decodes to the provided `Ev` type.
140	pub fn find_last<Ev: StaticEvent>(&self) -> Result<Option<Ev>, Error> {
141		self.find::<Ev>().last().transpose()
142	}
143
144	/// Find an event that decodes to the type provided. Returns true if it was found.
145	pub fn has<Ev: StaticEvent>(&self) -> Result<bool, Error> {
146		Ok(self.find::<Ev>().next().transpose()?.is_some())
147	}
148}
149
150/// This trait is implemented on the statically generated root event type, so that we're able
151/// to decode it properly via a pallet event that impls `DecodeAsMetadata`. This is necessary
152/// becasue the "root event" type is generated using pallet info but doesn't actually exist in the
153/// metadata types, so we have no easy way to decode things into it via type information and need a
154/// little help via codegen.
155// Based on https://github.com/paritytech/subxt/blob/8413c4d2dd625335b9200dc2289670accdf3391a/subxt/src/events/events_type.rs#L417-L432
156#[doc(hidden)]
157pub trait RootEvent: Sized {
158	/// Given details of the pallet event we want to decode, and the name of the pallet, try to hand
159	/// back a "root event".
160	fn root_event(
161		pallet_bytes: &[u8],
162		pallet_name: &str,
163		pallet_event_ty: u32,
164		metadata: &Metadata,
165	) -> Result<Self, Error>;
166}
167
168/// Details for the given event plucked from the metadata.
169// Based on https://github.com/paritytech/subxt/blob/8413c4d2dd625335b9200dc2289670accdf3391a/subxt/src/events/events_type.rs#L411-L415
170#[derive(Clone)]
171pub struct EventMetadataDetails<'a> {
172	pub pallet: PalletMetadata<'a>,
173	pub variant: &'a scale_info::Variant<scale_info::form::PortableForm>,
174}
175
176#[cfg(test)]
177mod tests {
178	use super::*;
179	use crate::{
180		test_utils::{
181			event_record, events, events_raw, metadata_with_version, SupportedMetadataVersions,
182		},
183		Phase,
184	};
185	use codec::Encode;
186	use scale_info::TypeInfo;
187	use scale_value::Value;
188	use sp_core::H256;
189	use test_case::test_case;
190
191	/// [`RawEventDetails`] can be annoying to test, because it contains
192	/// type info in the decoded field Values. Strip that here so that
193	/// we can compare fields more easily.
194	#[derive(Debug, PartialEq, Clone)]
195	pub struct TestRawEventDetails {
196		pub phase: Phase,
197		pub index: u32,
198		pub pallet: String,
199		pub pallet_index: u8,
200		pub variant: String,
201		pub variant_index: u8,
202		pub fields: Vec<Value>,
203	}
204
205	/// Compare some actual [`RawEventDetails`] with a hand-constructed
206	/// (probably) [`TestRawEventDetails`].
207	pub fn assert_raw_events_match(actual: EventDetails<H256>, expected: TestRawEventDetails) {
208		let actual_fields_no_context: Vec<_> = actual
209			.field_values()
210			.expect("can decode field values (2)")
211			.into_values()
212			.map(|value| value.remove_context())
213			.collect();
214
215		// Check each of the other fields:
216		assert_eq!(actual.phase(), expected.phase);
217		assert_eq!(actual.index(), expected.index);
218		assert_eq!(actual.pallet_name(), expected.pallet);
219		assert_eq!(actual.pallet_index(), expected.pallet_index);
220		assert_eq!(actual.variant_name(), expected.variant);
221		assert_eq!(actual.variant_index(), expected.variant_index);
222		assert_eq!(actual_fields_no_context, expected.fields);
223	}
224
225	#[test_case(SupportedMetadataVersions::V14)]
226	#[test_case(SupportedMetadataVersions::V15)]
227	fn dynamically_decode_single_event(metadata_version: SupportedMetadataVersions) {
228		#[derive(Clone, Debug, PartialEq, Decode, Encode, TypeInfo)]
229		enum Event {
230			A(u8, bool, Vec<String>),
231		}
232
233		// Create fake metadata that knows about our single event, above:
234		let metadata = metadata_with_version::<Event>(metadata_version);
235
236		// Encode our events in the format we expect back from a node, and
237		// construst an Events object to iterate them:
238		let event = Event::A(1, true, vec!["Hi".into()]);
239		let events = events::<Event>(
240			metadata.clone(),
241			vec![event_record(Phase::ApplyExtrinsic(123), event)],
242		);
243
244		let mut event_details = events.iter();
245		assert_raw_events_match(
246			event_details.next().unwrap().unwrap(),
247			TestRawEventDetails {
248				phase: Phase::ApplyExtrinsic(123),
249				index: 0,
250				pallet: "Test".to_string(),
251				pallet_index: 0,
252				variant: "A".to_string(),
253				variant_index: 0,
254				fields: vec![
255					Value::u128(1u128),
256					Value::bool(true),
257					Value::unnamed_composite(vec![Value::string("Hi")]),
258				],
259			},
260		);
261		assert!(event_details.next().is_none());
262	}
263
264	#[test_case(SupportedMetadataVersions::V14)]
265	#[test_case(SupportedMetadataVersions::V15)]
266	fn dynamically_decode_multiple_events(metadata_version: SupportedMetadataVersions) {
267		#[derive(Clone, Copy, Debug, PartialEq, Decode, Encode, TypeInfo)]
268		enum Event {
269			A(u8),
270			B(bool),
271		}
272
273		// Create fake metadata that knows about our single event, above:
274		let metadata = metadata_with_version::<Event>(metadata_version);
275
276		// Encode our events in the format we expect back from a node, and
277		// construst an Events object to iterate them:
278		let event1 = Event::A(1);
279		let event2 = Event::B(true);
280		let event3 = Event::A(234);
281
282		let events = events::<Event>(
283			metadata.clone(),
284			vec![
285				event_record(Phase::Initialization, event1),
286				event_record(Phase::ApplyExtrinsic(123), event2),
287				event_record(Phase::Finalization, event3),
288			],
289		);
290
291		let mut event_details = events.iter();
292
293		assert_raw_events_match(
294			event_details.next().unwrap().unwrap(),
295			TestRawEventDetails {
296				index: 0,
297				phase: Phase::Initialization,
298				pallet: "Test".to_string(),
299				pallet_index: 0,
300				variant: "A".to_string(),
301				variant_index: 0,
302				fields: vec![Value::u128(1u128)],
303			},
304		);
305		assert_raw_events_match(
306			event_details.next().unwrap().unwrap(),
307			TestRawEventDetails {
308				index: 1,
309				phase: Phase::ApplyExtrinsic(123),
310				pallet: "Test".to_string(),
311				pallet_index: 0,
312				variant: "B".to_string(),
313				variant_index: 1,
314				fields: vec![Value::bool(true)],
315			},
316		);
317		assert_raw_events_match(
318			event_details.next().unwrap().unwrap(),
319			TestRawEventDetails {
320				index: 2,
321				phase: Phase::Finalization,
322				pallet: "Test".to_string(),
323				pallet_index: 0,
324				variant: "A".to_string(),
325				variant_index: 0,
326				fields: vec![Value::u128(234u128)],
327			},
328		);
329		assert!(event_details.next().is_none());
330	}
331
332	#[test_case(SupportedMetadataVersions::V14)]
333	#[test_case(SupportedMetadataVersions::V15)]
334	fn dynamically_decode_multiple_events_until_error(metadata_version: SupportedMetadataVersions) {
335		#[derive(Clone, Debug, PartialEq, Decode, Encode, TypeInfo)]
336		enum Event {
337			A(u8),
338			B(bool),
339		}
340
341		// Create fake metadata that knows about our single event, above:
342		let metadata = metadata_with_version::<Event>(metadata_version);
343
344		// Encode 2 events:
345		let mut event_bytes = vec![];
346		event_record(Phase::Initialization, Event::A(1)).encode_to(&mut event_bytes);
347		event_record(Phase::ApplyExtrinsic(123), Event::B(true)).encode_to(&mut event_bytes);
348
349		// Push a few naff bytes to the end (a broken third event):
350		event_bytes.extend_from_slice(&[3, 127, 45, 0, 2]);
351
352		// Encode our events in the format we expect back from a node, and
353		// construst an Events object to iterate them:
354		let events = events_raw(
355			metadata.clone(),
356			event_bytes,
357			3, // 2 "good" events, and then it'll hit the naff bytes.
358		);
359
360		let mut events_iter = events.iter();
361		assert_raw_events_match(
362			events_iter.next().unwrap().unwrap(),
363			TestRawEventDetails {
364				index: 0,
365				phase: Phase::Initialization,
366				pallet: "Test".to_string(),
367				pallet_index: 0,
368				variant: "A".to_string(),
369				variant_index: 0,
370				fields: vec![Value::u128(1u128)],
371			},
372		);
373		assert_raw_events_match(
374			events_iter.next().unwrap().unwrap(),
375			TestRawEventDetails {
376				index: 1,
377				phase: Phase::ApplyExtrinsic(123),
378				pallet: "Test".to_string(),
379				pallet_index: 0,
380				variant: "B".to_string(),
381				variant_index: 1,
382				fields: vec![Value::bool(true)],
383			},
384		);
385
386		// We'll hit an error trying to decode the third event:
387		assert!(events_iter.next().unwrap().is_err());
388		// ... and then "None" from then on.
389		assert!(events_iter.next().is_none());
390		assert!(events_iter.next().is_none());
391	}
392
393	#[test_case(SupportedMetadataVersions::V14)]
394	#[test_case(SupportedMetadataVersions::V15)]
395	fn compact_event_field(metadata_version: SupportedMetadataVersions) {
396		#[derive(Clone, Debug, PartialEq, Encode, Decode, TypeInfo)]
397		enum Event {
398			A(#[codec(compact)] u32),
399		}
400
401		// Create fake metadata that knows about our single event, above:
402		let metadata = metadata_with_version::<Event>(metadata_version);
403
404		// Encode our events in the format we expect back from a node, and
405		// construst an Events object to iterate them:
406		let events =
407			events::<Event>(metadata.clone(), vec![event_record(Phase::Finalization, Event::A(1))]);
408
409		// Dynamically decode:
410		let mut event_details = events.iter();
411		assert_raw_events_match(
412			event_details.next().unwrap().unwrap(),
413			TestRawEventDetails {
414				index: 0,
415				phase: Phase::Finalization,
416				pallet: "Test".to_string(),
417				pallet_index: 0,
418				variant: "A".to_string(),
419				variant_index: 0,
420				fields: vec![Value::u128(1u128)],
421			},
422		);
423		assert!(event_details.next().is_none());
424	}
425
426	#[test_case(SupportedMetadataVersions::V14)]
427	#[test_case(SupportedMetadataVersions::V15)]
428	fn compact_wrapper_struct_field(metadata_version: SupportedMetadataVersions) {
429		#[derive(Clone, Decode, Debug, PartialEq, Encode, TypeInfo)]
430		enum Event {
431			A(#[codec(compact)] CompactWrapper),
432		}
433
434		#[derive(Clone, Decode, Debug, PartialEq, codec::CompactAs, Encode, TypeInfo)]
435		struct CompactWrapper(u64);
436
437		// Create fake metadata that knows about our single event, above:
438		let metadata = metadata_with_version::<Event>(metadata_version);
439
440		// Encode our events in the format we expect back from a node, and
441		// construct an Events object to iterate them:
442		let events = events::<Event>(
443			metadata.clone(),
444			vec![event_record(Phase::Finalization, Event::A(CompactWrapper(1)))],
445		);
446
447		// Dynamically decode:
448		let mut event_details = events.iter();
449		assert_raw_events_match(
450			event_details.next().unwrap().unwrap(),
451			TestRawEventDetails {
452				index: 0,
453				phase: Phase::Finalization,
454				pallet: "Test".to_string(),
455				pallet_index: 0,
456				variant: "A".to_string(),
457				variant_index: 0,
458				fields: vec![Value::unnamed_composite(vec![Value::u128(1)])],
459			},
460		);
461		assert!(event_details.next().is_none());
462	}
463
464	#[test_case(SupportedMetadataVersions::V14)]
465	#[test_case(SupportedMetadataVersions::V15)]
466	fn event_containing_explicit_index(metadata_version: SupportedMetadataVersions) {
467		#[derive(Clone, Debug, PartialEq, Eq, Decode, Encode, TypeInfo)]
468		#[repr(u8)]
469		#[allow(trivial_numeric_casts, clippy::unnecessary_cast)] // required because the Encode derive produces a warning otherwise
470		pub enum MyType {
471			B = 10u8,
472		}
473
474		#[derive(Clone, Debug, PartialEq, Decode, Encode, TypeInfo)]
475		enum Event {
476			A(MyType),
477		}
478
479		// Create fake metadata that knows about our single event, above:
480		let metadata = metadata_with_version::<Event>(metadata_version);
481
482		// Encode our events in the format we expect back from a node, and
483		// construct an Events object to iterate them:
484		let events = events::<Event>(
485			metadata.clone(),
486			vec![event_record(Phase::Finalization, Event::A(MyType::B))],
487		);
488
489		// Dynamically decode:
490		let mut event_details = events.iter();
491		assert_raw_events_match(
492			event_details.next().unwrap().unwrap(),
493			TestRawEventDetails {
494				index: 0,
495				phase: Phase::Finalization,
496				pallet: "Test".to_string(),
497				pallet_index: 0,
498				variant: "A".to_string(),
499				variant_index: 0,
500				fields: vec![Value::unnamed_variant("B", vec![])],
501			},
502		);
503		assert!(event_details.next().is_none());
504	}
505}