548 lines
15 KiB
Rust
548 lines
15 KiB
Rust
// Copyright (C) Parity Technologies (UK) Ltd.
|
|
// This file is part of Pezcumulus.
|
|
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
|
|
|
|
// Pezcumulus is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
|
|
// Pezcumulus is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Pezcumulus. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
use std::{
|
|
collections::{BTreeMap, VecDeque},
|
|
pin::Pin,
|
|
};
|
|
|
|
use futures::{Stream, StreamExt};
|
|
use pezcumulus_primitives_core::{InboundDownwardMessage, ParaId, PersistedValidationData};
|
|
use pezcumulus_relay_chain_interface::{RelayChainError, RelayChainResult};
|
|
use pezcumulus_relay_chain_rpc_interface::RelayChainRpcClient;
|
|
use pezkuwi_core_primitives::{Block, BlockNumber, Hash, Header};
|
|
use pezkuwi_overseer::{ChainApiBackend, RuntimeApiSubsystemClient};
|
|
use pezkuwi_primitives::{
|
|
async_backing::{AsyncBackingParams, BackingState, Constraints},
|
|
slashing, ApprovalVotingParams, CoreIndex, NodeFeatures,
|
|
};
|
|
use pezsc_authority_discovery::{AuthorityDiscovery, Error as AuthorityDiscoveryError};
|
|
use pezsc_client_api::AuxStore;
|
|
use pezsp_api::{ApiError, RuntimeApiInfo};
|
|
use pezsp_blockchain::Info;
|
|
use pezsp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor};
|
|
|
|
#[derive(Clone)]
|
|
pub struct BlockChainRpcClient {
|
|
rpc_client: RelayChainRpcClient,
|
|
}
|
|
|
|
impl BlockChainRpcClient {
|
|
pub fn new(rpc_client: RelayChainRpcClient) -> Self {
|
|
Self { rpc_client }
|
|
}
|
|
|
|
pub async fn chain_get_header(
|
|
&self,
|
|
hash: Option<Hash>,
|
|
) -> Result<Option<Header>, RelayChainError> {
|
|
self.rpc_client.chain_get_header(hash).await
|
|
}
|
|
|
|
pub async fn block_get_hash(
|
|
&self,
|
|
number: Option<BlockNumber>,
|
|
) -> Result<Option<Hash>, RelayChainError> {
|
|
self.rpc_client.chain_get_block_hash(number).await
|
|
}
|
|
}
|
|
|
|
#[async_trait::async_trait]
|
|
impl ChainApiBackend for BlockChainRpcClient {
|
|
async fn header(
|
|
&self,
|
|
hash: <Block as BlockT>::Hash,
|
|
) -> pezsp_blockchain::Result<Option<<Block as BlockT>::Header>> {
|
|
Ok(self.rpc_client.chain_get_header(Some(hash)).await?)
|
|
}
|
|
|
|
async fn info(&self) -> pezsp_blockchain::Result<Info<Block>> {
|
|
let (best_header_opt, genesis_hash, finalized_head) = futures::try_join!(
|
|
self.rpc_client.chain_get_header(None),
|
|
self.rpc_client.chain_get_head(Some(0)),
|
|
self.rpc_client.chain_get_finalized_head()
|
|
)?;
|
|
let best_header = best_header_opt.ok_or_else(|| {
|
|
RelayChainError::GenericError(
|
|
"Unable to retrieve best header from relay chain.".to_string(),
|
|
)
|
|
})?;
|
|
|
|
let finalized_header =
|
|
self.rpc_client.chain_get_header(Some(finalized_head)).await?.ok_or_else(|| {
|
|
RelayChainError::GenericError(
|
|
"Unable to retrieve finalized header from relay chain.".to_string(),
|
|
)
|
|
})?;
|
|
Ok(Info {
|
|
best_hash: best_header.hash(),
|
|
best_number: best_header.number,
|
|
genesis_hash,
|
|
finalized_hash: finalized_head,
|
|
finalized_number: finalized_header.number,
|
|
finalized_state: Some((finalized_header.hash(), finalized_header.number)),
|
|
number_leaves: 1,
|
|
block_gap: None,
|
|
})
|
|
}
|
|
|
|
async fn number(
|
|
&self,
|
|
hash: <Block as BlockT>::Hash,
|
|
) -> pezsp_blockchain::Result<Option<<<Block as BlockT>::Header as HeaderT>::Number>> {
|
|
Ok(self
|
|
.rpc_client
|
|
.chain_get_header(Some(hash))
|
|
.await?
|
|
.map(|maybe_header| maybe_header.number))
|
|
}
|
|
|
|
async fn hash(
|
|
&self,
|
|
number: NumberFor<Block>,
|
|
) -> pezsp_blockchain::Result<Option<<Block as BlockT>::Hash>> {
|
|
Ok(self.rpc_client.chain_get_block_hash(number.into()).await?)
|
|
}
|
|
}
|
|
|
|
#[async_trait::async_trait]
|
|
impl RuntimeApiSubsystemClient for BlockChainRpcClient {
|
|
async fn validators(
|
|
&self,
|
|
at: Hash,
|
|
) -> Result<Vec<pezkuwi_primitives::ValidatorId>, pezsp_api::ApiError> {
|
|
Ok(self.rpc_client.teyrchain_host_validators(at).await?)
|
|
}
|
|
|
|
async fn validator_groups(
|
|
&self,
|
|
at: Hash,
|
|
) -> Result<
|
|
(
|
|
Vec<Vec<pezkuwi_primitives::ValidatorIndex>>,
|
|
pezkuwi_primitives::GroupRotationInfo<BlockNumber>,
|
|
),
|
|
pezsp_api::ApiError,
|
|
> {
|
|
Ok(self.rpc_client.teyrchain_host_validator_groups(at).await?)
|
|
}
|
|
|
|
async fn availability_cores(
|
|
&self,
|
|
at: Hash,
|
|
) -> Result<
|
|
Vec<pezkuwi_primitives::CoreState<Hash, pezkuwi_core_primitives::BlockNumber>>,
|
|
pezsp_api::ApiError,
|
|
> {
|
|
Ok(self.rpc_client.teyrchain_host_availability_cores(at).await?)
|
|
}
|
|
|
|
async fn persisted_validation_data(
|
|
&self,
|
|
at: Hash,
|
|
para_id: ParaId,
|
|
assumption: pezkuwi_primitives::OccupiedCoreAssumption,
|
|
) -> Result<Option<PersistedValidationData<Hash, BlockNumber>>, pezsp_api::ApiError> {
|
|
Ok(self
|
|
.rpc_client
|
|
.teyrchain_host_persisted_validation_data(at, para_id, assumption)
|
|
.await?)
|
|
}
|
|
|
|
async fn assumed_validation_data(
|
|
&self,
|
|
at: Hash,
|
|
para_id: ParaId,
|
|
expected_persisted_validation_data_hash: Hash,
|
|
) -> Result<
|
|
Option<(
|
|
PersistedValidationData<Hash, BlockNumber>,
|
|
pezkuwi_primitives::ValidationCodeHash,
|
|
)>,
|
|
pezsp_api::ApiError,
|
|
> {
|
|
Ok(self
|
|
.rpc_client
|
|
.teyrchain_host_assumed_validation_data(
|
|
at,
|
|
para_id,
|
|
expected_persisted_validation_data_hash,
|
|
)
|
|
.await?)
|
|
}
|
|
|
|
async fn check_validation_outputs(
|
|
&self,
|
|
at: Hash,
|
|
para_id: ParaId,
|
|
outputs: pezkuwi_primitives::CandidateCommitments,
|
|
) -> Result<bool, pezsp_api::ApiError> {
|
|
Ok(self
|
|
.rpc_client
|
|
.teyrchain_host_check_validation_outputs(at, para_id, outputs)
|
|
.await?)
|
|
}
|
|
|
|
async fn session_index_for_child(
|
|
&self,
|
|
at: Hash,
|
|
) -> Result<pezkuwi_primitives::SessionIndex, pezsp_api::ApiError> {
|
|
Ok(self.rpc_client.teyrchain_host_session_index_for_child(at).await?)
|
|
}
|
|
|
|
async fn validation_code(
|
|
&self,
|
|
at: Hash,
|
|
para_id: ParaId,
|
|
assumption: pezkuwi_primitives::OccupiedCoreAssumption,
|
|
) -> Result<Option<pezkuwi_primitives::ValidationCode>, pezsp_api::ApiError> {
|
|
Ok(self.rpc_client.teyrchain_host_validation_code(at, para_id, assumption).await?)
|
|
}
|
|
|
|
async fn candidate_pending_availability(
|
|
&self,
|
|
at: Hash,
|
|
para_id: pezcumulus_primitives_core::ParaId,
|
|
) -> Result<Option<pezkuwi_primitives::CommittedCandidateReceiptV2<Hash>>, pezsp_api::ApiError>
|
|
{
|
|
Ok(self
|
|
.rpc_client
|
|
.teyrchain_host_candidate_pending_availability(at, para_id)
|
|
.await?)
|
|
}
|
|
|
|
async fn candidate_events(
|
|
&self,
|
|
at: Hash,
|
|
) -> Result<Vec<pezkuwi_primitives::CandidateEvent<Hash>>, pezsp_api::ApiError> {
|
|
Ok(self.rpc_client.teyrchain_host_candidate_events(at).await?)
|
|
}
|
|
|
|
async fn dmq_contents(
|
|
&self,
|
|
at: Hash,
|
|
recipient: ParaId,
|
|
) -> Result<Vec<InboundDownwardMessage<BlockNumber>>, pezsp_api::ApiError> {
|
|
Ok(self.rpc_client.teyrchain_host_dmq_contents(recipient, at).await?)
|
|
}
|
|
|
|
async fn inbound_hrmp_channels_contents(
|
|
&self,
|
|
at: Hash,
|
|
recipient: ParaId,
|
|
) -> Result<
|
|
std::collections::BTreeMap<
|
|
ParaId,
|
|
Vec<pezkuwi_core_primitives::InboundHrmpMessage<BlockNumber>>,
|
|
>,
|
|
pezsp_api::ApiError,
|
|
> {
|
|
Ok(self
|
|
.rpc_client
|
|
.teyrchain_host_inbound_hrmp_channels_contents(recipient, at)
|
|
.await?)
|
|
}
|
|
|
|
async fn validation_code_by_hash(
|
|
&self,
|
|
at: Hash,
|
|
validation_code_hash: pezkuwi_primitives::ValidationCodeHash,
|
|
) -> Result<Option<pezkuwi_primitives::ValidationCode>, pezsp_api::ApiError> {
|
|
Ok(self
|
|
.rpc_client
|
|
.teyrchain_host_validation_code_by_hash(at, validation_code_hash)
|
|
.await?)
|
|
}
|
|
|
|
async fn on_chain_votes(
|
|
&self,
|
|
at: Hash,
|
|
) -> Result<Option<pezkuwi_primitives::ScrapedOnChainVotes<Hash>>, pezsp_api::ApiError> {
|
|
Ok(self.rpc_client.teyrchain_host_on_chain_votes(at).await?)
|
|
}
|
|
|
|
async fn session_info(
|
|
&self,
|
|
at: Hash,
|
|
index: pezkuwi_primitives::SessionIndex,
|
|
) -> Result<Option<pezkuwi_primitives::SessionInfo>, pezsp_api::ApiError> {
|
|
Ok(self.rpc_client.teyrchain_host_session_info(at, index).await?)
|
|
}
|
|
|
|
async fn session_executor_params(
|
|
&self,
|
|
at: Hash,
|
|
session_index: pezkuwi_primitives::SessionIndex,
|
|
) -> Result<Option<pezkuwi_primitives::ExecutorParams>, pezsp_api::ApiError> {
|
|
Ok(self
|
|
.rpc_client
|
|
.teyrchain_host_session_executor_params(at, session_index)
|
|
.await?)
|
|
}
|
|
|
|
async fn submit_pvf_check_statement(
|
|
&self,
|
|
at: Hash,
|
|
stmt: pezkuwi_primitives::PvfCheckStatement,
|
|
signature: pezkuwi_primitives::ValidatorSignature,
|
|
) -> Result<(), pezsp_api::ApiError> {
|
|
Ok(self
|
|
.rpc_client
|
|
.teyrchain_host_submit_pvf_check_statement(at, stmt, signature)
|
|
.await?)
|
|
}
|
|
|
|
async fn pvfs_require_precheck(
|
|
&self,
|
|
at: Hash,
|
|
) -> Result<Vec<pezkuwi_primitives::ValidationCodeHash>, pezsp_api::ApiError> {
|
|
Ok(self.rpc_client.teyrchain_host_pvfs_require_precheck(at).await?)
|
|
}
|
|
|
|
async fn validation_code_hash(
|
|
&self,
|
|
at: Hash,
|
|
para_id: ParaId,
|
|
assumption: pezkuwi_primitives::OccupiedCoreAssumption,
|
|
) -> Result<Option<pezkuwi_primitives::ValidationCodeHash>, pezsp_api::ApiError> {
|
|
Ok(self
|
|
.rpc_client
|
|
.teyrchain_host_validation_code_hash(at, para_id, assumption)
|
|
.await?)
|
|
}
|
|
|
|
async fn current_epoch(
|
|
&self,
|
|
at: Hash,
|
|
) -> Result<pezsp_consensus_babe::Epoch, pezsp_api::ApiError> {
|
|
Ok(self.rpc_client.babe_api_current_epoch(at).await?)
|
|
}
|
|
|
|
async fn authorities(
|
|
&self,
|
|
at: Hash,
|
|
) -> std::result::Result<Vec<pezkuwi_primitives::AuthorityDiscoveryId>, pezsp_api::ApiError> {
|
|
Ok(self.rpc_client.authority_discovery_authorities(at).await?)
|
|
}
|
|
|
|
async fn api_version_teyrchain_host(
|
|
&self,
|
|
at: Hash,
|
|
) -> Result<Option<u32>, pezsp_api::ApiError> {
|
|
let api_id = <dyn pezkuwi_primitives::runtime_api::TeyrchainHost<Block>>::ID;
|
|
Ok(self.rpc_client.runtime_version(at).await.map(|v| v.api_version(&api_id))?)
|
|
}
|
|
|
|
async fn disputes(
|
|
&self,
|
|
at: Hash,
|
|
) -> Result<
|
|
Vec<(
|
|
pezkuwi_primitives::SessionIndex,
|
|
pezkuwi_primitives::CandidateHash,
|
|
pezkuwi_primitives::DisputeState<pezkuwi_primitives::BlockNumber>,
|
|
)>,
|
|
ApiError,
|
|
> {
|
|
Ok(self.rpc_client.teyrchain_host_disputes(at).await?)
|
|
}
|
|
|
|
async fn unapplied_slashes(
|
|
&self,
|
|
at: Hash,
|
|
) -> Result<
|
|
Vec<(
|
|
pezkuwi_primitives::SessionIndex,
|
|
pezkuwi_primitives::CandidateHash,
|
|
slashing::LegacyPendingSlashes,
|
|
)>,
|
|
ApiError,
|
|
> {
|
|
Ok(self.rpc_client.teyrchain_host_unapplied_slashes(at).await?)
|
|
}
|
|
|
|
async fn unapplied_slashes_v2(
|
|
&self,
|
|
at: Hash,
|
|
) -> Result<
|
|
Vec<(
|
|
pezkuwi_primitives::SessionIndex,
|
|
pezkuwi_primitives::CandidateHash,
|
|
slashing::PendingSlashes,
|
|
)>,
|
|
ApiError,
|
|
> {
|
|
Ok(self.rpc_client.teyrchain_host_unapplied_slashes_v2(at).await?)
|
|
}
|
|
|
|
async fn key_ownership_proof(
|
|
&self,
|
|
at: Hash,
|
|
validator_id: pezkuwi_primitives::ValidatorId,
|
|
) -> Result<Option<slashing::OpaqueKeyOwnershipProof>, ApiError> {
|
|
Ok(self.rpc_client.teyrchain_host_key_ownership_proof(at, validator_id).await?)
|
|
}
|
|
|
|
async fn submit_report_dispute_lost(
|
|
&self,
|
|
at: Hash,
|
|
dispute_proof: slashing::DisputeProof,
|
|
key_ownership_proof: slashing::OpaqueKeyOwnershipProof,
|
|
) -> Result<Option<()>, ApiError> {
|
|
Ok(self
|
|
.rpc_client
|
|
.teyrchain_host_submit_report_dispute_lost(at, dispute_proof, key_ownership_proof)
|
|
.await?)
|
|
}
|
|
|
|
async fn minimum_backing_votes(
|
|
&self,
|
|
at: Hash,
|
|
session_index: pezkuwi_primitives::SessionIndex,
|
|
) -> Result<u32, ApiError> {
|
|
Ok(self.rpc_client.teyrchain_host_minimum_backing_votes(at, session_index).await?)
|
|
}
|
|
|
|
async fn disabled_validators(
|
|
&self,
|
|
at: Hash,
|
|
) -> Result<Vec<pezkuwi_primitives::ValidatorIndex>, ApiError> {
|
|
Ok(self.rpc_client.teyrchain_host_disabled_validators(at).await?)
|
|
}
|
|
|
|
async fn async_backing_params(&self, at: Hash) -> Result<AsyncBackingParams, ApiError> {
|
|
Ok(self.rpc_client.teyrchain_host_async_backing_params(at).await?)
|
|
}
|
|
|
|
async fn para_backing_state(
|
|
&self,
|
|
at: Hash,
|
|
para_id: ParaId,
|
|
) -> Result<Option<BackingState>, ApiError> {
|
|
Ok(self.rpc_client.teyrchain_host_para_backing_state(at, para_id).await?)
|
|
}
|
|
|
|
/// Approval voting configuration parameters
|
|
async fn approval_voting_params(
|
|
&self,
|
|
at: Hash,
|
|
session_index: pezkuwi_primitives::SessionIndex,
|
|
) -> Result<ApprovalVotingParams, ApiError> {
|
|
Ok(self
|
|
.rpc_client
|
|
.teyrchain_host_staging_approval_voting_params(at, session_index)
|
|
.await?)
|
|
}
|
|
|
|
async fn node_features(&self, at: Hash) -> Result<NodeFeatures, ApiError> {
|
|
Ok(self.rpc_client.teyrchain_host_node_features(at).await?)
|
|
}
|
|
|
|
async fn claim_queue(
|
|
&self,
|
|
at: Hash,
|
|
) -> Result<BTreeMap<CoreIndex, VecDeque<ParaId>>, ApiError> {
|
|
Ok(self.rpc_client.teyrchain_host_claim_queue(at).await?)
|
|
}
|
|
|
|
async fn candidates_pending_availability(
|
|
&self,
|
|
at: Hash,
|
|
para_id: pezcumulus_primitives_core::ParaId,
|
|
) -> Result<Vec<pezkuwi_primitives::CommittedCandidateReceiptV2<Hash>>, pezsp_api::ApiError> {
|
|
Ok(self
|
|
.rpc_client
|
|
.teyrchain_host_candidates_pending_availability(at, para_id)
|
|
.await?)
|
|
}
|
|
|
|
async fn backing_constraints(
|
|
&self,
|
|
at: Hash,
|
|
para_id: ParaId,
|
|
) -> Result<Option<Constraints>, ApiError> {
|
|
Ok(self.rpc_client.teyrchain_host_backing_constraints(at, para_id).await?)
|
|
}
|
|
|
|
async fn scheduling_lookahead(&self, at: Hash) -> Result<u32, pezsp_api::ApiError> {
|
|
Ok(self.rpc_client.teyrchain_host_scheduling_lookahead(at).await?)
|
|
}
|
|
|
|
async fn validation_code_bomb_limit(&self, at: Hash) -> Result<u32, pezsp_api::ApiError> {
|
|
Ok(self.rpc_client.teyrchain_host_validation_code_bomb_limit(at).await?)
|
|
}
|
|
|
|
async fn para_ids(&self, at: Hash) -> Result<Vec<ParaId>, pezsp_api::ApiError> {
|
|
Ok(self.rpc_client.teyrchain_host_para_ids(at).await?)
|
|
}
|
|
}
|
|
|
|
#[async_trait::async_trait]
|
|
impl AuthorityDiscovery<Block> for BlockChainRpcClient {
|
|
async fn authorities(
|
|
&self,
|
|
at: Hash,
|
|
) -> std::result::Result<Vec<pezkuwi_primitives::AuthorityDiscoveryId>, pezsp_api::ApiError> {
|
|
let result = self.rpc_client.authority_discovery_authorities(at).await?;
|
|
Ok(result)
|
|
}
|
|
|
|
async fn best_hash(&self) -> std::result::Result<Hash, AuthorityDiscoveryError> {
|
|
self.block_get_hash(None)
|
|
.await
|
|
.ok()
|
|
.flatten()
|
|
.ok_or_else(|| AuthorityDiscoveryError::BestBlockFetchingError)
|
|
}
|
|
}
|
|
|
|
impl BlockChainRpcClient {
|
|
pub async fn import_notification_stream(
|
|
&self,
|
|
) -> RelayChainResult<Pin<Box<dyn Stream<Item = Header> + Send>>> {
|
|
Ok(self.rpc_client.get_imported_heads_stream()?.boxed())
|
|
}
|
|
|
|
pub async fn finality_notification_stream(
|
|
&self,
|
|
) -> RelayChainResult<Pin<Box<dyn Stream<Item = Header> + Send>>> {
|
|
Ok(self.rpc_client.get_finalized_heads_stream()?.boxed())
|
|
}
|
|
}
|
|
|
|
// Implementation required by ChainApiSubsystem
|
|
// but never called in our case.
|
|
impl AuxStore for BlockChainRpcClient {
|
|
fn insert_aux<
|
|
'a,
|
|
'b: 'a,
|
|
'c: 'a,
|
|
I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
|
|
D: IntoIterator<Item = &'a &'b [u8]>,
|
|
>(
|
|
&self,
|
|
_insert: I,
|
|
_delete: D,
|
|
) -> pezsp_blockchain::Result<()> {
|
|
unimplemented!("Not supported on the RPC collator")
|
|
}
|
|
|
|
fn get_aux(&self, _key: &[u8]) -> pezsp_blockchain::Result<Option<Vec<u8>>> {
|
|
unimplemented!("Not supported on the RPC collator")
|
|
}
|
|
}
|