mod decode_as_event; use crate::config::{Config, HashFor}; use crate::error::EventsError; use crate::{backend::BackendExt, client::OnlineClientAtBlockT}; use codec::{Compact, Decode, Encode}; use scale_decode::{DecodeAsFields, DecodeAsType}; use std::marker::PhantomData; use std::sync::Arc; use subxt_metadata::Metadata; pub use decode_as_event::DecodeAsEvent; /// The events at some block. #[derive(Debug)] pub struct Events { metadata: Arc, // Note; raw event bytes are prefixed with a Compact containing // the number of events to be decoded. The start_idx reflects that, so // that we can skip over those bytes when decoding them event_bytes: Vec, start_idx: usize, num_events: u32, marker: core::marker::PhantomData, } impl Events { pub(crate) async fn fetch(client: impl OnlineClientAtBlockT) -> Result { // Fetch the bytes. Ensure things work if we get 0 bytes back. let block_hash = client.block_hash(); let event_bytes = client .backend() .storage_fetch_value(system_events_key().to_vec(), block_hash) .await .map_err(EventsError::CannotFetchEventBytes)? .unwrap_or_default(); // event_bytes is a SCALE encoded vector of events. So, pluck the // compact encoded length from the front, leaving the remaining bytes // for our iterating to decode. // // Note: if we get no bytes back, avoid an error reading vec length // and default to 0 events. let cursor = &mut &*event_bytes; let num_events = >::decode(cursor).unwrap_or(Compact(0)).0; // Start decoding after the compact encoded bytes. let start_idx = event_bytes.len() - cursor.len(); Ok(Self { metadata: client.metadata(), event_bytes, start_idx, num_events, marker: PhantomData, }) } /// The number of events. pub fn len(&self) -> u32 { self.num_events } /// Are there no events in this block? // Note: mainly here to satisfy clippy. pub fn is_empty(&self) -> bool { self.num_events == 0 } /// Return the bytes representing all of the events. pub fn bytes(&self) -> &[u8] { &self.event_bytes } /// Iterate over all of the events, using metadata to dynamically /// decode them as we go, and returning the raw bytes and other associated /// details. If an error occurs, all subsequent iterations return `None`. // Dev note: The returned iterator is 'static + Send so that we can box it up and make // use of it with our `FilterEvents` stuff. pub fn iter(&'_ self) -> impl Iterator, EventsError>> + Send + Sync { // The event bytes ignoring the compact encoded length on the front: let event_bytes = &*self.event_bytes; let metadata = &*self.metadata; let num_events = self.num_events; let mut pos = self.start_idx; let mut index = 0; core::iter::from_fn(move || { if event_bytes.len() <= pos || num_events == index { None } else { match Event::decode_from(metadata, event_bytes, pos, index) { Ok(event_details) => { // Skip over decoded bytes in next iteration: pos += event_details.bytes().len(); // Increment the index: index += 1; // Return the event details: Some(Ok(event_details)) } Err(e) => { // By setting the position to the "end" of the event bytes, // the cursor len will become 0 and the iterator will return `None` // from now on: pos = event_bytes.len(); Some(Err(e)) } } } }) } /// Iterate through the events, Decoding and returning any that match the given type. /// /// This is a convenience function for calling [`Self::iter`] and then [`Event::decode_call_data_fields_as`] /// on each event that we iterate over, filtering those that don't match. pub fn find(&self) -> impl Iterator> { self.iter() .filter_map(|e| e.ok()) .filter_map(|e| e.decode_fields_as::()) } /// Find an event matching the given type, returning true if it exists. This function does _not_ /// try to actually decode the event bytes into the given type. pub fn has(&self) -> bool { self.iter().filter_map(|e| e.ok()).any(|e| e.is::()) } } /// A phase of a block's execution. #[derive(Copy, Clone, Debug, Eq, PartialEq, Decode, Encode)] pub enum Phase { /// Applying an extrinsic. ApplyExtrinsic(u32), /// Finalizing the block. Finalization, /// Initializing the block. Initialization, } /// The event details. #[derive(Debug, Clone)] pub struct Event<'events, T: Config> { pallet_name: &'events str, event_name: &'events str, metadata: &'events Metadata, // all of the event bytes (not just this one). all_bytes: &'events [u8], // event phase. phase: Phase, /// The index of the event in the list of events in a given block. index: u32, // start of the bytes (phase, pallet/variant index and then fields and then topic to follow). start_idx: usize, // start of the event (ie pallet/variant index and then the fields and topic after). event_start_idx: usize, // start of the fields (ie after phase and pallet/variant index). event_fields_start_idx: usize, // end of the fields. event_fields_end_idx: usize, // end of everything (fields + topics) end_idx: usize, // event topics. topics: Vec>, } impl<'events, T: Config> Event<'events, T> { /// Attempt to dynamically decode a single event from our events input. fn decode_from( metadata: &'events Metadata, all_bytes: &'events [u8], start_idx: usize, index: u32, ) -> Result, EventsError> { let input = &mut &all_bytes[start_idx..]; let phase = Phase::decode(input).map_err(EventsError::CannotDecodePhase)?; let event_start_idx = all_bytes.len() - input.len(); let pallet_index = u8::decode(input).map_err(EventsError::CannotDecodePalletIndex)?; let variant_index = u8::decode(input).map_err(EventsError::CannotDecodeVariantIndex)?; let event_fields_start_idx = all_bytes.len() - input.len(); // Get metadata for the event: let event_pallet = metadata .pallet_by_event_index(pallet_index) .ok_or_else(|| EventsError::CannotFindPalletWithIndex(pallet_index))?; let event_variant = event_pallet .event_variant_by_index(variant_index) .ok_or_else(|| EventsError::CannotFindVariantWithIndex { pallet_name: event_pallet.name().to_string(), variant_index, })?; tracing::debug!( "Decoding Event '{}::{}'", event_pallet.name(), &event_variant.name ); // Skip over the bytes belonging to this event. for field_metadata in &event_variant.fields { // Skip over the bytes for this field: scale_decode::visitor::decode_with_visitor( input, field_metadata.ty.id, metadata.types(), scale_decode::visitor::IgnoreVisitor::new(), ) .map_err(|e| EventsError::CannotDecodeFieldInEvent { pallet_name: event_pallet.name().to_string(), event_name: event_variant.name.clone(), field_name: field_metadata .name .clone() .unwrap_or("".to_string()), reason: e, })?; } // the end of the field bytes. let event_fields_end_idx = all_bytes.len() - input.len(); // topics come after the event data in EventRecord. let topics = Vec::>::decode(input).map_err(EventsError::CannotDecodeEventTopics)?; // what bytes did we skip over in total, including topics. let end_idx = all_bytes.len() - input.len(); Ok(Event { pallet_name: event_pallet.name(), event_name: &event_variant.name, phase, index, start_idx, event_start_idx, event_fields_start_idx, event_fields_end_idx, end_idx, all_bytes, metadata, topics, }) } /// When was the event produced? pub fn phase(&self) -> Phase { self.phase } /// What index is this event in the stored events for this block. pub fn index(&self) -> u32 { self.index } /// The index of the pallet that the event originated from. pub fn pallet_index(&self) -> u8 { // Note: never panics; we expect these bytes to exist // in order that the EventDetails could be created. self.all_bytes[self.event_fields_start_idx - 2] } /// The index of the event variant that the event originated from. pub fn event_index(&self) -> u8 { // Note: never panics; we expect these bytes to exist // in order that the EventDetails could be created. self.all_bytes[self.event_fields_start_idx - 1] } /// The name of the pallet from whence the Event originated. pub fn pallet_name(&self) -> &str { self.pallet_name } /// The name of the event (ie the name of the variant that it corresponds to). pub fn event_name(&self) -> &str { self.event_name } /// Return _all_ of the bytes representing this event, which include, in order: /// - The phase. /// - Pallet and event index. /// - Event fields. /// - Event Topics. pub fn bytes(&self) -> &[u8] { &self.all_bytes[self.start_idx..self.end_idx] } /// Return the bytes representing the fields stored in this event. pub fn field_bytes(&self) -> &[u8] { &self.all_bytes[self.event_fields_start_idx..self.event_fields_end_idx] } /// Return the topics associated with this event. pub fn topics(&self) -> &[HashFor] { &self.topics } /// Return true if this [`Event`] matches the provided type. pub fn is(&self) -> bool { E::is_event(self.pallet_name(), self.event_name()) } /// Attempt to decode this [`Event`] into an outer event enum type (which includes /// the pallet and event enum variants as well as the event fields). One compatible /// type for this is exposed via static codegen as a root level `Event` type. pub fn decode_as(&self) -> Result { let bytes = &self.all_bytes[self.event_start_idx..self.event_fields_end_idx]; let decoded = E::decode_as_type( &mut &bytes[..], self.metadata.outer_enums().event_enum_ty(), self.metadata.types(), ) .map_err(|e| { let md = self.event_metadata(); EventsError::CannotDecodeEventEnum { pallet_name: md.pallet.name().to_string(), event_name: md.variant.name.clone(), reason: e, } })?; Ok(decoded) } /// Decode the event call data fields into some type which implements [`DecodeAsEvent`]. /// /// Event types generated via the [`crate::subxt!`] macro implement this. pub fn decode_fields_as(&self) -> Option> { if self.is::() { Some(self.decode_fields_unchecked_as::()) } else { None } } /// Decode the event call data fields into some type which implements [`DecodeAsFields`]. /// /// This ignores the pallet and event name information, so you should check those via [`Self::pallet_name()`] /// and [`Self::event_name()`] to confirm that this event is the one you are intending to decode. /// /// Prefer to use [`Self::decode_call_data_fields_as`] where possible. pub fn decode_fields_unchecked_as(&self) -> Result { let bytes = &mut self.field_bytes(); let event_metadata = self.event_metadata(); let mut fields = event_metadata .variant .fields .iter() .map(|f| scale_decode::Field::new(f.ty.id, f.name.as_deref())); let decoded = E::decode_as_fields(bytes, &mut fields, self.metadata.types()).map_err(|e| { EventsError::CannotDecodeEventFields { pallet_name: event_metadata.pallet.name().to_string(), event_name: event_metadata.variant.name.clone(), reason: e, } })?; Ok(decoded) } /// Fetch details from the metadata for this event. This is used for decoding but /// we try to avoid using it elsewhere. fn event_metadata(&self) -> EventMetadataDetails<'_> { let pallet = self .metadata .pallet_by_event_index(self.pallet_index()) .expect("event pallet to be found; we did this already during decoding"); let variant = pallet .event_variant_by_index(self.event_index()) .expect("event variant to be found; we did this already during decoding"); EventMetadataDetails { pallet, variant } } } // The storage key needed to access events. fn system_events_key() -> [u8; 32] { let a = sp_crypto_hashing::twox_128(b"System"); let b = sp_crypto_hashing::twox_128(b"Events"); let mut res = [0; 32]; res[0..16].clone_from_slice(&a); res[16..32].clone_from_slice(&b); res } /// Details for the given event plucked from the metadata. struct EventMetadataDetails<'a> { /// Metadata for the pallet that the event belongs to. pub pallet: subxt_metadata::PalletMetadata<'a>, /// Metadata for the variant which describes the pallet events. pub variant: &'a scale_info::Variant, }