1use std::{
19 collections::{BTreeMap, VecDeque},
20 pin::Pin,
21 sync::Arc,
22};
23
24use futures::Stream;
25use polkadot_overseer::prometheus::PrometheusError;
26use sc_client_api::StorageProof;
27use sp_version::RuntimeVersion;
28
29use async_trait::async_trait;
30use codec::{Decode, Encode, Error as CodecError};
31use jsonrpsee_core::ClientError as JsonRpcError;
32use sp_api::ApiError;
33
34use cumulus_primitives_core::relay_chain::{
35 vstaging::RelayParentInfo, BlockId, CandidateEvent, Hash as RelayHash, NodeFeatures,
36};
37pub use cumulus_primitives_core::{
38 relay_chain::{
39 BlockNumber, CommittedCandidateReceiptV2 as CommittedCandidateReceipt, CoreIndex,
40 CoreState, Hash as PHash, Header as PHeader, InboundHrmpMessage, OccupiedCoreAssumption,
41 SessionIndex, ValidationCodeHash, ValidatorId,
42 },
43 InboundDownwardMessage, ParaId, PersistedValidationData,
44};
45pub use polkadot_overseer::Handle as OverseerHandle;
46pub use sp_state_machine::StorageValue;
47pub use sp_storage::ChildInfo;
48
49pub type RelayChainResult<T> = Result<T, RelayChainError>;
50
51#[derive(thiserror::Error, Debug)]
52pub enum RelayChainError {
53 #[error("Error occurred while calling relay chain runtime: {0}")]
54 ApiError(#[from] ApiError),
55 #[error("Timeout while waiting for relay-chain block `{0}` to be imported.")]
56 WaitTimeout(PHash),
57 #[error("Import listener closed while waiting for relay-chain block `{0}` to be imported.")]
58 ImportListenerClosed(PHash),
59 #[error(
60 "Blockchain returned an error while waiting for relay-chain block `{0}` to be imported: {1}"
61 )]
62 WaitBlockchainError(PHash, sp_blockchain::Error),
63 #[error("Blockchain returned an error: {0}")]
64 BlockchainError(#[from] sp_blockchain::Error),
65 #[error("State machine error occurred: {0}")]
66 StateMachineError(Box<dyn sp_state_machine::Error>),
67 #[error("Unable to call RPC method '{0}'")]
68 RpcCallError(String),
69 #[error("RPC Error: '{0}'")]
70 JsonRpcError(#[from] JsonRpcError),
71 #[error("Unable to communicate with RPC worker: {0}")]
72 WorkerCommunicationError(String),
73 #[error("Scale codec deserialization error: {0}")]
74 DeserializationError(CodecError),
75 #[error(transparent)]
76 Application(#[from] Box<dyn std::error::Error + Send + Sync + 'static>),
77 #[error("Prometheus error: {0}")]
78 PrometheusError(#[from] PrometheusError),
79 #[error("Unspecified error occurred: {0}")]
80 GenericError(String),
81}
82
83impl From<RelayChainError> for ApiError {
84 fn from(r: RelayChainError) -> Self {
85 sp_api::ApiError::Application(Box::new(r))
86 }
87}
88
89impl From<CodecError> for RelayChainError {
90 fn from(e: CodecError) -> Self {
91 RelayChainError::DeserializationError(e)
92 }
93}
94
95impl From<RelayChainError> for sp_blockchain::Error {
96 fn from(r: RelayChainError) -> Self {
97 sp_blockchain::Error::Application(Box::new(r))
98 }
99}
100
101impl<T: std::error::Error + Send + Sync + 'static> From<Box<T>> for RelayChainError {
102 fn from(r: Box<T>) -> Self {
103 RelayChainError::Application(r)
104 }
105}
106
107#[async_trait]
109pub trait RelayChainInterface: Send + Sync {
110 async fn get_storage_by_key(
112 &self,
113 relay_parent: PHash,
114 key: &[u8],
115 ) -> RelayChainResult<Option<StorageValue>>;
116
117 async fn validators(&self, block_id: PHash) -> RelayChainResult<Vec<ValidatorId>>;
119
120 async fn best_block_hash(&self) -> RelayChainResult<PHash>;
122
123 async fn header(&self, block_id: BlockId) -> RelayChainResult<Option<PHeader>>;
125
126 async fn finalized_block_hash(&self) -> RelayChainResult<PHash>;
128
129 async fn call_runtime_api(
131 &self,
132 method_name: &'static str,
133 hash: RelayHash,
134 payload: &[u8],
135 ) -> RelayChainResult<Vec<u8>>;
136
137 async fn retrieve_dmq_contents(
142 &self,
143 para_id: ParaId,
144 relay_parent: PHash,
145 ) -> RelayChainResult<Vec<InboundDownwardMessage>>;
146
147 async fn retrieve_all_inbound_hrmp_channel_contents(
152 &self,
153 para_id: ParaId,
154 relay_parent: PHash,
155 ) -> RelayChainResult<BTreeMap<ParaId, Vec<InboundHrmpMessage>>>;
156
157 async fn persisted_validation_data(
163 &self,
164 block_id: PHash,
165 para_id: ParaId,
166 _: OccupiedCoreAssumption,
167 ) -> RelayChainResult<Option<PersistedValidationData>>;
168
169 #[deprecated(
173 note = "`candidate_pending_availability` only returns one candidate and is deprecated. Use `candidates_pending_availability` instead."
174 )]
175 async fn candidate_pending_availability(
176 &self,
177 block_id: PHash,
178 para_id: ParaId,
179 ) -> RelayChainResult<Option<CommittedCandidateReceipt>>;
180
181 async fn session_index_for_child(&self, block_id: PHash) -> RelayChainResult<SessionIndex>;
183
184 async fn import_notification_stream(
186 &self,
187 ) -> RelayChainResult<Pin<Box<dyn Stream<Item = PHeader> + Send>>>;
188
189 async fn new_best_notification_stream(
191 &self,
192 ) -> RelayChainResult<Pin<Box<dyn Stream<Item = PHeader> + Send>>>;
193
194 async fn wait_for_block(&self, hash: PHash) -> RelayChainResult<()>;
199
200 async fn finality_notification_stream(
202 &self,
203 ) -> RelayChainResult<Pin<Box<dyn Stream<Item = PHeader> + Send>>>;
204
205 async fn is_major_syncing(&self) -> RelayChainResult<bool>;
208
209 fn overseer_handle(&self) -> RelayChainResult<OverseerHandle>;
211
212 async fn prove_read(
214 &self,
215 relay_parent: PHash,
216 relevant_keys: &Vec<Vec<u8>>,
217 ) -> RelayChainResult<StorageProof>;
218
219 async fn prove_child_read(
221 &self,
222 relay_parent: PHash,
223 child_info: &ChildInfo,
224 child_keys: &[Vec<u8>],
225 ) -> RelayChainResult<StorageProof>;
226
227 async fn validation_code_hash(
230 &self,
231 relay_parent: PHash,
232 para_id: ParaId,
233 occupied_core_assumption: OccupiedCoreAssumption,
234 ) -> RelayChainResult<Option<ValidationCodeHash>>;
235
236 async fn candidates_pending_availability(
238 &self,
239 block_id: PHash,
240 para_id: ParaId,
241 ) -> RelayChainResult<Vec<CommittedCandidateReceipt>>;
242
243 async fn version(&self, relay_parent: PHash) -> RelayChainResult<RuntimeVersion>;
245
246 async fn availability_cores(
250 &self,
251 relay_parent: PHash,
252 ) -> RelayChainResult<Vec<CoreState<PHash, BlockNumber>>>;
253
254 async fn claim_queue(
256 &self,
257 relay_parent: PHash,
258 ) -> RelayChainResult<BTreeMap<CoreIndex, VecDeque<ParaId>>>;
259
260 async fn scheduling_lookahead(&self, relay_parent: PHash) -> RelayChainResult<u32>;
262
263 async fn candidate_events(&self, at: RelayHash) -> RelayChainResult<Vec<CandidateEvent>>;
264
265 async fn max_relay_parent_session_age(&self, at: RelayHash) -> RelayChainResult<u32>;
266
267 async fn node_features(&self, at: RelayHash) -> RelayChainResult<NodeFeatures>;
268
269 async fn ancestor_relay_parent_info(
270 &self,
271 at: RelayHash,
272 session_index: SessionIndex,
273 relay_parent: RelayHash,
274 ) -> RelayChainResult<Option<RelayParentInfo<RelayHash, BlockNumber>>>;
275}
276
277#[async_trait]
278impl<T> RelayChainInterface for Arc<T>
279where
280 T: RelayChainInterface + ?Sized,
281{
282 async fn retrieve_dmq_contents(
283 &self,
284 para_id: ParaId,
285 relay_parent: PHash,
286 ) -> RelayChainResult<Vec<InboundDownwardMessage>> {
287 (**self).retrieve_dmq_contents(para_id, relay_parent).await
288 }
289
290 async fn retrieve_all_inbound_hrmp_channel_contents(
291 &self,
292 para_id: ParaId,
293 relay_parent: PHash,
294 ) -> RelayChainResult<BTreeMap<ParaId, Vec<InboundHrmpMessage>>> {
295 (**self).retrieve_all_inbound_hrmp_channel_contents(para_id, relay_parent).await
296 }
297
298 async fn persisted_validation_data(
299 &self,
300 block_id: PHash,
301 para_id: ParaId,
302 occupied_core_assumption: OccupiedCoreAssumption,
303 ) -> RelayChainResult<Option<PersistedValidationData>> {
304 (**self)
305 .persisted_validation_data(block_id, para_id, occupied_core_assumption)
306 .await
307 }
308
309 #[allow(deprecated)]
310 async fn candidate_pending_availability(
311 &self,
312 block_id: PHash,
313 para_id: ParaId,
314 ) -> RelayChainResult<Option<CommittedCandidateReceipt>> {
315 (**self).candidate_pending_availability(block_id, para_id).await
316 }
317
318 async fn session_index_for_child(&self, block_id: PHash) -> RelayChainResult<SessionIndex> {
319 (**self).session_index_for_child(block_id).await
320 }
321
322 async fn validators(&self, block_id: PHash) -> RelayChainResult<Vec<ValidatorId>> {
323 (**self).validators(block_id).await
324 }
325
326 async fn import_notification_stream(
327 &self,
328 ) -> RelayChainResult<Pin<Box<dyn Stream<Item = PHeader> + Send>>> {
329 (**self).import_notification_stream().await
330 }
331
332 async fn finality_notification_stream(
333 &self,
334 ) -> RelayChainResult<Pin<Box<dyn Stream<Item = PHeader> + Send>>> {
335 (**self).finality_notification_stream().await
336 }
337
338 async fn best_block_hash(&self) -> RelayChainResult<PHash> {
339 (**self).best_block_hash().await
340 }
341
342 async fn finalized_block_hash(&self) -> RelayChainResult<PHash> {
343 (**self).finalized_block_hash().await
344 }
345
346 async fn call_runtime_api(
347 &self,
348 method_name: &'static str,
349 hash: RelayHash,
350 payload: &[u8],
351 ) -> RelayChainResult<Vec<u8>> {
352 (**self).call_runtime_api(method_name, hash, payload).await
353 }
354
355 async fn is_major_syncing(&self) -> RelayChainResult<bool> {
356 (**self).is_major_syncing().await
357 }
358
359 fn overseer_handle(&self) -> RelayChainResult<OverseerHandle> {
360 (**self).overseer_handle()
361 }
362
363 async fn get_storage_by_key(
364 &self,
365 relay_parent: PHash,
366 key: &[u8],
367 ) -> RelayChainResult<Option<StorageValue>> {
368 (**self).get_storage_by_key(relay_parent, key).await
369 }
370
371 async fn prove_read(
372 &self,
373 relay_parent: PHash,
374 relevant_keys: &Vec<Vec<u8>>,
375 ) -> RelayChainResult<StorageProof> {
376 (**self).prove_read(relay_parent, relevant_keys).await
377 }
378
379 async fn prove_child_read(
380 &self,
381 relay_parent: PHash,
382 child_info: &ChildInfo,
383 child_keys: &[Vec<u8>],
384 ) -> RelayChainResult<StorageProof> {
385 (**self).prove_child_read(relay_parent, child_info, child_keys).await
386 }
387
388 async fn wait_for_block(&self, hash: PHash) -> RelayChainResult<()> {
389 (**self).wait_for_block(hash).await
390 }
391
392 async fn new_best_notification_stream(
393 &self,
394 ) -> RelayChainResult<Pin<Box<dyn Stream<Item = PHeader> + Send>>> {
395 (**self).new_best_notification_stream().await
396 }
397
398 async fn header(&self, block_id: BlockId) -> RelayChainResult<Option<PHeader>> {
399 (**self).header(block_id).await
400 }
401
402 async fn validation_code_hash(
403 &self,
404 relay_parent: PHash,
405 para_id: ParaId,
406 occupied_core_assumption: OccupiedCoreAssumption,
407 ) -> RelayChainResult<Option<ValidationCodeHash>> {
408 (**self)
409 .validation_code_hash(relay_parent, para_id, occupied_core_assumption)
410 .await
411 }
412
413 async fn availability_cores(
414 &self,
415 relay_parent: PHash,
416 ) -> RelayChainResult<Vec<CoreState<PHash, BlockNumber>>> {
417 (**self).availability_cores(relay_parent).await
418 }
419
420 async fn candidates_pending_availability(
421 &self,
422 block_id: PHash,
423 para_id: ParaId,
424 ) -> RelayChainResult<Vec<CommittedCandidateReceipt>> {
425 (**self).candidates_pending_availability(block_id, para_id).await
426 }
427
428 async fn version(&self, relay_parent: PHash) -> RelayChainResult<RuntimeVersion> {
429 (**self).version(relay_parent).await
430 }
431
432 async fn claim_queue(
433 &self,
434 relay_parent: PHash,
435 ) -> RelayChainResult<BTreeMap<CoreIndex, VecDeque<ParaId>>> {
436 (**self).claim_queue(relay_parent).await
437 }
438
439 async fn scheduling_lookahead(&self, relay_parent: PHash) -> RelayChainResult<u32> {
440 (**self).scheduling_lookahead(relay_parent).await
441 }
442
443 async fn candidate_events(&self, at: RelayHash) -> RelayChainResult<Vec<CandidateEvent>> {
444 (**self).candidate_events(at).await
445 }
446
447 async fn max_relay_parent_session_age(&self, at: RelayHash) -> RelayChainResult<u32> {
448 (**self).max_relay_parent_session_age(at).await
449 }
450
451 async fn node_features(&self, at: RelayHash) -> RelayChainResult<NodeFeatures> {
452 (**self).node_features(at).await
453 }
454
455 async fn ancestor_relay_parent_info(
456 &self,
457 at: RelayHash,
458 session_index: SessionIndex,
459 relay_parent: RelayHash,
460 ) -> RelayChainResult<Option<RelayParentInfo<RelayHash, BlockNumber>>> {
461 (**self).ancestor_relay_parent_info(at, session_index, relay_parent).await
462 }
463}
464
465pub async fn call_runtime_api<R>(
469 client: &(impl RelayChainInterface + ?Sized),
470 method_name: &'static str,
471 hash: RelayHash,
472 payload: impl Encode,
473) -> RelayChainResult<R>
474where
475 R: Decode,
476{
477 let res = client.call_runtime_api(method_name, hash, &payload.encode()).await?;
478 Decode::decode(&mut &*res).map_err(Into::into)
479}