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 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
270#[async_trait]
271impl<T> RelayChainInterface for Arc<T>
272where
273 T: RelayChainInterface + ?Sized,
274{
275 async fn retrieve_dmq_contents(
276 &self,
277 para_id: ParaId,
278 relay_parent: PHash,
279 ) -> RelayChainResult<Vec<InboundDownwardMessage>> {
280 (**self).retrieve_dmq_contents(para_id, relay_parent).await
281 }
282
283 async fn retrieve_all_inbound_hrmp_channel_contents(
284 &self,
285 para_id: ParaId,
286 relay_parent: PHash,
287 ) -> RelayChainResult<BTreeMap<ParaId, Vec<InboundHrmpMessage>>> {
288 (**self).retrieve_all_inbound_hrmp_channel_contents(para_id, relay_parent).await
289 }
290
291 async fn persisted_validation_data(
292 &self,
293 block_id: PHash,
294 para_id: ParaId,
295 occupied_core_assumption: OccupiedCoreAssumption,
296 ) -> RelayChainResult<Option<PersistedValidationData>> {
297 (**self)
298 .persisted_validation_data(block_id, para_id, occupied_core_assumption)
299 .await
300 }
301
302 #[allow(deprecated)]
303 async fn candidate_pending_availability(
304 &self,
305 block_id: PHash,
306 para_id: ParaId,
307 ) -> RelayChainResult<Option<CommittedCandidateReceipt>> {
308 (**self).candidate_pending_availability(block_id, para_id).await
309 }
310
311 async fn session_index_for_child(&self, block_id: PHash) -> RelayChainResult<SessionIndex> {
312 (**self).session_index_for_child(block_id).await
313 }
314
315 async fn validators(&self, block_id: PHash) -> RelayChainResult<Vec<ValidatorId>> {
316 (**self).validators(block_id).await
317 }
318
319 async fn import_notification_stream(
320 &self,
321 ) -> RelayChainResult<Pin<Box<dyn Stream<Item = PHeader> + Send>>> {
322 (**self).import_notification_stream().await
323 }
324
325 async fn finality_notification_stream(
326 &self,
327 ) -> RelayChainResult<Pin<Box<dyn Stream<Item = PHeader> + Send>>> {
328 (**self).finality_notification_stream().await
329 }
330
331 async fn best_block_hash(&self) -> RelayChainResult<PHash> {
332 (**self).best_block_hash().await
333 }
334
335 async fn finalized_block_hash(&self) -> RelayChainResult<PHash> {
336 (**self).finalized_block_hash().await
337 }
338
339 async fn call_runtime_api(
340 &self,
341 method_name: &'static str,
342 hash: RelayHash,
343 payload: &[u8],
344 ) -> RelayChainResult<Vec<u8>> {
345 (**self).call_runtime_api(method_name, hash, payload).await
346 }
347
348 async fn is_major_syncing(&self) -> RelayChainResult<bool> {
349 (**self).is_major_syncing().await
350 }
351
352 fn overseer_handle(&self) -> RelayChainResult<OverseerHandle> {
353 (**self).overseer_handle()
354 }
355
356 async fn get_storage_by_key(
357 &self,
358 relay_parent: PHash,
359 key: &[u8],
360 ) -> RelayChainResult<Option<StorageValue>> {
361 (**self).get_storage_by_key(relay_parent, key).await
362 }
363
364 async fn prove_read(
365 &self,
366 relay_parent: PHash,
367 relevant_keys: &Vec<Vec<u8>>,
368 ) -> RelayChainResult<StorageProof> {
369 (**self).prove_read(relay_parent, relevant_keys).await
370 }
371
372 async fn prove_child_read(
373 &self,
374 relay_parent: PHash,
375 child_info: &ChildInfo,
376 child_keys: &[Vec<u8>],
377 ) -> RelayChainResult<StorageProof> {
378 (**self).prove_child_read(relay_parent, child_info, child_keys).await
379 }
380
381 async fn wait_for_block(&self, hash: PHash) -> RelayChainResult<()> {
382 (**self).wait_for_block(hash).await
383 }
384
385 async fn new_best_notification_stream(
386 &self,
387 ) -> RelayChainResult<Pin<Box<dyn Stream<Item = PHeader> + Send>>> {
388 (**self).new_best_notification_stream().await
389 }
390
391 async fn header(&self, block_id: BlockId) -> RelayChainResult<Option<PHeader>> {
392 (**self).header(block_id).await
393 }
394
395 async fn validation_code_hash(
396 &self,
397 relay_parent: PHash,
398 para_id: ParaId,
399 occupied_core_assumption: OccupiedCoreAssumption,
400 ) -> RelayChainResult<Option<ValidationCodeHash>> {
401 (**self)
402 .validation_code_hash(relay_parent, para_id, occupied_core_assumption)
403 .await
404 }
405
406 async fn availability_cores(
407 &self,
408 relay_parent: PHash,
409 ) -> RelayChainResult<Vec<CoreState<PHash, BlockNumber>>> {
410 (**self).availability_cores(relay_parent).await
411 }
412
413 async fn candidates_pending_availability(
414 &self,
415 block_id: PHash,
416 para_id: ParaId,
417 ) -> RelayChainResult<Vec<CommittedCandidateReceipt>> {
418 (**self).candidates_pending_availability(block_id, para_id).await
419 }
420
421 async fn version(&self, relay_parent: PHash) -> RelayChainResult<RuntimeVersion> {
422 (**self).version(relay_parent).await
423 }
424
425 async fn claim_queue(
426 &self,
427 relay_parent: PHash,
428 ) -> RelayChainResult<BTreeMap<CoreIndex, VecDeque<ParaId>>> {
429 (**self).claim_queue(relay_parent).await
430 }
431
432 async fn scheduling_lookahead(&self, relay_parent: PHash) -> RelayChainResult<u32> {
433 (**self).scheduling_lookahead(relay_parent).await
434 }
435
436 async fn candidate_events(&self, at: RelayHash) -> RelayChainResult<Vec<CandidateEvent>> {
437 (**self).candidate_events(at).await
438 }
439
440 async fn max_relay_parent_session_age(&self, at: RelayHash) -> RelayChainResult<u32> {
441 (**self).max_relay_parent_session_age(at).await
442 }
443
444 async fn node_features(&self, at: RelayHash) -> RelayChainResult<NodeFeatures> {
445 (**self).node_features(at).await
446 }
447}
448
449pub async fn call_runtime_api<R>(
453 client: &(impl RelayChainInterface + ?Sized),
454 method_name: &'static str,
455 hash: RelayHash,
456 payload: impl Encode,
457) -> RelayChainResult<R>
458where
459 R: Decode,
460{
461 let res = client.call_runtime_api(method_name, hash, &payload.encode()).await?;
462 Decode::decode(&mut &*res).map_err(Into::into)
463}