mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 22:11:06 +00:00
Introduce interface for relay chain interaction (#835)
This commit is contained in:
@@ -20,12 +20,8 @@
|
||||
//! that use the relay chain provided consensus. See [`BlockAnnounceValidator`]
|
||||
//! and [`WaitToAnnounce`] for more information about this implementation.
|
||||
|
||||
use sc_client_api::{Backend, BlockchainEvents};
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
use sp_blockchain::HeaderBackend;
|
||||
use sp_consensus::{
|
||||
block_validation::{BlockAnnounceValidator as BlockAnnounceValidatorT, Validation},
|
||||
SyncOracle,
|
||||
use sp_consensus::block_validation::{
|
||||
BlockAnnounceValidator as BlockAnnounceValidatorT, Validation,
|
||||
};
|
||||
use sp_core::traits::SpawnNamed;
|
||||
use sp_runtime::{
|
||||
@@ -33,12 +29,12 @@ use sp_runtime::{
|
||||
traits::{Block as BlockT, Header as HeaderT},
|
||||
};
|
||||
|
||||
use polkadot_client::ClientHandle;
|
||||
use cumulus_relay_chain_interface::RelayChainInterface;
|
||||
use polkadot_node_primitives::{CollationSecondedSignal, Statement};
|
||||
use polkadot_parachain::primitives::HeadData;
|
||||
use polkadot_primitives::v1::{
|
||||
Block as PBlock, CandidateReceipt, CompactStatement, Hash as PHash, Id as ParaId,
|
||||
OccupiedCoreAssumption, ParachainHost, SigningContext, UncheckedSigned,
|
||||
OccupiedCoreAssumption, SigningContext, UncheckedSigned,
|
||||
};
|
||||
|
||||
use codec::{Decode, DecodeAll, Encode};
|
||||
@@ -50,11 +46,8 @@ use futures::{
|
||||
|
||||
use std::{convert::TryFrom, fmt, marker::PhantomData, pin::Pin, sync::Arc};
|
||||
|
||||
use wait_on_relay_chain_block::WaitOnRelayChainBlock;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
mod wait_on_relay_chain_block;
|
||||
|
||||
const LOG_TARGET: &str = "sync::cumulus";
|
||||
|
||||
@@ -135,19 +128,18 @@ impl BlockAnnounceData {
|
||||
/// Check the signature of the statement.
|
||||
///
|
||||
/// Returns an `Err(_)` if it failed.
|
||||
fn check_signature<P>(
|
||||
fn check_signature<RCInterface>(
|
||||
self,
|
||||
relay_chain_client: &Arc<P>,
|
||||
relay_chain_client: &RCInterface,
|
||||
) -> Result<Validation, BlockAnnounceError>
|
||||
where
|
||||
P: ProvideRuntimeApi<PBlock> + Send + Sync + 'static,
|
||||
P::Api: ParachainHost<PBlock>,
|
||||
RCInterface: RelayChainInterface + 'static,
|
||||
{
|
||||
let runtime_api = relay_chain_client.runtime_api();
|
||||
let validator_index = self.statement.unchecked_validator_index();
|
||||
|
||||
let runtime_api_block_id = BlockId::Hash(self.relay_parent);
|
||||
let session_index = match runtime_api.session_index_for_child(&runtime_api_block_id) {
|
||||
let session_index = match relay_chain_client.session_index_for_child(&runtime_api_block_id)
|
||||
{
|
||||
Ok(r) => r,
|
||||
Err(e) => return Err(BlockAnnounceError(format!("{:?}", e))),
|
||||
};
|
||||
@@ -155,7 +147,7 @@ impl BlockAnnounceData {
|
||||
let signing_context = SigningContext { parent_hash: self.relay_parent, session_index };
|
||||
|
||||
// Check that the signer is a legit validator.
|
||||
let authorities = match runtime_api.validators(&runtime_api_block_id) {
|
||||
let authorities = match relay_chain_client.validators(&runtime_api_block_id) {
|
||||
Ok(r) => r,
|
||||
Err(e) => return Err(BlockAnnounceError(format!("{:?}", e))),
|
||||
};
|
||||
@@ -230,52 +222,37 @@ impl TryFrom<&'_ CollationSecondedSignal> for BlockAnnounceData {
|
||||
/// chain. If it is at the tip, it is required to provide a justification or otherwise we reject
|
||||
/// it. However, if the announcement is for a block below the tip the announcement is accepted
|
||||
/// as it probably comes from a node that is currently syncing the chain.
|
||||
pub struct BlockAnnounceValidator<Block, R, B, BCE> {
|
||||
pub struct BlockAnnounceValidator<Block, RCInterface> {
|
||||
phantom: PhantomData<Block>,
|
||||
relay_chain_client: Arc<R>,
|
||||
relay_chain_backend: Arc<B>,
|
||||
relay_chain_interface: RCInterface,
|
||||
para_id: ParaId,
|
||||
relay_chain_sync_oracle: Box<dyn SyncOracle + Send>,
|
||||
wait_on_relay_chain_block: WaitOnRelayChainBlock<B, BCE>,
|
||||
}
|
||||
|
||||
impl<Block, R, B, BCE> BlockAnnounceValidator<Block, R, B, BCE> {
|
||||
impl<Block, RCInterface> BlockAnnounceValidator<Block, RCInterface>
|
||||
where
|
||||
RCInterface: Clone,
|
||||
{
|
||||
/// Create a new [`BlockAnnounceValidator`].
|
||||
pub fn new(
|
||||
relay_chain_client: Arc<R>,
|
||||
para_id: ParaId,
|
||||
relay_chain_sync_oracle: Box<dyn SyncOracle + Send>,
|
||||
relay_chain_backend: Arc<B>,
|
||||
relay_chain_blockchain_events: Arc<BCE>,
|
||||
) -> Self {
|
||||
pub fn new(relay_chain_interface: RCInterface, para_id: ParaId) -> Self {
|
||||
Self {
|
||||
phantom: Default::default(),
|
||||
relay_chain_client,
|
||||
relay_chain_interface: relay_chain_interface.clone(),
|
||||
para_id,
|
||||
relay_chain_sync_oracle,
|
||||
relay_chain_backend: relay_chain_backend.clone(),
|
||||
wait_on_relay_chain_block: WaitOnRelayChainBlock::new(
|
||||
relay_chain_backend,
|
||||
relay_chain_blockchain_events,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Block: BlockT, R, B, BCE> BlockAnnounceValidator<Block, R, B, BCE>
|
||||
impl<Block: BlockT, RCInterface> BlockAnnounceValidator<Block, RCInterface>
|
||||
where
|
||||
R: ProvideRuntimeApi<PBlock> + Send + Sync + 'static,
|
||||
R::Api: ParachainHost<PBlock>,
|
||||
B: Backend<PBlock> + 'static,
|
||||
RCInterface: RelayChainInterface + Clone,
|
||||
{
|
||||
/// Get the included block of the given parachain in the relay chain.
|
||||
fn included_block(
|
||||
relay_chain_client: &R,
|
||||
relay_chain_interface: &RCInterface,
|
||||
block_id: &BlockId<PBlock>,
|
||||
para_id: ParaId,
|
||||
) -> Result<Block::Header, BoxedError> {
|
||||
let validation_data = relay_chain_client
|
||||
.runtime_api()
|
||||
let validation_data = relay_chain_interface
|
||||
.persisted_validation_data(block_id, para_id, OccupiedCoreAssumption::TimedOut)
|
||||
.map_err(|e| Box::new(BlockAnnounceError(format!("{:?}", e))) as Box<_>)?
|
||||
.ok_or_else(|| {
|
||||
@@ -293,12 +270,11 @@ where
|
||||
|
||||
/// Get the backed block hash of the given parachain in the relay chain.
|
||||
fn backed_block_hash(
|
||||
relay_chain_client: &R,
|
||||
relay_chain_interface: &RCInterface,
|
||||
block_id: &BlockId<PBlock>,
|
||||
para_id: ParaId,
|
||||
) -> Result<Option<PHash>, BoxedError> {
|
||||
let candidate_receipt = relay_chain_client
|
||||
.runtime_api()
|
||||
let candidate_receipt = relay_chain_interface
|
||||
.candidate_pending_availability(block_id, para_id)
|
||||
.map_err(|e| Box::new(BlockAnnounceError(format!("{:?}", e))) as Box<_>)?;
|
||||
|
||||
@@ -310,21 +286,20 @@ where
|
||||
&self,
|
||||
header: Block::Header,
|
||||
) -> impl Future<Output = Result<Validation, BoxedError>> {
|
||||
let relay_chain_client = self.relay_chain_client.clone();
|
||||
let relay_chain_backend = self.relay_chain_backend.clone();
|
||||
let relay_chain_interface = self.relay_chain_interface.clone();
|
||||
let para_id = self.para_id;
|
||||
|
||||
async move {
|
||||
// Check if block is equal or higher than best (this requires a justification)
|
||||
let relay_chain_info = relay_chain_backend.blockchain().info();
|
||||
let runtime_api_block_id = BlockId::Hash(relay_chain_info.best_hash);
|
||||
let relay_chain_best_hash = relay_chain_interface.best_block_hash();
|
||||
let runtime_api_block_id = BlockId::Hash(relay_chain_best_hash);
|
||||
let block_number = header.number();
|
||||
|
||||
let best_head =
|
||||
Self::included_block(&*relay_chain_client, &runtime_api_block_id, para_id)?;
|
||||
Self::included_block(&relay_chain_interface, &runtime_api_block_id, para_id)?;
|
||||
let known_best_number = best_head.number();
|
||||
let backed_block =
|
||||
|| Self::backed_block_hash(&*relay_chain_client, &runtime_api_block_id, para_id);
|
||||
|| Self::backed_block_hash(&relay_chain_interface, &runtime_api_block_id, para_id);
|
||||
|
||||
if best_head == header {
|
||||
tracing::debug!(target: LOG_TARGET, "Announced block matches best block.",);
|
||||
@@ -348,20 +323,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<Block: BlockT, P, B, BCE> BlockAnnounceValidatorT<Block>
|
||||
for BlockAnnounceValidator<Block, P, B, BCE>
|
||||
impl<Block: BlockT, RCInterface> BlockAnnounceValidatorT<Block>
|
||||
for BlockAnnounceValidator<Block, RCInterface>
|
||||
where
|
||||
P: ProvideRuntimeApi<PBlock> + Send + Sync + 'static,
|
||||
P::Api: ParachainHost<PBlock>,
|
||||
B: Backend<PBlock> + 'static,
|
||||
BCE: BlockchainEvents<PBlock> + 'static + Send + Sync,
|
||||
RCInterface: RelayChainInterface + Clone + 'static,
|
||||
{
|
||||
fn validate(
|
||||
&mut self,
|
||||
header: &Block::Header,
|
||||
mut data: &[u8],
|
||||
) -> Pin<Box<dyn Future<Output = Result<Validation, BoxedError>> + Send>> {
|
||||
if self.relay_chain_sync_oracle.is_major_syncing() {
|
||||
if self.relay_chain_interface.is_major_syncing() {
|
||||
return ready(Ok(Validation::Success { is_new_best: false })).boxed()
|
||||
}
|
||||
|
||||
@@ -381,9 +353,8 @@ where
|
||||
.boxed(),
|
||||
};
|
||||
|
||||
let relay_chain_client = self.relay_chain_client.clone();
|
||||
let relay_chain_interface = self.relay_chain_interface.clone();
|
||||
let header_encoded = header.encode();
|
||||
let wait_on_relay_chain_block = self.wait_on_relay_chain_block.clone();
|
||||
|
||||
async move {
|
||||
if let Err(e) = block_announce_data.validate(header_encoded) {
|
||||
@@ -392,106 +363,19 @@ where
|
||||
|
||||
let relay_parent = block_announce_data.receipt.descriptor.relay_parent;
|
||||
|
||||
wait_on_relay_chain_block
|
||||
.wait_on_relay_chain_block(relay_parent)
|
||||
relay_chain_interface
|
||||
.wait_for_block(relay_parent)
|
||||
.await
|
||||
.map_err(|e| Box::new(BlockAnnounceError(e.to_string())) as Box<_>)?;
|
||||
|
||||
block_announce_data
|
||||
.check_signature(&relay_chain_client)
|
||||
.check_signature(&relay_chain_interface)
|
||||
.map_err(|e| Box::new(e) as Box<_>)
|
||||
}
|
||||
.boxed()
|
||||
}
|
||||
}
|
||||
|
||||
/// Build a block announce validator instance.
|
||||
///
|
||||
/// Returns a boxed [`BlockAnnounceValidator`].
|
||||
pub fn build_block_announce_validator<Block: BlockT, B>(
|
||||
relay_chain_client: polkadot_client::Client,
|
||||
para_id: ParaId,
|
||||
relay_chain_sync_oracle: Box<dyn SyncOracle + Send>,
|
||||
relay_chain_backend: Arc<B>,
|
||||
) -> Box<dyn BlockAnnounceValidatorT<Block> + Send>
|
||||
where
|
||||
B: Backend<PBlock> + Send + 'static,
|
||||
{
|
||||
BlockAnnounceValidatorBuilder::new(
|
||||
relay_chain_client,
|
||||
para_id,
|
||||
relay_chain_sync_oracle,
|
||||
relay_chain_backend,
|
||||
)
|
||||
.build()
|
||||
}
|
||||
|
||||
/// Block announce validator builder.
|
||||
///
|
||||
/// Builds a [`BlockAnnounceValidator`] for a parachain. As this requires
|
||||
/// a concrete relay chain client instance, the builder takes a [`polkadot_client::Client`]
|
||||
/// that wraps this concrete instanace. By using [`polkadot_client::ExecuteWithClient`]
|
||||
/// the builder gets access to this concrete instance.
|
||||
struct BlockAnnounceValidatorBuilder<Block, B> {
|
||||
phantom: PhantomData<Block>,
|
||||
relay_chain_client: polkadot_client::Client,
|
||||
para_id: ParaId,
|
||||
relay_chain_sync_oracle: Box<dyn SyncOracle + Send>,
|
||||
relay_chain_backend: Arc<B>,
|
||||
}
|
||||
|
||||
impl<Block: BlockT, B> BlockAnnounceValidatorBuilder<Block, B>
|
||||
where
|
||||
B: Backend<PBlock> + Send + 'static,
|
||||
{
|
||||
/// Create a new instance of the builder.
|
||||
fn new(
|
||||
relay_chain_client: polkadot_client::Client,
|
||||
para_id: ParaId,
|
||||
relay_chain_sync_oracle: Box<dyn SyncOracle + Send>,
|
||||
relay_chain_backend: Arc<B>,
|
||||
) -> Self {
|
||||
Self {
|
||||
relay_chain_client,
|
||||
para_id,
|
||||
relay_chain_sync_oracle,
|
||||
relay_chain_backend,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Build the block announce validator.
|
||||
fn build(self) -> Box<dyn BlockAnnounceValidatorT<Block> + Send> {
|
||||
self.relay_chain_client.clone().execute_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Block: BlockT, B> polkadot_client::ExecuteWithClient
|
||||
for BlockAnnounceValidatorBuilder<Block, B>
|
||||
where
|
||||
B: Backend<PBlock> + Send + 'static,
|
||||
{
|
||||
type Output = Box<dyn BlockAnnounceValidatorT<Block> + Send>;
|
||||
|
||||
fn execute_with_client<PClient, Api, PBackend>(self, client: Arc<PClient>) -> Self::Output
|
||||
where
|
||||
<Api as sp_api::ApiExt<PBlock>>::StateBackend:
|
||||
sp_api::StateBackend<sp_runtime::traits::BlakeTwo256>,
|
||||
PBackend: Backend<PBlock>,
|
||||
PBackend::State: sp_api::StateBackend<sp_runtime::traits::BlakeTwo256>,
|
||||
Api: polkadot_client::RuntimeApiCollection<StateBackend = PBackend::State>,
|
||||
PClient: polkadot_client::AbstractClient<PBlock, PBackend, Api = Api> + 'static,
|
||||
{
|
||||
Box::new(BlockAnnounceValidator::new(
|
||||
client.clone(),
|
||||
self.para_id,
|
||||
self.relay_chain_sync_oracle,
|
||||
self.relay_chain_backend,
|
||||
client,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// Wait before announcing a block that a candidate message has been received for this block, then
|
||||
/// add this message as justification for the block announcement.
|
||||
///
|
||||
|
||||
Reference in New Issue
Block a user