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::PendingSlashes,
365 )>,
366 ApiError,
367 > {
368 Ok(self.rpc_client.parachain_host_unapplied_slashes(at).await?)
369 }
370
371 async fn key_ownership_proof(
372 &self,
373 at: Hash,
374 validator_id: polkadot_primitives::ValidatorId,
375 ) -> Result<Option<slashing::OpaqueKeyOwnershipProof>, ApiError> {
376 Ok(self.rpc_client.parachain_host_key_ownership_proof(at, validator_id).await?)
377 }
378
379 async fn submit_report_dispute_lost(
380 &self,
381 at: Hash,
382 dispute_proof: slashing::DisputeProof,
383 key_ownership_proof: slashing::OpaqueKeyOwnershipProof,
384 ) -> Result<Option<()>, ApiError> {
385 Ok(self
386 .rpc_client
387 .parachain_host_submit_report_dispute_lost(at, dispute_proof, key_ownership_proof)
388 .await?)
389 }
390
391 async fn minimum_backing_votes(
392 &self,
393 at: Hash,
394 session_index: polkadot_primitives::SessionIndex,
395 ) -> Result<u32, ApiError> {
396 Ok(self.rpc_client.parachain_host_minimum_backing_votes(at, session_index).await?)
397 }
398
399 async fn disabled_validators(
400 &self,
401 at: Hash,
402 ) -> Result<Vec<polkadot_primitives::ValidatorIndex>, ApiError> {
403 Ok(self.rpc_client.parachain_host_disabled_validators(at).await?)
404 }
405
406 async fn async_backing_params(&self, at: Hash) -> Result<AsyncBackingParams, ApiError> {
407 Ok(self.rpc_client.parachain_host_async_backing_params(at).await?)
408 }
409
410 async fn para_backing_state(
411 &self,
412 at: Hash,
413 para_id: ParaId,
414 ) -> Result<Option<BackingState>, ApiError> {
415 Ok(self.rpc_client.parachain_host_para_backing_state(at, para_id).await?)
416 }
417
418 async fn approval_voting_params(
420 &self,
421 at: Hash,
422 session_index: polkadot_primitives::SessionIndex,
423 ) -> Result<ApprovalVotingParams, ApiError> {
424 Ok(self
425 .rpc_client
426 .parachain_host_staging_approval_voting_params(at, session_index)
427 .await?)
428 }
429
430 async fn node_features(&self, at: Hash) -> Result<NodeFeatures, ApiError> {
431 Ok(self.rpc_client.parachain_host_node_features(at).await?)
432 }
433
434 async fn claim_queue(
435 &self,
436 at: Hash,
437 ) -> Result<BTreeMap<CoreIndex, VecDeque<ParaId>>, ApiError> {
438 Ok(self.rpc_client.parachain_host_claim_queue(at).await?)
439 }
440
441 async fn candidates_pending_availability(
442 &self,
443 at: Hash,
444 para_id: cumulus_primitives_core::ParaId,
445 ) -> Result<Vec<polkadot_primitives::CommittedCandidateReceiptV2<Hash>>, sp_api::ApiError> {
446 Ok(self
447 .rpc_client
448 .parachain_host_candidates_pending_availability(at, para_id)
449 .await?)
450 }
451
452 async fn backing_constraints(
453 &self,
454 at: Hash,
455 para_id: ParaId,
456 ) -> Result<Option<Constraints>, ApiError> {
457 Ok(self.rpc_client.parachain_host_backing_constraints(at, para_id).await?)
458 }
459
460 async fn scheduling_lookahead(&self, at: Hash) -> Result<u32, sp_api::ApiError> {
461 Ok(self.rpc_client.parachain_host_scheduling_lookahead(at).await?)
462 }
463
464 async fn validation_code_bomb_limit(&self, at: Hash) -> Result<u32, sp_api::ApiError> {
465 Ok(self.rpc_client.parachain_host_validation_code_bomb_limit(at).await?)
466 }
467
468 async fn para_ids(&self, at: Hash) -> Result<Vec<ParaId>, sp_api::ApiError> {
469 Ok(self.rpc_client.parachain_host_para_ids(at).await?)
470 }
471}
472
473#[async_trait::async_trait]
474impl AuthorityDiscovery<Block> for BlockChainRpcClient {
475 async fn authorities(
476 &self,
477 at: Hash,
478 ) -> std::result::Result<Vec<polkadot_primitives::AuthorityDiscoveryId>, sp_api::ApiError> {
479 let result = self.rpc_client.authority_discovery_authorities(at).await?;
480 Ok(result)
481 }
482
483 async fn best_hash(&self) -> std::result::Result<Hash, AuthorityDiscoveryError> {
484 self.block_get_hash(None)
485 .await
486 .ok()
487 .flatten()
488 .ok_or_else(|| AuthorityDiscoveryError::BestBlockFetchingError)
489 }
490}
491
492impl BlockChainRpcClient {
493 pub async fn import_notification_stream(
494 &self,
495 ) -> RelayChainResult<Pin<Box<dyn Stream<Item = Header> + Send>>> {
496 Ok(self.rpc_client.get_imported_heads_stream()?.boxed())
497 }
498
499 pub async fn finality_notification_stream(
500 &self,
501 ) -> RelayChainResult<Pin<Box<dyn Stream<Item = Header> + Send>>> {
502 Ok(self.rpc_client.get_finalized_heads_stream()?.boxed())
503 }
504}
505
506impl AuxStore for BlockChainRpcClient {
509 fn insert_aux<
510 'a,
511 'b: 'a,
512 'c: 'a,
513 I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
514 D: IntoIterator<Item = &'a &'b [u8]>,
515 >(
516 &self,
517 _insert: I,
518 _delete: D,
519 ) -> sp_blockchain::Result<()> {
520 unimplemented!("Not supported on the RPC collator")
521 }
522
523 fn get_aux(&self, _key: &[u8]) -> sp_blockchain::Result<Option<Vec<u8>>> {
524 unimplemented!("Not supported on the RPC collator")
525 }
526}