mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 03:31:05 +00:00
Companion for Substrate#8526 (#2845)
* Update branch * Make it compile * Compile * gate approval-checking logic (#2470) * Fix build * Updates * Fix merge * Adds missing crate * Companion for Substrate#8386 https://github.com/paritytech/substrate/pull/8386 * Fix fix fix * Fix * Fix compilation * Rewrite to `ParachainsInherentDataProvider` * Make it compile * Renamings * Revert stuff * Remove stale file * Guide updates * Update node/core/parachains-inherent/src/lib.rs Co-authored-by: Andronik Ordian <write@reusable.software> * Update node/core/parachains-inherent/src/lib.rs Co-authored-by: Andronik Ordian <write@reusable.software> * Apply suggestions from code review * Reset accidental changes * More * Remove stale file * update Substrate Co-authored-by: Robert Habermeier <rphmeier@gmail.com> Co-authored-by: Andronik Ordian <write@reusable.software> Co-authored-by: parity-processbot <>
This commit is contained in:
Generated
+169
-170
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -56,7 +56,7 @@ members = [
|
||||
"node/core/candidate-selection",
|
||||
"node/core/candidate-validation",
|
||||
"node/core/chain-api",
|
||||
"node/core/proposer",
|
||||
"node/core/parachains-inherent",
|
||||
"node/core/provisioner",
|
||||
"node/core/pvf",
|
||||
"node/core/runtime-api",
|
||||
|
||||
@@ -5,7 +5,7 @@ authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
polkadot-primitives = { package = "polkadot-primitives", path = "../primitives" }
|
||||
polkadot-primitives = { path = "../primitives" }
|
||||
polkadot-node-primitives = { package = "polkadot-node-primitives", path = "../node/primitives" }
|
||||
novelpoly = { package = "reed-solomon-novelpoly", version = "1.0.0" }
|
||||
parity-scale-codec = { version = "2.0.0", default-features = false, features = ["std", "derive"] }
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
[package]
|
||||
name = "polkadot-node-core-parachains-inherent"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
futures = "0.3.12"
|
||||
futures-timer = "3.0.2"
|
||||
tracing = "0.1.25"
|
||||
thiserror = "1.0.23"
|
||||
async-trait = "0.1.47"
|
||||
polkadot-node-subsystem = { path = "../../subsystem" }
|
||||
polkadot-overseer = { path = "../../overseer" }
|
||||
polkadot-primitives = { path = "../../../primitives" }
|
||||
sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
@@ -0,0 +1,138 @@
|
||||
// Copyright 2021 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Polkadot.
|
||||
|
||||
// Polkadot is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Polkadot is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! The parachain inherent data provider
|
||||
//!
|
||||
//! Parachain backing and approval is an off-chain process, but the parachain needs to progress on chain as well. To
|
||||
//! make it progress on chain a block producer needs to forward information about the state of a parachain to the
|
||||
//! runtime. This information is forwarded through an inherent to the runtime. Here we provide the
|
||||
//! [`ParachainInherentDataProvider`] that requests the relevant data from the provisioner subsystem and creates the
|
||||
//! the inherent data that the runtime will use to create an inherent.
|
||||
|
||||
#![deny(unused_crate_dependencies, unused_results)]
|
||||
|
||||
use futures::{select, FutureExt};
|
||||
use polkadot_node_subsystem::{
|
||||
messages::{AllMessages, ProvisionerMessage}, SubsystemError,
|
||||
};
|
||||
use polkadot_overseer::OverseerHandler;
|
||||
use polkadot_primitives::v1::{
|
||||
Block, Hash, InherentData as ParachainsInherentData,
|
||||
};
|
||||
use sp_blockchain::HeaderBackend;
|
||||
use sp_runtime::generic::BlockId;
|
||||
use std::time;
|
||||
|
||||
/// How long to wait for the provisioner, before giving up.
|
||||
const PROVISIONER_TIMEOUT: time::Duration = core::time::Duration::from_millis(2500);
|
||||
|
||||
/// Provides the parachains inherent data.
|
||||
pub struct ParachainsInherentDataProvider {
|
||||
inherent_data: ParachainsInherentData,
|
||||
}
|
||||
|
||||
impl ParachainsInherentDataProvider {
|
||||
/// Create a new instance of the [`ParachainsInherentDataProvider`].
|
||||
pub async fn create<C: HeaderBackend<Block>>(
|
||||
client: &C,
|
||||
mut overseer: OverseerHandler,
|
||||
parent: Hash,
|
||||
) -> Result<Self, Error> {
|
||||
let pid = async {
|
||||
let (sender, receiver) = futures::channel::oneshot::channel();
|
||||
overseer.wait_for_activation(parent, sender).await;
|
||||
receiver.await.map_err(|_| Error::ClosedChannelAwaitingActivation)?.map_err(Error::Subsystem)?;
|
||||
|
||||
let (sender, receiver) = futures::channel::oneshot::channel();
|
||||
overseer.send_msg(AllMessages::Provisioner(
|
||||
ProvisionerMessage::RequestInherentData(parent, sender),
|
||||
)).await;
|
||||
|
||||
receiver.await.map_err(|_| Error::ClosedChannelAwaitingInherentData)
|
||||
};
|
||||
|
||||
let mut timeout = futures_timer::Delay::new(PROVISIONER_TIMEOUT).fuse();
|
||||
|
||||
let parent_header = match client.header(BlockId::Hash(parent)) {
|
||||
Ok(Some(h)) => h,
|
||||
Ok(None) => return Err(Error::ParentHeaderNotFound(parent)),
|
||||
Err(err) => return Err(Error::Blockchain(err)),
|
||||
};
|
||||
|
||||
let res = select! {
|
||||
pid = pid.fuse() => pid,
|
||||
_ = timeout => Err(Error::Timeout),
|
||||
};
|
||||
|
||||
let inherent_data = match res {
|
||||
Ok(pd) => ParachainsInherentData {
|
||||
bitfields: pd.bitfields,
|
||||
backed_candidates: pd.backed_candidates,
|
||||
disputes: pd.disputes,
|
||||
parent_header,
|
||||
},
|
||||
Err(err) => {
|
||||
tracing::debug!(
|
||||
?err,
|
||||
"Could not get provisioner inherent data; injecting default data",
|
||||
);
|
||||
ParachainsInherentData {
|
||||
bitfields: Vec::new(),
|
||||
backed_candidates: Vec::new(),
|
||||
disputes: Vec::new(),
|
||||
parent_header,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Self { inherent_data })
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl sp_inherents::InherentDataProvider for ParachainsInherentDataProvider {
|
||||
fn provide_inherent_data(&self, inherent_data: &mut sp_inherents::InherentData) -> Result<(), sp_inherents::Error> {
|
||||
inherent_data.put_data(
|
||||
polkadot_primitives::v1::PARACHAINS_INHERENT_IDENTIFIER,
|
||||
&self.inherent_data,
|
||||
)
|
||||
}
|
||||
|
||||
async fn try_handle_error(
|
||||
&self,
|
||||
_: &sp_inherents::InherentIdentifier,
|
||||
_: &[u8],
|
||||
) -> Option<Result<(), sp_inherents::Error>> {
|
||||
// Inherent isn't checked and can not return any error
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("Blockchain error")]
|
||||
Blockchain(sp_blockchain::Error),
|
||||
#[error("Timeout: provisioner did not return inherent data after {:?}", PROVISIONER_TIMEOUT)]
|
||||
Timeout,
|
||||
#[error("Could not find the parent header in the blockchain: {:?}", _0)]
|
||||
ParentHeaderNotFound(Hash),
|
||||
#[error("Closed channel from overseer when awaiting activation")]
|
||||
ClosedChannelAwaitingActivation,
|
||||
#[error("Closed channel from provisioner when awaiting inherent data")]
|
||||
ClosedChannelAwaitingInherentData,
|
||||
#[error("Subsystem failed")]
|
||||
Subsystem(SubsystemError),
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
[package]
|
||||
name = "polkadot-node-core-proposer"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
futures = "0.3.12"
|
||||
futures-timer = "3.0.2"
|
||||
tracing = "0.1.25"
|
||||
polkadot-node-subsystem = { path = "../../subsystem" }
|
||||
polkadot-overseer = { path = "../../overseer" }
|
||||
polkadot-primitives = { path = "../../../primitives" }
|
||||
sc-basic-authorship = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sc-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sc-telemetry = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
prometheus-endpoint = { package = "substrate-prometheus-endpoint", git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
@@ -1,311 +0,0 @@
|
||||
// Copyright 2020 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Polkadot.
|
||||
|
||||
// Polkadot is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Polkadot is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! The proposer proposes new blocks to include
|
||||
|
||||
#![deny(unused_crate_dependencies, unused_results)]
|
||||
|
||||
use futures::prelude::*;
|
||||
use futures::select;
|
||||
use polkadot_node_subsystem::{
|
||||
jaeger,
|
||||
messages::{AllMessages, ProvisionerInherentData, ProvisionerMessage}, SubsystemError,
|
||||
};
|
||||
use polkadot_overseer::OverseerHandler;
|
||||
use polkadot_primitives::v1::{
|
||||
Block, Hash, Header, InherentData as ParachainsInherentData,
|
||||
};
|
||||
use sc_block_builder::{BlockBuilderApi, BlockBuilderProvider};
|
||||
use sc_telemetry::TelemetryHandle;
|
||||
use sp_core::traits::SpawnNamed;
|
||||
use sp_api::{ApiExt, ProvideRuntimeApi};
|
||||
use sp_blockchain::HeaderBackend;
|
||||
use sp_consensus::{Proposal, DisableProofRecording};
|
||||
use sp_inherents::InherentData;
|
||||
use sp_runtime::traits::{DigestFor, HashFor};
|
||||
use sp_transaction_pool::TransactionPool;
|
||||
use prometheus_endpoint::Registry as PrometheusRegistry;
|
||||
use std::{fmt, pin::Pin, sync::Arc, time};
|
||||
|
||||
/// How long proposing can take, before we give up and err out. We need a relatively large timeout
|
||||
/// here as long as we have large payload in statement distribution. Assuming we can reach most
|
||||
/// nodes within two hops, we will take about 2 seconds for transferring statements (data transfer
|
||||
/// only). If necessary, we could be able to reduce this to 3 seconds. To consider: The lower the
|
||||
/// riskier that we will not be able to include a candidate.
|
||||
const PROPOSE_TIMEOUT: core::time::Duration = core::time::Duration::from_millis(4000);
|
||||
|
||||
/// Custom Proposer factory for Polkadot
|
||||
pub struct ProposerFactory<TxPool, Backend, Client> {
|
||||
inner: sc_basic_authorship::ProposerFactory<TxPool, Backend, Client, DisableProofRecording>,
|
||||
overseer: OverseerHandler,
|
||||
}
|
||||
|
||||
impl<TxPool, Backend, Client> ProposerFactory<TxPool, Backend, Client> {
|
||||
pub fn new(
|
||||
spawn_handle: impl SpawnNamed + 'static,
|
||||
client: Arc<Client>,
|
||||
transaction_pool: Arc<TxPool>,
|
||||
overseer: OverseerHandler,
|
||||
prometheus: Option<&PrometheusRegistry>,
|
||||
telemetry: Option<TelemetryHandle>,
|
||||
) -> Self {
|
||||
ProposerFactory {
|
||||
inner: sc_basic_authorship::ProposerFactory::new(
|
||||
spawn_handle,
|
||||
client,
|
||||
transaction_pool,
|
||||
prometheus,
|
||||
telemetry,
|
||||
),
|
||||
overseer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<TxPool, Backend, Client> sp_consensus::Environment<Block>
|
||||
for ProposerFactory<TxPool, Backend, Client>
|
||||
where
|
||||
TxPool: 'static + TransactionPool<Block = Block>,
|
||||
Client: 'static
|
||||
+ BlockBuilderProvider<Backend, Block, Client>
|
||||
+ ProvideRuntimeApi<Block>
|
||||
+ HeaderBackend<Block>
|
||||
+ Send
|
||||
+ Sync,
|
||||
Client::Api:
|
||||
BlockBuilderApi<Block> + ApiExt<Block>,
|
||||
Backend:
|
||||
'static + sc_client_api::Backend<Block, State = sp_api::StateBackendFor<Client, Block>>,
|
||||
// Rust bug: https://github.com/rust-lang/rust/issues/24159
|
||||
sp_api::StateBackendFor<Client, Block>: sp_api::StateBackend<HashFor<Block>> + Send,
|
||||
{
|
||||
type CreateProposer = Pin<Box<
|
||||
dyn Future<Output = Result<Self::Proposer, Self::Error>> + Send + 'static,
|
||||
>>;
|
||||
type Proposer = Proposer<TxPool, Backend, Client>;
|
||||
type Error = Error;
|
||||
|
||||
fn init(&mut self, parent_header: &Header) -> Self::CreateProposer {
|
||||
// create the inner proposer
|
||||
let proposer = self.inner.init(parent_header).into_inner();
|
||||
|
||||
// data to be moved into the future
|
||||
let overseer = self.overseer.clone();
|
||||
let parent_header_hash = parent_header.hash();
|
||||
let parent_header = parent_header.clone();
|
||||
|
||||
async move {
|
||||
Ok(Proposer {
|
||||
inner: proposer?,
|
||||
overseer,
|
||||
parent_header,
|
||||
parent_header_hash,
|
||||
})
|
||||
}.boxed()
|
||||
}
|
||||
}
|
||||
|
||||
/// Custom Proposer for Polkadot.
|
||||
///
|
||||
/// This proposer gets the ProvisionerInherentData and injects it into the wrapped
|
||||
/// proposer's inherent data, then delegates the actual proposal generation.
|
||||
pub struct Proposer<TxPool: TransactionPool<Block = Block>, Backend, Client> {
|
||||
inner: sc_basic_authorship::Proposer<Backend, Block, Client, TxPool, DisableProofRecording>,
|
||||
overseer: OverseerHandler,
|
||||
parent_header: Header,
|
||||
parent_header_hash: Hash,
|
||||
}
|
||||
|
||||
// This impl has the same generic bounds as the Proposer impl.
|
||||
impl<TxPool, Backend, Client> Proposer<TxPool, Backend, Client>
|
||||
where
|
||||
TxPool: 'static + TransactionPool<Block = Block>,
|
||||
Client: 'static
|
||||
+ BlockBuilderProvider<Backend, Block, Client>
|
||||
+ ProvideRuntimeApi<Block>
|
||||
+ HeaderBackend<Block>
|
||||
+ Send
|
||||
+ Sync,
|
||||
Client::Api:
|
||||
BlockBuilderApi<Block> + ApiExt<Block>,
|
||||
Backend:
|
||||
'static + sc_client_api::Backend<Block, State = sp_api::StateBackendFor<Client, Block>>,
|
||||
// Rust bug: https://github.com/rust-lang/rust/issues/24159
|
||||
sp_api::StateBackendFor<Client, Block>: sp_api::StateBackend<HashFor<Block>> + Send,
|
||||
{
|
||||
/// Get provisioner inherent data
|
||||
///
|
||||
/// This function has a constant timeout: `PROPOSE_TIMEOUT`.
|
||||
async fn get_provisioner_data(&self) -> Result<ProvisionerInherentData, Error> {
|
||||
// clone this (lightweight) data because we're going to move it into the future
|
||||
let mut overseer = self.overseer.clone();
|
||||
let parent_header_hash = self.parent_header_hash.clone();
|
||||
|
||||
let pid = async {
|
||||
let (sender, receiver) = futures::channel::oneshot::channel();
|
||||
overseer.wait_for_activation(parent_header_hash, sender).await;
|
||||
receiver.await.map_err(|_| Error::ClosedChannelAwaitingActivation)??;
|
||||
|
||||
let (sender, receiver) = futures::channel::oneshot::channel();
|
||||
overseer.send_msg(AllMessages::Provisioner(
|
||||
ProvisionerMessage::RequestInherentData(parent_header_hash, sender),
|
||||
)).await;
|
||||
|
||||
receiver.await.map_err(|_| Error::ClosedChannelAwaitingInherentData)
|
||||
};
|
||||
|
||||
let mut timeout = futures_timer::Delay::new(PROPOSE_TIMEOUT).fuse();
|
||||
|
||||
select! {
|
||||
pid = pid.fuse() => pid,
|
||||
_ = timeout => Err(Error::Timeout),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<TxPool, Backend, Client> sp_consensus::Proposer<Block> for Proposer<TxPool, Backend, Client>
|
||||
where
|
||||
TxPool: 'static + TransactionPool<Block = Block>,
|
||||
Client: 'static
|
||||
+ BlockBuilderProvider<Backend, Block, Client>
|
||||
+ ProvideRuntimeApi<Block>
|
||||
+ HeaderBackend<Block>
|
||||
+ Send
|
||||
+ Sync,
|
||||
Client::Api:
|
||||
BlockBuilderApi<Block> + ApiExt<Block>,
|
||||
Backend:
|
||||
'static + sc_client_api::Backend<Block, State = sp_api::StateBackendFor<Client, Block>>,
|
||||
// Rust bug: https://github.com/rust-lang/rust/issues/24159
|
||||
sp_api::StateBackendFor<Client, Block>: sp_api::StateBackend<HashFor<Block>> + Send,
|
||||
{
|
||||
type Transaction = sc_client_api::TransactionFor<Backend, Block>;
|
||||
type Proposal = Pin<Box<
|
||||
dyn Future<Output = Result<Proposal<Block, sp_api::TransactionFor<Client, Block>, ()>, Error>> + Send,
|
||||
>>;
|
||||
type Error = Error;
|
||||
type ProofRecording = DisableProofRecording;
|
||||
type Proof = ();
|
||||
|
||||
fn propose(
|
||||
self,
|
||||
mut inherent_data: InherentData,
|
||||
inherent_digests: DigestFor<Block>,
|
||||
max_duration: time::Duration,
|
||||
block_size_limit: Option<usize>,
|
||||
) -> Self::Proposal {
|
||||
async move {
|
||||
let span = jaeger::Span::new(self.parent_header_hash, "propose");
|
||||
let _span = span.child("get-provisioner");
|
||||
|
||||
let parachains_inherent_data = match self.get_provisioner_data().await {
|
||||
Ok(pd) => ParachainsInherentData {
|
||||
bitfields: pd.bitfields,
|
||||
backed_candidates: pd.backed_candidates,
|
||||
disputes: pd.disputes,
|
||||
parent_header: self.parent_header,
|
||||
},
|
||||
Err(err) => {
|
||||
tracing::warn!(err = ?err, "could not get provisioner inherent data; injecting default data");
|
||||
ParachainsInherentData {
|
||||
bitfields: Vec::new(),
|
||||
backed_candidates: Vec::new(),
|
||||
disputes: Vec::new(),
|
||||
parent_header: self.parent_header,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
drop(_span);
|
||||
|
||||
inherent_data.put_data(
|
||||
polkadot_primitives::v1::PARACHAINS_INHERENT_IDENTIFIER,
|
||||
¶chains_inherent_data,
|
||||
)?;
|
||||
|
||||
let _span = span.child("authorship-propose");
|
||||
self.inner
|
||||
.propose(inherent_data, inherent_digests, max_duration, block_size_limit)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
.boxed()
|
||||
}
|
||||
}
|
||||
|
||||
// It would have been more ergonomic to use thiserror to derive the
|
||||
// From implementations, Display, and std::error::Error, but unfortunately
|
||||
// one of the wrapped errors (sp_inherents::Error) also
|
||||
// don't impl std::error::Error, which breaks the thiserror derive.
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
Consensus(sp_consensus::Error),
|
||||
Blockchain(sp_blockchain::Error),
|
||||
Inherent(sp_inherents::Error),
|
||||
Timeout,
|
||||
ClosedChannelAwaitingActivation,
|
||||
ClosedChannelAwaitingInherentData,
|
||||
Subsystem(SubsystemError)
|
||||
}
|
||||
|
||||
impl From<sp_consensus::Error> for Error {
|
||||
fn from(e: sp_consensus::Error) -> Error {
|
||||
Error::Consensus(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<sp_blockchain::Error> for Error {
|
||||
fn from(e: sp_blockchain::Error) -> Error {
|
||||
Error::Blockchain(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<sp_inherents::Error> for Error {
|
||||
fn from(e: sp_inherents::Error) -> Error {
|
||||
Error::Inherent(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SubsystemError> for Error {
|
||||
fn from(e: SubsystemError) -> Error {
|
||||
Error::Subsystem(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::Consensus(err) => write!(f, "consensus error: {}", err),
|
||||
Self::Blockchain(err) => write!(f, "blockchain error: {}", err),
|
||||
Self::Inherent(err) => write!(f, "inherent error: {:?}", err),
|
||||
Self::Timeout => write!(f, "timeout: provisioner did not return inherent data after {:?}", PROPOSE_TIMEOUT),
|
||||
Self::ClosedChannelAwaitingActivation => write!(f, "closed channel from overseer when awaiting activation"),
|
||||
Self::ClosedChannelAwaitingInherentData => write!(f, "closed channel from provisioner when awaiting inherent data"),
|
||||
Self::Subsystem(err) => write!(f, "subsystem error: {:?}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for Error {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::Consensus(err) => Some(err),
|
||||
Self::Blockchain(err) => Some(err),
|
||||
Self::Subsystem(err) => Some(err),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -445,7 +445,6 @@ impl OverseerHandler {
|
||||
}
|
||||
|
||||
/// Wait for a block with the given hash to be in the active-leaves set.
|
||||
/// This method is used for external code like `Proposer` that doesn't subscribe to Overseer's signals.
|
||||
///
|
||||
/// The response channel responds if the hash was activated and is closed if the hash was deactivated.
|
||||
/// Note that due the fact the overseer doesn't store the whole active-leaves set, only deltas,
|
||||
|
||||
@@ -15,6 +15,7 @@ sc-block-builder = { git = "https://github.com/paritytech/substrate", branch = "
|
||||
sc-chain-spec = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sc-client-db = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sc-consensus-uncles = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sc-consensus-slots = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sc-executor = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
@@ -22,12 +23,12 @@ sc-finality-grandpa-warp-sync = { git = "https://github.com/paritytech/substrate
|
||||
sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sc-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sc-basic-authorship = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
service = { package = "sc-service", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
telemetry = { package = "sc-telemetry", git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
# Substrate Primitives
|
||||
sp-authority-discovery = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
babe-primitives = { package = "sp-consensus-babe", git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
consensus_common = { package = "sp-consensus", git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
grandpa_primitives = { package = "sp-finality-grandpa", git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
inherents = { package = "sp-inherents", git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
@@ -43,6 +44,8 @@ sp-session = { git = "https://github.com/paritytech/substrate", branch = "master
|
||||
sp-storage = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-consensus-babe = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
# Substrate Pallets
|
||||
@@ -67,7 +70,7 @@ kvdb = "0.9.0"
|
||||
kvdb-rocksdb = { version = "0.11.0", optional = true }
|
||||
|
||||
# Polkadot
|
||||
polkadot-node-core-proposer = { path = "../core/proposer" }
|
||||
polkadot-node-core-parachains-inherent = { path = "../core/parachains-inherent" }
|
||||
polkadot-overseer = { path = "../overseer" }
|
||||
polkadot-parachain = { path = "../../parachain" }
|
||||
polkadot-primitives = { path = "../../primitives" }
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
use rococo::constants::size::MAX_CODE_SIZE;
|
||||
use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
|
||||
use babe_primitives::AuthorityId as BabeId;
|
||||
use sp_consensus_babe::AuthorityId as BabeId;
|
||||
use beefy_primitives::ecdsa::AuthorityId as BeefyId;
|
||||
use grandpa::AuthorityId as GrandpaId;
|
||||
use hex_literal::hex;
|
||||
|
||||
@@ -32,7 +32,7 @@ use consensus_common::BlockStatus;
|
||||
pub trait RuntimeApiCollection:
|
||||
sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
|
||||
+ sp_api::ApiExt<Block>
|
||||
+ babe_primitives::BabeApi<Block>
|
||||
+ sp_consensus_babe::BabeApi<Block>
|
||||
+ grandpa_primitives::GrandpaApi<Block>
|
||||
+ ParachainHost<Block>
|
||||
+ sp_block_builder::BlockBuilder<Block>
|
||||
@@ -52,7 +52,7 @@ impl<Api> RuntimeApiCollection for Api
|
||||
where
|
||||
Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
|
||||
+ sp_api::ApiExt<Block>
|
||||
+ babe_primitives::BabeApi<Block>
|
||||
+ sp_consensus_babe::BabeApi<Block>
|
||||
+ grandpa_primitives::GrandpaApi<Block>
|
||||
+ ParachainHost<Block>
|
||||
+ sp_block_builder::BlockBuilder<Block>
|
||||
|
||||
@@ -32,7 +32,6 @@ use {
|
||||
polkadot_node_core_av_store::Error as AvailabilityError,
|
||||
polkadot_node_core_approval_voting::Config as ApprovalVotingConfig,
|
||||
polkadot_node_core_candidate_validation::Config as CandidateValidationConfig,
|
||||
polkadot_node_core_proposer::ProposerFactory,
|
||||
polkadot_overseer::{AllSubsystems, BlockInfo, Overseer, OverseerHandler},
|
||||
polkadot_primitives::v1::ParachainHost,
|
||||
sc_authority_discovery::Service as AuthorityDiscoveryService,
|
||||
@@ -41,7 +40,7 @@ use {
|
||||
sp_trie::PrefixedMemoryDB,
|
||||
sc_client_api::{AuxStore, ExecutorProvider},
|
||||
sc_keystore::LocalKeystore,
|
||||
babe_primitives::BabeApi,
|
||||
sp_consensus_babe::BabeApi,
|
||||
grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider},
|
||||
beefy_primitives::ecdsa::AuthoritySignature as BeefySignature,
|
||||
sp_runtime::traits::Header as HeaderT,
|
||||
@@ -263,8 +262,6 @@ fn new_partial<RuntimeApi, Executor>(
|
||||
set_prometheus_registry(config)?;
|
||||
|
||||
|
||||
let inherent_data_providers = inherents::InherentDataProviders::new();
|
||||
|
||||
let telemetry = config.telemetry_endpoints.clone()
|
||||
.filter(|x| !x.is_empty())
|
||||
.map(move |endpoints| -> Result<_, telemetry::Error> {
|
||||
@@ -331,13 +328,24 @@ fn new_partial<RuntimeApi, Executor>(
|
||||
client.clone(),
|
||||
)?;
|
||||
|
||||
let slot_duration = babe_link.config().slot_duration();
|
||||
let import_queue = babe::import_queue(
|
||||
babe_link.clone(),
|
||||
block_import.clone(),
|
||||
Some(Box::new(justification_import)),
|
||||
client.clone(),
|
||||
select_chain.clone(),
|
||||
inherent_data_providers.clone(),
|
||||
move |_, ()| async move {
|
||||
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
|
||||
|
||||
let slot =
|
||||
sp_consensus_babe::inherents::InherentDataProvider::from_timestamp_and_duration(
|
||||
*timestamp,
|
||||
slot_duration,
|
||||
);
|
||||
|
||||
Ok((timestamp, slot))
|
||||
},
|
||||
&task_manager.spawn_essential_handle(),
|
||||
config.prometheus_registry(),
|
||||
consensus_common::CanAuthorWithNativeVersion::new(client.executor().clone()),
|
||||
@@ -407,7 +415,6 @@ fn new_partial<RuntimeApi, Executor>(
|
||||
select_chain,
|
||||
import_queue,
|
||||
transaction_pool,
|
||||
inherent_data_providers,
|
||||
other: (rpc_extensions_builder, import_setup, rpc_setup, slot_duration, telemetry)
|
||||
})
|
||||
}
|
||||
@@ -708,7 +715,6 @@ pub fn new_full<RuntimeApi, Executor>(
|
||||
select_chain,
|
||||
import_queue,
|
||||
transaction_pool,
|
||||
inherent_data_providers,
|
||||
other: (rpc_extensions_builder, import_setup, rpc_setup, slot_duration, mut telemetry)
|
||||
} = new_partial::<RuntimeApi, Executor>(&mut config, jaeger_agent, telemetry_worker_handle)?;
|
||||
|
||||
@@ -893,21 +899,25 @@ pub fn new_full<RuntimeApi, Executor>(
|
||||
}));
|
||||
|
||||
Some(overseer_handler)
|
||||
} else { None };
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if role.is_authority() {
|
||||
let can_author_with =
|
||||
consensus_common::CanAuthorWithNativeVersion::new(client.executor().clone());
|
||||
|
||||
let proposer = ProposerFactory::new(
|
||||
let proposer = sc_basic_authorship::ProposerFactory::new(
|
||||
task_manager.spawn_handle(),
|
||||
client.clone(),
|
||||
transaction_pool,
|
||||
overseer_handler.as_ref().ok_or(Error::AuthoritiesRequireRealOverseer)?.clone(),
|
||||
prometheus_registry.as_ref(),
|
||||
telemetry.as_ref().map(|x| x.handle()),
|
||||
);
|
||||
|
||||
let client_clone = client.clone();
|
||||
let overseer_handler = overseer_handler.as_ref().ok_or(Error::AuthoritiesRequireRealOverseer)?.clone();
|
||||
let slot_duration = babe_link.config().slot_duration();
|
||||
let babe_config = babe::BabeParams {
|
||||
keystore: keystore_container.sync_keystore(),
|
||||
client: client.clone(),
|
||||
@@ -915,7 +925,32 @@ pub fn new_full<RuntimeApi, Executor>(
|
||||
block_import,
|
||||
env: proposer,
|
||||
sync_oracle: network.clone(),
|
||||
inherent_data_providers: inherent_data_providers.clone(),
|
||||
create_inherent_data_providers: move |parent, ()| {
|
||||
let client_clone = client_clone.clone();
|
||||
let overseer_handler = overseer_handler.clone();
|
||||
async move {
|
||||
let parachain = polkadot_node_core_parachains_inherent::ParachainsInherentDataProvider::create(
|
||||
&*client_clone,
|
||||
overseer_handler,
|
||||
parent,
|
||||
).await.map_err(|e| Box::new(e))?;
|
||||
|
||||
let uncles = sc_consensus_uncles::create_uncles_inherent_data_provider(
|
||||
&*client_clone,
|
||||
parent,
|
||||
)?;
|
||||
|
||||
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
|
||||
|
||||
let slot =
|
||||
sp_consensus_babe::inherents::InherentDataProvider::from_timestamp_and_duration(
|
||||
*timestamp,
|
||||
slot_duration,
|
||||
);
|
||||
|
||||
Ok((timestamp, slot, uncles, parachain))
|
||||
}
|
||||
},
|
||||
force_authoring,
|
||||
backoff_authoring_blocks,
|
||||
babe_link,
|
||||
@@ -1096,16 +1131,25 @@ fn new_light<Runtime, Dispatch>(mut config: Configuration) -> Result<(
|
||||
client.clone(),
|
||||
)?;
|
||||
|
||||
let inherent_data_providers = inherents::InherentDataProviders::new();
|
||||
|
||||
// FIXME: pruning task isn't started since light client doesn't do `AuthoritySetup`.
|
||||
let slot_duration = babe_link.config().slot_duration();
|
||||
let import_queue = babe::import_queue(
|
||||
babe_link,
|
||||
babe_block_import,
|
||||
Some(Box::new(justification_import)),
|
||||
client.clone(),
|
||||
select_chain.clone(),
|
||||
inherent_data_providers.clone(),
|
||||
move |_, ()| async move {
|
||||
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
|
||||
|
||||
let slot =
|
||||
sp_consensus_babe::inherents::InherentDataProvider::from_timestamp_and_duration(
|
||||
*timestamp,
|
||||
slot_duration,
|
||||
);
|
||||
|
||||
Ok((timestamp, slot))
|
||||
},
|
||||
&task_manager.spawn_essential_handle(),
|
||||
config.prometheus_registry(),
|
||||
consensus_common::NeverCanAuthor,
|
||||
|
||||
@@ -380,7 +380,7 @@ sequenceDiagram
|
||||
participant CB as CandidateBacking
|
||||
participant BD as BitfieldDistribution
|
||||
participant RA as RuntimeApi
|
||||
participant PO as Proposer
|
||||
participant PI as ParachainsInherentDataProvider
|
||||
|
||||
alt receive provisionable data
|
||||
alt
|
||||
@@ -395,33 +395,24 @@ sequenceDiagram
|
||||
|
||||
Note over PV: store bitfields and backed candidates
|
||||
else receive request for inherent data
|
||||
PO ->> PV: RequestInherentData
|
||||
PI ->> PV: RequestInherentData
|
||||
alt we have already constructed the inherent data
|
||||
PV ->> PO: send the inherent data
|
||||
PV ->> PI: send the inherent data
|
||||
else we have not yet constructed the inherent data
|
||||
Note over PV,PO: Store the return sender without sending immediately
|
||||
Note over PV,PI: Store the return sender without sending immediately
|
||||
end
|
||||
else timer times out
|
||||
note over PV: Waited 2 seconds
|
||||
PV -->> RA: RuntimeApiRequest::AvailabilityCores
|
||||
Note over PV: construct and store the inherent data
|
||||
loop over stored inherent data requests
|
||||
PV ->> PO: (SignedAvailabilityBitfields, BackedCandidates)
|
||||
PV ->> PI: (SignedAvailabilityBitfields, BackedCandidates)
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
In principle, any arbitrary subsystem could send a `RequestInherentData` to the `Provisioner`. In practice,
|
||||
only the `Proposer` does so.
|
||||
only the `ParachainsInherentDataProvider` does so.
|
||||
|
||||
The proposer is an atypical subsystem in that, unlike most of them, it is not primarily driven by
|
||||
the `Overseer`, but instead by the `sp_consensus::Environment` and `sp_consensus::Proposer` traits
|
||||
from Substrate. It doesn't make much sense to diagram this flow because it's very linear:
|
||||
|
||||
- Substrate creates a `Proposer` from the `ProposerFactory` once per upcoming block, using the `parent_header: Header`.
|
||||
- At some later point, it calls `Proposer::propose(self, ...)`, consuming the proposer to generate a proposal
|
||||
- `Proposer::propose` sends a `RequestInherentData` to the `Provisioner`. This has a fixed timeout of
|
||||
2.5 seconds, meaning that the provisioner has approximately 0.5 seconds to generate and send the data.
|
||||
|
||||
The tuple `(SignedAvailabilityBitfields, BackedCandidates, ParentHeader)` is injected by the `Proposer`
|
||||
The tuple `(SignedAvailabilityBitfields, BackedCandidates, ParentHeader)` is injected by the `ParachainsInherentDataProvider`
|
||||
into the inherent data. From that point on, control passes from the node to the runtime.
|
||||
|
||||
@@ -564,9 +564,6 @@ enum ProvisionerMessage {
|
||||
/// advancing the state of parachain consensus in a block building upon the given hash.
|
||||
///
|
||||
/// If called at different points in time, this may give different results.
|
||||
///
|
||||
/// This is expected to be used by a proposer, to inject that information into the InherentData
|
||||
/// where it can be assembled into the ParaInherent.
|
||||
RequestInherentData(Hash, oneshot::Sender<ParaInherentData>),
|
||||
/// This data should become part of a relay chain block
|
||||
ProvisionableData(ProvisionableData),
|
||||
|
||||
@@ -49,10 +49,10 @@ keyring = { package = "sp-keyring", git = "https://github.com/paritytech/substra
|
||||
sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
pallet-babe = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-application-crypto = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
frame-support-test = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
pallet-randomness-collective-flip = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
pallet-staking-reward-curve = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
pallet-treasury = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
frame-support-test = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
serde_json = "1.0.61"
|
||||
libsecp256k1 = "0.3.5"
|
||||
sp-version = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
|
||||
@@ -31,6 +31,7 @@ use frame_support::{
|
||||
dispatch::DispatchResultWithPostInfo,
|
||||
weights::{DispatchClass, Weight},
|
||||
traits::Get,
|
||||
inherent::{InherentIdentifier, InherentData, MakeFatalError, ProvideInherent},
|
||||
};
|
||||
use frame_system::ensure_none;
|
||||
use crate::{
|
||||
@@ -38,7 +39,6 @@ use crate::{
|
||||
scheduler::{self, FreedReason},
|
||||
ump,
|
||||
};
|
||||
use inherents::{InherentIdentifier, InherentData, MakeFatalError, ProvideInherent};
|
||||
|
||||
const LOG_TARGET: &str = "runtime::inclusion-inherent";
|
||||
// In the future, we should benchmark these consts; these are all untested assumptions for now.
|
||||
|
||||
Reference in New Issue
Block a user