From 6e2c9c2702cb7fc8cd851c063fe77a64a23909a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bigna=20H=C3=A4rdi?= Date: Thu, 27 Apr 2023 11:28:44 +0200 Subject: [PATCH] Add `next_events_from_metadata` and rename `next_event` (#545) * remove obsolete comment * make pub things pub --- examples/examples/event_callback.rs | 2 +- node-api/src/events.rs | 3 -- src/api/rpc_api/events.rs | 61 +++++++++++++++++++---------- testing/examples/events_tests.rs | 16 +++++++- 4 files changed, 56 insertions(+), 26 deletions(-) diff --git a/examples/examples/event_callback.rs b/examples/examples/event_callback.rs index 59186ed9e..10b0e166c 100644 --- a/examples/examples/event_callback.rs +++ b/examples/examples/event_callback.rs @@ -39,7 +39,7 @@ async fn main() { // Wait for event callbacks from the node, which are received via subscription. for _ in 0..5 { - let event_records = subscription.next_event::().unwrap().unwrap(); + let event_records = subscription.next_events::().unwrap().unwrap(); for event_record in &event_records { println!("decoded: {:?} {:?}", event_record.phase, event_record.event); match &event_record.event { diff --git a/node-api/src/events.rs b/node-api/src/events.rs index 0f13196a7..02f66d50e 100644 --- a/node-api/src/events.rs +++ b/node-api/src/events.rs @@ -24,9 +24,6 @@ use sp_core::H256; /// A collection of events obtained from a block, bundled with the necessary /// information needed to decode and iterate over them. -// -// In subxt, this was generic over a `Config` type, but it's sole usage was to derive the -// hash type. We omitted this here and use the `ac_primitives::Hash` instead. #[derive(Clone, Debug)] pub struct Events { metadata: Metadata, diff --git a/src/api/rpc_api/events.rs b/src/api/rpc_api/events.rs index 1e83a842e..19193e56a 100644 --- a/src/api/rpc_api/events.rs +++ b/src/api/rpc_api/events.rs @@ -17,7 +17,7 @@ use crate::{ GetChainInfo, GetStorage, }; use ac_compose_macros::rpc_params; -use ac_node_api::{EventDetails, EventRecord, Events, Phase}; +use ac_node_api::{metadata::Metadata, EventDetails, EventRecord, Events, Phase}; use ac_primitives::{ExtrinsicParams, FrameSystemConfig, StorageChangeSet}; use alloc::{vec, vec::Vec}; use codec::{Decode, Encode}; @@ -83,22 +83,30 @@ where /// Simplifies the event retrieval from the subscription. pub struct EventSubscription { pub subscription: Subscription, + pub metadata: Metadata, _phantom: PhantomData, } +impl EventSubscription { + /// Create a new wrapper around the subscription. + pub fn new(subscription: Subscription, metadata: Metadata) -> Self { + Self { subscription, metadata, _phantom: Default::default() } + } + + /// Update the metadata. + pub fn update_metadata(&mut self, metadata: Metadata) { + self.metadata = metadata + } +} + impl EventSubscription where - Hash: DeserializeOwned, + Hash: DeserializeOwned + Copy, Subscription: HandleSubscription>, { - /// Create a new wrapper around the subscription. - pub fn new(subscription: Subscription) -> Self { - Self { subscription, _phantom: Default::default() } - } - /// Wait for the next value from the internal subscription. /// Upon encounter, it retrieves and decodes the expected `EventRecord`. - pub fn next_event( + pub fn next_events( &mut self, ) -> Option>>> { let change_set = match self.subscription.next()? { @@ -109,8 +117,29 @@ where // changes in the set. Also, we don't care about the key but only the data, so take // the second value in the tuple of two. let storage_data = change_set.changes[0].1.as_ref()?; - let events = Decode::decode(&mut storage_data.0.as_slice()).map_err(Error::Codec); - Some(events) + let event_records = Decode::decode(&mut storage_data.0.as_slice()).map_err(Error::Codec); + Some(event_records) + } + + /// Wait for the next value from the internal subscription. + /// Upon encounter, it retrieves and decodes the expected `EventDetails`. + // + // On the contrary to `next_events` this function only needs up-to-date metadata + // and is therefore updateable during runtime. + pub fn next_events_from_metadata(&mut self) -> Option>> { + let change_set = match self.subscription.next()? { + Ok(set) => set, + Err(e) => return Some(Err(Error::RpcClient(e))), + }; + let block_hash = change_set.block; + // Since we subscribed to only the events key, we can simply take the first value of the + // changes in the set. Also, we don't care about the key but only the data, so take + // the second value in the tuple of two. + let storage_data = change_set.changes[0].1.as_ref()?; + let event_bytes = storage_data.0.clone(); + + let events = Events::::new(self.metadata.clone(), block_hash, event_bytes); + Some(Ok(events)) } /// Unsubscribe from the internal subscription. @@ -119,16 +148,6 @@ where } } -impl From for EventSubscription -where - Hash: DeserializeOwned, - Subscription: HandleSubscription>, -{ - fn from(subscription: Subscription) -> Self { - EventSubscription::new(subscription) - } -} - pub trait SubscribeEvents { type Client: Subscribe; type Hash: DeserializeOwned; @@ -151,7 +170,7 @@ where let subscription = self .client() .subscribe("state_subscribeStorage", rpc_params![vec![key]], "state_unsubscribeStorage") - .map(|sub| sub.into())?; + .map(|sub| EventSubscription::new(sub, self.metadata().clone()))?; Ok(subscription) } } diff --git a/testing/examples/events_tests.rs b/testing/examples/events_tests.rs index 99b4071e6..1eea28cad 100644 --- a/testing/examples/events_tests.rs +++ b/testing/examples/events_tests.rs @@ -70,7 +70,7 @@ async fn main() { // Wait for event callbacks from the node, which are received via subscription. for _ in 0..5 { let event_records = event_subscription - .next_event::::Hash>() + .next_events::::Hash>() .unwrap() .unwrap(); for event_record in &event_records { @@ -81,6 +81,20 @@ async fn main() { } } } + + // Wait for event callbacks from the node, which are received via subscription, in case no RuntimeEvents are accessible. + for _ in 0..5 { + let events = event_subscription.next_events_from_metadata().unwrap().unwrap(); + for event in events.iter() { + let event = event.unwrap(); + println!("got event: {:?} {:?}", event.pallet_name(), event.variant_name()); + if let Ok(Some(_extrinisic_success)) = event.as_event::() { + println!("Got System event, all good"); + } else { + panic!("Unexpected event"); + } + } + } } fn assert_assosciated_events_match_expected(events: Vec) {