ac_node_api/events/
raw_event_details.rs

1// This file bases on subxt (Parity Technologies (UK))
2// https://github.com/paritytech/subxt/
3// And was adapted by Supercomputing Systems AG.
4
5// Copyright 2019-2023 Parity Technologies (UK) Ltd.
6// This file is dual-licensed as Apache-2.0 or GPL-3.0.
7// see LICENSE for license details.
8
9//! A representation of a block of events.
10
11use crate::{
12	error::{DispatchError, Error},
13	events::{EventMetadataDetails, RootEvent},
14	metadata::MetadataError,
15	EventDetails, Metadata, Phase, StaticEvent,
16};
17use alloc::{
18	string::{String, ToString},
19	sync::Arc,
20	vec::Vec,
21};
22use codec::{Decode, Encode};
23use log::*;
24use scale_info::PortableRegistry;
25use scale_value::Composite;
26
27/// Raw event details without the associated metadata
28// Based on subxt EventDetails.
29// https://github.com/paritytech/subxt/blob/8413c4d2dd625335b9200dc2289670accdf3391a/subxt/src/events/events_type.rs#L197-L216
30#[derive(Debug, Clone, Encode, Decode, PartialEq)]
31pub struct RawEventDetails<Hash: Decode + Encode> {
32	phase: Phase,
33	/// The index of the event in the list of events in a given block.
34	index: u32,
35	/// Raw event bytes, inlcuding
36	/// - The phase.
37	/// - Pallet and event index.
38	/// - Event fields.
39	/// - Event Topics.
40	bytes: Vec<u8>,
41	/// Raw event field bytes.
42	field_bytes: Vec<u8>,
43	/// Associated Pallet information.
44	pallet_index: u8,
45	pallet_name: String,
46	pallet_bytes: Vec<u8>,
47	/// Associated Variant information.
48	variant_index: u8,
49	variant_name: String,
50	/// Associated Topcis.
51	topics: Vec<Hash>,
52}
53
54impl<Hash: Encode + Decode> RawEventDetails<Hash> {
55	/// When was the event produced?
56	pub fn phase(&self) -> Phase {
57		self.phase
58	}
59
60	/// What index is this event in the stored events for this block.
61	pub fn index(&self) -> u32 {
62		self.index
63	}
64
65	/// The index of the pallet that the event originated from.
66	pub fn pallet_index(&self) -> u8 {
67		// Note: never panics; we expect these bytes to exist
68		// in order that the EventDetails could be created.
69		self.pallet_index
70	}
71
72	/// The index of the event variant that the event originated from.
73	pub fn variant_index(&self) -> u8 {
74		// Note: never panics; we expect these bytes to exist
75		// in order that the EventDetails could be created.
76		self.variant_index
77	}
78
79	/// The name of the pallet from whence the Event originated.
80	pub fn pallet_name(&self) -> &str {
81		&self.pallet_name
82	}
83
84	/// The name of the event (ie the name of the variant that it corresponds to).
85	pub fn variant_name(&self) -> &str {
86		&self.variant_name
87	}
88
89	/// Fetch details from the metadata for this event.
90	pub fn event_metadata<'a>(
91		&'a self,
92		metadata: &'a Metadata,
93	) -> Result<EventMetadataDetails<'a>, Error> {
94		let pallet = metadata
95			.pallet_by_index(self.pallet_index())
96			.ok_or(Error::Metadata(MetadataError::PalletIndexNotFound(self.pallet_index())))?;
97		let variant = pallet
98			.event_variant_by_index(self.variant_index())
99			.ok_or(Error::Metadata(MetadataError::VariantIndexNotFound(self.variant_index())))?;
100		let event_metadata = EventMetadataDetails { pallet, variant };
101		self.metadata_sanity_check(&event_metadata)?;
102		Ok(event_metadata)
103	}
104
105	/// Return _all_ of the bytes representing this event, which include, in order:
106	/// - The phase.
107	/// - Pallet and event index.
108	/// - Event fields.
109	/// - Event Topics.
110	pub fn bytes(&self) -> &[u8] {
111		&self.bytes
112	}
113
114	/// Return the bytes representing the fields stored in this event.
115	pub fn field_bytes(&self) -> &[u8] {
116		&self.field_bytes
117	}
118
119	/// Decode and provide the event fields back in the form of a [`scale_value::Composite`]
120	/// type which represents the named or unnamed fields that were present in the event.
121	pub fn field_values(&self, metadata: &Metadata) -> Result<Composite<u32>, Error> {
122		let event_metadata = self.event_metadata(metadata)?;
123		self.field_values_inner(&event_metadata, metadata.types())
124	}
125
126	/// Attempt to decode these [`EventDetails`] into a specific static event.
127	/// This targets the fields within the event directly. You can also attempt to
128	/// decode the entirety of the event type (including the pallet and event
129	/// variants) using [`EventDetails::as_root_event()`].
130	pub fn as_event<E: StaticEvent>(&self) -> Result<Option<E>, Error> {
131		if self.pallet_name() == E::PALLET && self.variant_name() == E::EVENT {
132			Ok(Some(E::decode(&mut self.field_bytes())?))
133		} else {
134			Ok(None)
135		}
136	}
137
138	/// Attempt to decode these [`EventDetails`] into a root event type (which includes
139	/// the pallet and event enum variants as well as the event fields). A compatible
140	/// type for this is exposed via static codegen as a root level `Event` type.
141	pub fn as_root_event<E: RootEvent>(&self, metadata: &Metadata) -> Result<E, Error> {
142		let event_metadata = self.event_metadata(metadata)?;
143		self.as_root_event_inner(metadata, &event_metadata)
144	}
145
146	/// Return the topics associated with this event.
147	pub fn topics(&self) -> &[Hash] {
148		&self.topics
149	}
150
151	pub fn pallet_bytes(&self) -> &[u8] {
152		&self.pallet_bytes
153	}
154}
155
156impl<Hash: Encode + Decode> RawEventDetails<Hash> {
157	/// Checks if the extrinsic has failed.
158	pub fn has_failed(&self) -> bool {
159		self.pallet_name() == "System" && self.variant_name() == "ExtrinsicFailed"
160	}
161
162	/// Returns the dispatch error of the failed extrinsic, if it has failed.
163	pub fn get_associated_dispatch_error(&self, metadata: &Metadata) -> Option<DispatchError> {
164		match self.has_failed() {
165			true => Some(
166				DispatchError::decode_from(self.field_bytes(), metadata)
167					.unwrap_or(DispatchError::CannotLookup),
168			),
169			false => None,
170		}
171	}
172
173	/// Checks if the event represents a code update (runtime update).
174	pub fn is_code_update(&self) -> bool {
175		self.pallet_name() == "System" && self.variant_name() == "CodeUpdated"
176	}
177}
178
179impl<Hash: Encode + Decode> From<EventDetails<Hash>> for RawEventDetails<Hash> {
180	fn from(val: EventDetails<Hash>) -> Self {
181		val.to_raw()
182	}
183}
184
185// Private / Crate methods
186impl<Hash: Encode + Decode> RawEventDetails<Hash> {
187	// Attempt to dynamically decode a single event from our events input.
188	pub(crate) fn decode_from(
189		metadata: &Metadata,
190		all_bytes: Arc<[u8]>,
191		start_idx: usize,
192		index: u32,
193	) -> Result<Self, Error> {
194		let input = &mut &all_bytes[start_idx..];
195
196		let phase = Phase::decode(input)?;
197
198		let event_start_idx = all_bytes.len() - input.len();
199
200		let pallet_index = u8::decode(input)?;
201		let variant_index = u8::decode(input)?;
202
203		let event_fields_start_idx = all_bytes.len() - input.len();
204
205		// Get metadata for the event:
206		let event_pallet = metadata.pallet_by_index_err(pallet_index)?;
207		let event_variant = event_pallet
208			.event_variant_by_index(variant_index)
209			.ok_or(MetadataError::VariantIndexNotFound(variant_index))?;
210		let pallet_name = event_pallet.name().to_string();
211		let variant_name = event_variant.name.to_string();
212		debug!("Decoding Event '{}::{}'", &pallet_name, &variant_name);
213
214		// Skip over the bytes belonging to this event.
215		for field_metadata in &event_variant.fields {
216			// Skip over the bytes for this field:
217			scale_decode::visitor::decode_with_visitor(
218				input,
219				field_metadata.ty.id,
220				metadata.types(),
221				scale_decode::visitor::IgnoreVisitor::new(),
222			)
223			.map_err(scale_decode::Error::from)?;
224		}
225
226		// the end of the field bytes.
227		let event_fields_end_idx = all_bytes.len() - input.len();
228
229		// topics come after the event data in EventRecord.
230		let topics = Vec::<Hash>::decode(input)?;
231
232		// what bytes did we skip over in total, including topics.
233		let end_idx = all_bytes.len() - input.len();
234		let pallet_bytes: Vec<u8> = all_bytes[event_start_idx + 1..event_fields_end_idx].into();
235		let pallet_index = all_bytes[event_fields_start_idx - 2];
236		let variant_index = all_bytes[event_fields_start_idx - 1];
237		let bytes: Vec<u8> = all_bytes[start_idx..end_idx].into();
238		let field_bytes: Vec<u8> = all_bytes[event_fields_start_idx..event_fields_end_idx].into();
239
240		Ok(RawEventDetails {
241			phase,
242			index,
243			bytes,
244			field_bytes,
245			pallet_index,
246			pallet_name,
247			pallet_bytes,
248			variant_index,
249			variant_name,
250			topics,
251		})
252	}
253
254	/// Fetch details from the metadata for this event.
255	pub(crate) fn event_metadata_unchecked<'a>(
256		&'a self,
257		metadata: &'a Metadata,
258	) -> EventMetadataDetails<'a> {
259		let pallet = metadata
260			.pallet_by_index(self.pallet_index())
261			.expect("event pallet to be found; we did this already during decoding");
262		let variant = pallet
263			.event_variant_by_index(self.variant_index())
264			.expect("event variant to be found; we did this already during decoding");
265
266		EventMetadataDetails { pallet, variant }
267	}
268
269	/// Decode and provide the event fields back in the form of a [`scale_value::Composite`]
270	/// type which represents the named or unnamed fields that were present in the event.
271	pub(crate) fn field_values_unchecked(
272		&self,
273		metadata: &Metadata,
274	) -> Result<Composite<u32>, Error> {
275		let event_metadata = self.event_metadata_unchecked(metadata);
276		self.field_values_inner(&event_metadata, metadata.types())
277	}
278
279	/// Attempt to decode these [`EventDetails`] into a root event type (which includes
280	/// the pallet and event enum variants as well as the event fields). A compatible
281	/// type for this is exposed via static codegen as a root level `Event` type.
282	pub(crate) fn as_root_event_unchecked<E: RootEvent>(
283		&self,
284		metadata: &Metadata,
285	) -> Result<E, Error> {
286		let event_metadata = self.event_metadata_unchecked(metadata);
287		self.as_root_event_inner(metadata, &event_metadata)
288	}
289
290	pub(crate) fn as_root_event_inner<E: RootEvent>(
291		&self,
292		metadata: &Metadata,
293		event_metadata: &EventMetadataDetails,
294	) -> Result<E, Error> {
295		let pallet_bytes = self.pallet_bytes();
296		let pallet_event_ty = event_metadata.pallet.event_ty_id().ok_or_else(|| {
297			MetadataError::EventTypeNotFoundInPallet(event_metadata.pallet.index())
298		})?;
299
300		E::root_event(pallet_bytes, self.pallet_name(), pallet_event_ty, metadata)
301	}
302
303	fn metadata_sanity_check(&self, event_metadata: &EventMetadataDetails) -> Result<(), Error> {
304		if event_metadata.pallet.name() != self.pallet_name()
305			|| event_metadata.variant.name != self.variant_name()
306		{
307			return Err(Error::Metadata(MetadataError::MetadataMismatch))
308		}
309		Ok(())
310	}
311
312	fn field_values_inner(
313		&self,
314		event_metadata: &EventMetadataDetails,
315		types: &PortableRegistry,
316	) -> Result<Composite<u32>, Error> {
317		let bytes = &mut self.field_bytes();
318		let mut fields = event_metadata
319			.variant
320			.fields
321			.iter()
322			.map(|f| scale_decode::Field::new(f.ty.id, f.name.as_deref()));
323		let decoded = scale_value::scale::decode_as_fields(bytes, &mut fields, types)?;
324
325		Ok(decoded)
326	}
327}
328
329/// Event related test utilities used outside this module.
330#[cfg(test)]
331pub(crate) mod test_utils {
332	use super::*;
333	use crate::{events::Compact, Events};
334	use codec::Encode;
335	use frame_metadata::{
336		v15::{
337			CustomMetadata, ExtrinsicMetadata, OuterEnums, PalletEventMetadata, PalletMetadata,
338			RuntimeMetadataV15,
339		},
340		RuntimeMetadataPrefixed,
341	};
342	use scale_info::{meta_type, TypeInfo};
343	use sp_core::H256;
344
345	/// An "outer" events enum containing exactly one event.
346	#[derive(
347		Encode,
348		Decode,
349		TypeInfo,
350		Clone,
351		Debug,
352		PartialEq,
353		Eq,
354		scale_encode::EncodeAsType,
355		scale_decode::DecodeAsType,
356	)]
357	pub enum AllEvents<Ev> {
358		Test(Ev),
359	}
360
361	/// This encodes to the same format an event is expected to encode to
362	/// in node System.Events storage.
363	#[derive(Encode)]
364	pub struct EventRecord<E: Encode> {
365		phase: Phase,
366		event: AllEvents<E>,
367		topics: Vec<H256>,
368	}
369
370	impl<E: Encode> EventRecord<E> {
371		/// Create a new event record with the given phase, event, and topics.
372		pub fn new(phase: Phase, event: E, topics: Vec<H256>) -> Self {
373			Self { phase, event: AllEvents::Test(event), topics }
374		}
375	}
376
377	/// Build an EventRecord, which encoded events in the format expected
378	/// to be handed back from storage queries to System.Events.
379	pub fn event_record<E: Encode>(phase: Phase, event: E) -> EventRecord<E> {
380		EventRecord::new(phase, event, vec![])
381	}
382
383	/// Build fake metadata consisting of a single pallet that knows
384	/// about the event type provided.
385	pub fn metadata<E: TypeInfo + 'static>() -> Metadata {
386		// Extrinsic needs to contain at least the generic type parameter "Call"
387		// for the metadata to be valid.
388		// The "Call" type from the metadata is used to decode extrinsics.
389		// In reality, the extrinsic type has "Call", "Address", "Extra", "Signature" generic types.
390		#[allow(unused)]
391		#[derive(TypeInfo)]
392		struct ExtrinsicType<Call> {
393			call: Call,
394		}
395		// Because this type is used to decode extrinsics, we expect this to be a TypeDefVariant.
396		// Each pallet must contain one single variant.
397		#[allow(unused)]
398		#[derive(TypeInfo)]
399		enum RuntimeCall {
400			PalletName(Pallet),
401		}
402		// The calls of the pallet.
403		#[allow(unused)]
404		#[derive(TypeInfo)]
405		enum Pallet {
406			#[allow(unused)]
407			SomeCall,
408		}
409
410		let pallets = vec![PalletMetadata {
411			name: "Test",
412			storage: None,
413			calls: None,
414			event: Some(PalletEventMetadata { ty: meta_type::<E>() }),
415			constants: vec![],
416			error: None,
417			index: 0,
418			docs: vec![],
419		}];
420
421		let extrinsic = ExtrinsicMetadata {
422			version: 0,
423			signed_extensions: vec![],
424			address_ty: meta_type::<()>(),
425			call_ty: meta_type::<RuntimeCall>(),
426			signature_ty: meta_type::<()>(),
427			extra_ty: meta_type::<()>(),
428		};
429
430		let meta = RuntimeMetadataV15::new(
431			pallets,
432			extrinsic,
433			meta_type::<()>(),
434			vec![],
435			OuterEnums {
436				call_enum_ty: meta_type::<()>(),
437				event_enum_ty: meta_type::<AllEvents<E>>(),
438				error_enum_ty: meta_type::<()>(),
439			},
440			CustomMetadata { map: Default::default() },
441		);
442		let runtime_metadata: RuntimeMetadataPrefixed = meta.into();
443		Metadata::try_from(runtime_metadata).unwrap()
444	}
445
446	/// Build an `Events` object for test purposes, based on the details provided,
447	/// and with a default block hash.
448	pub fn events<E: Decode + Encode>(
449		metadata: Metadata,
450		event_records: Vec<EventRecord<E>>,
451	) -> Events<H256> {
452		let num_events = event_records.len() as u32;
453		let mut event_bytes = Vec::new();
454		for ev in event_records {
455			ev.encode_to(&mut event_bytes);
456		}
457		events_raw(metadata, event_bytes, num_events)
458	}
459
460	/// Much like [`events`], but takes pre-encoded events and event count, so that we can
461	/// mess with the bytes in tests if we need to.
462	pub fn events_raw(metadata: Metadata, event_bytes: Vec<u8>, num_events: u32) -> Events<H256> {
463		// Prepend compact encoded length to event bytes:
464		let mut all_event_bytes = Compact(num_events).encode();
465		all_event_bytes.extend(event_bytes);
466		Events::new(metadata, H256::default(), all_event_bytes)
467	}
468}
469
470#[cfg(test)]
471mod tests {
472	use super::{
473		test_utils::{event_record, events, events_raw, EventRecord},
474		*,
475	};
476	use codec::Encode;
477	use scale_info::TypeInfo;
478	use scale_value::Value;
479	use sp_core::H256;
480
481	/// Build a fake wrapped metadata.
482	fn metadata<E: TypeInfo + 'static>() -> Metadata {
483		test_utils::metadata::<E>()
484	}
485
486	/// [`RawEventDetails`] can be annoying to test, because it contains
487	/// type info in the decoded field Values. Strip that here so that
488	/// we can compare fields more easily.
489	#[derive(Debug, PartialEq, Eq, Clone)]
490	pub struct TestRawEventDetails {
491		pub phase: Phase,
492		pub index: u32,
493		pub pallet: String,
494		pub pallet_index: u8,
495		pub variant: String,
496		pub variant_index: u8,
497		pub fields: Vec<scale_value::Value>,
498	}
499
500	/// Compare some actual [`RawEventDetails`] with a hand-constructed
501	/// (probably) [`TestRawEventDetails`].
502	pub fn assert_raw_events_match(
503		actual: RawEventDetails<H256>,
504		expected: TestRawEventDetails,
505		metadata: &Metadata,
506	) {
507		let actual_fields_no_context: Vec<_> = actual
508			.field_values(metadata)
509			.expect("can decode field values (2)")
510			.into_values()
511			.map(|value| value.remove_context())
512			.collect();
513
514		// Check each of the other fields:
515		assert_eq!(actual.phase(), expected.phase);
516		assert_eq!(actual.index(), expected.index);
517		assert_eq!(actual.pallet_name(), expected.pallet);
518		assert_eq!(actual.pallet_index(), expected.pallet_index);
519		assert_eq!(actual.variant_name(), expected.variant);
520		assert_eq!(actual.variant_index(), expected.variant_index);
521		assert_eq!(actual_fields_no_context, expected.fields);
522	}
523
524	#[test]
525	fn dynamically_decode_single_event() {
526		#[derive(Clone, Debug, PartialEq, Decode, Encode, TypeInfo)]
527		enum Event {
528			A(u8, bool, Vec<String>),
529		}
530
531		// Create fake metadata that knows about our single event, above:
532		let metadata = metadata::<Event>();
533
534		// Encode our events in the format we expect back from a node, and
535		// construst an Events object to iterate them:
536		let event = Event::A(1, true, vec!["Hi".into()]);
537		let events = events::<Event>(
538			metadata.clone(),
539			vec![event_record(Phase::ApplyExtrinsic(123), event)],
540		);
541
542		let mut event_details_iter = events.iter();
543		assert_raw_events_match(
544			event_details_iter.next().unwrap().unwrap().to_raw(),
545			TestRawEventDetails {
546				phase: Phase::ApplyExtrinsic(123),
547				index: 0,
548				pallet: "Test".to_string(),
549				pallet_index: 0,
550				variant: "A".to_string(),
551				variant_index: 0,
552				fields: vec![
553					Value::u128(1),
554					Value::bool(true),
555					Value::unnamed_composite(vec![Value::string("Hi")]),
556				],
557			},
558			&metadata,
559		);
560		assert!(event_details_iter.next().is_none());
561	}
562
563	#[test]
564	fn dynamically_decode_multiple_events() {
565		#[derive(Clone, Copy, Debug, PartialEq, Decode, Encode, TypeInfo)]
566		enum Event {
567			A(u8),
568			B(bool),
569		}
570
571		// Create fake metadata that knows about our single event, above:
572		let metadata = metadata::<Event>();
573
574		// Encode our events in the format we expect back from a node, and
575		// construst an Events object to iterate them:
576		let event1 = Event::A(1);
577		let event2 = Event::B(true);
578		let event3 = Event::A(234);
579
580		let events = events::<Event>(
581			metadata.clone(),
582			vec![
583				event_record(Phase::Initialization, event1),
584				event_record(Phase::ApplyExtrinsic(123), event2),
585				event_record(Phase::Finalization, event3),
586			],
587		);
588
589		let mut event_details_iter = events.iter();
590
591		assert_raw_events_match(
592			event_details_iter.next().unwrap().unwrap().to_raw(),
593			TestRawEventDetails {
594				index: 0,
595				phase: Phase::Initialization,
596				pallet: "Test".to_string(),
597				pallet_index: 0,
598				variant: "A".to_string(),
599				variant_index: 0,
600				fields: vec![Value::u128(1)],
601			},
602			&metadata,
603		);
604		assert_raw_events_match(
605			event_details_iter.next().unwrap().unwrap().to_raw(),
606			TestRawEventDetails {
607				index: 1,
608				phase: Phase::ApplyExtrinsic(123),
609				pallet: "Test".to_string(),
610				pallet_index: 0,
611				variant: "B".to_string(),
612				variant_index: 1,
613				fields: vec![Value::bool(true)],
614			},
615			&metadata,
616		);
617		assert_raw_events_match(
618			event_details_iter.next().unwrap().unwrap().to_raw(),
619			TestRawEventDetails {
620				index: 2,
621				phase: Phase::Finalization,
622				pallet: "Test".to_string(),
623				pallet_index: 0,
624				variant: "A".to_string(),
625				variant_index: 0,
626				fields: vec![Value::u128(234)],
627			},
628			&metadata,
629		);
630		assert!(event_details_iter.next().is_none());
631	}
632
633	#[test]
634	fn dynamically_decode_multiple_events_until_error() {
635		#[derive(Clone, Debug, PartialEq, Decode, Encode, TypeInfo)]
636		enum Event {
637			A(u8),
638			B(bool),
639		}
640
641		// Create fake metadata that knows about our single event, above:
642		let metadata = metadata::<Event>();
643
644		// Encode 2 events:
645		let mut event_bytes = vec![];
646		event_record(Phase::Initialization, Event::A(1)).encode_to(&mut event_bytes);
647		event_record(Phase::ApplyExtrinsic(123), Event::B(true)).encode_to(&mut event_bytes);
648
649		// Push a few naff bytes to the end (a broken third event):
650		event_bytes.extend_from_slice(&[3, 127, 45, 0, 2]);
651
652		// Encode our events in the format we expect back from a node, and
653		// construst an Events object to iterate them:
654		let events = events_raw(
655			metadata.clone(),
656			event_bytes,
657			3, // 2 "good" events, and then it'll hit the naff bytes.
658		);
659		let mut event_details_iter = events.iter();
660		assert_raw_events_match(
661			event_details_iter.next().unwrap().unwrap().to_raw(),
662			TestRawEventDetails {
663				index: 0,
664				phase: Phase::Initialization,
665				pallet: "Test".to_string(),
666				pallet_index: 0,
667				variant: "A".to_string(),
668				variant_index: 0,
669				fields: vec![Value::u128(1)],
670			},
671			&metadata,
672		);
673		assert_raw_events_match(
674			event_details_iter.next().unwrap().unwrap().to_raw(),
675			TestRawEventDetails {
676				index: 1,
677				phase: Phase::ApplyExtrinsic(123),
678				pallet: "Test".to_string(),
679				pallet_index: 0,
680				variant: "B".to_string(),
681				variant_index: 1,
682				fields: vec![Value::bool(true)],
683			},
684			&metadata,
685		);
686
687		// We'll hit an error trying to decode the third event:
688		assert!(event_details_iter.next().unwrap().is_err());
689		// ... and then "None" from then on.
690		assert!(event_details_iter.next().is_none());
691		assert!(event_details_iter.next().is_none());
692	}
693
694	#[test]
695	fn compact_event_field() {
696		#[derive(Clone, Debug, PartialEq, Encode, Decode, TypeInfo)]
697		enum Event {
698			A(#[codec(compact)] u32),
699		}
700
701		// Create fake metadata that knows about our single event, above:
702		let metadata = metadata::<Event>();
703
704		// Encode our events in the format we expect back from a node, and
705		// construst an Events object to iterate them:
706		let events =
707			events::<Event>(metadata.clone(), vec![event_record(Phase::Finalization, Event::A(1))]);
708
709		// Dynamically decode:
710		let mut event_details_iter = events.iter();
711		assert_raw_events_match(
712			event_details_iter.next().unwrap().unwrap().to_raw(),
713			TestRawEventDetails {
714				index: 0,
715				phase: Phase::Finalization,
716				pallet: "Test".to_string(),
717				pallet_index: 0,
718				variant: "A".to_string(),
719				variant_index: 0,
720				fields: vec![Value::u128(1)],
721			},
722			&metadata,
723		);
724		assert!(event_details_iter.next().is_none());
725	}
726
727	#[test]
728	fn compact_wrapper_struct_field() {
729		#[derive(Clone, Decode, Debug, PartialEq, Encode, TypeInfo)]
730		enum Event {
731			A(#[codec(compact)] CompactWrapper),
732		}
733
734		#[derive(Clone, Decode, Debug, PartialEq, codec::CompactAs, Encode, TypeInfo)]
735		struct CompactWrapper(u64);
736
737		// Create fake metadata that knows about our single event, above:
738		let metadata = metadata::<Event>();
739
740		// Encode our events in the format we expect back from a node, and
741		// construct an Events object to iterate them:
742		let events = events::<Event>(
743			metadata.clone(),
744			vec![event_record(Phase::Finalization, Event::A(CompactWrapper(1)))],
745		);
746
747		// Dynamically decode:
748		let mut event_details_iter = events.iter();
749		assert_raw_events_match(
750			event_details_iter.next().unwrap().unwrap().to_raw(),
751			TestRawEventDetails {
752				index: 0,
753				phase: Phase::Finalization,
754				pallet: "Test".to_string(),
755				pallet_index: 0,
756				variant: "A".to_string(),
757				variant_index: 0,
758				fields: vec![Value::unnamed_composite(vec![Value::u128(1)])],
759			},
760			&metadata,
761		);
762		assert!(event_details_iter.next().is_none());
763	}
764
765	#[test]
766	fn event_containing_explicit_index() {
767		#[derive(Clone, Debug, PartialEq, Eq, Decode, Encode, TypeInfo)]
768		#[repr(u8)]
769		#[allow(trivial_numeric_casts, clippy::unnecessary_cast)] // required because the Encode derive produces a warning otherwise
770		pub enum MyType {
771			B = 10u8,
772		}
773
774		#[derive(Clone, Debug, PartialEq, Decode, Encode, TypeInfo)]
775		enum Event {
776			A(MyType),
777		}
778
779		// Create fake metadata that knows about our single event, above:
780		let metadata = metadata::<Event>();
781
782		// Encode our events in the format we expect back from a node, and
783		// construct an Events object to iterate them:
784		let events = events::<Event>(
785			metadata.clone(),
786			vec![event_record(Phase::Finalization, Event::A(MyType::B))],
787		);
788
789		// Dynamically decode:
790		let mut event_details_iter = events.iter();
791		assert_raw_events_match(
792			event_details_iter.next().unwrap().unwrap().to_raw(),
793			TestRawEventDetails {
794				index: 0,
795				phase: Phase::Finalization,
796				pallet: "Test".to_string(),
797				pallet_index: 0,
798				variant: "A".to_string(),
799				variant_index: 0,
800				fields: vec![Value::unnamed_variant("B", vec![])],
801			},
802			&metadata,
803		);
804		assert!(event_details_iter.next().is_none());
805	}
806
807	#[test]
808	fn topics() {
809		#[derive(Clone, Debug, PartialEq, Decode, Encode, TypeInfo, scale_decode::DecodeAsType)]
810		enum Event {
811			A(u8, bool, Vec<String>),
812		}
813
814		// Create fake metadata that knows about our single event, above:
815		let metadata = metadata::<Event>();
816
817		// Encode our events in the format we expect back from a node, and
818		// construct an Events object to iterate them:
819		let event = Event::A(1, true, vec!["Hi".into()]);
820		let topics = vec![H256::from_low_u64_le(123), H256::from_low_u64_le(456)];
821		let events = events::<Event>(
822			metadata,
823			vec![EventRecord::new(Phase::ApplyExtrinsic(123), event, topics.clone())],
824		);
825
826		let ev = events
827			.iter()
828			.next()
829			.expect("one event expected")
830			.expect("event should be extracted OK");
831
832		assert_eq!(topics, ev.topics());
833	}
834
835	#[test]
836	fn encode_decode() {
837		#[derive(Clone, Debug, PartialEq, Decode, Encode, TypeInfo, scale_decode::DecodeAsType)]
838		enum Event {
839			A(#[codec(compact)] u32),
840		}
841
842		// Create fake metadata that knows about our single event, above:
843		let metadata = metadata::<Event>();
844
845		// Encode our events in the format we expect back from a node, and
846		// construst an Events object to iterate them:
847		let events =
848			events::<Event>(metadata.clone(), vec![event_record(Phase::Finalization, Event::A(1))]);
849
850		// Dynamically decode:
851		let raw_event_details = events.iter().next().unwrap().unwrap().to_raw();
852
853		// Statically Encode/Decode:
854		let encoded = raw_event_details.encode();
855		let decoded = RawEventDetails::decode(&mut encoded.as_slice()).unwrap();
856
857		assert_eq!(raw_event_details, decoded);
858	}
859}