Fix decoding events via .as_root_event() and add test (#767)

* fix decoding events via as_root_event and add test

* fmt and clippy

* Update subxt/src/events/events_type.rs

Co-authored-by: Alexandru Vasile <60601340+lexnv@users.noreply.github.com>

Co-authored-by: Alexandru Vasile <60601340+lexnv@users.noreply.github.com>
This commit is contained in:
James Wilson
2023-01-11 11:04:05 +00:00
committed by GitHub
parent b316301d61
commit a71f32f60d
+51 -11
View File
@@ -201,10 +201,12 @@ pub struct EventDetails {
all_bytes: Arc<[u8]>, all_bytes: Arc<[u8]>,
// start of the bytes (phase, pallet/variant index and then fields and then topic to follow). // start of the bytes (phase, pallet/variant index and then fields and then topic to follow).
start_idx: usize, start_idx: usize,
// start of the fields (ie after phase nad pallet/variant index). // start of the event (ie pallet/variant index and then the fields and topic after).
fields_start_idx: usize, event_start_idx: usize,
// start of the fields (ie after phase and pallet/variant index).
event_fields_start_idx: usize,
// end of the fields. // end of the fields.
fields_end_idx: usize, event_fields_end_idx: usize,
// end of everything (fields + topics) // end of everything (fields + topics)
end_idx: usize, end_idx: usize,
metadata: Metadata, metadata: Metadata,
@@ -221,10 +223,13 @@ impl EventDetails {
let input = &mut &all_bytes[start_idx..]; let input = &mut &all_bytes[start_idx..];
let phase = Phase::decode(input)?; let phase = Phase::decode(input)?;
let event_start_idx = all_bytes.len() - input.len();
let pallet_index = u8::decode(input)?; let pallet_index = u8::decode(input)?;
let variant_index = u8::decode(input)?; let variant_index = u8::decode(input)?;
let fields_start_idx = all_bytes.len() - input.len(); let event_fields_start_idx = all_bytes.len() - input.len();
// Get metadata for the event: // Get metadata for the event:
let event_metadata = metadata.event(pallet_index, variant_index)?; let event_metadata = metadata.event(pallet_index, variant_index)?;
@@ -246,7 +251,7 @@ impl EventDetails {
} }
// the end of the field bytes. // the end of the field bytes.
let fields_end_idx = all_bytes.len() - input.len(); let event_fields_end_idx = all_bytes.len() - input.len();
// topics come after the event data in EventRecord. They aren't used for // topics come after the event data in EventRecord. They aren't used for
// anything at the moment, so just decode and throw them away. // anything at the moment, so just decode and throw them away.
@@ -259,8 +264,9 @@ impl EventDetails {
phase, phase,
index, index,
start_idx, start_idx,
fields_start_idx, event_start_idx,
fields_end_idx, event_fields_start_idx,
event_fields_end_idx,
end_idx, end_idx,
all_bytes, all_bytes,
metadata, metadata,
@@ -281,14 +287,14 @@ impl EventDetails {
pub fn pallet_index(&self) -> u8 { pub fn pallet_index(&self) -> u8 {
// Note: never panics; we expect these bytes to exist // Note: never panics; we expect these bytes to exist
// in order that the EventDetails could be created. // in order that the EventDetails could be created.
self.all_bytes[self.fields_start_idx - 2] self.all_bytes[self.event_fields_start_idx - 2]
} }
/// The index of the event variant that the event originated from. /// The index of the event variant that the event originated from.
pub fn variant_index(&self) -> u8 { pub fn variant_index(&self) -> u8 {
// Note: never panics; we expect these bytes to exist // Note: never panics; we expect these bytes to exist
// in order that the EventDetails could be created. // in order that the EventDetails could be created.
self.all_bytes[self.fields_start_idx - 1] self.all_bytes[self.event_fields_start_idx - 1]
} }
/// The name of the pallet from whence the Event originated. /// The name of the pallet from whence the Event originated.
@@ -319,7 +325,7 @@ impl EventDetails {
/// Return the bytes representing the fields stored in this event. /// Return the bytes representing the fields stored in this event.
pub fn field_bytes(&self) -> &[u8] { pub fn field_bytes(&self) -> &[u8] {
&self.all_bytes[self.fields_start_idx..self.fields_end_idx] &self.all_bytes[self.event_fields_start_idx..self.event_fields_end_idx]
} }
/// Decode and provide the event fields back in the form of a [`scale_value::Composite`] /// Decode and provide the event fields back in the form of a [`scale_value::Composite`]
@@ -384,7 +390,7 @@ impl EventDetails {
/// the pallet and event enum variants as well as the event fields). A compatible /// the pallet and event enum variants as well as the event fields). A compatible
/// type for this is exposed via static codegen as a root level `Event` type. /// type for this is exposed via static codegen as a root level `Event` type.
pub fn as_root_event<E: Decode>(&self) -> Result<E, CodecError> { pub fn as_root_event<E: Decode>(&self) -> Result<E, CodecError> {
E::decode(&mut self.bytes()) E::decode(&mut &self.all_bytes[self.event_start_idx..self.event_fields_end_idx])
} }
} }
@@ -503,6 +509,7 @@ mod tests {
event_record, event_record,
events, events,
events_raw, events_raw,
AllEvents,
}, },
*, *,
}; };
@@ -572,6 +579,39 @@ mod tests {
assert_eq!(actual_fields_no_context, expected.fields); assert_eq!(actual_fields_no_context, expected.fields);
} }
#[test]
fn statically_decode_single_root_event() {
#[derive(Clone, Debug, PartialEq, Decode, Encode, TypeInfo)]
enum Event {
A(u8, bool, Vec<String>),
}
// Create fake metadata that knows about our single event, above:
let metadata = metadata::<Event>();
// Encode our events in the format we expect back from a node, and
// construst an Events object to iterate them:
let event = Event::A(1, true, vec!["Hi".into()]);
let events = events::<Event>(
metadata,
vec![event_record(Phase::ApplyExtrinsic(123), event.clone())],
);
let ev = events
.iter()
.next()
.expect("one event expected")
.expect("event should be extracted OK");
// This is the line we're testing:
let decoded_event = ev
.as_root_event::<AllEvents<Event>>()
.expect("can decode event into root enum again");
// It should equal the event we put in:
assert_eq!(decoded_event, AllEvents::Test(event));
}
#[test] #[test]
fn dynamically_decode_single_event() { fn dynamically_decode_single_event() {
#[derive(Clone, Debug, PartialEq, Decode, Encode, TypeInfo)] #[derive(Clone, Debug, PartialEq, Decode, Encode, TypeInfo)]