subxt/blocks/
block_types.rs1use crate::{
6 backend::BlockRef,
7 blocks::Extrinsics,
8 client::{OfflineClientT, OnlineClientT},
9 config::{Config, HashFor, Header},
10 error::{BlockError, DecodeError, Error},
11 events,
12 runtime_api::RuntimeApi,
13 storage::Storage,
14};
15
16use codec::{Decode, Encode};
17use futures::lock::Mutex as AsyncMutex;
18use std::sync::Arc;
19
20pub struct Block<T: Config, C> {
22 header: T::Header,
23 block_ref: BlockRef<HashFor<T>>,
24 client: C,
25 cached_events: CachedEvents<T>,
28}
29
30impl<T: Config, C: Clone> Clone for Block<T, C> {
31 fn clone(&self) -> Self {
32 Self {
33 header: self.header.clone(),
34 block_ref: self.block_ref.clone(),
35 client: self.client.clone(),
36 cached_events: self.cached_events.clone(),
37 }
38 }
39}
40
41pub(crate) type CachedEvents<T> = Arc<AsyncMutex<Option<events::Events<T>>>>;
44
45impl<T, C> Block<T, C>
46where
47 T: Config,
48 C: OfflineClientT<T>,
49{
50 pub(crate) fn new(header: T::Header, block_ref: BlockRef<HashFor<T>>, client: C) -> Self {
51 Block {
52 header,
53 block_ref,
54 client,
55 cached_events: Default::default(),
56 }
57 }
58
59 pub fn reference(&self) -> BlockRef<HashFor<T>> {
62 self.block_ref.clone()
63 }
64
65 pub fn hash(&self) -> HashFor<T> {
67 self.block_ref.hash()
68 }
69
70 pub fn number(&self) -> <T::Header as crate::config::Header>::Number {
72 self.header().number()
73 }
74
75 pub fn header(&self) -> &T::Header {
77 &self.header
78 }
79}
80
81impl<T, C> Block<T, C>
82where
83 T: Config,
84 C: OnlineClientT<T>,
85{
86 pub async fn events(&self) -> Result<events::Events<T>, Error> {
88 get_events(&self.client, self.hash(), &self.cached_events).await
89 }
90
91 pub async fn extrinsics(&self) -> Result<Extrinsics<T, C>, Error> {
93 let block_hash = self.hash();
94 let Some(extrinsics) = self.client.backend().block_body(block_hash).await? else {
95 return Err(BlockError::not_found(block_hash).into());
96 };
97
98 Extrinsics::new(
99 self.client.clone(),
100 extrinsics,
101 self.cached_events.clone(),
102 block_hash,
103 )
104 }
105
106 pub fn storage(&self) -> Storage<T, C> {
108 Storage::new(self.client.clone(), self.block_ref.clone())
109 }
110
111 pub async fn runtime_api(&self) -> Result<RuntimeApi<T, C>, Error> {
113 Ok(RuntimeApi::new(self.client.clone(), self.block_ref.clone()))
114 }
115
116 pub async fn account_nonce(&self, account_id: &T::AccountId) -> Result<u64, Error> {
118 get_account_nonce(&self.client, account_id, self.hash()).await
119 }
120}
121
122pub(crate) async fn get_events<C, T>(
124 client: &C,
125 block_hash: HashFor<T>,
126 cached_events: &AsyncMutex<Option<events::Events<T>>>,
127) -> Result<events::Events<T>, Error>
128where
129 T: Config,
130 C: OnlineClientT<T>,
131{
132 let mut lock = cached_events.lock().await;
136 let events = match &*lock {
137 Some(events) => events.clone(),
138 None => {
139 let events = events::EventsClient::new(client.clone())
140 .at(block_hash)
141 .await?;
142 lock.replace(events.clone());
143 events
144 }
145 };
146
147 Ok(events)
148}
149
150pub(crate) async fn get_account_nonce<C, T>(
152 client: &C,
153 account_id: &T::AccountId,
154 block_hash: HashFor<T>,
155) -> Result<u64, Error>
156where
157 C: OnlineClientT<T>,
158 T: Config,
159{
160 let account_nonce_bytes = client
161 .backend()
162 .call(
163 "AccountNonceApi_account_nonce",
164 Some(&account_id.encode()),
165 block_hash,
166 )
167 .await?;
168
169 let cursor = &mut &account_nonce_bytes[..];
171 let account_nonce: u64 = match account_nonce_bytes.len() {
172 2 => u16::decode(cursor)?.into(),
173 4 => u32::decode(cursor)?.into(),
174 8 => u64::decode(cursor)?,
175 _ => {
176 return Err(Error::Decode(DecodeError::custom_string(format!(
177 "state call AccountNonceApi_account_nonce returned an unexpected number of bytes: {} (expected 2, 4 or 8)",
178 account_nonce_bytes.len()
179 ))));
180 }
181 };
182 Ok(account_nonce)
183}