1use std::{
19 collections::{BTreeMap, VecDeque},
20 pin::Pin,
21};
22
23use cumulus_primitives_core::{InboundDownwardMessage, ParaId, PersistedValidationData};
24use cumulus_relay_chain_interface::{RelayChainError, RelayChainResult};
25use cumulus_relay_chain_rpc_interface::RelayChainRpcClient;
26use futures::{Stream, StreamExt};
27use polkadot_core_primitives::{Block, BlockNumber, Hash, Header};
28use polkadot_overseer::{ChainApiBackend, RuntimeApiSubsystemClient};
29use polkadot_primitives::{
30 async_backing::{AsyncBackingParams, BackingState, Constraints},
31 slashing, ApprovalVotingParams, CoreIndex, NodeFeatures,
32};
33use sc_authority_discovery::{AuthorityDiscovery, Error as AuthorityDiscoveryError};
34use sc_client_api::AuxStore;
35use sp_api::{ApiError, RuntimeApiInfo};
36use sp_blockchain::Info;
37use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor};
38
39#[derive(Clone)]
40pub struct BlockChainRpcClient {
41 rpc_client: RelayChainRpcClient,
42}
43
44impl BlockChainRpcClient {
45 pub fn new(rpc_client: RelayChainRpcClient) -> Self {
46 Self { rpc_client }
47 }
48
49 pub async fn chain_get_header(
50 &self,
51 hash: Option<Hash>,
52 ) -> Result<Option<Header>, RelayChainError> {
53 self.rpc_client.chain_get_header(hash).await
54 }
55
56 pub async fn block_get_hash(
57 &self,
58 number: Option<BlockNumber>,
59 ) -> Result<Option<Hash>, RelayChainError> {
60 self.rpc_client.chain_get_block_hash(number).await
61 }
62}
63
64#[async_trait::async_trait]
65impl ChainApiBackend for BlockChainRpcClient {
66 async fn header(
67 &self,
68 hash: <Block as BlockT>::Hash,
69 ) -> sp_blockchain::Result<Option<<Block as BlockT>::Header>> {
70 Ok(self.rpc_client.chain_get_header(Some(hash)).await?)
71 }
72
73 async fn info(&self) -> sp_blockchain::Result<Info<Block>> {
74 let (best_header_opt, genesis_hash, finalized_head) = futures::try_join!(
75 self.rpc_client.chain_get_header(None),
76 self.rpc_client.chain_get_head(Some(0)),
77 self.rpc_client.chain_get_finalized_head()
78 )?;
79 let best_header = best_header_opt.ok_or_else(|| {
80 RelayChainError::GenericError(
81 "Unable to retrieve best header from relay chain.".to_string(),
82 )
83 })?;
84
85 let finalized_header =
86 self.rpc_client.chain_get_header(Some(finalized_head)).await?.ok_or_else(|| {
87 RelayChainError::GenericError(
88 "Unable to retrieve finalized header from relay chain.".to_string(),
89 )
90 })?;
91 Ok(Info {
92 best_hash: best_header.hash(),
93 best_number: best_header.number,
94 genesis_hash,
95 finalized_hash: finalized_head,
96 finalized_number: finalized_header.number,
97 finalized_state: Some((finalized_header.hash(), finalized_header.number)),
98 number_leaves: 1,
99 block_gap: None,
100 })
101 }
102
103 async fn number(
104 &self,
105 hash: <Block as BlockT>::Hash,
106 ) -> sp_blockchain::Result<Option<<<Block as BlockT>::Header as HeaderT>::Number>> {
107 Ok(self
108 .rpc_client
109 .chain_get_header(Some(hash))
110 .await?
111 .map(|maybe_header| maybe_header.number))
112 }
113
114 async fn hash(
115 &self,
116 number: NumberFor<Block>,
117 ) -> sp_blockchain::Result<Option<<Block as BlockT>::Hash>> {
118 Ok(self.rpc_client.chain_get_block_hash(number.into()).await?)
119 }
120}
121
122#[async_trait::async_trait]
123impl RuntimeApiSubsystemClient for BlockChainRpcClient {
124 async fn validators(
125 &self,
126 at: Hash,
127 ) -> Result<Vec<polkadot_primitives::ValidatorId>, sp_api::ApiError> {
128 Ok(self.rpc_client.parachain_host_validators(at).await?)
129 }
130
131 async fn validator_groups(
132 &self,
133 at: Hash,
134 ) -> Result<
135 (
136 Vec<Vec<polkadot_primitives::ValidatorIndex>>,
137 polkadot_primitives::GroupRotationInfo<BlockNumber>,
138 ),
139 sp_api::ApiError,
140 > {
141 Ok(self.rpc_client.parachain_host_validator_groups(at).await?)
142 }
143
144 async fn availability_cores(
145 &self,
146 at: Hash,
147 ) -> Result<
148 Vec<polkadot_primitives::CoreState<Hash, polkadot_core_primitives::BlockNumber>>,
149 sp_api::ApiError,
150 > {
151 Ok(self.rpc_client.parachain_host_availability_cores(at).await?)
152 }
153
154 async fn persisted_validation_data(
155 &self,
156 at: Hash,
157 para_id: ParaId,
158 assumption: polkadot_primitives::OccupiedCoreAssumption,
159 ) -> Result<Option<PersistedValidationData<Hash, BlockNumber>>, sp_api::ApiError> {
160 Ok(self
161 .rpc_client
162 .parachain_host_persisted_validation_data(at, para_id, assumption)
163 .await?)
164 }
165
166 async fn assumed_validation_data(
167 &self,
168 at: Hash,
169 para_id: ParaId,
170 expected_persisted_validation_data_hash: Hash,
171 ) -> Result<
172 Option<(
173 PersistedValidationData<Hash, BlockNumber>,
174 polkadot_primitives::ValidationCodeHash,
175 )>,
176 sp_api::ApiError,
177 > {
178 Ok(self
179 .rpc_client
180 .parachain_host_assumed_validation_data(
181 at,
182 para_id,
183 expected_persisted_validation_data_hash,
184 )
185 .await?)
186 }
187
188 async fn check_validation_outputs(
189 &self,
190 at: Hash,
191 para_id: ParaId,
192 outputs: polkadot_primitives::CandidateCommitments,
193 ) -> Result<bool, sp_api::ApiError> {
194 Ok(self
195 .rpc_client
196 .parachain_host_check_validation_outputs(at, para_id, outputs)
197 .await?)
198 }
199
200 async fn session_index_for_child(
201 &self,
202 at: Hash,
203 ) -> Result<polkadot_primitives::SessionIndex, sp_api::ApiError> {
204 Ok(self.rpc_client.parachain_host_session_index_for_child(at).await?)
205 }
206
207 async fn validation_code(
208 &self,
209 at: Hash,
210 para_id: ParaId,
211 assumption: polkadot_primitives::OccupiedCoreAssumption,
212 ) -> Result<Option<polkadot_primitives::ValidationCode>, sp_api::ApiError> {
213 Ok(self.rpc_client.parachain_host_validation_code(at, para_id, assumption).await?)
214 }
215
216 async fn candidate_pending_availability(
217 &self,
218 at: Hash,
219 para_id: cumulus_primitives_core::ParaId,
220 ) -> Result<Option<polkadot_primitives::CommittedCandidateReceiptV2<Hash>>, sp_api::ApiError> {
221 Ok(self
222 .rpc_client
223 .parachain_host_candidate_pending_availability(at, para_id)
224 .await?)
225 }
226
227 async fn candidate_events(
228 &self,
229 at: Hash,
230 ) -> Result<Vec<polkadot_primitives::CandidateEvent<Hash>>, sp_api::ApiError> {
231 Ok(self.rpc_client.parachain_host_candidate_events(at).await?)
232 }
233
234 async fn dmq_contents(
235 &self,
236 at: Hash,
237 recipient: ParaId,
238 ) -> Result<Vec<InboundDownwardMessage<BlockNumber>>, sp_api::ApiError> {
239 Ok(self.rpc_client.parachain_host_dmq_contents(recipient, at).await?)
240 }
241
242 async fn inbound_hrmp_channels_contents(
243 &self,
244 at: Hash,
245 recipient: ParaId,
246 ) -> Result<
247 std::collections::BTreeMap<
248 ParaId,
249 Vec<polkadot_core_primitives::InboundHrmpMessage<BlockNumber>>,
250 >,
251 sp_api::ApiError,
252 > {
253 Ok(self
254 .rpc_client
255 .parachain_host_inbound_hrmp_channels_contents(recipient, at)
256 .await?)
257 }
258
259 async fn validation_code_by_hash(
260 &self,
261 at: Hash,
262 validation_code_hash: polkadot_primitives::ValidationCodeHash,
263 ) -> Result<Option<polkadot_primitives::ValidationCode>, sp_api::ApiError> {
264 Ok(self
265 .rpc_client
266 .parachain_host_validation_code_by_hash(at, validation_code_hash)
267 .await?)
268 }
269
270 async fn on_chain_votes(
271 &self,
272 at: Hash,
273 ) -> Result<Option<polkadot_primitives::ScrapedOnChainVotes<Hash>>, sp_api::ApiError> {
274 Ok(self.rpc_client.parachain_host_on_chain_votes(at).await?)
275 }
276
277 async fn session_info(
278 &self,
279 at: Hash,
280 index: polkadot_primitives::SessionIndex,
281 ) -> Result<Option<polkadot_primitives::SessionInfo>, sp_api::ApiError> {
282 Ok(self.rpc_client.parachain_host_session_info(at, index).await?)
283 }
284
285 async fn session_executor_params(
286 &self,
287 at: Hash,
288 session_index: polkadot_primitives::SessionIndex,
289 ) -> Result<Option<polkadot_primitives::ExecutorParams>, sp_api::ApiError> {
290 Ok(self
291 .rpc_client
292 .parachain_host_session_executor_params(at, session_index)
293 .await?)
294 }
295
296 async fn submit_pvf_check_statement(
297 &self,
298 at: Hash,
299 stmt: polkadot_primitives::PvfCheckStatement,
300 signature: polkadot_primitives::ValidatorSignature,
301 ) -> Result<(), sp_api::ApiError> {
302 Ok(self
303 .rpc_client
304 .parachain_host_submit_pvf_check_statement(at, stmt, signature)
305 .await?)
306 }
307
308 async fn pvfs_require_precheck(
309 &self,
310 at: Hash,
311 ) -> Result<Vec<polkadot_primitives::ValidationCodeHash>, sp_api::ApiError> {
312 Ok(self.rpc_client.parachain_host_pvfs_require_precheck(at).await?)
313 }
314
315 async fn validation_code_hash(
316 &self,
317 at: Hash,
318 para_id: ParaId,
319 assumption: polkadot_primitives::OccupiedCoreAssumption,
320 ) -> Result<Option<polkadot_primitives::ValidationCodeHash>, sp_api::ApiError> {
321 Ok(self
322 .rpc_client
323 .parachain_host_validation_code_hash(at, para_id, assumption)
324 .await?)
325 }
326
327 async fn current_epoch(&self, at: Hash) -> Result<sp_consensus_babe::Epoch, sp_api::ApiError> {
328 Ok(self.rpc_client.babe_api_current_epoch(at).await?)
329 }
330
331 async fn authorities(
332 &self,
333 at: Hash,
334 ) -> std::result::Result<Vec<polkadot_primitives::AuthorityDiscoveryId>, sp_api::ApiError> {
335 Ok(self.rpc_client.authority_discovery_authorities(at).await?)
336 }
337
338 async fn api_version_parachain_host(&self, at: Hash) -> Result<Option<u32>, sp_api::ApiError> {
339 let api_id = <dyn polkadot_primitives::runtime_api::ParachainHost<Block>>::ID;
340 Ok(self.rpc_client.runtime_version(at).await.map(|v| v.api_version(&api_id))?)
341 }
342
343 async fn disputes(
344 &self,
345 at: Hash,
346 ) -> Result<
347 Vec<(
348 polkadot_primitives::SessionIndex,
349 polkadot_primitives::CandidateHash,
350 polkadot_primitives::DisputeState<polkadot_primitives::BlockNumber>,
351 )>,
352 ApiError,
353 > {
354 Ok(self.rpc_client.parachain_host_disputes(at).await?)
355 }
356
357 async fn unapplied_slashes(
358 &self,
359 at: Hash,
360 ) -> Result<
361 Vec<(
362 polkadot_primitives::SessionIndex,
363 polkadot_primitives::CandidateHash,
364 slashing::LegacyPendingSlashes,
365 )>,
366 ApiError,
367 > {
368 Ok(self.rpc_client.parachain_host_unapplied_slashes(at).await?)
369 }
370
371 async fn unapplied_slashes_v2(
372 &self,
373 at: Hash,
374 ) -> Result<
375 Vec<(
376 polkadot_primitives::SessionIndex,
377 polkadot_primitives::CandidateHash,
378 slashing::PendingSlashes,
379 )>,
380 ApiError,
381 > {
382 Ok(self.rpc_client.parachain_host_unapplied_slashes_v2(at).await?)
383 }
384
385 async fn key_ownership_proof(
386 &self,
387 at: Hash,
388 validator_id: polkadot_primitives::ValidatorId,
389 ) -> Result<Option<slashing::OpaqueKeyOwnershipProof>, ApiError> {
390 Ok(self.rpc_client.parachain_host_key_ownership_proof(at, validator_id).await?)
391 }
392
393 async fn submit_report_dispute_lost(
394 &self,
395 at: Hash,
396 dispute_proof: slashing::DisputeProof,
397 key_ownership_proof: slashing::OpaqueKeyOwnershipProof,
398 ) -> Result<Option<()>, ApiError> {
399 Ok(self
400 .rpc_client
401 .parachain_host_submit_report_dispute_lost(at, dispute_proof, key_ownership_proof)
402 .await?)
403 }
404
405 async fn minimum_backing_votes(
406 &self,
407 at: Hash,
408 session_index: polkadot_primitives::SessionIndex,
409 ) -> Result<u32, ApiError> {
410 Ok(self.rpc_client.parachain_host_minimum_backing_votes(at, session_index).await?)
411 }
412
413 async fn disabled_validators(
414 &self,
415 at: Hash,
416 ) -> Result<Vec<polkadot_primitives::ValidatorIndex>, ApiError> {
417 Ok(self.rpc_client.parachain_host_disabled_validators(at).await?)
418 }
419
420 async fn async_backing_params(&self, at: Hash) -> Result<AsyncBackingParams, ApiError> {
421 Ok(self.rpc_client.parachain_host_async_backing_params(at).await?)
422 }
423
424 async fn para_backing_state(
425 &self,
426 at: Hash,
427 para_id: ParaId,
428 ) -> Result<Option<BackingState>, ApiError> {
429 Ok(self.rpc_client.parachain_host_para_backing_state(at, para_id).await?)
430 }
431
432 async fn approval_voting_params(
434 &self,
435 at: Hash,
436 session_index: polkadot_primitives::SessionIndex,
437 ) -> Result<ApprovalVotingParams, ApiError> {
438 Ok(self
439 .rpc_client
440 .parachain_host_staging_approval_voting_params(at, session_index)
441 .await?)
442 }
443
444 async fn node_features(&self, at: Hash) -> Result<NodeFeatures, ApiError> {
445 Ok(self.rpc_client.parachain_host_node_features(at).await?)
446 }
447
448 async fn claim_queue(
449 &self,
450 at: Hash,
451 ) -> Result<BTreeMap<CoreIndex, VecDeque<ParaId>>, ApiError> {
452 Ok(self.rpc_client.parachain_host_claim_queue(at).await?)
453 }
454
455 async fn candidates_pending_availability(
456 &self,
457 at: Hash,
458 para_id: cumulus_primitives_core::ParaId,
459 ) -> Result<Vec<polkadot_primitives::CommittedCandidateReceiptV2<Hash>>, sp_api::ApiError> {
460 Ok(self
461 .rpc_client
462 .parachain_host_candidates_pending_availability(at, para_id)
463 .await?)
464 }
465
466 async fn backing_constraints(
467 &self,
468 at: Hash,
469 para_id: ParaId,
470 ) -> Result<Option<Constraints>, ApiError> {
471 Ok(self.rpc_client.parachain_host_backing_constraints(at, para_id).await?)
472 }
473
474 async fn scheduling_lookahead(&self, at: Hash) -> Result<u32, sp_api::ApiError> {
475 Ok(self.rpc_client.parachain_host_scheduling_lookahead(at).await?)
476 }
477
478 async fn validation_code_bomb_limit(&self, at: Hash) -> Result<u32, sp_api::ApiError> {
479 Ok(self.rpc_client.parachain_host_validation_code_bomb_limit(at).await?)
480 }
481
482 async fn para_ids(&self, at: Hash) -> Result<Vec<ParaId>, sp_api::ApiError> {
483 Ok(self.rpc_client.parachain_host_para_ids(at).await?)
484 }
485
486 async fn max_relay_parent_session_age(&self, at: Hash) -> Result<u32, sp_api::ApiError> {
487 Ok(self.rpc_client.parachain_host_max_relay_parent_session_age(at).await?)
488 }
489
490 async fn ancestor_relay_parent_info(
491 &self,
492 at: Hash,
493 session_index: polkadot_primitives::SessionIndex,
494 relay_parent: Hash,
495 ) -> Result<
496 Option<polkadot_primitives::vstaging::RelayParentInfo<Hash, BlockNumber>>,
497 sp_api::ApiError,
498 > {
499 Ok(self
500 .rpc_client
501 .parachain_host_ancestor_relay_parent_info(at, session_index, relay_parent)
502 .await?)
503 }
504}
505
506#[async_trait::async_trait]
507impl AuthorityDiscovery<Block> for BlockChainRpcClient {
508 async fn authorities(
509 &self,
510 at: Hash,
511 ) -> std::result::Result<Vec<polkadot_primitives::AuthorityDiscoveryId>, sp_api::ApiError> {
512 let result = self.rpc_client.authority_discovery_authorities(at).await?;
513 Ok(result)
514 }
515
516 async fn best_hash(&self) -> std::result::Result<Hash, AuthorityDiscoveryError> {
517 self.block_get_hash(None)
518 .await
519 .ok()
520 .flatten()
521 .ok_or_else(|| AuthorityDiscoveryError::BestBlockFetchingError)
522 }
523}
524
525impl BlockChainRpcClient {
526 pub async fn import_notification_stream(
527 &self,
528 ) -> RelayChainResult<Pin<Box<dyn Stream<Item = Header> + Send>>> {
529 Ok(self.rpc_client.get_imported_heads_stream()?.boxed())
530 }
531
532 pub async fn finality_notification_stream(
533 &self,
534 ) -> RelayChainResult<Pin<Box<dyn Stream<Item = Header> + Send>>> {
535 Ok(self.rpc_client.get_finalized_heads_stream()?.boxed())
536 }
537}
538
539impl AuxStore for BlockChainRpcClient {
542 fn insert_aux<
543 'a,
544 'b: 'a,
545 'c: 'a,
546 I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
547 D: IntoIterator<Item = &'a &'b [u8]>,
548 >(
549 &self,
550 _insert: I,
551 _delete: D,
552 ) -> sp_blockchain::Result<()> {
553 unimplemented!("Not supported on the RPC collator")
554 }
555
556 fn get_aux(&self, _key: &[u8]) -> sp_blockchain::Result<Option<Vec<u8>>> {
557 unimplemented!("Not supported on the RPC collator")
558 }
559}