mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-19 11:11:03 +00:00
Unify RelayChainInterface error handling and introduce async (#909)
This commit is contained in:
Generated
+3
@@ -1895,14 +1895,17 @@ dependencies = [
|
|||||||
"async-trait",
|
"async-trait",
|
||||||
"cumulus-primitives-core",
|
"cumulus-primitives-core",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
|
"futures 0.3.19",
|
||||||
"parking_lot 0.11.2",
|
"parking_lot 0.11.2",
|
||||||
"polkadot-overseer",
|
"polkadot-overseer",
|
||||||
"sc-client-api",
|
"sc-client-api",
|
||||||
|
"sc-service",
|
||||||
"sp-api",
|
"sp-api",
|
||||||
"sp-blockchain",
|
"sp-blockchain",
|
||||||
"sp-core",
|
"sp-core",
|
||||||
"sp-runtime",
|
"sp-runtime",
|
||||||
"sp-state-machine",
|
"sp-state-machine",
|
||||||
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ cumulus-relay-chain-interface = { path = "../../relay-chain-interface" }
|
|||||||
futures = { version = "0.3.8", features = ["compat"] }
|
futures = { version = "0.3.8", features = ["compat"] }
|
||||||
codec = { package = "parity-scale-codec", version = "2.3.0", features = [ "derive" ] }
|
codec = { package = "parity-scale-codec", version = "2.3.0", features = [ "derive" ] }
|
||||||
tracing = "0.1.25"
|
tracing = "0.1.25"
|
||||||
async-trait = "0.1.42"
|
async-trait = "0.1.52"
|
||||||
dyn-clone = "1.0.4"
|
dyn-clone = "1.0.4"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|||||||
@@ -14,12 +14,13 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
|
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use cumulus_relay_chain_interface::RelayChainInterface;
|
use async_trait::async_trait;
|
||||||
|
use cumulus_relay_chain_interface::{RelayChainInterface, RelayChainResult};
|
||||||
use sc_client_api::{
|
use sc_client_api::{
|
||||||
Backend, BlockBackend, BlockImportNotification, BlockchainEvents, Finalizer, UsageProvider,
|
Backend, BlockBackend, BlockImportNotification, BlockchainEvents, Finalizer, UsageProvider,
|
||||||
};
|
};
|
||||||
use sc_consensus::{BlockImport, BlockImportParams, ForkChoiceStrategy};
|
use sc_consensus::{BlockImport, BlockImportParams, ForkChoiceStrategy};
|
||||||
use sp_blockchain::{Error as ClientError, Result as ClientResult};
|
use sp_blockchain::Error as ClientError;
|
||||||
use sp_consensus::{BlockOrigin, BlockStatus};
|
use sp_consensus::{BlockOrigin, BlockStatus};
|
||||||
use sp_runtime::{
|
use sp_runtime::{
|
||||||
generic::BlockId,
|
generic::BlockId,
|
||||||
@@ -29,11 +30,14 @@ use sp_runtime::{
|
|||||||
use polkadot_primitives::v1::{Block as PBlock, Id as ParaId, OccupiedCoreAssumption};
|
use polkadot_primitives::v1::{Block as PBlock, Id as ParaId, OccupiedCoreAssumption};
|
||||||
|
|
||||||
use codec::Decode;
|
use codec::Decode;
|
||||||
use futures::{future, select, FutureExt, Stream, StreamExt};
|
use futures::{select, FutureExt, Stream, StreamExt};
|
||||||
|
|
||||||
use std::{pin::Pin, sync::Arc};
|
use std::{pin::Pin, sync::Arc};
|
||||||
|
|
||||||
|
const LOG_TARGET: &str = "cumulus-consensus";
|
||||||
|
|
||||||
/// Helper for the relay chain client. This is expected to be a lightweight handle like an `Arc`.
|
/// Helper for the relay chain client. This is expected to be a lightweight handle like an `Arc`.
|
||||||
|
#[async_trait]
|
||||||
pub trait RelaychainClient: Clone + 'static {
|
pub trait RelaychainClient: Clone + 'static {
|
||||||
/// The error type for interacting with the Polkadot client.
|
/// The error type for interacting with the Polkadot client.
|
||||||
type Error: std::fmt::Debug + Send;
|
type Error: std::fmt::Debug + Send;
|
||||||
@@ -42,17 +46,17 @@ pub trait RelaychainClient: Clone + 'static {
|
|||||||
type HeadStream: Stream<Item = Vec<u8>> + Send + Unpin;
|
type HeadStream: Stream<Item = Vec<u8>> + Send + Unpin;
|
||||||
|
|
||||||
/// Get a stream of new best heads for the given parachain.
|
/// Get a stream of new best heads for the given parachain.
|
||||||
fn new_best_heads(&self, para_id: ParaId) -> Self::HeadStream;
|
async fn new_best_heads(&self, para_id: ParaId) -> RelayChainResult<Self::HeadStream>;
|
||||||
|
|
||||||
/// Get a stream of finalized heads for the given parachain.
|
/// Get a stream of finalized heads for the given parachain.
|
||||||
fn finalized_heads(&self, para_id: ParaId) -> Self::HeadStream;
|
async fn finalized_heads(&self, para_id: ParaId) -> RelayChainResult<Self::HeadStream>;
|
||||||
|
|
||||||
/// Returns the parachain head for the given `para_id` at the given block id.
|
/// Returns the parachain head for the given `para_id` at the given block id.
|
||||||
fn parachain_head_at(
|
async fn parachain_head_at(
|
||||||
&self,
|
&self,
|
||||||
at: &BlockId<PBlock>,
|
at: &BlockId<PBlock>,
|
||||||
para_id: ParaId,
|
para_id: ParaId,
|
||||||
) -> ClientResult<Option<Vec<u8>>>;
|
) -> RelayChainResult<Option<Vec<u8>>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Follow the finalized head of the given parachain.
|
/// Follow the finalized head of the given parachain.
|
||||||
@@ -66,7 +70,13 @@ where
|
|||||||
R: RelaychainClient,
|
R: RelaychainClient,
|
||||||
B: Backend<Block>,
|
B: Backend<Block>,
|
||||||
{
|
{
|
||||||
let mut finalized_heads = relay_chain.finalized_heads(para_id);
|
let mut finalized_heads = match relay_chain.finalized_heads(para_id).await {
|
||||||
|
Ok(finalized_heads_stream) => finalized_heads_stream,
|
||||||
|
Err(err) => {
|
||||||
|
tracing::error!(target: LOG_TARGET, error = ?err, "Unable to retrieve finalized heads stream.");
|
||||||
|
return
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let finalized_head = if let Some(h) = finalized_heads.next().await {
|
let finalized_head = if let Some(h) = finalized_heads.next().await {
|
||||||
@@ -165,7 +175,14 @@ async fn follow_new_best<P, R, Block, B>(
|
|||||||
R: RelaychainClient,
|
R: RelaychainClient,
|
||||||
B: Backend<Block>,
|
B: Backend<Block>,
|
||||||
{
|
{
|
||||||
let mut new_best_heads = relay_chain.new_best_heads(para_id).fuse();
|
let mut new_best_heads = match relay_chain.new_best_heads(para_id).await {
|
||||||
|
Ok(best_heads_stream) => best_heads_stream.fuse(),
|
||||||
|
Err(err) => {
|
||||||
|
tracing::error!(target: LOG_TARGET, error = ?err, "Unable to retrieve best heads stream.");
|
||||||
|
return
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
let mut imported_blocks = parachain.import_notification_stream().fuse();
|
let mut imported_blocks = parachain.import_notification_stream().fuse();
|
||||||
// The unset best header of the parachain. Will be `Some(_)` when we have imported a relay chain
|
// The unset best header of the parachain. Will be `Some(_)` when we have imported a relay chain
|
||||||
// block before the parachain block it included. In this case we need to wait for this block to
|
// block before the parachain block it included. In this case we need to wait for this block to
|
||||||
@@ -368,6 +385,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
impl<RCInterface> RelaychainClient for RCInterface
|
impl<RCInterface> RelaychainClient for RCInterface
|
||||||
where
|
where
|
||||||
RCInterface: RelayChainInterface + Clone + 'static,
|
RCInterface: RelayChainInterface + Clone + 'static,
|
||||||
@@ -376,39 +394,53 @@ where
|
|||||||
|
|
||||||
type HeadStream = Pin<Box<dyn Stream<Item = Vec<u8>> + Send>>;
|
type HeadStream = Pin<Box<dyn Stream<Item = Vec<u8>> + Send>>;
|
||||||
|
|
||||||
fn new_best_heads(&self, para_id: ParaId) -> Self::HeadStream {
|
async fn new_best_heads(&self, para_id: ParaId) -> RelayChainResult<Self::HeadStream> {
|
||||||
let relay_chain = self.clone();
|
let relay_chain = self.clone();
|
||||||
|
|
||||||
self.import_notification_stream()
|
let new_best_notification_stream = self
|
||||||
|
.new_best_notification_stream()
|
||||||
|
.await?
|
||||||
.filter_map(move |n| {
|
.filter_map(move |n| {
|
||||||
future::ready(if n.is_new_best {
|
let relay_chain = relay_chain.clone();
|
||||||
relay_chain.parachain_head_at(&BlockId::hash(n.hash), para_id).ok().flatten()
|
async move {
|
||||||
} else {
|
relay_chain
|
||||||
None
|
.parachain_head_at(&BlockId::hash(n.hash()), para_id)
|
||||||
})
|
.await
|
||||||
|
.ok()
|
||||||
|
.flatten()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.boxed()
|
.boxed();
|
||||||
|
Ok(new_best_notification_stream)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finalized_heads(&self, para_id: ParaId) -> Self::HeadStream {
|
async fn finalized_heads(&self, para_id: ParaId) -> RelayChainResult<Self::HeadStream> {
|
||||||
let relay_chain = self.clone();
|
let relay_chain = self.clone();
|
||||||
|
|
||||||
self.finality_notification_stream()
|
let finality_notification_stream = self
|
||||||
|
.finality_notification_stream()
|
||||||
|
.await?
|
||||||
.filter_map(move |n| {
|
.filter_map(move |n| {
|
||||||
future::ready(
|
let relay_chain = relay_chain.clone();
|
||||||
relay_chain.parachain_head_at(&BlockId::hash(n.hash), para_id).ok().flatten(),
|
async move {
|
||||||
)
|
relay_chain
|
||||||
|
.parachain_head_at(&BlockId::hash(n.hash()), para_id)
|
||||||
|
.await
|
||||||
|
.ok()
|
||||||
|
.flatten()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.boxed()
|
.boxed();
|
||||||
|
Ok(finality_notification_stream)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parachain_head_at(
|
async fn parachain_head_at(
|
||||||
&self,
|
&self,
|
||||||
at: &BlockId<PBlock>,
|
at: &BlockId<PBlock>,
|
||||||
para_id: ParaId,
|
para_id: ParaId,
|
||||||
) -> ClientResult<Option<Vec<u8>>> {
|
) -> RelayChainResult<Option<Vec<u8>>> {
|
||||||
self.persisted_validation_data(at, para_id, OccupiedCoreAssumption::TimedOut)
|
self.persisted_validation_data(at, para_id, OccupiedCoreAssumption::TimedOut)
|
||||||
|
.await
|
||||||
.map(|s| s.map(|s| s.parent_head.0))
|
.map(|s| s.map(|s| s.parent_head.0))
|
||||||
.map_err(Into::into)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,9 @@
|
|||||||
|
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
|
use async_trait::async_trait;
|
||||||
use codec::Encode;
|
use codec::Encode;
|
||||||
|
use cumulus_relay_chain_interface::RelayChainResult;
|
||||||
use cumulus_test_client::{
|
use cumulus_test_client::{
|
||||||
runtime::{Block, Header},
|
runtime::{Block, Header},
|
||||||
Backend, Client, InitBlockBuilder, TestClientBuilder, TestClientBuilderExt,
|
Backend, Client, InitBlockBuilder, TestClientBuilder, TestClientBuilderExt,
|
||||||
@@ -26,7 +28,7 @@ use futures_timer::Delay;
|
|||||||
use polkadot_primitives::v1::{Block as PBlock, Id as ParaId};
|
use polkadot_primitives::v1::{Block as PBlock, Id as ParaId};
|
||||||
use sc_client_api::UsageProvider;
|
use sc_client_api::UsageProvider;
|
||||||
use sc_consensus::{BlockImport, BlockImportParams, ForkChoiceStrategy};
|
use sc_consensus::{BlockImport, BlockImportParams, ForkChoiceStrategy};
|
||||||
use sp_blockchain::{Error as ClientError, Result as ClientResult};
|
use sp_blockchain::Error as ClientError;
|
||||||
use sp_consensus::BlockOrigin;
|
use sp_consensus::BlockOrigin;
|
||||||
use sp_runtime::generic::BlockId;
|
use sp_runtime::generic::BlockId;
|
||||||
use std::{
|
use std::{
|
||||||
@@ -66,12 +68,13 @@ impl Relaychain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
impl crate::parachain_consensus::RelaychainClient for Relaychain {
|
impl crate::parachain_consensus::RelaychainClient for Relaychain {
|
||||||
type Error = ClientError;
|
type Error = ClientError;
|
||||||
|
|
||||||
type HeadStream = Box<dyn Stream<Item = Vec<u8>> + Send + Unpin>;
|
type HeadStream = Box<dyn Stream<Item = Vec<u8>> + Send + Unpin>;
|
||||||
|
|
||||||
fn new_best_heads(&self, _: ParaId) -> Self::HeadStream {
|
async fn new_best_heads(&self, _: ParaId) -> RelayChainResult<Self::HeadStream> {
|
||||||
let stream = self
|
let stream = self
|
||||||
.inner
|
.inner
|
||||||
.lock()
|
.lock()
|
||||||
@@ -80,10 +83,10 @@ impl crate::parachain_consensus::RelaychainClient for Relaychain {
|
|||||||
.take()
|
.take()
|
||||||
.expect("Should only be called once");
|
.expect("Should only be called once");
|
||||||
|
|
||||||
Box::new(stream.map(|v| v.encode()))
|
Ok(Box::new(stream.map(|v| v.encode())))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finalized_heads(&self, _: ParaId) -> Self::HeadStream {
|
async fn finalized_heads(&self, _: ParaId) -> RelayChainResult<Self::HeadStream> {
|
||||||
let stream = self
|
let stream = self
|
||||||
.inner
|
.inner
|
||||||
.lock()
|
.lock()
|
||||||
@@ -92,10 +95,14 @@ impl crate::parachain_consensus::RelaychainClient for Relaychain {
|
|||||||
.take()
|
.take()
|
||||||
.expect("Should only be called once");
|
.expect("Should only be called once");
|
||||||
|
|
||||||
Box::new(stream.map(|v| v.encode()))
|
Ok(Box::new(stream.map(|v| v.encode())))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parachain_head_at(&self, _: &BlockId<PBlock>, _: ParaId) -> ClientResult<Option<Vec<u8>>> {
|
async fn parachain_head_at(
|
||||||
|
&self,
|
||||||
|
_: &BlockId<PBlock>,
|
||||||
|
_: ParaId,
|
||||||
|
) -> RelayChainResult<Option<Vec<u8>>> {
|
||||||
unimplemented!("Not required for tests")
|
unimplemented!("Not required for tests")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ where
|
|||||||
.propose(
|
.propose(
|
||||||
inherent_data,
|
inherent_data,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
//TODO: Fix this.
|
// TODO: Fix this.
|
||||||
Duration::from_millis(500),
|
Duration::from_millis(500),
|
||||||
// Set the block limit to 50% of the maximum PoV size.
|
// Set the block limit to 50% of the maximum PoV size.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -38,11 +38,7 @@ use polkadot_primitives::v1::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use codec::{Decode, DecodeAll, Encode};
|
use codec::{Decode, DecodeAll, Encode};
|
||||||
use futures::{
|
use futures::{channel::oneshot, future::FutureExt, Future};
|
||||||
channel::oneshot,
|
|
||||||
future::{ready, FutureExt},
|
|
||||||
Future,
|
|
||||||
};
|
|
||||||
|
|
||||||
use std::{convert::TryFrom, fmt, marker::PhantomData, pin::Pin, sync::Arc};
|
use std::{convert::TryFrom, fmt, marker::PhantomData, pin::Pin, sync::Arc};
|
||||||
|
|
||||||
@@ -128,7 +124,7 @@ impl BlockAnnounceData {
|
|||||||
/// Check the signature of the statement.
|
/// Check the signature of the statement.
|
||||||
///
|
///
|
||||||
/// Returns an `Err(_)` if it failed.
|
/// Returns an `Err(_)` if it failed.
|
||||||
fn check_signature<RCInterface>(
|
async fn check_signature<RCInterface>(
|
||||||
self,
|
self,
|
||||||
relay_chain_client: &RCInterface,
|
relay_chain_client: &RCInterface,
|
||||||
) -> Result<Validation, BlockAnnounceError>
|
) -> Result<Validation, BlockAnnounceError>
|
||||||
@@ -138,16 +134,16 @@ impl BlockAnnounceData {
|
|||||||
let validator_index = self.statement.unchecked_validator_index();
|
let validator_index = self.statement.unchecked_validator_index();
|
||||||
|
|
||||||
let runtime_api_block_id = BlockId::Hash(self.relay_parent);
|
let runtime_api_block_id = BlockId::Hash(self.relay_parent);
|
||||||
let session_index = match relay_chain_client.session_index_for_child(&runtime_api_block_id)
|
let session_index =
|
||||||
{
|
match relay_chain_client.session_index_for_child(&runtime_api_block_id).await {
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
Err(e) => return Err(BlockAnnounceError(format!("{:?}", e))),
|
Err(e) => return Err(BlockAnnounceError(format!("{:?}", e))),
|
||||||
};
|
};
|
||||||
|
|
||||||
let signing_context = SigningContext { parent_hash: self.relay_parent, session_index };
|
let signing_context = SigningContext { parent_hash: self.relay_parent, session_index };
|
||||||
|
|
||||||
// Check that the signer is a legit validator.
|
// Check that the signer is a legit validator.
|
||||||
let authorities = match relay_chain_client.validators(&runtime_api_block_id) {
|
let authorities = match relay_chain_client.validators(&runtime_api_block_id).await {
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
Err(e) => return Err(BlockAnnounceError(format!("{:?}", e))),
|
Err(e) => return Err(BlockAnnounceError(format!("{:?}", e))),
|
||||||
};
|
};
|
||||||
@@ -222,6 +218,7 @@ impl TryFrom<&'_ CollationSecondedSignal> for BlockAnnounceData {
|
|||||||
/// chain. If it is at the tip, it is required to provide a justification or otherwise we reject
|
/// 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
|
/// 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.
|
/// as it probably comes from a node that is currently syncing the chain.
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct BlockAnnounceValidator<Block, RCInterface> {
|
pub struct BlockAnnounceValidator<Block, RCInterface> {
|
||||||
phantom: PhantomData<Block>,
|
phantom: PhantomData<Block>,
|
||||||
relay_chain_interface: RCInterface,
|
relay_chain_interface: RCInterface,
|
||||||
@@ -247,13 +244,14 @@ where
|
|||||||
RCInterface: RelayChainInterface + Clone,
|
RCInterface: RelayChainInterface + Clone,
|
||||||
{
|
{
|
||||||
/// Get the included block of the given parachain in the relay chain.
|
/// Get the included block of the given parachain in the relay chain.
|
||||||
fn included_block(
|
async fn included_block(
|
||||||
relay_chain_interface: &RCInterface,
|
relay_chain_interface: &RCInterface,
|
||||||
block_id: &BlockId<PBlock>,
|
block_id: &BlockId<PBlock>,
|
||||||
para_id: ParaId,
|
para_id: ParaId,
|
||||||
) -> Result<Block::Header, BoxedError> {
|
) -> Result<Block::Header, BoxedError> {
|
||||||
let validation_data = relay_chain_interface
|
let validation_data = relay_chain_interface
|
||||||
.persisted_validation_data(block_id, para_id, OccupiedCoreAssumption::TimedOut)
|
.persisted_validation_data(block_id, para_id, OccupiedCoreAssumption::TimedOut)
|
||||||
|
.await
|
||||||
.map_err(|e| Box::new(BlockAnnounceError(format!("{:?}", e))) as Box<_>)?
|
.map_err(|e| Box::new(BlockAnnounceError(format!("{:?}", e))) as Box<_>)?
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
Box::new(BlockAnnounceError("Could not find parachain head in relay chain".into()))
|
Box::new(BlockAnnounceError("Could not find parachain head in relay chain".into()))
|
||||||
@@ -269,56 +267,59 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the backed block hash of the given parachain in the relay chain.
|
/// Get the backed block hash of the given parachain in the relay chain.
|
||||||
fn backed_block_hash(
|
async fn backed_block_hash(
|
||||||
relay_chain_interface: &RCInterface,
|
relay_chain_interface: &RCInterface,
|
||||||
block_id: &BlockId<PBlock>,
|
block_id: &BlockId<PBlock>,
|
||||||
para_id: ParaId,
|
para_id: ParaId,
|
||||||
) -> Result<Option<PHash>, BoxedError> {
|
) -> Result<Option<PHash>, BoxedError> {
|
||||||
let candidate_receipt = relay_chain_interface
|
let candidate_receipt = relay_chain_interface
|
||||||
.candidate_pending_availability(block_id, para_id)
|
.candidate_pending_availability(block_id, para_id)
|
||||||
|
.await
|
||||||
.map_err(|e| Box::new(BlockAnnounceError(format!("{:?}", e))) as Box<_>)?;
|
.map_err(|e| Box::new(BlockAnnounceError(format!("{:?}", e))) as Box<_>)?;
|
||||||
|
|
||||||
Ok(candidate_receipt.map(|cr| cr.descriptor.para_head))
|
Ok(candidate_receipt.map(|cr| cr.descriptor.para_head))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle a block announcement with empty data (no statement) attached to it.
|
/// Handle a block announcement with empty data (no statement) attached to it.
|
||||||
fn handle_empty_block_announce_data(
|
async fn handle_empty_block_announce_data(
|
||||||
&self,
|
&self,
|
||||||
header: Block::Header,
|
header: Block::Header,
|
||||||
) -> impl Future<Output = Result<Validation, BoxedError>> {
|
) -> Result<Validation, BoxedError> {
|
||||||
let relay_chain_interface = self.relay_chain_interface.clone();
|
let relay_chain_interface = self.relay_chain_interface.clone();
|
||||||
let para_id = self.para_id;
|
let para_id = self.para_id;
|
||||||
|
|
||||||
async move {
|
// Check if block is equal or higher than best (this requires a justification)
|
||||||
// Check if block is equal or higher than best (this requires a justification)
|
let relay_chain_best_hash = relay_chain_interface
|
||||||
let relay_chain_best_hash = relay_chain_interface.best_block_hash();
|
.best_block_hash()
|
||||||
let runtime_api_block_id = BlockId::Hash(relay_chain_best_hash);
|
.await
|
||||||
let block_number = header.number();
|
.map_err(|e| Box::new(e) as Box<_>)?;
|
||||||
|
let runtime_api_block_id = BlockId::Hash(relay_chain_best_hash);
|
||||||
|
let block_number = header.number();
|
||||||
|
|
||||||
let best_head =
|
let best_head =
|
||||||
Self::included_block(&relay_chain_interface, &runtime_api_block_id, para_id)?;
|
Self::included_block(&relay_chain_interface, &runtime_api_block_id, para_id).await?;
|
||||||
let known_best_number = best_head.number();
|
let known_best_number = best_head.number();
|
||||||
let backed_block =
|
let backed_block = || async {
|
||||||
|| Self::backed_block_hash(&relay_chain_interface, &runtime_api_block_id, para_id);
|
Self::backed_block_hash(&relay_chain_interface, &runtime_api_block_id, para_id).await
|
||||||
|
};
|
||||||
|
|
||||||
if best_head == header {
|
if best_head == header {
|
||||||
tracing::debug!(target: LOG_TARGET, "Announced block matches best block.",);
|
tracing::debug!(target: LOG_TARGET, "Announced block matches best block.",);
|
||||||
|
|
||||||
Ok(Validation::Success { is_new_best: true })
|
Ok(Validation::Success { is_new_best: true })
|
||||||
} else if Some(HeadData(header.encode()).hash()) == backed_block()? {
|
} else if Some(HeadData(header.encode()).hash()) == backed_block().await? {
|
||||||
tracing::debug!(target: LOG_TARGET, "Announced block matches latest backed block.",);
|
tracing::debug!(target: LOG_TARGET, "Announced block matches latest backed block.",);
|
||||||
|
|
||||||
Ok(Validation::Success { is_new_best: true })
|
Ok(Validation::Success { is_new_best: true })
|
||||||
} else if block_number >= known_best_number {
|
} else if block_number >= known_best_number {
|
||||||
tracing::debug!(
|
tracing::debug!(
|
||||||
target: LOG_TARGET,
|
target: LOG_TARGET,
|
||||||
"Validation failed because a justification is needed if the block at the top of the chain."
|
"Validation failed because a justification is needed if the block at the top of the chain."
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(Validation::Failure { disconnect: false })
|
Ok(Validation::Failure { disconnect: false })
|
||||||
} else {
|
} else {
|
||||||
Ok(Validation::Success { is_new_best: false })
|
Ok(Validation::Success { is_new_best: false })
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -331,32 +332,40 @@ where
|
|||||||
fn validate(
|
fn validate(
|
||||||
&mut self,
|
&mut self,
|
||||||
header: &Block::Header,
|
header: &Block::Header,
|
||||||
mut data: &[u8],
|
data: &[u8],
|
||||||
) -> Pin<Box<dyn Future<Output = Result<Validation, BoxedError>> + Send>> {
|
) -> Pin<Box<dyn Future<Output = Result<Validation, BoxedError>> + Send>> {
|
||||||
if self.relay_chain_interface.is_major_syncing() {
|
|
||||||
return ready(Ok(Validation::Success { is_new_best: false })).boxed()
|
|
||||||
}
|
|
||||||
|
|
||||||
if data.is_empty() {
|
|
||||||
return self.handle_empty_block_announce_data(header.clone()).boxed()
|
|
||||||
}
|
|
||||||
|
|
||||||
let block_announce_data = match BlockAnnounceData::decode_all(&mut data) {
|
|
||||||
Ok(r) => r,
|
|
||||||
Err(err) =>
|
|
||||||
return async move {
|
|
||||||
Err(Box::new(BlockAnnounceError(format!(
|
|
||||||
"Can not decode the `BlockAnnounceData`: {:?}",
|
|
||||||
err
|
|
||||||
))) as Box<_>)
|
|
||||||
}
|
|
||||||
.boxed(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let relay_chain_interface = self.relay_chain_interface.clone();
|
let relay_chain_interface = self.relay_chain_interface.clone();
|
||||||
|
let mut data = data.to_vec();
|
||||||
|
let header = header.clone();
|
||||||
let header_encoded = header.encode();
|
let header_encoded = header.encode();
|
||||||
|
let block_announce_validator = self.clone();
|
||||||
|
|
||||||
async move {
|
async move {
|
||||||
|
let relay_chain_is_syncing = relay_chain_interface
|
||||||
|
.is_major_syncing()
|
||||||
|
.await
|
||||||
|
.map_err(|e| {
|
||||||
|
tracing::error!(target: LOG_TARGET, "Unable to determine sync status. {}", e)
|
||||||
|
})
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
|
if relay_chain_is_syncing {
|
||||||
|
return Ok(Validation::Success { is_new_best: false })
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.is_empty() {
|
||||||
|
return block_announce_validator.handle_empty_block_announce_data(header).await
|
||||||
|
}
|
||||||
|
|
||||||
|
let block_announce_data = match BlockAnnounceData::decode_all(&mut data) {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(err) =>
|
||||||
|
return Err(Box::new(BlockAnnounceError(format!(
|
||||||
|
"Can not decode the `BlockAnnounceData`: {:?}",
|
||||||
|
err
|
||||||
|
))) as Box<_>),
|
||||||
|
};
|
||||||
|
|
||||||
if let Err(e) = block_announce_data.validate(header_encoded) {
|
if let Err(e) = block_announce_data.validate(header_encoded) {
|
||||||
return Ok(e)
|
return Ok(e)
|
||||||
}
|
}
|
||||||
@@ -370,6 +379,7 @@ where
|
|||||||
|
|
||||||
block_announce_data
|
block_announce_data
|
||||||
.check_signature(&relay_chain_interface)
|
.check_signature(&relay_chain_interface)
|
||||||
|
.await
|
||||||
.map_err(|e| Box::new(e) as Box<_>)
|
.map_err(|e| Box::new(e) as Box<_>)
|
||||||
}
|
}
|
||||||
.boxed()
|
.boxed()
|
||||||
|
|||||||
@@ -16,15 +16,15 @@
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use cumulus_relay_chain_interface::WaitError;
|
use cumulus_relay_chain_interface::{RelayChainError, RelayChainResult};
|
||||||
use cumulus_relay_chain_local::{check_block_in_chain, BlockCheckStatus};
|
use cumulus_relay_chain_local::{check_block_in_chain, BlockCheckStatus};
|
||||||
use cumulus_test_service::runtime::{Block, Hash, Header};
|
use cumulus_test_service::runtime::{Block, Hash, Header};
|
||||||
use futures::{executor::block_on, poll, task::Poll, FutureExt, StreamExt};
|
use futures::{executor::block_on, poll, task::Poll, FutureExt, Stream, StreamExt};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use polkadot_node_primitives::{SignedFullStatement, Statement};
|
use polkadot_node_primitives::{SignedFullStatement, Statement};
|
||||||
use polkadot_primitives::v1::{
|
use polkadot_primitives::v1::{
|
||||||
Block as PBlock, CandidateCommitments, CandidateDescriptor, CollatorPair,
|
CandidateCommitments, CandidateDescriptor, CollatorPair, CommittedCandidateReceipt,
|
||||||
CommittedCandidateReceipt, Hash as PHash, HeadData, Id as ParaId, InboundDownwardMessage,
|
Hash as PHash, HeadData, Header as PHeader, Id as ParaId, InboundDownwardMessage,
|
||||||
InboundHrmpMessage, OccupiedCoreAssumption, PersistedValidationData, SessionIndex,
|
InboundHrmpMessage, OccupiedCoreAssumption, PersistedValidationData, SessionIndex,
|
||||||
SigningContext, ValidationCodeHash, ValidatorId,
|
SigningContext, ValidationCodeHash, ValidatorId,
|
||||||
};
|
};
|
||||||
@@ -77,53 +77,60 @@ impl DummyRelayChainInterface {
|
|||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl RelayChainInterface for DummyRelayChainInterface {
|
impl RelayChainInterface for DummyRelayChainInterface {
|
||||||
fn validators(
|
async fn validators(
|
||||||
&self,
|
&self,
|
||||||
_: &cumulus_primitives_core::relay_chain::BlockId,
|
_: &cumulus_primitives_core::relay_chain::BlockId,
|
||||||
) -> Result<Vec<ValidatorId>, sp_api::ApiError> {
|
) -> RelayChainResult<Vec<ValidatorId>> {
|
||||||
Ok(self.data.lock().validators.clone())
|
Ok(self.data.lock().validators.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_status(
|
async fn block_status(
|
||||||
&self,
|
&self,
|
||||||
block_id: cumulus_primitives_core::relay_chain::BlockId,
|
block_id: cumulus_primitives_core::relay_chain::BlockId,
|
||||||
) -> Result<sp_blockchain::BlockStatus, sp_blockchain::Error> {
|
) -> RelayChainResult<sp_blockchain::BlockStatus> {
|
||||||
self.relay_backend.blockchain().status(block_id)
|
self.relay_backend
|
||||||
|
.blockchain()
|
||||||
|
.status(block_id)
|
||||||
|
.map_err(RelayChainError::BlockchainError)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn best_block_hash(&self) -> PHash {
|
async fn best_block_hash(&self) -> RelayChainResult<PHash> {
|
||||||
self.relay_backend.blockchain().info().best_hash
|
Ok(self.relay_backend.blockchain().info().best_hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn retrieve_dmq_contents(&self, _: ParaId, _: PHash) -> Option<Vec<InboundDownwardMessage>> {
|
async fn retrieve_dmq_contents(
|
||||||
unimplemented!("Not needed for test")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn retrieve_all_inbound_hrmp_channel_contents(
|
|
||||||
&self,
|
&self,
|
||||||
_: ParaId,
|
_: ParaId,
|
||||||
_: PHash,
|
_: PHash,
|
||||||
) -> Option<BTreeMap<ParaId, Vec<InboundHrmpMessage>>> {
|
) -> RelayChainResult<Vec<InboundDownwardMessage>> {
|
||||||
Some(BTreeMap::new())
|
unimplemented!("Not needed for test")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn persisted_validation_data(
|
async fn retrieve_all_inbound_hrmp_channel_contents(
|
||||||
|
&self,
|
||||||
|
_: ParaId,
|
||||||
|
_: PHash,
|
||||||
|
) -> RelayChainResult<BTreeMap<ParaId, Vec<InboundHrmpMessage>>> {
|
||||||
|
Ok(BTreeMap::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn persisted_validation_data(
|
||||||
&self,
|
&self,
|
||||||
_: &cumulus_primitives_core::relay_chain::BlockId,
|
_: &cumulus_primitives_core::relay_chain::BlockId,
|
||||||
_: ParaId,
|
_: ParaId,
|
||||||
_: OccupiedCoreAssumption,
|
_: OccupiedCoreAssumption,
|
||||||
) -> Result<Option<PersistedValidationData>, sp_api::ApiError> {
|
) -> RelayChainResult<Option<PersistedValidationData>> {
|
||||||
Ok(Some(PersistedValidationData {
|
Ok(Some(PersistedValidationData {
|
||||||
parent_head: HeadData(default_header().encode()),
|
parent_head: HeadData(default_header().encode()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn candidate_pending_availability(
|
async fn candidate_pending_availability(
|
||||||
&self,
|
&self,
|
||||||
_: &cumulus_primitives_core::relay_chain::BlockId,
|
_: &cumulus_primitives_core::relay_chain::BlockId,
|
||||||
_: ParaId,
|
_: ParaId,
|
||||||
) -> Result<Option<CommittedCandidateReceipt>, sp_api::ApiError> {
|
) -> RelayChainResult<Option<CommittedCandidateReceipt>> {
|
||||||
if self.data.lock().has_pending_availability {
|
if self.data.lock().has_pending_availability {
|
||||||
Ok(Some(CommittedCandidateReceipt {
|
Ok(Some(CommittedCandidateReceipt {
|
||||||
descriptor: CandidateDescriptor {
|
descriptor: CandidateDescriptor {
|
||||||
@@ -152,60 +159,58 @@ impl RelayChainInterface for DummyRelayChainInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn session_index_for_child(
|
async fn session_index_for_child(
|
||||||
&self,
|
&self,
|
||||||
_: &cumulus_primitives_core::relay_chain::BlockId,
|
_: &cumulus_primitives_core::relay_chain::BlockId,
|
||||||
) -> Result<SessionIndex, sp_api::ApiError> {
|
) -> RelayChainResult<SessionIndex> {
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_notification_stream(&self) -> sc_client_api::ImportNotifications<PBlock> {
|
async fn import_notification_stream(
|
||||||
self.relay_client.import_notification_stream()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn finality_notification_stream(&self) -> sc_client_api::FinalityNotifications<PBlock> {
|
|
||||||
self.relay_client.finality_notification_stream()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn storage_changes_notification_stream(
|
|
||||||
&self,
|
&self,
|
||||||
filter_keys: Option<&[sc_client_api::StorageKey]>,
|
) -> RelayChainResult<Pin<Box<dyn Stream<Item = PHeader> + Send>>> {
|
||||||
child_filter_keys: Option<
|
Ok(Box::pin(
|
||||||
&[(sc_client_api::StorageKey, Option<Vec<sc_client_api::StorageKey>>)],
|
self.relay_client
|
||||||
>,
|
.import_notification_stream()
|
||||||
) -> sc_client_api::blockchain::Result<sc_client_api::StorageEventStream<PHash>> {
|
.map(|notification| notification.header),
|
||||||
self.relay_client
|
))
|
||||||
.storage_changes_notification_stream(filter_keys, child_filter_keys)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_major_syncing(&self) -> bool {
|
async fn finality_notification_stream(
|
||||||
false
|
&self,
|
||||||
|
) -> RelayChainResult<Pin<Box<dyn Stream<Item = PHeader> + Send>>> {
|
||||||
|
Ok(Box::pin(
|
||||||
|
self.relay_client
|
||||||
|
.finality_notification_stream()
|
||||||
|
.map(|notification| notification.header),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn overseer_handle(&self) -> Option<Handle> {
|
async fn is_major_syncing(&self) -> RelayChainResult<bool> {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn overseer_handle(&self) -> RelayChainResult<Option<Handle>> {
|
||||||
unimplemented!("Not needed for test")
|
unimplemented!("Not needed for test")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_storage_by_key(
|
async fn get_storage_by_key(
|
||||||
&self,
|
&self,
|
||||||
_: &polkadot_service::BlockId,
|
_: &polkadot_service::BlockId,
|
||||||
_: &[u8],
|
_: &[u8],
|
||||||
) -> Result<Option<StorageValue>, sp_blockchain::Error> {
|
) -> RelayChainResult<Option<StorageValue>> {
|
||||||
unimplemented!("Not needed for test")
|
unimplemented!("Not needed for test")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prove_read(
|
async fn prove_read(
|
||||||
&self,
|
&self,
|
||||||
_: &polkadot_service::BlockId,
|
_: &polkadot_service::BlockId,
|
||||||
_: &Vec<Vec<u8>>,
|
_: &Vec<Vec<u8>>,
|
||||||
) -> Result<Option<sc_client_api::StorageProof>, Box<dyn sp_state_machine::Error>> {
|
) -> RelayChainResult<sc_client_api::StorageProof> {
|
||||||
unimplemented!("Not needed for test")
|
unimplemented!("Not needed for test")
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn wait_for_block(
|
async fn wait_for_block(&self, hash: PHash) -> RelayChainResult<()> {
|
||||||
&self,
|
|
||||||
hash: PHash,
|
|
||||||
) -> Result<(), cumulus_relay_chain_interface::WaitError> {
|
|
||||||
let mut listener = match check_block_in_chain(
|
let mut listener = match check_block_in_chain(
|
||||||
self.relay_backend.clone(),
|
self.relay_backend.clone(),
|
||||||
self.relay_client.clone(),
|
self.relay_client.clone(),
|
||||||
@@ -219,16 +224,32 @@ impl RelayChainInterface for DummyRelayChainInterface {
|
|||||||
|
|
||||||
loop {
|
loop {
|
||||||
futures::select! {
|
futures::select! {
|
||||||
_ = timeout => return Err(WaitError::Timeout(hash)),
|
_ = timeout => return Err(RelayChainError::WaitTimeout(hash)),
|
||||||
evt = listener.next() => match evt {
|
evt = listener.next() => match evt {
|
||||||
Some(evt) if evt.hash == hash => return Ok(()),
|
Some(evt) if evt.hash == hash => return Ok(()),
|
||||||
// Not the event we waited on.
|
// Not the event we waited on.
|
||||||
Some(_) => continue,
|
Some(_) => continue,
|
||||||
None => return Err(WaitError::ImportListenerClosed(hash)),
|
None => return Err(RelayChainError::ImportListenerClosed(hash)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn new_best_notification_stream(
|
||||||
|
&self,
|
||||||
|
) -> RelayChainResult<Pin<Box<dyn Stream<Item = PHeader> + Send>>> {
|
||||||
|
let notifications_stream =
|
||||||
|
self.relay_client
|
||||||
|
.import_notification_stream()
|
||||||
|
.filter_map(|notification| async move {
|
||||||
|
if notification.is_new_best {
|
||||||
|
Some(notification.header)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Ok(Box::pin(notifications_stream))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_validator_and_api(
|
fn make_validator_and_api(
|
||||||
@@ -274,6 +295,7 @@ async fn make_gossip_message_and_header(
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
let session_index = relay_chain_interface
|
let session_index = relay_chain_interface
|
||||||
.session_index_for_child(&BlockId::Hash(relay_parent))
|
.session_index_for_child(&BlockId::Hash(relay_parent))
|
||||||
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let signing_context = SigningContext { parent_hash: relay_parent, session_index };
|
let signing_context = SigningContext { parent_hash: relay_parent, session_index };
|
||||||
|
|
||||||
@@ -442,9 +464,9 @@ fn check_statement_is_correctly_signed() {
|
|||||||
assert_eq!(Validation::Failure { disconnect: true }, res.unwrap());
|
assert_eq!(Validation::Failure { disconnect: true }, res.unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[tokio::test]
|
||||||
fn check_statement_seconded() {
|
async fn check_statement_seconded() {
|
||||||
let (mut validator, api) = make_validator_and_api();
|
let (mut validator, relay_chain_interface) = make_validator_and_api();
|
||||||
let header = default_header();
|
let header = default_header();
|
||||||
let relay_parent = H256::from_low_u64_be(1);
|
let relay_parent = H256::from_low_u64_be(1);
|
||||||
|
|
||||||
@@ -455,7 +477,10 @@ fn check_statement_seconded() {
|
|||||||
Some(&Sr25519Keyring::Alice.to_seed()),
|
Some(&Sr25519Keyring::Alice.to_seed()),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let session_index = api.session_index_for_child(&BlockId::Hash(relay_parent)).unwrap();
|
let session_index = relay_chain_interface
|
||||||
|
.session_index_for_child(&BlockId::Hash(relay_parent))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
let signing_context = SigningContext { parent_hash: relay_parent, session_index };
|
let signing_context = SigningContext { parent_hash: relay_parent, session_index };
|
||||||
|
|
||||||
let statement = Statement::Valid(Default::default());
|
let statement = Statement::Valid(Default::default());
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ use polkadot_primitives::v1::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use cumulus_primitives_core::ParachainBlockData;
|
use cumulus_primitives_core::ParachainBlockData;
|
||||||
use cumulus_relay_chain_interface::RelayChainInterface;
|
use cumulus_relay_chain_interface::{RelayChainInterface, RelayChainResult};
|
||||||
|
|
||||||
use codec::Decode;
|
use codec::Decode;
|
||||||
use futures::{select, stream::FuturesUnordered, Future, FutureExt, Stream, StreamExt};
|
use futures::{select, stream::FuturesUnordered, Future, FutureExt, Stream, StreamExt};
|
||||||
@@ -381,7 +381,14 @@ where
|
|||||||
let mut imported_blocks = self.parachain_client.import_notification_stream().fuse();
|
let mut imported_blocks = self.parachain_client.import_notification_stream().fuse();
|
||||||
let mut finalized_blocks = self.parachain_client.finality_notification_stream().fuse();
|
let mut finalized_blocks = self.parachain_client.finality_notification_stream().fuse();
|
||||||
let pending_candidates =
|
let pending_candidates =
|
||||||
pending_candidates(self.relay_chain_interface.clone(), self.para_id).fuse();
|
match pending_candidates(self.relay_chain_interface.clone(), self.para_id).await {
|
||||||
|
Ok(pending_candidate_stream) => pending_candidate_stream.fuse(),
|
||||||
|
Err(err) => {
|
||||||
|
tracing::error!(target: LOG_TARGET, error = ?err, "Unable to retrieve pending candidate stream.");
|
||||||
|
return
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
futures::pin_mut!(pending_candidates);
|
futures::pin_mut!(pending_candidates);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
@@ -435,28 +442,41 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a stream over pending candidates for the parachain corresponding to `para_id`.
|
/// Returns a stream over pending candidates for the parachain corresponding to `para_id`.
|
||||||
fn pending_candidates(
|
async fn pending_candidates(
|
||||||
relay_chain_client: impl RelayChainInterface,
|
relay_chain_client: impl RelayChainInterface + Clone,
|
||||||
para_id: ParaId,
|
para_id: ParaId,
|
||||||
) -> impl Stream<Item = (CommittedCandidateReceipt, SessionIndex)> {
|
) -> RelayChainResult<impl Stream<Item = (CommittedCandidateReceipt, SessionIndex)>> {
|
||||||
relay_chain_client.import_notification_stream().filter_map(move |n| {
|
let import_notification_stream = relay_chain_client.import_notification_stream().await?;
|
||||||
let res = relay_chain_client
|
|
||||||
.candidate_pending_availability(&BlockId::hash(n.hash), para_id)
|
|
||||||
.and_then(|pa| {
|
|
||||||
relay_chain_client
|
|
||||||
.session_index_for_child(&BlockId::hash(n.hash))
|
|
||||||
.map(|v| pa.map(|pa| (pa, v)))
|
|
||||||
})
|
|
||||||
.map_err(|e| {
|
|
||||||
tracing::error!(
|
|
||||||
target: LOG_TARGET,
|
|
||||||
error = ?e,
|
|
||||||
"Failed fetch pending candidates.",
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.ok()
|
|
||||||
.flatten();
|
|
||||||
|
|
||||||
async move { res }
|
let filtered_stream = import_notification_stream.filter_map(move |n| {
|
||||||
})
|
let client_for_closure = relay_chain_client.clone();
|
||||||
|
async move {
|
||||||
|
let block_id = BlockId::hash(n.hash());
|
||||||
|
let pending_availability_result = client_for_closure
|
||||||
|
.candidate_pending_availability(&block_id, para_id)
|
||||||
|
.await
|
||||||
|
.map_err(|e| {
|
||||||
|
tracing::error!(
|
||||||
|
target: LOG_TARGET,
|
||||||
|
error = ?e,
|
||||||
|
"Failed to fetch pending candidates.",
|
||||||
|
)
|
||||||
|
});
|
||||||
|
let session_index_result =
|
||||||
|
client_for_closure.session_index_for_child(&block_id).await.map_err(|e| {
|
||||||
|
tracing::error!(
|
||||||
|
target: LOG_TARGET,
|
||||||
|
error = ?e,
|
||||||
|
"Failed to fetch session index.",
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Ok(Some(candidate)) = pending_availability_result {
|
||||||
|
session_index_result.map(|session_index| (candidate, session_index)).ok()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Ok(filtered_stream)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,10 @@ sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master
|
|||||||
sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
|
sc-service = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
|
|
||||||
|
futures = "0.3.1"
|
||||||
parking_lot = "0.11.1"
|
parking_lot = "0.11.1"
|
||||||
derive_more = "0.99.2"
|
derive_more = "0.99.2"
|
||||||
async-trait = "0.1.52"
|
async-trait = "0.1.52"
|
||||||
|
thiserror = "1.0.30"
|
||||||
|
|||||||
@@ -14,136 +14,140 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
|
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::{collections::BTreeMap, sync::Arc};
|
use std::{collections::BTreeMap, pin::Pin, sync::Arc};
|
||||||
|
|
||||||
use cumulus_primitives_core::{
|
use cumulus_primitives_core::{
|
||||||
relay_chain::{
|
relay_chain::{
|
||||||
v1::{CommittedCandidateReceipt, OccupiedCoreAssumption, SessionIndex, ValidatorId},
|
v1::{CommittedCandidateReceipt, OccupiedCoreAssumption, SessionIndex, ValidatorId},
|
||||||
Block as PBlock, BlockId, Hash as PHash, InboundHrmpMessage,
|
BlockId, Hash as PHash, Header as PHeader, InboundHrmpMessage,
|
||||||
},
|
},
|
||||||
InboundDownwardMessage, ParaId, PersistedValidationData,
|
InboundDownwardMessage, ParaId, PersistedValidationData,
|
||||||
};
|
};
|
||||||
use polkadot_overseer::Handle as OverseerHandle;
|
use polkadot_overseer::Handle as OverseerHandle;
|
||||||
use sc_client_api::{blockchain::BlockStatus, StorageProof};
|
use sc_client_api::{blockchain::BlockStatus, StorageProof};
|
||||||
|
|
||||||
|
use futures::Stream;
|
||||||
|
|
||||||
|
use async_trait::async_trait;
|
||||||
use sp_api::ApiError;
|
use sp_api::ApiError;
|
||||||
use sp_state_machine::StorageValue;
|
use sp_state_machine::StorageValue;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
pub type RelayChainResult<T> = Result<T, RelayChainError>;
|
||||||
|
|
||||||
#[derive(Debug, derive_more::Display)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum WaitError {
|
pub enum RelayChainError {
|
||||||
#[display(fmt = "Timeout while waiting for relay-chain block `{}` to be imported.", _0)]
|
#[error("Error occured while calling relay chain runtime: {0:?}")]
|
||||||
Timeout(PHash),
|
ApiError(#[from] ApiError),
|
||||||
#[display(
|
#[error("Timeout while waiting for relay-chain block `{0}` to be imported.")]
|
||||||
fmt = "Import listener closed while waiting for relay-chain block `{}` to be imported.",
|
WaitTimeout(PHash),
|
||||||
_0
|
#[error("Import listener closed while waiting for relay-chain block `{0}` to be imported.")]
|
||||||
)]
|
|
||||||
ImportListenerClosed(PHash),
|
ImportListenerClosed(PHash),
|
||||||
#[display(
|
#[error("Blockchain returned an error while waiting for relay-chain block `{0}` to be imported: {1:?}")]
|
||||||
fmt = "Blockchain returned an error while waiting for relay-chain block `{}` to be imported: {:?}",
|
WaitBlockchainError(PHash, sp_blockchain::Error),
|
||||||
_0,
|
#[error("Blockchain returned an error: {0:?}")]
|
||||||
_1
|
BlockchainError(#[from] sp_blockchain::Error),
|
||||||
)]
|
#[error("State machine error occured: {0:?}")]
|
||||||
BlockchainError(PHash, sp_blockchain::Error),
|
StateMachineError(Box<dyn sp_state_machine::Error>),
|
||||||
|
#[error("Unspecified error occured: {0:?}")]
|
||||||
|
GenericError(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait that provides all necessary methods for interaction between collator and relay chain.
|
/// Trait that provides all necessary methods for interaction between collator and relay chain.
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait RelayChainInterface: Send + Sync {
|
pub trait RelayChainInterface: Send + Sync {
|
||||||
/// Fetch a storage item by key.
|
/// Fetch a storage item by key.
|
||||||
fn get_storage_by_key(
|
async fn get_storage_by_key(
|
||||||
&self,
|
&self,
|
||||||
block_id: &BlockId,
|
block_id: &BlockId,
|
||||||
key: &[u8],
|
key: &[u8],
|
||||||
) -> Result<Option<StorageValue>, sp_blockchain::Error>;
|
) -> RelayChainResult<Option<StorageValue>>;
|
||||||
|
|
||||||
/// Fetch a vector of current validators.
|
/// Fetch a vector of current validators.
|
||||||
fn validators(&self, block_id: &BlockId) -> Result<Vec<ValidatorId>, ApiError>;
|
async fn validators(&self, block_id: &BlockId) -> RelayChainResult<Vec<ValidatorId>>;
|
||||||
|
|
||||||
/// Get the status of a given block.
|
/// Get the status of a given block.
|
||||||
fn block_status(&self, block_id: BlockId) -> Result<BlockStatus, sp_blockchain::Error>;
|
async fn block_status(&self, block_id: BlockId) -> RelayChainResult<BlockStatus>;
|
||||||
|
|
||||||
/// Get the hash of the current best block.
|
/// Get the hash of the current best block.
|
||||||
fn best_block_hash(&self) -> PHash;
|
async fn best_block_hash(&self) -> RelayChainResult<PHash>;
|
||||||
|
|
||||||
/// Returns the whole contents of the downward message queue for the parachain we are collating
|
/// Returns the whole contents of the downward message queue for the parachain we are collating
|
||||||
/// for.
|
/// for.
|
||||||
///
|
///
|
||||||
/// Returns `None` in case of an error.
|
/// Returns `None` in case of an error.
|
||||||
fn retrieve_dmq_contents(
|
async fn retrieve_dmq_contents(
|
||||||
&self,
|
&self,
|
||||||
para_id: ParaId,
|
para_id: ParaId,
|
||||||
relay_parent: PHash,
|
relay_parent: PHash,
|
||||||
) -> Option<Vec<InboundDownwardMessage>>;
|
) -> RelayChainResult<Vec<InboundDownwardMessage>>;
|
||||||
|
|
||||||
/// Returns channels contents for each inbound HRMP channel addressed to the parachain we are
|
/// Returns channels contents for each inbound HRMP channel addressed to the parachain we are
|
||||||
/// collating for.
|
/// collating for.
|
||||||
///
|
///
|
||||||
/// Empty channels are also included.
|
/// Empty channels are also included.
|
||||||
fn retrieve_all_inbound_hrmp_channel_contents(
|
async fn retrieve_all_inbound_hrmp_channel_contents(
|
||||||
&self,
|
&self,
|
||||||
para_id: ParaId,
|
para_id: ParaId,
|
||||||
relay_parent: PHash,
|
relay_parent: PHash,
|
||||||
) -> Option<BTreeMap<ParaId, Vec<InboundHrmpMessage>>>;
|
) -> RelayChainResult<BTreeMap<ParaId, Vec<InboundHrmpMessage>>>;
|
||||||
|
|
||||||
/// Yields the persisted validation data for the given `ParaId` along with an assumption that
|
/// Yields the persisted validation data for the given `ParaId` along with an assumption that
|
||||||
/// should be used if the para currently occupies a core.
|
/// should be used if the para currently occupies a core.
|
||||||
///
|
///
|
||||||
/// Returns `None` if either the para is not registered or the assumption is `Freed`
|
/// Returns `None` if either the para is not registered or the assumption is `Freed`
|
||||||
/// and the para already occupies a core.
|
/// and the para already occupies a core.
|
||||||
fn persisted_validation_data(
|
async fn persisted_validation_data(
|
||||||
&self,
|
&self,
|
||||||
block_id: &BlockId,
|
block_id: &BlockId,
|
||||||
para_id: ParaId,
|
para_id: ParaId,
|
||||||
_: OccupiedCoreAssumption,
|
_: OccupiedCoreAssumption,
|
||||||
) -> Result<Option<PersistedValidationData>, ApiError>;
|
) -> RelayChainResult<Option<PersistedValidationData>>;
|
||||||
|
|
||||||
/// Get the receipt of a candidate pending availability. This returns `Some` for any paras
|
/// Get the receipt of a candidate pending availability. This returns `Some` for any paras
|
||||||
/// assigned to occupied cores in `availability_cores` and `None` otherwise.
|
/// assigned to occupied cores in `availability_cores` and `None` otherwise.
|
||||||
fn candidate_pending_availability(
|
async fn candidate_pending_availability(
|
||||||
&self,
|
&self,
|
||||||
block_id: &BlockId,
|
block_id: &BlockId,
|
||||||
para_id: ParaId,
|
para_id: ParaId,
|
||||||
) -> Result<Option<CommittedCandidateReceipt>, ApiError>;
|
) -> RelayChainResult<Option<CommittedCandidateReceipt>>;
|
||||||
|
|
||||||
/// Returns the session index expected at a child of the block.
|
/// Returns the session index expected at a child of the block.
|
||||||
fn session_index_for_child(&self, block_id: &BlockId) -> Result<SessionIndex, ApiError>;
|
async fn session_index_for_child(&self, block_id: &BlockId) -> RelayChainResult<SessionIndex>;
|
||||||
|
|
||||||
/// Get a stream of import block notifications.
|
/// Get a stream of import block notifications.
|
||||||
fn import_notification_stream(&self) -> sc_client_api::ImportNotifications<PBlock>;
|
async fn import_notification_stream(
|
||||||
|
&self,
|
||||||
|
) -> RelayChainResult<Pin<Box<dyn Stream<Item = PHeader> + Send>>>;
|
||||||
|
|
||||||
|
/// Get a stream of new best block notifications.
|
||||||
|
async fn new_best_notification_stream(
|
||||||
|
&self,
|
||||||
|
) -> RelayChainResult<Pin<Box<dyn Stream<Item = PHeader> + Send>>>;
|
||||||
|
|
||||||
/// Wait for a block with a given hash in the relay chain.
|
/// Wait for a block with a given hash in the relay chain.
|
||||||
///
|
///
|
||||||
/// This method returns immediately on error or if the block is already
|
/// This method returns immediately on error or if the block is already
|
||||||
/// reported to be in chain. Otherwise, it waits for the block to arrive.
|
/// reported to be in chain. Otherwise, it waits for the block to arrive.
|
||||||
async fn wait_for_block(&self, hash: PHash) -> Result<(), WaitError>;
|
async fn wait_for_block(&self, hash: PHash) -> RelayChainResult<()>;
|
||||||
|
|
||||||
/// Get a stream of finality notifications.
|
/// Get a stream of finality notifications.
|
||||||
fn finality_notification_stream(&self) -> sc_client_api::FinalityNotifications<PBlock>;
|
async fn finality_notification_stream(
|
||||||
|
|
||||||
/// Get a stream of storage change notifications.
|
|
||||||
fn storage_changes_notification_stream(
|
|
||||||
&self,
|
&self,
|
||||||
filter_keys: Option<&[sc_client_api::StorageKey]>,
|
) -> RelayChainResult<Pin<Box<dyn Stream<Item = PHeader> + Send>>>;
|
||||||
child_filter_keys: Option<
|
|
||||||
&[(sc_client_api::StorageKey, Option<Vec<sc_client_api::StorageKey>>)],
|
|
||||||
>,
|
|
||||||
) -> sc_client_api::blockchain::Result<sc_client_api::StorageEventStream<PHash>>;
|
|
||||||
|
|
||||||
/// Whether the synchronization service is undergoing major sync.
|
/// Whether the synchronization service is undergoing major sync.
|
||||||
/// Returns true if so.
|
/// Returns true if so.
|
||||||
fn is_major_syncing(&self) -> bool;
|
async fn is_major_syncing(&self) -> RelayChainResult<bool>;
|
||||||
|
|
||||||
/// Get a handle to the overseer.
|
/// Get a handle to the overseer.
|
||||||
fn overseer_handle(&self) -> Option<OverseerHandle>;
|
fn overseer_handle(&self) -> RelayChainResult<Option<OverseerHandle>>;
|
||||||
|
|
||||||
/// Generate a storage read proof.
|
/// Generate a storage read proof.
|
||||||
fn prove_read(
|
async fn prove_read(
|
||||||
&self,
|
&self,
|
||||||
block_id: &BlockId,
|
block_id: &BlockId,
|
||||||
relevant_keys: &Vec<Vec<u8>>,
|
relevant_keys: &Vec<Vec<u8>>,
|
||||||
) -> Result<Option<StorageProof>, Box<dyn sp_state_machine::Error>>;
|
) -> RelayChainResult<StorageProof>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
@@ -151,98 +155,100 @@ impl<T> RelayChainInterface for Arc<T>
|
|||||||
where
|
where
|
||||||
T: RelayChainInterface + ?Sized,
|
T: RelayChainInterface + ?Sized,
|
||||||
{
|
{
|
||||||
fn retrieve_dmq_contents(
|
async fn retrieve_dmq_contents(
|
||||||
&self,
|
&self,
|
||||||
para_id: ParaId,
|
para_id: ParaId,
|
||||||
relay_parent: PHash,
|
relay_parent: PHash,
|
||||||
) -> Option<Vec<InboundDownwardMessage>> {
|
) -> RelayChainResult<Vec<InboundDownwardMessage>> {
|
||||||
(**self).retrieve_dmq_contents(para_id, relay_parent)
|
(**self).retrieve_dmq_contents(para_id, relay_parent).await
|
||||||
}
|
}
|
||||||
|
|
||||||
fn retrieve_all_inbound_hrmp_channel_contents(
|
async fn retrieve_all_inbound_hrmp_channel_contents(
|
||||||
&self,
|
&self,
|
||||||
para_id: ParaId,
|
para_id: ParaId,
|
||||||
relay_parent: PHash,
|
relay_parent: PHash,
|
||||||
) -> Option<BTreeMap<ParaId, Vec<InboundHrmpMessage>>> {
|
) -> RelayChainResult<BTreeMap<ParaId, Vec<InboundHrmpMessage>>> {
|
||||||
(**self).retrieve_all_inbound_hrmp_channel_contents(para_id, relay_parent)
|
(**self).retrieve_all_inbound_hrmp_channel_contents(para_id, relay_parent).await
|
||||||
}
|
}
|
||||||
|
|
||||||
fn persisted_validation_data(
|
async fn persisted_validation_data(
|
||||||
&self,
|
&self,
|
||||||
block_id: &BlockId,
|
block_id: &BlockId,
|
||||||
para_id: ParaId,
|
para_id: ParaId,
|
||||||
occupied_core_assumption: OccupiedCoreAssumption,
|
occupied_core_assumption: OccupiedCoreAssumption,
|
||||||
) -> Result<Option<PersistedValidationData>, ApiError> {
|
) -> RelayChainResult<Option<PersistedValidationData>> {
|
||||||
(**self).persisted_validation_data(block_id, para_id, occupied_core_assumption)
|
(**self)
|
||||||
|
.persisted_validation_data(block_id, para_id, occupied_core_assumption)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
fn candidate_pending_availability(
|
async fn candidate_pending_availability(
|
||||||
&self,
|
&self,
|
||||||
block_id: &BlockId,
|
block_id: &BlockId,
|
||||||
para_id: ParaId,
|
para_id: ParaId,
|
||||||
) -> Result<Option<CommittedCandidateReceipt>, ApiError> {
|
) -> RelayChainResult<Option<CommittedCandidateReceipt>> {
|
||||||
(**self).candidate_pending_availability(block_id, para_id)
|
(**self).candidate_pending_availability(block_id, para_id).await
|
||||||
}
|
}
|
||||||
|
|
||||||
fn session_index_for_child(&self, block_id: &BlockId) -> Result<SessionIndex, ApiError> {
|
async fn session_index_for_child(&self, block_id: &BlockId) -> RelayChainResult<SessionIndex> {
|
||||||
(**self).session_index_for_child(block_id)
|
(**self).session_index_for_child(block_id).await
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validators(&self, block_id: &BlockId) -> Result<Vec<ValidatorId>, ApiError> {
|
async fn validators(&self, block_id: &BlockId) -> RelayChainResult<Vec<ValidatorId>> {
|
||||||
(**self).validators(block_id)
|
(**self).validators(block_id).await
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_notification_stream(&self) -> sc_client_api::ImportNotifications<PBlock> {
|
async fn import_notification_stream(
|
||||||
(**self).import_notification_stream()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn finality_notification_stream(&self) -> sc_client_api::FinalityNotifications<PBlock> {
|
|
||||||
(**self).finality_notification_stream()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn storage_changes_notification_stream(
|
|
||||||
&self,
|
&self,
|
||||||
filter_keys: Option<&[sc_client_api::StorageKey]>,
|
) -> RelayChainResult<Pin<Box<dyn Stream<Item = PHeader> + Send>>> {
|
||||||
child_filter_keys: Option<
|
(**self).import_notification_stream().await
|
||||||
&[(sc_client_api::StorageKey, Option<Vec<sc_client_api::StorageKey>>)],
|
|
||||||
>,
|
|
||||||
) -> sc_client_api::blockchain::Result<sc_client_api::StorageEventStream<PHash>> {
|
|
||||||
(**self).storage_changes_notification_stream(filter_keys, child_filter_keys)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn best_block_hash(&self) -> PHash {
|
async fn finality_notification_stream(
|
||||||
(**self).best_block_hash()
|
&self,
|
||||||
|
) -> RelayChainResult<Pin<Box<dyn Stream<Item = PHeader> + Send>>> {
|
||||||
|
(**self).finality_notification_stream().await
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_status(&self, block_id: BlockId) -> Result<BlockStatus, sp_blockchain::Error> {
|
async fn best_block_hash(&self) -> RelayChainResult<PHash> {
|
||||||
(**self).block_status(block_id)
|
(**self).best_block_hash().await
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_major_syncing(&self) -> bool {
|
async fn block_status(&self, block_id: BlockId) -> RelayChainResult<BlockStatus> {
|
||||||
(**self).is_major_syncing()
|
(**self).block_status(block_id).await
|
||||||
}
|
}
|
||||||
|
|
||||||
fn overseer_handle(&self) -> Option<OverseerHandle> {
|
async fn is_major_syncing(&self) -> RelayChainResult<bool> {
|
||||||
|
(**self).is_major_syncing().await
|
||||||
|
}
|
||||||
|
|
||||||
|
fn overseer_handle(&self) -> RelayChainResult<Option<OverseerHandle>> {
|
||||||
(**self).overseer_handle()
|
(**self).overseer_handle()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_storage_by_key(
|
async fn get_storage_by_key(
|
||||||
&self,
|
&self,
|
||||||
block_id: &BlockId,
|
block_id: &BlockId,
|
||||||
key: &[u8],
|
key: &[u8],
|
||||||
) -> Result<Option<StorageValue>, sp_blockchain::Error> {
|
) -> RelayChainResult<Option<StorageValue>> {
|
||||||
(**self).get_storage_by_key(block_id, key)
|
(**self).get_storage_by_key(block_id, key).await
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prove_read(
|
async fn prove_read(
|
||||||
&self,
|
&self,
|
||||||
block_id: &BlockId,
|
block_id: &BlockId,
|
||||||
relevant_keys: &Vec<Vec<u8>>,
|
relevant_keys: &Vec<Vec<u8>>,
|
||||||
) -> Result<Option<StorageProof>, Box<dyn sp_state_machine::Error>> {
|
) -> RelayChainResult<StorageProof> {
|
||||||
(**self).prove_read(block_id, relevant_keys)
|
(**self).prove_read(block_id, relevant_keys).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn wait_for_block(&self, hash: PHash) -> Result<(), WaitError> {
|
async fn wait_for_block(&self, hash: PHash) -> RelayChainResult<()> {
|
||||||
(**self).wait_for_block(hash).await
|
(**self).wait_for_block(hash).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn new_best_notification_stream(
|
||||||
|
&self,
|
||||||
|
) -> RelayChainResult<Pin<Box<dyn Stream<Item = PHeader> + Send>>> {
|
||||||
|
(**self).new_best_notification_stream().await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,19 +14,19 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
|
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::{sync::Arc, time::Duration};
|
use std::{pin::Pin, sync::Arc, time::Duration};
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use cumulus_primitives_core::{
|
use cumulus_primitives_core::{
|
||||||
relay_chain::{
|
relay_chain::{
|
||||||
v1::{CommittedCandidateReceipt, OccupiedCoreAssumption, SessionIndex, ValidatorId},
|
v1::{CommittedCandidateReceipt, OccupiedCoreAssumption, SessionIndex, ValidatorId},
|
||||||
v2::ParachainHost,
|
v2::ParachainHost,
|
||||||
Block as PBlock, BlockId, Hash as PHash, InboundHrmpMessage,
|
Block as PBlock, BlockId, Hash as PHash, Header as PHeader, InboundHrmpMessage,
|
||||||
},
|
},
|
||||||
InboundDownwardMessage, ParaId, PersistedValidationData,
|
InboundDownwardMessage, ParaId, PersistedValidationData,
|
||||||
};
|
};
|
||||||
use cumulus_relay_chain_interface::{RelayChainInterface, WaitError};
|
use cumulus_relay_chain_interface::{RelayChainError, RelayChainInterface, RelayChainResult};
|
||||||
use futures::{FutureExt, StreamExt};
|
use futures::{FutureExt, Stream, StreamExt};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use polkadot_client::{ClientHandle, ExecuteWithClient, FullBackend};
|
use polkadot_client::{ClientHandle, ExecuteWithClient, FullBackend};
|
||||||
use polkadot_service::{
|
use polkadot_service::{
|
||||||
@@ -37,12 +37,11 @@ use sc_client_api::{
|
|||||||
StorageProof, UsageProvider,
|
StorageProof, UsageProvider,
|
||||||
};
|
};
|
||||||
use sc_telemetry::TelemetryWorkerHandle;
|
use sc_telemetry::TelemetryWorkerHandle;
|
||||||
use sp_api::{ApiError, ProvideRuntimeApi};
|
use sp_api::ProvideRuntimeApi;
|
||||||
use sp_consensus::SyncOracle;
|
use sp_consensus::SyncOracle;
|
||||||
use sp_core::{sp_std::collections::btree_map::BTreeMap, Pair};
|
use sp_core::{sp_std::collections::btree_map::BTreeMap, Pair};
|
||||||
use sp_state_machine::{Backend as StateBackend, StorageValue};
|
use sp_state_machine::{Backend as StateBackend, StorageValue};
|
||||||
|
|
||||||
const LOG_TARGET: &str = "relay-chain-local";
|
|
||||||
/// The timeout in seconds after that the waiting for a block should be aborted.
|
/// The timeout in seconds after that the waiting for a block should be aborted.
|
||||||
const TIMEOUT_IN_SECONDS: u64 = 6;
|
const TIMEOUT_IN_SECONDS: u64 = 6;
|
||||||
|
|
||||||
@@ -88,158 +87,117 @@ where
|
|||||||
+ Send,
|
+ Send,
|
||||||
Client::Api: ParachainHost<PBlock> + BabeApi<PBlock>,
|
Client::Api: ParachainHost<PBlock> + BabeApi<PBlock>,
|
||||||
{
|
{
|
||||||
fn retrieve_dmq_contents(
|
async fn retrieve_dmq_contents(
|
||||||
&self,
|
&self,
|
||||||
para_id: ParaId,
|
para_id: ParaId,
|
||||||
relay_parent: PHash,
|
relay_parent: PHash,
|
||||||
) -> Option<Vec<InboundDownwardMessage>> {
|
) -> RelayChainResult<Vec<InboundDownwardMessage>> {
|
||||||
self.full_client
|
Ok(self.full_client.runtime_api().dmq_contents_with_context(
|
||||||
.runtime_api()
|
&BlockId::hash(relay_parent),
|
||||||
.dmq_contents_with_context(
|
sp_core::ExecutionContext::Importing,
|
||||||
&BlockId::hash(relay_parent),
|
para_id,
|
||||||
sp_core::ExecutionContext::Importing,
|
)?)
|
||||||
para_id,
|
|
||||||
)
|
|
||||||
.map_err(|e| {
|
|
||||||
tracing::error!(
|
|
||||||
target: LOG_TARGET,
|
|
||||||
relay_parent = ?relay_parent,
|
|
||||||
error = ?e,
|
|
||||||
"An error occured during requesting the downward messages.",
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.ok()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn retrieve_all_inbound_hrmp_channel_contents(
|
async fn retrieve_all_inbound_hrmp_channel_contents(
|
||||||
&self,
|
&self,
|
||||||
para_id: ParaId,
|
para_id: ParaId,
|
||||||
relay_parent: PHash,
|
relay_parent: PHash,
|
||||||
) -> Option<BTreeMap<ParaId, Vec<InboundHrmpMessage>>> {
|
) -> RelayChainResult<BTreeMap<ParaId, Vec<InboundHrmpMessage>>> {
|
||||||
self.full_client
|
Ok(self.full_client.runtime_api().inbound_hrmp_channels_contents_with_context(
|
||||||
.runtime_api()
|
&BlockId::hash(relay_parent),
|
||||||
.inbound_hrmp_channels_contents_with_context(
|
sp_core::ExecutionContext::Importing,
|
||||||
&BlockId::hash(relay_parent),
|
para_id,
|
||||||
sp_core::ExecutionContext::Importing,
|
)?)
|
||||||
para_id,
|
|
||||||
)
|
|
||||||
.map_err(|e| {
|
|
||||||
tracing::error!(
|
|
||||||
target: LOG_TARGET,
|
|
||||||
relay_parent = ?relay_parent,
|
|
||||||
error = ?e,
|
|
||||||
"An error occured during requesting the inbound HRMP messages.",
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.ok()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn persisted_validation_data(
|
async fn persisted_validation_data(
|
||||||
&self,
|
&self,
|
||||||
block_id: &BlockId,
|
block_id: &BlockId,
|
||||||
para_id: ParaId,
|
para_id: ParaId,
|
||||||
occupied_core_assumption: OccupiedCoreAssumption,
|
occupied_core_assumption: OccupiedCoreAssumption,
|
||||||
) -> Result<Option<PersistedValidationData>, ApiError> {
|
) -> RelayChainResult<Option<PersistedValidationData>> {
|
||||||
self.full_client.runtime_api().persisted_validation_data(
|
Ok(self.full_client.runtime_api().persisted_validation_data(
|
||||||
block_id,
|
block_id,
|
||||||
para_id,
|
para_id,
|
||||||
occupied_core_assumption,
|
occupied_core_assumption,
|
||||||
)
|
)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn candidate_pending_availability(
|
async fn candidate_pending_availability(
|
||||||
&self,
|
&self,
|
||||||
block_id: &BlockId,
|
block_id: &BlockId,
|
||||||
para_id: ParaId,
|
para_id: ParaId,
|
||||||
) -> Result<Option<CommittedCandidateReceipt>, ApiError> {
|
) -> RelayChainResult<Option<CommittedCandidateReceipt>> {
|
||||||
self.full_client.runtime_api().candidate_pending_availability(block_id, para_id)
|
Ok(self
|
||||||
|
.full_client
|
||||||
|
.runtime_api()
|
||||||
|
.candidate_pending_availability(block_id, para_id)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn session_index_for_child(&self, block_id: &BlockId) -> Result<SessionIndex, ApiError> {
|
async fn session_index_for_child(&self, block_id: &BlockId) -> RelayChainResult<SessionIndex> {
|
||||||
self.full_client.runtime_api().session_index_for_child(block_id)
|
Ok(self.full_client.runtime_api().session_index_for_child(block_id)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validators(&self, block_id: &BlockId) -> Result<Vec<ValidatorId>, ApiError> {
|
async fn validators(&self, block_id: &BlockId) -> RelayChainResult<Vec<ValidatorId>> {
|
||||||
self.full_client.runtime_api().validators(block_id)
|
Ok(self.full_client.runtime_api().validators(block_id)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_notification_stream(&self) -> sc_client_api::ImportNotifications<PBlock> {
|
async fn import_notification_stream(
|
||||||
self.full_client.import_notification_stream()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn finality_notification_stream(&self) -> sc_client_api::FinalityNotifications<PBlock> {
|
|
||||||
self.full_client.finality_notification_stream()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn storage_changes_notification_stream(
|
|
||||||
&self,
|
&self,
|
||||||
filter_keys: Option<&[sc_client_api::StorageKey]>,
|
) -> RelayChainResult<Pin<Box<dyn Stream<Item = PHeader> + Send>>> {
|
||||||
child_filter_keys: Option<
|
let notification_stream = self
|
||||||
&[(sc_client_api::StorageKey, Option<Vec<sc_client_api::StorageKey>>)],
|
.full_client
|
||||||
>,
|
.import_notification_stream()
|
||||||
) -> sc_client_api::blockchain::Result<sc_client_api::StorageEventStream<PHash>> {
|
.map(|notification| notification.header);
|
||||||
self.full_client
|
Ok(Box::pin(notification_stream))
|
||||||
.storage_changes_notification_stream(filter_keys, child_filter_keys)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn best_block_hash(&self) -> PHash {
|
async fn finality_notification_stream(
|
||||||
self.backend.blockchain().info().best_hash
|
&self,
|
||||||
|
) -> RelayChainResult<Pin<Box<dyn Stream<Item = PHeader> + Send>>> {
|
||||||
|
let notification_stream = self
|
||||||
|
.full_client
|
||||||
|
.finality_notification_stream()
|
||||||
|
.map(|notification| notification.header);
|
||||||
|
Ok(Box::pin(notification_stream))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_status(&self, block_id: BlockId) -> Result<BlockStatus, sp_blockchain::Error> {
|
async fn best_block_hash(&self) -> RelayChainResult<PHash> {
|
||||||
self.backend.blockchain().status(block_id)
|
Ok(self.backend.blockchain().info().best_hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_major_syncing(&self) -> bool {
|
async fn block_status(&self, block_id: BlockId) -> RelayChainResult<BlockStatus> {
|
||||||
|
Ok(self.backend.blockchain().status(block_id)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn is_major_syncing(&self) -> RelayChainResult<bool> {
|
||||||
let mut network = self.sync_oracle.lock();
|
let mut network = self.sync_oracle.lock();
|
||||||
network.is_major_syncing()
|
Ok(network.is_major_syncing())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn overseer_handle(&self) -> Option<Handle> {
|
fn overseer_handle(&self) -> RelayChainResult<Option<Handle>> {
|
||||||
self.overseer_handle.clone()
|
Ok(self.overseer_handle.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_storage_by_key(
|
async fn get_storage_by_key(
|
||||||
&self,
|
&self,
|
||||||
block_id: &BlockId,
|
block_id: &BlockId,
|
||||||
key: &[u8],
|
key: &[u8],
|
||||||
) -> Result<Option<StorageValue>, sp_blockchain::Error> {
|
) -> RelayChainResult<Option<StorageValue>> {
|
||||||
let state = self.backend.state_at(*block_id)?;
|
let state = self.backend.state_at(*block_id)?;
|
||||||
state.storage(key).map_err(sp_blockchain::Error::Storage)
|
state.storage(key).map_err(RelayChainError::GenericError)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prove_read(
|
async fn prove_read(
|
||||||
&self,
|
&self,
|
||||||
block_id: &BlockId,
|
block_id: &BlockId,
|
||||||
relevant_keys: &Vec<Vec<u8>>,
|
relevant_keys: &Vec<Vec<u8>>,
|
||||||
) -> Result<Option<StorageProof>, Box<dyn sp_state_machine::Error>> {
|
) -> RelayChainResult<StorageProof> {
|
||||||
let state_backend = self
|
let state_backend = self.backend.state_at(*block_id)?;
|
||||||
.backend
|
|
||||||
.state_at(*block_id)
|
|
||||||
.map_err(|e| {
|
|
||||||
tracing::error!(
|
|
||||||
target: LOG_TARGET,
|
|
||||||
relay_parent = ?block_id,
|
|
||||||
error = ?e,
|
|
||||||
"Cannot obtain the state of the relay chain.",
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.ok();
|
|
||||||
|
|
||||||
match state_backend {
|
sp_state_machine::prove_read(state_backend, relevant_keys)
|
||||||
Some(state) => sp_state_machine::prove_read(state, relevant_keys)
|
.map_err(RelayChainError::StateMachineError)
|
||||||
.map_err(|e| {
|
|
||||||
tracing::error!(
|
|
||||||
target: LOG_TARGET,
|
|
||||||
relay_parent = ?block_id,
|
|
||||||
error = ?e,
|
|
||||||
"Failed to collect required relay chain state storage proof.",
|
|
||||||
);
|
|
||||||
e
|
|
||||||
})
|
|
||||||
.map(Some),
|
|
||||||
None => Ok(None),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wait for a given relay chain block in an async way.
|
/// Wait for a given relay chain block in an async way.
|
||||||
@@ -259,7 +217,7 @@ where
|
|||||||
///
|
///
|
||||||
/// The timeout is set to 6 seconds. This should be enough time to import the block in the current
|
/// The timeout is set to 6 seconds. This should be enough time to import the block in the current
|
||||||
/// round and if not, the new round of the relay chain already started anyway.
|
/// round and if not, the new round of the relay chain already started anyway.
|
||||||
async fn wait_for_block(&self, hash: PHash) -> Result<(), WaitError> {
|
async fn wait_for_block(&self, hash: PHash) -> RelayChainResult<()> {
|
||||||
let mut listener =
|
let mut listener =
|
||||||
match check_block_in_chain(self.backend.clone(), self.full_client.clone(), hash)? {
|
match check_block_in_chain(self.backend.clone(), self.full_client.clone(), hash)? {
|
||||||
BlockCheckStatus::InChain => return Ok(()),
|
BlockCheckStatus::InChain => return Ok(()),
|
||||||
@@ -270,16 +228,28 @@ where
|
|||||||
|
|
||||||
loop {
|
loop {
|
||||||
futures::select! {
|
futures::select! {
|
||||||
_ = timeout => return Err(WaitError::Timeout(hash)),
|
_ = timeout => return Err(RelayChainError::WaitTimeout(hash)),
|
||||||
evt = listener.next() => match evt {
|
evt = listener.next() => match evt {
|
||||||
Some(evt) if evt.hash == hash => return Ok(()),
|
Some(evt) if evt.hash == hash => return Ok(()),
|
||||||
// Not the event we waited on.
|
// Not the event we waited on.
|
||||||
Some(_) => continue,
|
Some(_) => continue,
|
||||||
None => return Err(WaitError::ImportListenerClosed(hash)),
|
None => return Err(RelayChainError::ImportListenerClosed(hash)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn new_best_notification_stream(
|
||||||
|
&self,
|
||||||
|
) -> RelayChainResult<Pin<Box<dyn Stream<Item = PHeader> + Send>>> {
|
||||||
|
let notifications_stream =
|
||||||
|
self.full_client
|
||||||
|
.import_notification_stream()
|
||||||
|
.filter_map(|notification| async move {
|
||||||
|
notification.is_new_best.then(|| notification.header)
|
||||||
|
});
|
||||||
|
Ok(Box::pin(notifications_stream))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum BlockCheckStatus {
|
pub enum BlockCheckStatus {
|
||||||
@@ -294,16 +264,15 @@ pub fn check_block_in_chain<Client>(
|
|||||||
backend: Arc<FullBackend>,
|
backend: Arc<FullBackend>,
|
||||||
client: Arc<Client>,
|
client: Arc<Client>,
|
||||||
hash: PHash,
|
hash: PHash,
|
||||||
) -> Result<BlockCheckStatus, WaitError>
|
) -> RelayChainResult<BlockCheckStatus>
|
||||||
where
|
where
|
||||||
Client: BlockchainEvents<PBlock>,
|
Client: BlockchainEvents<PBlock>,
|
||||||
{
|
{
|
||||||
let _lock = backend.get_import_lock().read();
|
let _lock = backend.get_import_lock().read();
|
||||||
|
|
||||||
let block_id = BlockId::Hash(hash);
|
let block_id = BlockId::Hash(hash);
|
||||||
match backend.blockchain().status(block_id) {
|
match backend.blockchain().status(block_id)? {
|
||||||
Ok(BlockStatus::InChain) => return Ok(BlockCheckStatus::InChain),
|
BlockStatus::InChain => return Ok(BlockCheckStatus::InChain),
|
||||||
Err(err) => return Err(WaitError::BlockchainError(hash, err)),
|
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -495,7 +464,7 @@ mod tests {
|
|||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
block_on(relay_chain_interface.wait_for_block(hash)),
|
block_on(relay_chain_interface.wait_for_block(hash)),
|
||||||
Err(WaitError::Timeout(_))
|
Err(RelayChainError::WaitTimeout(_))
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -107,10 +107,13 @@ where
|
|||||||
.spawn_essential_handle()
|
.spawn_essential_handle()
|
||||||
.spawn("cumulus-consensus", None, consensus);
|
.spawn("cumulus-consensus", None, consensus);
|
||||||
|
|
||||||
|
let overseer_handle = relay_chain_interface
|
||||||
|
.overseer_handle()
|
||||||
|
.map_err(|e| sc_service::Error::Application(Box::new(e)))?
|
||||||
|
.ok_or_else(|| "Polkadot full node did not provide an `OverseerHandle`!")?;
|
||||||
|
|
||||||
let pov_recovery = cumulus_client_pov_recovery::PoVRecovery::new(
|
let pov_recovery = cumulus_client_pov_recovery::PoVRecovery::new(
|
||||||
relay_chain_interface
|
overseer_handle.clone(),
|
||||||
.overseer_handle()
|
|
||||||
.ok_or_else(|| "Polkadot full node did not provide an `OverseerHandle`!")?,
|
|
||||||
// We want that collators wait at maximum the relay chain slot duration before starting
|
// We want that collators wait at maximum the relay chain slot duration before starting
|
||||||
// to recover blocks.
|
// to recover blocks.
|
||||||
cumulus_client_pov_recovery::RecoveryDelay::WithMax { max: relay_chain_slot_duration },
|
cumulus_client_pov_recovery::RecoveryDelay::WithMax { max: relay_chain_slot_duration },
|
||||||
@@ -128,9 +131,7 @@ where
|
|||||||
runtime_api: client.clone(),
|
runtime_api: client.clone(),
|
||||||
block_status,
|
block_status,
|
||||||
announce_block,
|
announce_block,
|
||||||
overseer_handle: relay_chain_interface
|
overseer_handle,
|
||||||
.overseer_handle()
|
|
||||||
.ok_or_else(|| "Polkadot full node did not provide an `OverseerHandle`!")?,
|
|
||||||
spawner,
|
spawner,
|
||||||
para_id,
|
para_id,
|
||||||
key: collator_key,
|
key: collator_key,
|
||||||
@@ -192,10 +193,13 @@ where
|
|||||||
.spawn_essential_handle()
|
.spawn_essential_handle()
|
||||||
.spawn("cumulus-consensus", None, consensus);
|
.spawn("cumulus-consensus", None, consensus);
|
||||||
|
|
||||||
|
let overseer_handle = relay_chain_interface
|
||||||
|
.overseer_handle()
|
||||||
|
.map_err(|e| sc_service::Error::Application(Box::new(e)))?
|
||||||
|
.ok_or_else(|| "Polkadot full node did not provide an `OverseerHandle`!")?;
|
||||||
|
|
||||||
let pov_recovery = cumulus_client_pov_recovery::PoVRecovery::new(
|
let pov_recovery = cumulus_client_pov_recovery::PoVRecovery::new(
|
||||||
relay_chain_interface
|
overseer_handle,
|
||||||
.overseer_handle()
|
|
||||||
.ok_or_else(|| "Polkadot full node did not provide an `OverseerHandle`!")?,
|
|
||||||
// Full nodes should at least wait 2.5 minutes (assuming 6 seconds slot duration) and
|
// Full nodes should at least wait 2.5 minutes (assuming 6 seconds slot duration) and
|
||||||
// in maximum 5 minutes before starting to recover blocks. Collators should already start
|
// in maximum 5 minutes before starting to recover blocks. Collators should already start
|
||||||
// the recovery way before full nodes try to recover a certain block and then share the
|
// the recovery way before full nodes try to recover a certain block and then share the
|
||||||
|
|||||||
@@ -605,7 +605,7 @@ pub mod pallet {
|
|||||||
#[pallet::genesis_build]
|
#[pallet::genesis_build]
|
||||||
impl<T: Config> GenesisBuild<T> for GenesisConfig {
|
impl<T: Config> GenesisBuild<T> for GenesisConfig {
|
||||||
fn build(&self) {
|
fn build(&self) {
|
||||||
//TODO: Remove after https://github.com/paritytech/cumulus/issues/479
|
// TODO: Remove after https://github.com/paritytech/cumulus/issues/479
|
||||||
sp_io::storage::set(b":c", &[]);
|
sp_io::storage::set(b":c", &[]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -436,14 +436,15 @@ pub async fn start_parachain_node(
|
|||||||
BuildAuraConsensusParams {
|
BuildAuraConsensusParams {
|
||||||
proposer_factory,
|
proposer_factory,
|
||||||
create_inherent_data_providers: move |_, (relay_parent, validation_data)| {
|
create_inherent_data_providers: move |_, (relay_parent, validation_data)| {
|
||||||
let parachain_inherent =
|
let relay_chain_interface = relay_chain_interface.clone();
|
||||||
|
async move {
|
||||||
|
let parachain_inherent =
|
||||||
cumulus_primitives_parachain_inherent::ParachainInherentData::create_at(
|
cumulus_primitives_parachain_inherent::ParachainInherentData::create_at(
|
||||||
relay_parent,
|
relay_parent,
|
||||||
&relay_chain_interface,
|
&relay_chain_interface,
|
||||||
&validation_data,
|
&validation_data,
|
||||||
id,
|
id,
|
||||||
);
|
).await;
|
||||||
async move {
|
|
||||||
let time = sp_timestamp::InherentDataProvider::from_system_time();
|
let time = sp_timestamp::InherentDataProvider::from_system_time();
|
||||||
|
|
||||||
let slot =
|
let slot =
|
||||||
|
|||||||
@@ -738,14 +738,15 @@ pub async fn start_rococo_parachain_node(
|
|||||||
>(BuildAuraConsensusParams {
|
>(BuildAuraConsensusParams {
|
||||||
proposer_factory,
|
proposer_factory,
|
||||||
create_inherent_data_providers: move |_, (relay_parent, validation_data)| {
|
create_inherent_data_providers: move |_, (relay_parent, validation_data)| {
|
||||||
|
let relay_chain_interface = relay_chain_interface.clone();
|
||||||
|
async move {
|
||||||
let parachain_inherent =
|
let parachain_inherent =
|
||||||
cumulus_primitives_parachain_inherent::ParachainInherentData::create_at(
|
cumulus_primitives_parachain_inherent::ParachainInherentData::create_at(
|
||||||
relay_parent,
|
relay_parent,
|
||||||
&relay_chain_interface,
|
&relay_chain_interface,
|
||||||
&validation_data,
|
&validation_data,
|
||||||
id,
|
id,
|
||||||
);
|
).await;
|
||||||
async move {
|
|
||||||
let time = sp_timestamp::InherentDataProvider::from_system_time();
|
let time = sp_timestamp::InherentDataProvider::from_system_time();
|
||||||
|
|
||||||
let slot =
|
let slot =
|
||||||
@@ -875,14 +876,15 @@ where
|
|||||||
block_import: client.clone(),
|
block_import: client.clone(),
|
||||||
relay_chain_interface: relay_chain_interface.clone(),
|
relay_chain_interface: relay_chain_interface.clone(),
|
||||||
create_inherent_data_providers: move |_, (relay_parent, validation_data)| {
|
create_inherent_data_providers: move |_, (relay_parent, validation_data)| {
|
||||||
let parachain_inherent =
|
let relay_chain_interface = relay_chain_interface.clone();
|
||||||
|
async move {
|
||||||
|
let parachain_inherent =
|
||||||
cumulus_primitives_parachain_inherent::ParachainInherentData::create_at(
|
cumulus_primitives_parachain_inherent::ParachainInherentData::create_at(
|
||||||
relay_parent,
|
relay_parent,
|
||||||
&relay_chain_interface,
|
&relay_chain_interface,
|
||||||
&validation_data,
|
&validation_data,
|
||||||
id,
|
id,
|
||||||
);
|
).await;
|
||||||
async move {
|
|
||||||
let parachain_inherent = parachain_inherent.ok_or_else(|| {
|
let parachain_inherent = parachain_inherent.ok_or_else(|| {
|
||||||
Box::<dyn std::error::Error + Send + Sync>::from(
|
Box::<dyn std::error::Error + Send + Sync>::from(
|
||||||
"Failed to create parachain inherent",
|
"Failed to create parachain inherent",
|
||||||
@@ -1157,14 +1159,15 @@ where
|
|||||||
proposer_factory,
|
proposer_factory,
|
||||||
create_inherent_data_providers:
|
create_inherent_data_providers:
|
||||||
move |_, (relay_parent, validation_data)| {
|
move |_, (relay_parent, validation_data)| {
|
||||||
let parachain_inherent =
|
let relay_chain_for_aura = relay_chain_for_aura.clone();
|
||||||
|
async move {
|
||||||
|
let parachain_inherent =
|
||||||
cumulus_primitives_parachain_inherent::ParachainInherentData::create_at(
|
cumulus_primitives_parachain_inherent::ParachainInherentData::create_at(
|
||||||
relay_parent,
|
relay_parent,
|
||||||
&relay_chain_for_aura,
|
&relay_chain_for_aura,
|
||||||
&validation_data,
|
&validation_data,
|
||||||
id,
|
id,
|
||||||
);
|
).await;
|
||||||
async move {
|
|
||||||
let time =
|
let time =
|
||||||
sp_timestamp::InherentDataProvider::from_system_time();
|
sp_timestamp::InherentDataProvider::from_system_time();
|
||||||
|
|
||||||
@@ -1216,14 +1219,15 @@ where
|
|||||||
relay_chain_interface: relay_chain_interface.clone(),
|
relay_chain_interface: relay_chain_interface.clone(),
|
||||||
create_inherent_data_providers:
|
create_inherent_data_providers:
|
||||||
move |_, (relay_parent, validation_data)| {
|
move |_, (relay_parent, validation_data)| {
|
||||||
let parachain_inherent =
|
let relay_chain_interface = relay_chain_interface.clone();
|
||||||
|
async move {
|
||||||
|
let parachain_inherent =
|
||||||
cumulus_primitives_parachain_inherent::ParachainInherentData::create_at(
|
cumulus_primitives_parachain_inherent::ParachainInherentData::create_at(
|
||||||
relay_parent,
|
relay_parent,
|
||||||
&relay_chain_interface,
|
&relay_chain_interface,
|
||||||
&validation_data,
|
&validation_data,
|
||||||
id,
|
id,
|
||||||
);
|
).await;
|
||||||
async move {
|
|
||||||
let parachain_inherent =
|
let parachain_inherent =
|
||||||
parachain_inherent.ok_or_else(|| {
|
parachain_inherent.ok_or_else(|| {
|
||||||
Box::<dyn std::error::Error + Send + Sync>::from(
|
Box::<dyn std::error::Error + Send + Sync>::from(
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ const LOG_TARGET: &str = "parachain-inherent";
|
|||||||
|
|
||||||
/// Collect the relevant relay chain state in form of a proof for putting it into the validation
|
/// Collect the relevant relay chain state in form of a proof for putting it into the validation
|
||||||
/// data inherent.
|
/// data inherent.
|
||||||
fn collect_relay_storage_proof(
|
async fn collect_relay_storage_proof(
|
||||||
relay_chain_interface: &impl RelayChainInterface,
|
relay_chain_interface: &impl RelayChainInterface,
|
||||||
para_id: ParaId,
|
para_id: ParaId,
|
||||||
relay_parent: PHash,
|
relay_parent: PHash,
|
||||||
@@ -42,6 +42,7 @@ fn collect_relay_storage_proof(
|
|||||||
&relay_parent_block_id,
|
&relay_parent_block_id,
|
||||||
&relay_well_known_keys::hrmp_ingress_channel_index(para_id),
|
&relay_well_known_keys::hrmp_ingress_channel_index(para_id),
|
||||||
)
|
)
|
||||||
|
.await
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
tracing::error!(
|
tracing::error!(
|
||||||
target: LOG_TARGET,
|
target: LOG_TARGET,
|
||||||
@@ -70,6 +71,7 @@ fn collect_relay_storage_proof(
|
|||||||
&relay_parent_block_id,
|
&relay_parent_block_id,
|
||||||
&relay_well_known_keys::hrmp_egress_channel_index(para_id),
|
&relay_well_known_keys::hrmp_egress_channel_index(para_id),
|
||||||
)
|
)
|
||||||
|
.await
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
tracing::error!(
|
tracing::error!(
|
||||||
target: LOG_TARGET,
|
target: LOG_TARGET,
|
||||||
@@ -108,26 +110,57 @@ fn collect_relay_storage_proof(
|
|||||||
relay_well_known_keys::hrmp_channels(HrmpChannelId { sender: para_id, recipient })
|
relay_well_known_keys::hrmp_channels(HrmpChannelId { sender: para_id, recipient })
|
||||||
}));
|
}));
|
||||||
|
|
||||||
relay_chain_interface.prove_read(&relay_parent_block_id, &relevant_keys).ok()?
|
relay_chain_interface
|
||||||
|
.prove_read(&relay_parent_block_id, &relevant_keys)
|
||||||
|
.await
|
||||||
|
.map_err(|e| {
|
||||||
|
tracing::error!(
|
||||||
|
target: LOG_TARGET,
|
||||||
|
relay_parent = ?relay_parent_block_id,
|
||||||
|
error = ?e,
|
||||||
|
"Cannot obtain read proof from relay chain.",
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParachainInherentData {
|
impl ParachainInherentData {
|
||||||
/// Create the [`ParachainInherentData`] at the given `relay_parent`.
|
/// Create the [`ParachainInherentData`] at the given `relay_parent`.
|
||||||
///
|
///
|
||||||
/// Returns `None` if the creation failed.
|
/// Returns `None` if the creation failed.
|
||||||
pub fn create_at(
|
pub async fn create_at(
|
||||||
relay_parent: PHash,
|
relay_parent: PHash,
|
||||||
relay_chain_interface: &impl RelayChainInterface,
|
relay_chain_interface: &impl RelayChainInterface,
|
||||||
validation_data: &PersistedValidationData,
|
validation_data: &PersistedValidationData,
|
||||||
para_id: ParaId,
|
para_id: ParaId,
|
||||||
) -> Option<ParachainInherentData> {
|
) -> Option<ParachainInherentData> {
|
||||||
let relay_chain_state =
|
let relay_chain_state =
|
||||||
collect_relay_storage_proof(relay_chain_interface, para_id, relay_parent)?;
|
collect_relay_storage_proof(relay_chain_interface, para_id, relay_parent).await?;
|
||||||
|
|
||||||
let downward_messages =
|
let downward_messages = relay_chain_interface
|
||||||
relay_chain_interface.retrieve_dmq_contents(para_id, relay_parent)?;
|
.retrieve_dmq_contents(para_id, relay_parent)
|
||||||
|
.await
|
||||||
|
.map_err(|e| {
|
||||||
|
tracing::error!(
|
||||||
|
target: LOG_TARGET,
|
||||||
|
relay_parent = ?relay_parent,
|
||||||
|
error = ?e,
|
||||||
|
"An error occured during requesting the downward messages.",
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.ok()?;
|
||||||
let horizontal_messages = relay_chain_interface
|
let horizontal_messages = relay_chain_interface
|
||||||
.retrieve_all_inbound_hrmp_channel_contents(para_id, relay_parent)?;
|
.retrieve_all_inbound_hrmp_channel_contents(para_id, relay_parent)
|
||||||
|
.await
|
||||||
|
.map_err(|e| {
|
||||||
|
tracing::error!(
|
||||||
|
target: LOG_TARGET,
|
||||||
|
relay_parent = ?relay_parent,
|
||||||
|
error = ?e,
|
||||||
|
"An error occured during requesting the inbound HRMP messages.",
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.ok()?;
|
||||||
|
|
||||||
Some(ParachainInherentData {
|
Some(ParachainInherentData {
|
||||||
downward_messages,
|
downward_messages,
|
||||||
|
|||||||
@@ -31,9 +31,9 @@ use cumulus_client_service::{
|
|||||||
use cumulus_primitives_core::ParaId;
|
use cumulus_primitives_core::ParaId;
|
||||||
use cumulus_relay_chain_local::RelayChainLocal;
|
use cumulus_relay_chain_local::RelayChainLocal;
|
||||||
use cumulus_test_runtime::{Hash, Header, NodeBlock as Block, RuntimeApi};
|
use cumulus_test_runtime::{Hash, Header, NodeBlock as Block, RuntimeApi};
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
use frame_system_rpc_runtime_api::AccountNonceApi;
|
use frame_system_rpc_runtime_api::AccountNonceApi;
|
||||||
use parking_lot::Mutex;
|
|
||||||
use polkadot_primitives::v1::{CollatorPair, Hash as PHash, PersistedValidationData};
|
use polkadot_primitives::v1::{CollatorPair, Hash as PHash, PersistedValidationData};
|
||||||
use polkadot_service::ProvideRuntimeApi;
|
use polkadot_service::ProvideRuntimeApi;
|
||||||
use sc_client_api::execution_extensions::ExecutionStrategies;
|
use sc_client_api::execution_extensions::ExecutionStrategies;
|
||||||
@@ -288,15 +288,16 @@ where
|
|||||||
para_id,
|
para_id,
|
||||||
proposer_factory,
|
proposer_factory,
|
||||||
move |_, (relay_parent, validation_data)| {
|
move |_, (relay_parent, validation_data)| {
|
||||||
let parachain_inherent =
|
let relay_chain_interface = relay_chain_interface_for_closure.clone();
|
||||||
|
async move {
|
||||||
|
let parachain_inherent =
|
||||||
cumulus_primitives_parachain_inherent::ParachainInherentData::create_at(
|
cumulus_primitives_parachain_inherent::ParachainInherentData::create_at(
|
||||||
relay_parent,
|
relay_parent,
|
||||||
&relay_chain_interface_for_closure,
|
&relay_chain_interface,
|
||||||
&validation_data,
|
&validation_data,
|
||||||
para_id,
|
para_id,
|
||||||
);
|
).await;
|
||||||
|
|
||||||
async move {
|
|
||||||
let time = sp_timestamp::InherentDataProvider::from_system_time();
|
let time = sp_timestamp::InherentDataProvider::from_system_time();
|
||||||
|
|
||||||
let parachain_inherent = parachain_inherent.ok_or_else(|| {
|
let parachain_inherent = parachain_inherent.ok_or_else(|| {
|
||||||
|
|||||||
Reference in New Issue
Block a user