substrate_api_client/api/rpc_api/
chain.rs1use crate::{
15 api::{Api, Result},
16 rpc::{Request, Subscribe},
17 Error,
18};
19use ac_compose_macros::rpc_params;
20use ac_primitives::config::Config;
21#[cfg(all(not(feature = "sync-api"), not(feature = "std")))]
22use alloc::boxed::Box;
23use alloc::vec::Vec;
24use log::*;
25use serde::de::DeserializeOwned;
26use sp_runtime::generic::SignedBlock;
27
28#[maybe_async::maybe_async(?Send)]
29pub trait GetChainInfo {
30 type BlockNumber;
31 type Hash;
32 type Header;
33 type Block;
34
35 async fn get_finalized_head(&self) -> Result<Option<Self::Hash>>;
36
37 async fn get_header(&self, hash: Option<Self::Hash>) -> Result<Option<Self::Header>>;
38
39 async fn get_block_hash(&self, number: Option<Self::BlockNumber>)
40 -> Result<Option<Self::Hash>>;
41
42 async fn get_genesis_block(&self) -> Result<Self::Block>;
44
45 async fn get_block(&self, hash: Option<Self::Hash>) -> Result<Option<Self::Block>>;
46
47 async fn get_block_by_num(
48 &self,
49 number: Option<Self::BlockNumber>,
50 ) -> Result<Option<Self::Block>>;
51
52 async fn get_signed_block(
57 &self,
58 hash: Option<Self::Hash>,
59 ) -> Result<Option<SignedBlock<Self::Block>>>;
60
61 async fn get_signed_block_by_num(
62 &self,
63 number: Option<Self::BlockNumber>,
64 ) -> Result<Option<SignedBlock<Self::Block>>>;
65
66 async fn get_finalized_block(&self) -> Result<Option<SignedBlock<Self::Block>>>;
68
69 async fn get_signed_blocks(
72 &self,
73 block_numbers: &[Self::BlockNumber],
74 ) -> Result<Vec<SignedBlock<Self::Block>>>;
75}
76
77#[maybe_async::maybe_async(?Send)]
78impl<T, Client> GetChainInfo for Api<T, Client>
79where
80 T: Config,
81 Client: Request,
82{
83 type BlockNumber = T::BlockNumber;
84 type Hash = T::Hash;
85 type Header = T::Header;
86 type Block = T::Block;
87
88 async fn get_finalized_head(&self) -> Result<Option<Self::Hash>> {
89 let finalized_block_hash =
90 self.client().request("chain_getFinalizedHead", rpc_params![]).await?;
91 Ok(finalized_block_hash)
92 }
93
94 async fn get_header(&self, hash: Option<Self::Hash>) -> Result<Option<Self::Header>> {
95 let block_hash = self.client().request("chain_getHeader", rpc_params![hash]).await?;
96 Ok(block_hash)
97 }
98
99 async fn get_block_hash(
100 &self,
101 number: Option<Self::BlockNumber>,
102 ) -> Result<Option<Self::Hash>> {
103 let block_hash = self.client().request("chain_getBlockHash", rpc_params![number]).await?;
104 Ok(block_hash)
105 }
106
107 async fn get_genesis_block(&self) -> Result<Self::Block> {
108 self.get_block(Some(self.genesis_hash())).await?.ok_or(Error::BlockHashNotFound)
109 }
110
111 async fn get_block(&self, hash: Option<Self::Hash>) -> Result<Option<Self::Block>> {
112 Self::get_signed_block(self, hash).await.map(|sb_opt| sb_opt.map(|sb| sb.block))
113 }
114
115 async fn get_block_by_num(
116 &self,
117 number: Option<Self::BlockNumber>,
118 ) -> Result<Option<Self::Block>> {
119 Self::get_signed_block_by_num(self, number)
120 .await
121 .map(|sb_opt| sb_opt.map(|sb| sb.block))
122 }
123
124 async fn get_signed_block(
125 &self,
126 hash: Option<Self::Hash>,
127 ) -> Result<Option<SignedBlock<Self::Block>>> {
128 let block = self.client().request("chain_getBlock", rpc_params![hash]).await?;
129 Ok(block)
130 }
131
132 async fn get_signed_block_by_num(
133 &self,
134 number: Option<Self::BlockNumber>,
135 ) -> Result<Option<SignedBlock<Self::Block>>> {
136 self.get_block_hash(number).await.map(|h| self.get_signed_block(h))?.await
137 }
138
139 async fn get_finalized_block(&self) -> Result<Option<SignedBlock<Self::Block>>> {
140 let hash = self.get_finalized_head().await?;
141 match hash {
142 Some(hash) => self.get_signed_block(Some(hash)).await,
143 None => Ok(None),
144 }
145 }
146
147 async fn get_signed_blocks(
148 &self,
149 block_numbers: &[Self::BlockNumber],
150 ) -> Result<Vec<SignedBlock<Self::Block>>> {
151 let mut blocks = Vec::<SignedBlock<Self::Block>>::new();
152
153 for n in block_numbers {
154 if let Some(block) = self.get_signed_block_by_num(Some(*n)).await? {
155 blocks.push(block);
156 }
157 }
158 Ok(blocks)
159 }
160}
161#[maybe_async::maybe_async(?Send)]
162pub trait SubscribeChain {
163 type Client: Subscribe;
164 type Header: DeserializeOwned;
165
166 async fn subscribe_finalized_heads(
167 &self,
168 ) -> Result<<Self::Client as Subscribe>::Subscription<Self::Header>>;
169}
170
171#[maybe_async::maybe_async(?Send)]
172impl<T, Client> SubscribeChain for Api<T, Client>
173where
174 T: Config,
175 Client: Subscribe,
176{
177 type Client = Client;
178 type Header = T::Header;
179
180 async fn subscribe_finalized_heads(
181 &self,
182 ) -> Result<<Self::Client as Subscribe>::Subscription<Self::Header>> {
183 debug!("subscribing to finalized heads");
184 self.client()
185 .subscribe(
186 "chain_subscribeFinalizedHeads",
187 rpc_params![],
188 "chain_unsubscribeFinalizedHeads",
189 )
190 .await
191 .map_err(|e| e.into())
192 }
193}