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:
Bastian Köcher
2021-05-03 17:21:13 +02:00
committed by GitHub
parent 774d612eef
commit 7830bae524
16 changed files with 402 additions and 549 deletions
+169 -170
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -56,7 +56,7 @@ members = [
"node/core/candidate-selection", "node/core/candidate-selection",
"node/core/candidate-validation", "node/core/candidate-validation",
"node/core/chain-api", "node/core/chain-api",
"node/core/proposer", "node/core/parachains-inherent",
"node/core/provisioner", "node/core/provisioner",
"node/core/pvf", "node/core/pvf",
"node/core/runtime-api", "node/core/runtime-api",
+1 -1
View File
@@ -5,7 +5,7 @@ authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018" edition = "2018"
[dependencies] [dependencies]
polkadot-primitives = { package = "polkadot-primitives", path = "../primitives" } polkadot-primitives = { path = "../primitives" }
polkadot-node-primitives = { package = "polkadot-node-primitives", path = "../node/primitives" } polkadot-node-primitives = { package = "polkadot-node-primitives", path = "../node/primitives" }
novelpoly = { package = "reed-solomon-novelpoly", version = "1.0.0" } novelpoly = { package = "reed-solomon-novelpoly", version = "1.0.0" }
parity-scale-codec = { version = "2.0.0", default-features = false, features = ["std", "derive"] } 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),
}
-25
View File
@@ -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" }
-311
View File
@@ -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,
&parachains_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
}
}
}
-1
View File
@@ -445,7 +445,6 @@ impl OverseerHandler {
} }
/// Wait for a block with the given hash to be in the active-leaves set. /// 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. /// 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, /// Note that due the fact the overseer doesn't store the whole active-leaves set, only deltas,
+5 -2
View File
@@ -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-chain-spec = { 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-client-db = { 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 = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-consensus-slots = { 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" } 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-network = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-transaction-pool = { 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-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 } 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" } telemetry = { package = "sc-telemetry", git = "https://github.com/paritytech/substrate", branch = "master" }
# Substrate Primitives # Substrate Primitives
sp-authority-discovery = { git = "https://github.com/paritytech/substrate", branch = "master" } 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" } 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" } 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" } 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-storage = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-transaction-pool = { 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-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" } sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master" }
# Substrate Pallets # Substrate Pallets
@@ -67,7 +70,7 @@ kvdb = "0.9.0"
kvdb-rocksdb = { version = "0.11.0", optional = true } kvdb-rocksdb = { version = "0.11.0", optional = true }
# Polkadot # Polkadot
polkadot-node-core-proposer = { path = "../core/proposer" } polkadot-node-core-parachains-inherent = { path = "../core/parachains-inherent" }
polkadot-overseer = { path = "../overseer" } polkadot-overseer = { path = "../overseer" }
polkadot-parachain = { path = "../../parachain" } polkadot-parachain = { path = "../../parachain" }
polkadot-primitives = { path = "../../primitives" } polkadot-primitives = { path = "../../primitives" }
+1 -1
View File
@@ -18,7 +18,7 @@
use rococo::constants::size::MAX_CODE_SIZE; use rococo::constants::size::MAX_CODE_SIZE;
use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; 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 beefy_primitives::ecdsa::AuthorityId as BeefyId;
use grandpa::AuthorityId as GrandpaId; use grandpa::AuthorityId as GrandpaId;
use hex_literal::hex; use hex_literal::hex;
+2 -2
View File
@@ -32,7 +32,7 @@ use consensus_common::BlockStatus;
pub trait RuntimeApiCollection: pub trait RuntimeApiCollection:
sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
+ sp_api::ApiExt<Block> + sp_api::ApiExt<Block>
+ babe_primitives::BabeApi<Block> + sp_consensus_babe::BabeApi<Block>
+ grandpa_primitives::GrandpaApi<Block> + grandpa_primitives::GrandpaApi<Block>
+ ParachainHost<Block> + ParachainHost<Block>
+ sp_block_builder::BlockBuilder<Block> + sp_block_builder::BlockBuilder<Block>
@@ -52,7 +52,7 @@ impl<Api> RuntimeApiCollection for Api
where where
Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
+ sp_api::ApiExt<Block> + sp_api::ApiExt<Block>
+ babe_primitives::BabeApi<Block> + sp_consensus_babe::BabeApi<Block>
+ grandpa_primitives::GrandpaApi<Block> + grandpa_primitives::GrandpaApi<Block>
+ ParachainHost<Block> + ParachainHost<Block>
+ sp_block_builder::BlockBuilder<Block> + sp_block_builder::BlockBuilder<Block>
+58 -14
View File
@@ -32,7 +32,6 @@ use {
polkadot_node_core_av_store::Error as AvailabilityError, polkadot_node_core_av_store::Error as AvailabilityError,
polkadot_node_core_approval_voting::Config as ApprovalVotingConfig, polkadot_node_core_approval_voting::Config as ApprovalVotingConfig,
polkadot_node_core_candidate_validation::Config as CandidateValidationConfig, polkadot_node_core_candidate_validation::Config as CandidateValidationConfig,
polkadot_node_core_proposer::ProposerFactory,
polkadot_overseer::{AllSubsystems, BlockInfo, Overseer, OverseerHandler}, polkadot_overseer::{AllSubsystems, BlockInfo, Overseer, OverseerHandler},
polkadot_primitives::v1::ParachainHost, polkadot_primitives::v1::ParachainHost,
sc_authority_discovery::Service as AuthorityDiscoveryService, sc_authority_discovery::Service as AuthorityDiscoveryService,
@@ -41,7 +40,7 @@ use {
sp_trie::PrefixedMemoryDB, sp_trie::PrefixedMemoryDB,
sc_client_api::{AuxStore, ExecutorProvider}, sc_client_api::{AuxStore, ExecutorProvider},
sc_keystore::LocalKeystore, sc_keystore::LocalKeystore,
babe_primitives::BabeApi, sp_consensus_babe::BabeApi,
grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider}, grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider},
beefy_primitives::ecdsa::AuthoritySignature as BeefySignature, beefy_primitives::ecdsa::AuthoritySignature as BeefySignature,
sp_runtime::traits::Header as HeaderT, sp_runtime::traits::Header as HeaderT,
@@ -263,8 +262,6 @@ fn new_partial<RuntimeApi, Executor>(
set_prometheus_registry(config)?; set_prometheus_registry(config)?;
let inherent_data_providers = inherents::InherentDataProviders::new();
let telemetry = config.telemetry_endpoints.clone() let telemetry = config.telemetry_endpoints.clone()
.filter(|x| !x.is_empty()) .filter(|x| !x.is_empty())
.map(move |endpoints| -> Result<_, telemetry::Error> { .map(move |endpoints| -> Result<_, telemetry::Error> {
@@ -331,13 +328,24 @@ fn new_partial<RuntimeApi, Executor>(
client.clone(), client.clone(),
)?; )?;
let slot_duration = babe_link.config().slot_duration();
let import_queue = babe::import_queue( let import_queue = babe::import_queue(
babe_link.clone(), babe_link.clone(),
block_import.clone(), block_import.clone(),
Some(Box::new(justification_import)), Some(Box::new(justification_import)),
client.clone(), client.clone(),
select_chain.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(), &task_manager.spawn_essential_handle(),
config.prometheus_registry(), config.prometheus_registry(),
consensus_common::CanAuthorWithNativeVersion::new(client.executor().clone()), consensus_common::CanAuthorWithNativeVersion::new(client.executor().clone()),
@@ -407,7 +415,6 @@ fn new_partial<RuntimeApi, Executor>(
select_chain, select_chain,
import_queue, import_queue,
transaction_pool, transaction_pool,
inherent_data_providers,
other: (rpc_extensions_builder, import_setup, rpc_setup, slot_duration, telemetry) other: (rpc_extensions_builder, import_setup, rpc_setup, slot_duration, telemetry)
}) })
} }
@@ -708,7 +715,6 @@ pub fn new_full<RuntimeApi, Executor>(
select_chain, select_chain,
import_queue, import_queue,
transaction_pool, transaction_pool,
inherent_data_providers,
other: (rpc_extensions_builder, import_setup, rpc_setup, slot_duration, mut telemetry) other: (rpc_extensions_builder, import_setup, rpc_setup, slot_duration, mut telemetry)
} = new_partial::<RuntimeApi, Executor>(&mut config, jaeger_agent, telemetry_worker_handle)?; } = new_partial::<RuntimeApi, Executor>(&mut config, jaeger_agent, telemetry_worker_handle)?;
@@ -893,21 +899,25 @@ pub fn new_full<RuntimeApi, Executor>(
})); }));
Some(overseer_handler) Some(overseer_handler)
} else { None }; } else {
None
};
if role.is_authority() { if role.is_authority() {
let can_author_with = let can_author_with =
consensus_common::CanAuthorWithNativeVersion::new(client.executor().clone()); consensus_common::CanAuthorWithNativeVersion::new(client.executor().clone());
let proposer = ProposerFactory::new( let proposer = sc_basic_authorship::ProposerFactory::new(
task_manager.spawn_handle(), task_manager.spawn_handle(),
client.clone(), client.clone(),
transaction_pool, transaction_pool,
overseer_handler.as_ref().ok_or(Error::AuthoritiesRequireRealOverseer)?.clone(),
prometheus_registry.as_ref(), prometheus_registry.as_ref(),
telemetry.as_ref().map(|x| x.handle()), 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 { let babe_config = babe::BabeParams {
keystore: keystore_container.sync_keystore(), keystore: keystore_container.sync_keystore(),
client: client.clone(), client: client.clone(),
@@ -915,7 +925,32 @@ pub fn new_full<RuntimeApi, Executor>(
block_import, block_import,
env: proposer, env: proposer,
sync_oracle: network.clone(), 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, force_authoring,
backoff_authoring_blocks, backoff_authoring_blocks,
babe_link, babe_link,
@@ -1096,16 +1131,25 @@ fn new_light<Runtime, Dispatch>(mut config: Configuration) -> Result<(
client.clone(), client.clone(),
)?; )?;
let inherent_data_providers = inherents::InherentDataProviders::new();
// FIXME: pruning task isn't started since light client doesn't do `AuthoritySetup`. // 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( let import_queue = babe::import_queue(
babe_link, babe_link,
babe_block_import, babe_block_import,
Some(Box::new(justification_import)), Some(Box::new(justification_import)),
client.clone(), client.clone(),
select_chain.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(), &task_manager.spawn_essential_handle(),
config.prometheus_registry(), config.prometheus_registry(),
consensus_common::NeverCanAuthor, consensus_common::NeverCanAuthor,
@@ -380,7 +380,7 @@ sequenceDiagram
participant CB as CandidateBacking participant CB as CandidateBacking
participant BD as BitfieldDistribution participant BD as BitfieldDistribution
participant RA as RuntimeApi participant RA as RuntimeApi
participant PO as Proposer participant PI as ParachainsInherentDataProvider
alt receive provisionable data alt receive provisionable data
alt alt
@@ -395,33 +395,24 @@ sequenceDiagram
Note over PV: store bitfields and backed candidates Note over PV: store bitfields and backed candidates
else receive request for inherent data else receive request for inherent data
PO ->> PV: RequestInherentData PI ->> PV: RequestInherentData
alt we have already constructed the inherent data 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 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 end
else timer times out else timer times out
note over PV: Waited 2 seconds note over PV: Waited 2 seconds
PV -->> RA: RuntimeApiRequest::AvailabilityCores PV -->> RA: RuntimeApiRequest::AvailabilityCores
Note over PV: construct and store the inherent data Note over PV: construct and store the inherent data
loop over stored inherent data requests loop over stored inherent data requests
PV ->> PO: (SignedAvailabilityBitfields, BackedCandidates) PV ->> PI: (SignedAvailabilityBitfields, BackedCandidates)
end end
end end
``` ```
In principle, any arbitrary subsystem could send a `RequestInherentData` to the `Provisioner`. In practice, 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 tuple `(SignedAvailabilityBitfields, BackedCandidates, ParentHeader)` is injected by the `ParachainsInherentDataProvider`
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`
into the inherent data. From that point on, control passes from the node to the runtime. 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. /// 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. /// 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>), RequestInherentData(Hash, oneshot::Sender<ParaInherentData>),
/// This data should become part of a relay chain block /// This data should become part of a relay chain block
ProvisionableData(ProvisionableData), ProvisionableData(ProvisionableData),
+1 -1
View File
@@ -49,10 +49,10 @@ keyring = { package = "sp-keyring", git = "https://github.com/paritytech/substra
sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-babe = { 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" } 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-randomness-collective-flip = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-staking-reward-curve = { 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" } 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" serde_json = "1.0.61"
libsecp256k1 = "0.3.5" libsecp256k1 = "0.3.5"
sp-version = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-version = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
@@ -31,6 +31,7 @@ use frame_support::{
dispatch::DispatchResultWithPostInfo, dispatch::DispatchResultWithPostInfo,
weights::{DispatchClass, Weight}, weights::{DispatchClass, Weight},
traits::Get, traits::Get,
inherent::{InherentIdentifier, InherentData, MakeFatalError, ProvideInherent},
}; };
use frame_system::ensure_none; use frame_system::ensure_none;
use crate::{ use crate::{
@@ -38,7 +39,6 @@ use crate::{
scheduler::{self, FreedReason}, scheduler::{self, FreedReason},
ump, ump,
}; };
use inherents::{InherentIdentifier, InherentData, MakeFatalError, ProvideInherent};
const LOG_TARGET: &str = "runtime::inclusion-inherent"; const LOG_TARGET: &str = "runtime::inclusion-inherent";
// In the future, we should benchmark these consts; these are all untested assumptions for now. // In the future, we should benchmark these consts; these are all untested assumptions for now.