gear_subxt/events/
events_client.rs

1// Copyright 2019-2023 Parity Technologies (UK) Ltd.
2// This file is dual-licensed as Apache-2.0 or GPL-3.0.
3// see LICENSE for license details.
4
5use crate::{client::OnlineClientT, error::Error, events::Events, rpc::types::StorageKey, Config};
6use derivative::Derivative;
7use std::future::Future;
8
9/// A client for working with events.
10#[derive(Derivative)]
11#[derivative(Clone(bound = "Client: Clone"))]
12pub struct EventsClient<T, Client> {
13    client: Client,
14    _marker: std::marker::PhantomData<T>,
15}
16
17impl<T, Client> EventsClient<T, Client> {
18    /// Create a new [`EventsClient`].
19    pub fn new(client: Client) -> Self {
20        Self {
21            client,
22            _marker: std::marker::PhantomData,
23        }
24    }
25}
26
27impl<T, Client> EventsClient<T, Client>
28where
29    T: Config,
30    Client: OnlineClientT<T>,
31{
32    /// Obtain events at some block hash.
33    ///
34    /// # Warning
35    ///
36    /// This call only supports blocks produced since the most recent
37    /// runtime upgrade. You can attempt to retrieve events from older blocks,
38    /// but may run into errors attempting to work with them.
39    pub fn at(
40        &self,
41        block_hash: T::Hash,
42    ) -> impl Future<Output = Result<Events<T>, Error>> + Send + 'static {
43        self.at_or_latest(Some(block_hash))
44    }
45
46    /// Obtain events at the latest block hash.
47    pub fn at_latest(&self) -> impl Future<Output = Result<Events<T>, Error>> + Send + 'static {
48        self.at_or_latest(None)
49    }
50
51    /// Obtain events at some block hash.
52    fn at_or_latest(
53        &self,
54        block_hash: Option<T::Hash>,
55    ) -> impl Future<Output = Result<Events<T>, Error>> + Send + 'static {
56        // Clone and pass the client in like this so that we can explicitly
57        // return a Future that's Send + 'static, rather than tied to &self.
58        let client = self.client.clone();
59        async move {
60            // If block hash is not provided, get the hash
61            // for the latest block and use that.
62            let block_hash = match block_hash {
63                Some(hash) => hash,
64                None => client
65                    .rpc()
66                    .block_hash(None)
67                    .await?
68                    .expect("didn't pass a block number; qed"),
69            };
70
71            let event_bytes = get_event_bytes(&client, Some(block_hash)).await?;
72            Ok(Events::new(client.metadata(), block_hash, event_bytes))
73        }
74    }
75}
76
77// The storage key needed to access events.
78fn system_events_key() -> StorageKey {
79    let mut storage_key = sp_core_hashing::twox_128(b"System").to_vec();
80    storage_key.extend(sp_core_hashing::twox_128(b"Events").to_vec());
81    StorageKey(storage_key)
82}
83
84// Get the event bytes from the provided client, at the provided block hash.
85pub(crate) async fn get_event_bytes<T, Client>(
86    client: &Client,
87    block_hash: Option<T::Hash>,
88) -> Result<Vec<u8>, Error>
89where
90    T: Config,
91    Client: OnlineClientT<T>,
92{
93    Ok(client
94        .rpc()
95        .storage(&system_events_key().0, block_hash)
96        .await?
97        .map(|e| e.0)
98        .unwrap_or_else(Vec::new))
99}