cumulus_relay_chain_interface/
lib.rs1use std::{
18 collections::{BTreeMap, VecDeque},
19 pin::Pin,
20 sync::Arc,
21};
22
23use futures::Stream;
24use polkadot_overseer::prometheus::PrometheusError;
25use sc_client_api::StorageProof;
26use sp_version::RuntimeVersion;
27
28use async_trait::async_trait;
29use codec::{Decode, Encode, Error as CodecError};
30use jsonrpsee_core::ClientError as JsonRpcError;
31use sp_api::ApiError;
32
33use cumulus_primitives_core::relay_chain::{BlockId, Hash as RelayHash};
34pub use cumulus_primitives_core::{
35 relay_chain::{
36 BlockNumber, CommittedCandidateReceipt, CoreIndex, CoreState, Hash as PHash,
37 Header as PHeader, InboundHrmpMessage, OccupiedCoreAssumption, SessionIndex,
38 ValidationCodeHash, ValidatorId,
39 },
40 InboundDownwardMessage, ParaId, PersistedValidationData,
41};
42pub use polkadot_overseer::Handle as OverseerHandle;
43pub use sp_state_machine::StorageValue;
44
45pub type RelayChainResult<T> = Result<T, RelayChainError>;
46
47#[derive(thiserror::Error, Debug)]
48pub enum RelayChainError {
49 #[error("Error occurred while calling relay chain runtime: {0}")]
50 ApiError(#[from] ApiError),
51 #[error("Timeout while waiting for relay-chain block `{0}` to be imported.")]
52 WaitTimeout(PHash),
53 #[error("Import listener closed while waiting for relay-chain block `{0}` to be imported.")]
54 ImportListenerClosed(PHash),
55 #[error(
56 "Blockchain returned an error while waiting for relay-chain block `{0}` to be imported: {1}"
57 )]
58 WaitBlockchainError(PHash, sp_blockchain::Error),
59 #[error("Blockchain returned an error: {0}")]
60 BlockchainError(#[from] sp_blockchain::Error),
61 #[error("State machine error occurred: {0}")]
62 StateMachineError(Box<dyn sp_state_machine::Error>),
63 #[error("Unable to call RPC method '{0}'")]
64 RpcCallError(String),
65 #[error("RPC Error: '{0}'")]
66 JsonRpcError(#[from] JsonRpcError),
67 #[error("Unable to communicate with RPC worker: {0}")]
68 WorkerCommunicationError(String),
69 #[error("Scale codec deserialization error: {0}")]
70 DeserializationError(CodecError),
71 #[error(transparent)]
72 Application(#[from] Box<dyn std::error::Error + Send + Sync + 'static>),
73 #[error("Prometheus error: {0}")]
74 PrometheusError(#[from] PrometheusError),
75 #[error("Unspecified error occurred: {0}")]
76 GenericError(String),
77}
78
79impl From<RelayChainError> for ApiError {
80 fn from(r: RelayChainError) -> Self {
81 sp_api::ApiError::Application(Box::new(r))
82 }
83}
84
85impl From<CodecError> for RelayChainError {
86 fn from(e: CodecError) -> Self {
87 RelayChainError::DeserializationError(e)
88 }
89}
90
91impl From<RelayChainError> for sp_blockchain::Error {
92 fn from(r: RelayChainError) -> Self {
93 sp_blockchain::Error::Application(Box::new(r))
94 }
95}
96
97impl<T: std::error::Error + Send + Sync + 'static> From<Box<T>> for RelayChainError {
98 fn from(r: Box<T>) -> Self {
99 RelayChainError::Application(r)
100 }
101}
102
103#[async_trait]
105pub trait RelayChainInterface: Send + Sync {
106 async fn get_storage_by_key(
108 &self,
109 relay_parent: PHash,
110 key: &[u8],
111 ) -> RelayChainResult<Option<StorageValue>>;
112
113 async fn validators(&self, block_id: PHash) -> RelayChainResult<Vec<ValidatorId>>;
115
116 async fn best_block_hash(&self) -> RelayChainResult<PHash>;
118
119 async fn header(&self, block_id: BlockId) -> RelayChainResult<Option<PHeader>>;
121
122 async fn finalized_block_hash(&self) -> RelayChainResult<PHash>;
124
125 async fn call_runtime_api(
127 &self,
128 method_name: &'static str,
129 hash: RelayHash,
130 payload: &[u8],
131 ) -> RelayChainResult<Vec<u8>>;
132
133 async fn retrieve_dmq_contents(
138 &self,
139 para_id: ParaId,
140 relay_parent: PHash,
141 ) -> RelayChainResult<Vec<InboundDownwardMessage>>;
142
143 async fn retrieve_all_inbound_hrmp_channel_contents(
148 &self,
149 para_id: ParaId,
150 relay_parent: PHash,
151 ) -> RelayChainResult<BTreeMap<ParaId, Vec<InboundHrmpMessage>>>;
152
153 async fn persisted_validation_data(
159 &self,
160 block_id: PHash,
161 para_id: ParaId,
162 _: OccupiedCoreAssumption,
163 ) -> RelayChainResult<Option<PersistedValidationData>>;
164
165 #[deprecated(
169 note = "`candidate_pending_availability` only returns one candidate and is deprecated. Use `candidates_pending_availability` instead."
170 )]
171 async fn candidate_pending_availability(
172 &self,
173 block_id: PHash,
174 para_id: ParaId,
175 ) -> RelayChainResult<Option<CommittedCandidateReceipt>>;
176
177 async fn session_index_for_child(&self, block_id: PHash) -> RelayChainResult<SessionIndex>;
179
180 async fn import_notification_stream(
182 &self,
183 ) -> RelayChainResult<Pin<Box<dyn Stream<Item = PHeader> + Send>>>;
184
185 async fn new_best_notification_stream(
187 &self,
188 ) -> RelayChainResult<Pin<Box<dyn Stream<Item = PHeader> + Send>>>;
189
190 async fn wait_for_block(&self, hash: PHash) -> RelayChainResult<()>;
195
196 async fn finality_notification_stream(
198 &self,
199 ) -> RelayChainResult<Pin<Box<dyn Stream<Item = PHeader> + Send>>>;
200
201 async fn is_major_syncing(&self) -> RelayChainResult<bool>;
204
205 fn overseer_handle(&self) -> RelayChainResult<OverseerHandle>;
207
208 async fn prove_read(
210 &self,
211 relay_parent: PHash,
212 relevant_keys: &Vec<Vec<u8>>,
213 ) -> RelayChainResult<StorageProof>;
214
215 async fn validation_code_hash(
218 &self,
219 relay_parent: PHash,
220 para_id: ParaId,
221 occupied_core_assumption: OccupiedCoreAssumption,
222 ) -> RelayChainResult<Option<ValidationCodeHash>>;
223
224 async fn candidates_pending_availability(
226 &self,
227 block_id: PHash,
228 para_id: ParaId,
229 ) -> RelayChainResult<Vec<CommittedCandidateReceipt>>;
230
231 async fn version(&self, relay_parent: PHash) -> RelayChainResult<RuntimeVersion>;
233
234 async fn availability_cores(
238 &self,
239 relay_parent: PHash,
240 ) -> RelayChainResult<Vec<CoreState<PHash, BlockNumber>>>;
241
242 async fn claim_queue(
244 &self,
245 relay_parent: PHash,
246 ) -> RelayChainResult<BTreeMap<CoreIndex, VecDeque<ParaId>>>;
247}
248
249#[async_trait]
250impl<T> RelayChainInterface for Arc<T>
251where
252 T: RelayChainInterface + ?Sized,
253{
254 async fn retrieve_dmq_contents(
255 &self,
256 para_id: ParaId,
257 relay_parent: PHash,
258 ) -> RelayChainResult<Vec<InboundDownwardMessage>> {
259 (**self).retrieve_dmq_contents(para_id, relay_parent).await
260 }
261
262 async fn retrieve_all_inbound_hrmp_channel_contents(
263 &self,
264 para_id: ParaId,
265 relay_parent: PHash,
266 ) -> RelayChainResult<BTreeMap<ParaId, Vec<InboundHrmpMessage>>> {
267 (**self).retrieve_all_inbound_hrmp_channel_contents(para_id, relay_parent).await
268 }
269
270 async fn persisted_validation_data(
271 &self,
272 block_id: PHash,
273 para_id: ParaId,
274 occupied_core_assumption: OccupiedCoreAssumption,
275 ) -> RelayChainResult<Option<PersistedValidationData>> {
276 (**self)
277 .persisted_validation_data(block_id, para_id, occupied_core_assumption)
278 .await
279 }
280
281 #[allow(deprecated)]
282 async fn candidate_pending_availability(
283 &self,
284 block_id: PHash,
285 para_id: ParaId,
286 ) -> RelayChainResult<Option<CommittedCandidateReceipt>> {
287 (**self).candidate_pending_availability(block_id, para_id).await
288 }
289
290 async fn session_index_for_child(&self, block_id: PHash) -> RelayChainResult<SessionIndex> {
291 (**self).session_index_for_child(block_id).await
292 }
293
294 async fn validators(&self, block_id: PHash) -> RelayChainResult<Vec<ValidatorId>> {
295 (**self).validators(block_id).await
296 }
297
298 async fn import_notification_stream(
299 &self,
300 ) -> RelayChainResult<Pin<Box<dyn Stream<Item = PHeader> + Send>>> {
301 (**self).import_notification_stream().await
302 }
303
304 async fn finality_notification_stream(
305 &self,
306 ) -> RelayChainResult<Pin<Box<dyn Stream<Item = PHeader> + Send>>> {
307 (**self).finality_notification_stream().await
308 }
309
310 async fn best_block_hash(&self) -> RelayChainResult<PHash> {
311 (**self).best_block_hash().await
312 }
313
314 async fn finalized_block_hash(&self) -> RelayChainResult<PHash> {
315 (**self).finalized_block_hash().await
316 }
317
318 async fn call_runtime_api(
319 &self,
320 method_name: &'static str,
321 hash: RelayHash,
322 payload: &[u8],
323 ) -> RelayChainResult<Vec<u8>> {
324 (**self).call_runtime_api(method_name, hash, payload).await
325 }
326
327 async fn is_major_syncing(&self) -> RelayChainResult<bool> {
328 (**self).is_major_syncing().await
329 }
330
331 fn overseer_handle(&self) -> RelayChainResult<OverseerHandle> {
332 (**self).overseer_handle()
333 }
334
335 async fn get_storage_by_key(
336 &self,
337 relay_parent: PHash,
338 key: &[u8],
339 ) -> RelayChainResult<Option<StorageValue>> {
340 (**self).get_storage_by_key(relay_parent, key).await
341 }
342
343 async fn prove_read(
344 &self,
345 relay_parent: PHash,
346 relevant_keys: &Vec<Vec<u8>>,
347 ) -> RelayChainResult<StorageProof> {
348 (**self).prove_read(relay_parent, relevant_keys).await
349 }
350
351 async fn wait_for_block(&self, hash: PHash) -> RelayChainResult<()> {
352 (**self).wait_for_block(hash).await
353 }
354
355 async fn new_best_notification_stream(
356 &self,
357 ) -> RelayChainResult<Pin<Box<dyn Stream<Item = PHeader> + Send>>> {
358 (**self).new_best_notification_stream().await
359 }
360
361 async fn header(&self, block_id: BlockId) -> RelayChainResult<Option<PHeader>> {
362 (**self).header(block_id).await
363 }
364
365 async fn validation_code_hash(
366 &self,
367 relay_parent: PHash,
368 para_id: ParaId,
369 occupied_core_assumption: OccupiedCoreAssumption,
370 ) -> RelayChainResult<Option<ValidationCodeHash>> {
371 (**self)
372 .validation_code_hash(relay_parent, para_id, occupied_core_assumption)
373 .await
374 }
375
376 async fn availability_cores(
377 &self,
378 relay_parent: PHash,
379 ) -> RelayChainResult<Vec<CoreState<PHash, BlockNumber>>> {
380 (**self).availability_cores(relay_parent).await
381 }
382
383 async fn candidates_pending_availability(
384 &self,
385 block_id: PHash,
386 para_id: ParaId,
387 ) -> RelayChainResult<Vec<CommittedCandidateReceipt>> {
388 (**self).candidates_pending_availability(block_id, para_id).await
389 }
390
391 async fn version(&self, relay_parent: PHash) -> RelayChainResult<RuntimeVersion> {
392 (**self).version(relay_parent).await
393 }
394
395 async fn claim_queue(
396 &self,
397 relay_parent: PHash,
398 ) -> RelayChainResult<BTreeMap<CoreIndex, VecDeque<ParaId>>> {
399 (**self).claim_queue(relay_parent).await
400 }
401}
402
403pub async fn call_runtime_api<R>(
407 client: &(impl RelayChainInterface + ?Sized),
408 method_name: &'static str,
409 hash: RelayHash,
410 payload: impl Encode,
411) -> RelayChainResult<R>
412where
413 R: Decode,
414{
415 let res = client.call_runtime_api(method_name, hash, &payload.encode()).await?;
416 Decode::decode(&mut &*res).map_err(Into::into)
417}