1use async_trait::async_trait;
18use polkadot_primitives::{
19 async_backing, runtime_api::ParachainHost, slashing, ApprovalVotingParams, Block, BlockNumber,
20 CandidateCommitments, CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreIndex,
21 CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Hash, Header, Id,
22 InboundDownwardMessage, InboundHrmpMessage, NodeFeatures, OccupiedCoreAssumption,
23 PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo,
24 ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature,
25};
26use sc_client_api::{AuxStore, HeaderBackend};
27use sc_transaction_pool_api::OffchainTransactionPoolFactory;
28use sp_api::{ApiError, ApiExt, ProvideRuntimeApi};
29use sp_authority_discovery::AuthorityDiscoveryApi;
30use sp_blockchain::{BlockStatus, Info};
31use sp_consensus_babe::{BabeApi, Epoch};
32use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor};
33use std::{
34 collections::{BTreeMap, VecDeque},
35 sync::Arc,
36};
37
38#[async_trait]
46pub trait ChainApiBackend: Send + Sync {
47 async fn header(&self, hash: Hash) -> sp_blockchain::Result<Option<Header>>;
49 async fn info(&self) -> sp_blockchain::Result<Info<Block>>;
51 async fn number(
53 &self,
54 hash: Hash,
55 ) -> sp_blockchain::Result<Option<<Header as HeaderT>::Number>>;
56 async fn hash(&self, number: NumberFor<Block>) -> sp_blockchain::Result<Option<Hash>>;
58}
59
60#[async_trait]
61impl<T> ChainApiBackend for T
62where
63 T: HeaderBackend<Block>,
64{
65 async fn header(&self, hash: Hash) -> sp_blockchain::Result<Option<Header>> {
67 HeaderBackend::header(self, hash)
68 }
69
70 async fn info(&self) -> sp_blockchain::Result<Info<Block>> {
72 Ok(HeaderBackend::info(self))
73 }
74
75 async fn number(
77 &self,
78 hash: Hash,
79 ) -> sp_blockchain::Result<Option<<Header as HeaderT>::Number>> {
80 HeaderBackend::number(self, hash)
81 }
82
83 async fn hash(&self, number: NumberFor<Block>) -> sp_blockchain::Result<Option<Hash>> {
85 HeaderBackend::hash(self, number)
86 }
87}
88
89#[async_trait]
91pub trait RuntimeApiSubsystemClient {
92 async fn api_version_parachain_host(&self, at: Hash) -> Result<Option<u32>, ApiError>;
94
95 async fn validators(&self, at: Hash) -> Result<Vec<ValidatorId>, ApiError>;
99
100 async fn validator_groups(
104 &self,
105 at: Hash,
106 ) -> Result<(Vec<Vec<ValidatorIndex>>, GroupRotationInfo<BlockNumber>), ApiError>;
107
108 async fn availability_cores(
111 &self,
112 at: Hash,
113 ) -> Result<Vec<CoreState<Hash, BlockNumber>>, ApiError>;
114
115 async fn persisted_validation_data(
121 &self,
122 at: Hash,
123 para_id: Id,
124 assumption: OccupiedCoreAssumption,
125 ) -> Result<Option<PersistedValidationData<Hash, BlockNumber>>, ApiError>;
126
127 async fn assumed_validation_data(
131 &self,
132 at: Hash,
133 para_id: Id,
134 expected_persisted_validation_data_hash: Hash,
135 ) -> Result<Option<(PersistedValidationData<Hash, BlockNumber>, ValidationCodeHash)>, ApiError>;
136
137 async fn check_validation_outputs(
139 &self,
140 at: Hash,
141 para_id: Id,
142 outputs: CandidateCommitments,
143 ) -> Result<bool, ApiError>;
144
145 async fn session_index_for_child(&self, at: Hash) -> Result<SessionIndex, ApiError>;
149
150 async fn validation_code(
155 &self,
156 at: Hash,
157 para_id: Id,
158 assumption: OccupiedCoreAssumption,
159 ) -> Result<Option<ValidationCode>, ApiError>;
160
161 async fn candidate_pending_availability(
164 &self,
165 at: Hash,
166 para_id: Id,
167 ) -> Result<Option<CommittedCandidateReceipt<Hash>>, ApiError>;
168
169 async fn candidate_events(&self, at: Hash) -> Result<Vec<CandidateEvent<Hash>>, ApiError>;
171
172 async fn dmq_contents(
174 &self,
175 at: Hash,
176 recipient: Id,
177 ) -> Result<Vec<InboundDownwardMessage<BlockNumber>>, ApiError>;
178
179 async fn inbound_hrmp_channels_contents(
182 &self,
183 at: Hash,
184 recipient: Id,
185 ) -> Result<BTreeMap<Id, Vec<InboundHrmpMessage<BlockNumber>>>, ApiError>;
186
187 async fn validation_code_by_hash(
189 &self,
190 at: Hash,
191 hash: ValidationCodeHash,
192 ) -> Result<Option<ValidationCode>, ApiError>;
193
194 async fn on_chain_votes(&self, at: Hash)
196 -> Result<Option<ScrapedOnChainVotes<Hash>>, ApiError>;
197
198 async fn session_info(
204 &self,
205 at: Hash,
206 index: SessionIndex,
207 ) -> Result<Option<SessionInfo>, ApiError>;
208
209 async fn submit_pvf_check_statement(
213 &self,
214 at: Hash,
215 stmt: PvfCheckStatement,
216 signature: ValidatorSignature,
217 ) -> Result<(), ApiError>;
218
219 async fn pvfs_require_precheck(&self, at: Hash) -> Result<Vec<ValidationCodeHash>, ApiError>;
223
224 async fn validation_code_hash(
229 &self,
230 at: Hash,
231 para_id: Id,
232 assumption: OccupiedCoreAssumption,
233 ) -> Result<Option<ValidationCodeHash>, ApiError>;
234
235 async fn disputes(
240 &self,
241 at: Hash,
242 ) -> Result<Vec<(SessionIndex, CandidateHash, DisputeState<BlockNumber>)>, ApiError>;
243
244 async fn unapplied_slashes(
248 &self,
249 at: Hash,
250 ) -> Result<Vec<(SessionIndex, CandidateHash, slashing::PendingSlashes)>, ApiError>;
251
252 async fn key_ownership_proof(
256 &self,
257 at: Hash,
258 validator_id: ValidatorId,
259 ) -> Result<Option<slashing::OpaqueKeyOwnershipProof>, ApiError>;
260
261 async fn submit_report_dispute_lost(
266 &self,
267 at: Hash,
268 dispute_proof: slashing::DisputeProof,
269 key_ownership_proof: slashing::OpaqueKeyOwnershipProof,
270 ) -> Result<Option<()>, ApiError>;
271
272 async fn current_epoch(&self, at: Hash) -> Result<Epoch, ApiError>;
276
277 async fn authorities(
281 &self,
282 at: Hash,
283 ) -> std::result::Result<Vec<sp_authority_discovery::AuthorityId>, ApiError>;
284
285 async fn session_executor_params(
287 &self,
288 at: Hash,
289 session_index: SessionIndex,
290 ) -> Result<Option<ExecutorParams>, ApiError>;
291
292 async fn minimum_backing_votes(
295 &self,
296 at: Hash,
297 session_index: SessionIndex,
298 ) -> Result<u32, ApiError>;
299
300 async fn async_backing_params(
304 &self,
305 at: Hash,
306 ) -> Result<polkadot_primitives::AsyncBackingParams, ApiError>;
307
308 async fn para_backing_state(
311 &self,
312 at: Hash,
313 para_id: Id,
314 ) -> Result<Option<async_backing::BackingState>, ApiError>;
315
316 async fn disabled_validators(&self, at: Hash) -> Result<Vec<ValidatorIndex>, ApiError>;
320
321 async fn node_features(&self, at: Hash) -> Result<NodeFeatures, ApiError>;
324
325 async fn approval_voting_params(
328 &self,
329 at: Hash,
330 session_index: SessionIndex,
331 ) -> Result<ApprovalVotingParams, ApiError>;
332
333 async fn claim_queue(&self, at: Hash) -> Result<BTreeMap<CoreIndex, VecDeque<Id>>, ApiError>;
336
337 async fn candidates_pending_availability(
340 &self,
341 at: Hash,
342 para_id: Id,
343 ) -> Result<Vec<CommittedCandidateReceipt<Hash>>, ApiError>;
344}
345
346pub struct DefaultSubsystemClient<Client> {
348 client: Arc<Client>,
349 offchain_transaction_pool_factory: OffchainTransactionPoolFactory<Block>,
350}
351
352impl<Client> DefaultSubsystemClient<Client> {
353 pub fn new(
355 client: Arc<Client>,
356 offchain_transaction_pool_factory: OffchainTransactionPoolFactory<Block>,
357 ) -> Self {
358 Self { client, offchain_transaction_pool_factory }
359 }
360}
361
362#[async_trait]
363impl<Client> RuntimeApiSubsystemClient for DefaultSubsystemClient<Client>
364where
365 Client: ProvideRuntimeApi<Block> + Send + Sync,
366 Client::Api: ParachainHost<Block> + BabeApi<Block> + AuthorityDiscoveryApi<Block>,
367{
368 async fn validators(&self, at: Hash) -> Result<Vec<ValidatorId>, ApiError> {
369 self.client.runtime_api().validators(at)
370 }
371
372 async fn validator_groups(
373 &self,
374 at: Hash,
375 ) -> Result<(Vec<Vec<ValidatorIndex>>, GroupRotationInfo<BlockNumber>), ApiError> {
376 self.client.runtime_api().validator_groups(at)
377 }
378
379 async fn availability_cores(
380 &self,
381 at: Hash,
382 ) -> Result<Vec<CoreState<Hash, BlockNumber>>, ApiError> {
383 self.client
384 .runtime_api()
385 .availability_cores(at)
386 .map(|cores| cores.into_iter().map(|core| core.into()).collect::<Vec<_>>())
387 }
388
389 async fn persisted_validation_data(
390 &self,
391 at: Hash,
392 para_id: Id,
393 assumption: OccupiedCoreAssumption,
394 ) -> Result<Option<PersistedValidationData<Hash, BlockNumber>>, ApiError> {
395 self.client.runtime_api().persisted_validation_data(at, para_id, assumption)
396 }
397
398 async fn assumed_validation_data(
399 &self,
400 at: Hash,
401 para_id: Id,
402 expected_persisted_validation_data_hash: Hash,
403 ) -> Result<Option<(PersistedValidationData<Hash, BlockNumber>, ValidationCodeHash)>, ApiError>
404 {
405 self.client.runtime_api().assumed_validation_data(
406 at,
407 para_id,
408 expected_persisted_validation_data_hash,
409 )
410 }
411
412 async fn check_validation_outputs(
413 &self,
414 at: Hash,
415 para_id: Id,
416 outputs: CandidateCommitments,
417 ) -> Result<bool, ApiError> {
418 self.client.runtime_api().check_validation_outputs(at, para_id, outputs)
419 }
420
421 async fn session_index_for_child(&self, at: Hash) -> Result<SessionIndex, ApiError> {
422 self.client.runtime_api().session_index_for_child(at)
423 }
424
425 async fn validation_code(
426 &self,
427 at: Hash,
428 para_id: Id,
429 assumption: OccupiedCoreAssumption,
430 ) -> Result<Option<ValidationCode>, ApiError> {
431 self.client.runtime_api().validation_code(at, para_id, assumption)
432 }
433
434 async fn candidate_pending_availability(
435 &self,
436 at: Hash,
437 para_id: Id,
438 ) -> Result<Option<CommittedCandidateReceipt<Hash>>, ApiError> {
439 self.client
440 .runtime_api()
441 .candidate_pending_availability(at, para_id)
442 .map(|maybe_candidate| maybe_candidate.map(|candidate| candidate.into()))
443 }
444
445 async fn candidates_pending_availability(
446 &self,
447 at: Hash,
448 para_id: Id,
449 ) -> Result<Vec<CommittedCandidateReceipt<Hash>>, ApiError> {
450 self.client
451 .runtime_api()
452 .candidates_pending_availability(at, para_id)
453 .map(|candidates| {
454 candidates.into_iter().map(|candidate| candidate.into()).collect::<Vec<_>>()
455 })
456 }
457
458 async fn candidate_events(&self, at: Hash) -> Result<Vec<CandidateEvent<Hash>>, ApiError> {
459 self.client
460 .runtime_api()
461 .candidate_events(at)
462 .map(|events| events.into_iter().map(|event| event.into()).collect::<Vec<_>>())
463 }
464
465 async fn dmq_contents(
466 &self,
467 at: Hash,
468 recipient: Id,
469 ) -> Result<Vec<InboundDownwardMessage<BlockNumber>>, ApiError> {
470 self.client.runtime_api().dmq_contents(at, recipient)
471 }
472
473 async fn inbound_hrmp_channels_contents(
474 &self,
475 at: Hash,
476 recipient: Id,
477 ) -> Result<BTreeMap<Id, Vec<InboundHrmpMessage<BlockNumber>>>, ApiError> {
478 self.client.runtime_api().inbound_hrmp_channels_contents(at, recipient)
479 }
480
481 async fn validation_code_by_hash(
482 &self,
483 at: Hash,
484 hash: ValidationCodeHash,
485 ) -> Result<Option<ValidationCode>, ApiError> {
486 self.client.runtime_api().validation_code_by_hash(at, hash)
487 }
488
489 async fn on_chain_votes(
490 &self,
491 at: Hash,
492 ) -> Result<Option<ScrapedOnChainVotes<Hash>>, ApiError> {
493 self.client
494 .runtime_api()
495 .on_chain_votes(at)
496 .map(|maybe_votes| maybe_votes.map(|votes| votes.into()))
497 }
498
499 async fn session_executor_params(
500 &self,
501 at: Hash,
502 session_index: SessionIndex,
503 ) -> Result<Option<ExecutorParams>, ApiError> {
504 self.client.runtime_api().session_executor_params(at, session_index)
505 }
506
507 async fn session_info(
508 &self,
509 at: Hash,
510 index: SessionIndex,
511 ) -> Result<Option<SessionInfo>, ApiError> {
512 self.client.runtime_api().session_info(at, index)
513 }
514
515 async fn submit_pvf_check_statement(
516 &self,
517 at: Hash,
518 stmt: PvfCheckStatement,
519 signature: ValidatorSignature,
520 ) -> Result<(), ApiError> {
521 let mut runtime_api = self.client.runtime_api();
522
523 runtime_api.register_extension(
524 self.offchain_transaction_pool_factory.offchain_transaction_pool(at),
525 );
526
527 runtime_api.submit_pvf_check_statement(at, stmt, signature)
528 }
529
530 async fn pvfs_require_precheck(&self, at: Hash) -> Result<Vec<ValidationCodeHash>, ApiError> {
531 self.client.runtime_api().pvfs_require_precheck(at)
532 }
533
534 async fn validation_code_hash(
535 &self,
536 at: Hash,
537 para_id: Id,
538 assumption: OccupiedCoreAssumption,
539 ) -> Result<Option<ValidationCodeHash>, ApiError> {
540 self.client.runtime_api().validation_code_hash(at, para_id, assumption)
541 }
542
543 async fn current_epoch(&self, at: Hash) -> Result<Epoch, ApiError> {
544 self.client.runtime_api().current_epoch(at)
545 }
546
547 async fn authorities(
548 &self,
549 at: Hash,
550 ) -> std::result::Result<Vec<sp_authority_discovery::AuthorityId>, ApiError> {
551 self.client.runtime_api().authorities(at)
552 }
553
554 async fn api_version_parachain_host(&self, at: Hash) -> Result<Option<u32>, ApiError> {
555 self.client.runtime_api().api_version::<dyn ParachainHost<Block>>(at)
556 }
557
558 async fn disputes(
559 &self,
560 at: Hash,
561 ) -> Result<Vec<(SessionIndex, CandidateHash, DisputeState<BlockNumber>)>, ApiError> {
562 self.client.runtime_api().disputes(at)
563 }
564
565 async fn unapplied_slashes(
566 &self,
567 at: Hash,
568 ) -> Result<Vec<(SessionIndex, CandidateHash, slashing::PendingSlashes)>, ApiError> {
569 self.client.runtime_api().unapplied_slashes(at)
570 }
571
572 async fn key_ownership_proof(
573 &self,
574 at: Hash,
575 validator_id: ValidatorId,
576 ) -> Result<Option<slashing::OpaqueKeyOwnershipProof>, ApiError> {
577 self.client.runtime_api().key_ownership_proof(at, validator_id)
578 }
579
580 async fn submit_report_dispute_lost(
581 &self,
582 at: Hash,
583 dispute_proof: slashing::DisputeProof,
584 key_ownership_proof: slashing::OpaqueKeyOwnershipProof,
585 ) -> Result<Option<()>, ApiError> {
586 let mut runtime_api = self.client.runtime_api();
587
588 runtime_api.register_extension(
589 self.offchain_transaction_pool_factory.offchain_transaction_pool(at),
590 );
591
592 runtime_api.submit_report_dispute_lost(at, dispute_proof, key_ownership_proof)
593 }
594
595 async fn minimum_backing_votes(
596 &self,
597 at: Hash,
598 _session_index: SessionIndex,
599 ) -> Result<u32, ApiError> {
600 self.client.runtime_api().minimum_backing_votes(at)
601 }
602
603 async fn para_backing_state(
604 &self,
605 at: Hash,
606 para_id: Id,
607 ) -> Result<Option<async_backing::BackingState>, ApiError> {
608 self.client
609 .runtime_api()
610 .para_backing_state(at, para_id)
611 .map(|maybe_backing_state| {
612 maybe_backing_state.map(|backing_state| backing_state.into())
613 })
614 }
615
616 async fn async_backing_params(
617 &self,
618 at: Hash,
619 ) -> Result<async_backing::AsyncBackingParams, ApiError> {
620 self.client.runtime_api().async_backing_params(at)
621 }
622
623 async fn node_features(&self, at: Hash) -> Result<NodeFeatures, ApiError> {
624 self.client.runtime_api().node_features(at)
625 }
626
627 async fn disabled_validators(&self, at: Hash) -> Result<Vec<ValidatorIndex>, ApiError> {
628 self.client.runtime_api().disabled_validators(at)
629 }
630
631 async fn approval_voting_params(
633 &self,
634 at: Hash,
635 _session_index: SessionIndex,
636 ) -> Result<ApprovalVotingParams, ApiError> {
637 self.client.runtime_api().approval_voting_params(at)
638 }
639
640 async fn claim_queue(&self, at: Hash) -> Result<BTreeMap<CoreIndex, VecDeque<Id>>, ApiError> {
641 self.client.runtime_api().claim_queue(at)
642 }
643}
644
645impl<Client, Block> HeaderBackend<Block> for DefaultSubsystemClient<Client>
646where
647 Client: HeaderBackend<Block>,
648 Block: sp_runtime::traits::Block,
649{
650 fn header(
651 &self,
652 hash: Block::Hash,
653 ) -> sc_client_api::blockchain::Result<Option<Block::Header>> {
654 self.client.header(hash)
655 }
656
657 fn info(&self) -> Info<Block> {
658 self.client.info()
659 }
660
661 fn status(&self, hash: Block::Hash) -> sc_client_api::blockchain::Result<BlockStatus> {
662 self.client.status(hash)
663 }
664
665 fn number(
666 &self,
667 hash: Block::Hash,
668 ) -> sc_client_api::blockchain::Result<Option<<<Block as BlockT>::Header as HeaderT>::Number>>
669 {
670 self.client.number(hash)
671 }
672
673 fn hash(
674 &self,
675 number: NumberFor<Block>,
676 ) -> sc_client_api::blockchain::Result<Option<Block::Hash>> {
677 self.client.hash(number)
678 }
679}
680
681impl<Client> AuxStore for DefaultSubsystemClient<Client>
682where
683 Client: AuxStore,
684{
685 fn insert_aux<
686 'a,
687 'b: 'a,
688 'c: 'a,
689 I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
690 D: IntoIterator<Item = &'a &'b [u8]>,
691 >(
692 &self,
693 insert: I,
694 delete: D,
695 ) -> sp_blockchain::Result<()> {
696 self.client.insert_aux(insert, delete)
697 }
698
699 fn get_aux(&self, key: &[u8]) -> sp_blockchain::Result<Option<Vec<u8>>> {
700 self.client.get_aux(key)
701 }
702}