From 709353cb63dff2ae67ec3b9f3bf13d22c71c7db0 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 31 May 2023 11:53:21 +0100 Subject: [PATCH 1/4] Add topics to `EventDetails` --- subxt/src/blocks/extrinsic_types.rs | 2 +- subxt/src/events/events_type.rs | 71 +++++++++++++++++++++++------ 2 files changed, 58 insertions(+), 15 deletions(-) diff --git a/subxt/src/blocks/extrinsic_types.rs b/subxt/src/blocks/extrinsic_types.rs index 953272b4fb..4b3b5b8c10 100644 --- a/subxt/src/blocks/extrinsic_types.rs +++ b/subxt/src/blocks/extrinsic_types.rs @@ -560,7 +560,7 @@ impl ExtrinsicEvents { /// /// This works in the same way that [`events::Events::iter()`] does, with the /// exception that it filters out events not related to the submitted extrinsic. - pub fn iter(&self) -> impl Iterator> + '_ { + pub fn iter(&self) -> impl Iterator, Error>> + '_ { self.events.iter().filter(|ev| { ev.as_ref() .map(|ev| ev.phase() == events::Phase::ApplyExtrinsic(self.idx)) diff --git a/subxt/src/events/events_type.rs b/subxt/src/events/events_type.rs index af196f9984..1d0fc49e91 100644 --- a/subxt/src/events/events_type.rs +++ b/subxt/src/events/events_type.rs @@ -121,7 +121,7 @@ impl Events { // use of it with our `FilterEvents` stuff. pub fn iter( &self, - ) -> impl Iterator> + Send + Sync + 'static { + ) -> impl Iterator, Error>> + Send + Sync + 'static { // The event bytes ignoring the compact encoded length on the front: let event_bytes = self.event_bytes.clone(); let metadata = self.metadata.clone(); @@ -133,7 +133,7 @@ impl Events { if event_bytes.len() <= pos || num_events == index { None } else { - match EventDetails::decode_from::( + match EventDetails::decode_from( metadata.clone(), event_bytes.clone(), pos, @@ -189,7 +189,7 @@ impl Events { /// The event details. #[derive(Debug, Clone)] -pub struct EventDetails { +pub struct EventDetails { phase: Phase, /// The index of the event in the list of events in a given block. index: u32, @@ -205,16 +205,17 @@ pub struct EventDetails { // end of everything (fields + topics) end_idx: usize, metadata: Metadata, + topics: Vec, } -impl EventDetails { +impl EventDetails { // Attempt to dynamically decode a single event from our events input. - fn decode_from( + fn decode_from( metadata: Metadata, all_bytes: Arc<[u8]>, start_idx: usize, index: u32, - ) -> Result { + ) -> Result, Error> { let input = &mut &all_bytes[start_idx..]; let phase = Phase::decode(input)?; @@ -254,7 +255,7 @@ impl EventDetails { // topics come after the event data in EventRecord. They aren't used for // anything at the moment, so just decode and throw them away. - let _topics = Vec::::decode(input)?; + let topics = Vec::::decode(input)?; // what bytes did we skip over in total, including topics. let end_idx = all_bytes.len() - input.len(); @@ -269,6 +270,7 @@ impl EventDetails { end_idx, all_bytes, metadata, + topics, }) } @@ -385,6 +387,11 @@ impl EventDetails { &self.metadata, ) } + + /// Return the topics associated with this event. + pub fn topics(&self) -> &[T::Hash] { + &self.topics + } } /// Details for the given event plucked from the metadata. @@ -467,14 +474,17 @@ pub(crate) mod test_utils { topics: Vec<::Hash>, } + impl EventRecord { + /// Create a new event record with the given phase, event, and topics. + pub fn new(phase: Phase, event: E, topics: Vec<::Hash>) -> Self { + Self { phase, event: AllEvents::Test(event), topics } + } + } + /// Build an EventRecord, which encoded events in the format expected /// to be handed back from storage queries to System.Events. pub fn event_record(phase: Phase, event: E) -> EventRecord { - EventRecord { - phase, - event: AllEvents::Test(event), - topics: vec![], - } + EventRecord::new(phase, event, vec![]) } /// Build fake metadata consisting of a single pallet that knows @@ -564,10 +574,12 @@ pub(crate) mod test_utils { #[cfg(test)] mod tests { use super::{ - test_utils::{event_record, events, events_raw, AllEvents}, + test_utils::{event_record, events, events_raw, AllEvents, EventRecord}, *, }; + use crate::SubstrateConfig; use codec::Encode; + use primitive_types::H256; use scale_info::TypeInfo; use scale_value::Value; @@ -596,7 +608,7 @@ mod tests { // Just for convenience, pass in the metadata type constructed // by the `metadata` function above to simplify caller code. metadata: &Metadata, - actual: EventDetails, + actual: EventDetails, expected: TestRawEventDetails, ) { let types = &metadata.types(); @@ -950,4 +962,35 @@ mod tests { ); assert!(event_details.next().is_none()); } + + #[test] + fn topics() { + #[derive(Clone, Debug, PartialEq, Decode, Encode, TypeInfo, scale_decode::DecodeAsType)] + enum Event { + A(u8, bool, Vec), + } + + // Create fake metadata that knows about our single event, above: + let metadata = metadata::(); + + // Encode our events in the format we expect back from a node, and + // construct an Events object to iterate them: + let event = Event::A(1, true, vec!["Hi".into()]); + let topics = vec![ + H256::from_low_u64_le(123), + H256::from_low_u64_le(456), + ]; + let events = events::( + metadata, + vec![EventRecord::new(Phase::ApplyExtrinsic(123), event.clone(), topics.clone())], + ); + + let ev = events + .iter() + .next() + .expect("one event expected") + .expect("event should be extracted OK"); + + assert_eq!(topics, ev.topics()); + } } From f6da8b5e1ca560f581d3b24e709e976f4aa300c1 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 31 May 2023 11:53:50 +0100 Subject: [PATCH 2/4] Update comment --- subxt/src/events/events_type.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/subxt/src/events/events_type.rs b/subxt/src/events/events_type.rs index 1d0fc49e91..451901b747 100644 --- a/subxt/src/events/events_type.rs +++ b/subxt/src/events/events_type.rs @@ -253,8 +253,7 @@ impl EventDetails { // the end of the field bytes. let event_fields_end_idx = all_bytes.len() - input.len(); - // topics come after the event data in EventRecord. They aren't used for - // anything at the moment, so just decode and throw them away. + // topics come after the event data in EventRecord. let topics = Vec::::decode(input)?; // what bytes did we skip over in total, including topics. From 2d170875c1867fe7be2b8f5cd76e5b20dce4578d Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 31 May 2023 11:54:17 +0100 Subject: [PATCH 3/4] Fmt --- subxt/src/events/events_type.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/subxt/src/events/events_type.rs b/subxt/src/events/events_type.rs index 451901b747..e8ba43ad66 100644 --- a/subxt/src/events/events_type.rs +++ b/subxt/src/events/events_type.rs @@ -133,12 +133,7 @@ impl Events { if event_bytes.len() <= pos || num_events == index { None } else { - match EventDetails::decode_from( - metadata.clone(), - event_bytes.clone(), - pos, - index, - ) { + match EventDetails::decode_from(metadata.clone(), event_bytes.clone(), pos, index) { Ok(event_details) => { // Skip over decoded bytes in next iteration: pos += event_details.bytes().len(); @@ -476,7 +471,11 @@ pub(crate) mod test_utils { impl EventRecord { /// Create a new event record with the given phase, event, and topics. pub fn new(phase: Phase, event: E, topics: Vec<::Hash>) -> Self { - Self { phase, event: AllEvents::Test(event), topics } + Self { + phase, + event: AllEvents::Test(event), + topics, + } } } @@ -975,13 +974,14 @@ mod tests { // Encode our events in the format we expect back from a node, and // construct an Events object to iterate them: let event = Event::A(1, true, vec!["Hi".into()]); - let topics = vec![ - H256::from_low_u64_le(123), - H256::from_low_u64_le(456), - ]; + let topics = vec![H256::from_low_u64_le(123), H256::from_low_u64_le(456)]; let events = events::( metadata, - vec![EventRecord::new(Phase::ApplyExtrinsic(123), event.clone(), topics.clone())], + vec![EventRecord::new( + Phase::ApplyExtrinsic(123), + event.clone(), + topics.clone(), + )], ); let ev = events From 1463ce2851d74e63f19e679f5bc6adb486c79b32 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 31 May 2023 12:08:11 +0100 Subject: [PATCH 4/4] Clippy --- subxt/src/events/events_type.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subxt/src/events/events_type.rs b/subxt/src/events/events_type.rs index e8ba43ad66..75d38d0eb5 100644 --- a/subxt/src/events/events_type.rs +++ b/subxt/src/events/events_type.rs @@ -979,7 +979,7 @@ mod tests { metadata, vec![EventRecord::new( Phase::ApplyExtrinsic(123), - event.clone(), + event, topics.clone(), )], );