Drop sc-client (#1037)

* WIP

* collator

* fix missing reference

* Make collator builder more generic

* all clear

* revert start colator fn

* fix return type of start_collator

* sc-consensus

* bump back to master

* Update collator/src/lib.rs

Co-Authored-By: Benjamin Kampmann <ben@gnunicorn.org>

* Update collator/src/lib.rs

Co-Authored-By: Pierre Krieger <pierre.krieger1708@gmail.com>

* uncomment type MaxIterations

* reactivate append storage feature

Co-authored-by: Benjamin Kampmann <ben@gnunicorn.org>
Co-authored-by: Pierre Krieger <pierre.krieger1708@gmail.com>
This commit is contained in:
Seun Lanlege
2020-04-28 15:20:47 +01:00
committed by GitHub
parent a211a2519f
commit 0e0760d56c
18 changed files with 763 additions and 810 deletions
+166 -185
View File
File diff suppressed because it is too large Load Diff
-1
View File
@@ -18,7 +18,6 @@ codec = { package = "parity-scale-codec", version = "1.3.0", features = ["derive
sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" }
consensus_common = { package = "sp-consensus", git = "https://github.com/paritytech/substrate", branch = "master" }
client = { package = "sc-client-api", git = "https://github.com/paritytech/substrate", branch = "master" }
sc-client = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
-1
View File
@@ -20,7 +20,6 @@ structopt = "0.3.8"
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-client = { 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-executor = { git = "https://github.com/paritytech/substrate", branch = "master" }
+50 -70
View File
@@ -15,9 +15,8 @@
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
use log::info;
use sp_runtime::traits::BlakeTwo256;
use service::{IdentifyVariant, Block, self, RuntimeApiCollection, TFullClient};
use sp_api::ConstructRuntimeApi;
use service::{IdentifyVariant, self};
use sc_executor::NativeExecutionDispatch;
use sc_cli::{SubstrateCli, Result};
use crate::cli::{Cli, Subcommand};
@@ -82,23 +81,56 @@ pub fn run() -> Result<()> {
info!(" KUSAMA FOUNDATION ");
info!("----------------------------");
run_node::<
service::kusama_runtime::RuntimeApi,
service::KusamaExecutor,
service::kusama_runtime::UncheckedExtrinsic,
>(runtime, authority_discovery_enabled, grandpa_pause)
runtime.run_node(
|config| {
service::kusama_new_light(config)
},
|config| {
service::kusama_new_full(
config,
None,
None,
authority_discovery_enabled,
6000,
grandpa_pause
).map(|(s, _, _)| s)
},
service::KusamaExecutor::native_version().runtime_version
)
} else if config.chain_spec.is_westend() {
run_node::<
service::westend_runtime::RuntimeApi,
service::WestendExecutor,
service::westend_runtime::UncheckedExtrinsic,
>(runtime, authority_discovery_enabled, grandpa_pause)
runtime.run_node(
|config| {
service::westend_new_light(config)
},
|config| {
service::westend_new_full(
config,
None,
None,
authority_discovery_enabled,
6000,
grandpa_pause
).map(|(s, _, _)| s)
},
service::WestendExecutor::native_version().runtime_version
)
} else {
run_node::<
service::polkadot_runtime::RuntimeApi,
service::PolkadotExecutor,
service::polkadot_runtime::UncheckedExtrinsic,
>(runtime, authority_discovery_enabled, grandpa_pause)
runtime.run_node(
|config| {
service::polkadot_new_light(config)
},
|config| {
service::polkadot_new_full(
config,
None,
None,
authority_discovery_enabled,
6000,
grandpa_pause
).map(|(s, _, _)| s)
},
service::PolkadotExecutor::native_version().runtime_version
)
}
},
Some(Subcommand::Base(subcommand)) => {
@@ -160,55 +192,3 @@ pub fn run() -> Result<()> {
},
}
}
fn run_node<R, D, E>(
runtime: sc_cli::Runner<Cli>,
authority_discovery_enabled: bool,
grandpa_pause: Option<(u32, u32)>,
) -> sc_cli::Result<()>
where
R: ConstructRuntimeApi<Block, service::TFullClient<Block, R, D>>
+ Send + Sync + 'static,
<R as ConstructRuntimeApi<Block, service::TFullClient<Block, R, D>>>::RuntimeApi:
RuntimeApiCollection<E, StateBackend = sc_client_api::StateBackendFor<service::TFullBackend<Block>, Block>>,
<R as ConstructRuntimeApi<Block, service::TLightClient<Block, R, D>>>::RuntimeApi:
RuntimeApiCollection<E, StateBackend = sc_client_api::StateBackendFor<service::TLightBackend<Block>, Block>>,
E: service::Codec + Send + Sync + 'static,
D: service::NativeExecutionDispatch + 'static,
// Rust bug: https://github.com/rust-lang/rust/issues/24159
<<R as ConstructRuntimeApi<Block, TFullClient<Block, R, D>>>::RuntimeApi as sp_api::ApiExt<Block>>::StateBackend:
sp_api::StateBackend<BlakeTwo256>,
// Rust bug: https://github.com/rust-lang/rust/issues/43580
R: ConstructRuntimeApi<
Block,
TLightClient<R, D>
>,
{
runtime.run_node(
|config| service::new_light::<R, D, E>(config),
|config| service::new_full::<R, D, E>(
config,
None,
None,
authority_discovery_enabled,
6000,
grandpa_pause,
).map(|(s, _)| s),
D::native_version().runtime_version,
)
}
// We can't simply use `service::TLightClient` due to a
// Rust bug: https://github.com/rust-lang/rust/issues/43580
type TLightClient<Runtime, Dispatch> = sc_client::Client<
sc_client::light::backend::Backend<sc_client_db::light::LightStorage<Block>, BlakeTwo256>,
sc_client::light::call_executor::GenesisCallExecutor<
sc_client::light::backend::Backend<sc_client_db::light::LightStorage<Block>, BlakeTwo256>,
sc_client::LocalCallExecutor<
sc_client::light::backend::Backend<sc_client_db::light::LightStorage<Block>, BlakeTwo256>,
sc_executor::NativeExecutor<Dispatch>
>
>,
Block,
Runtime
>;
+2 -1
View File
@@ -7,7 +7,8 @@ edition = "2018"
[dependencies]
futures = "0.3.4"
sc-client = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-service = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-executor = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-cli = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" }
+74 -59
View File
@@ -52,9 +52,8 @@ use std::pin::Pin;
use futures::{future, Future, Stream, FutureExt, TryFutureExt, StreamExt, task::Spawn};
use log::warn;
use sc_client::BlockchainEvents;
use sc_client_api::StateBackend;
use sp_core::Pair;
use sp_runtime::traits::BlakeTwo256;
use polkadot_primitives::{
BlockId, Hash, Block,
parachain::{
@@ -72,7 +71,9 @@ pub use polkadot_validation::SignedStatement;
pub use polkadot_primitives::parachain::CollatorId;
pub use sc_network::PeerId;
pub use service::RuntimeApiCollection;
use sc_service::ClientProvider;
pub use sc_cli::SubstrateCli;
use sp_api::{ConstructRuntimeApi, ApiExt, HashFor};
const COLLATION_TIMEOUT: Duration = Duration::from_secs(30);
@@ -114,34 +115,24 @@ impl fmt::Display for Error {
}
}
/// The Polkadot client type.
pub type PolkadotClient<B, E, R> = sc_client::Client<B, E, Block, R>;
/// Something that can build a `ParachainContext`.
pub trait BuildParachainContext {
/// The parachain context produced by the `build` function.
type ParachainContext: self::ParachainContext;
/// Build the `ParachainContext`.
fn build<B, E, R, SP, Extrinsic>(
fn build<Client, SP, Extrinsic>(
self,
client: Arc<PolkadotClient<B, E, R>>,
client: Arc<Client>,
spawner: SP,
network: impl Network + Clone + 'static,
) -> Result<Self::ParachainContext, ()>
where
PolkadotClient<B, E, R>: ProvideRuntimeApi<Block>,
<PolkadotClient<B, E, R> as ProvideRuntimeApi<Block>>::Api: RuntimeApiCollection<Extrinsic>,
// Rust bug: https://github.com/rust-lang/rust/issues/24159
<<PolkadotClient<B, E, R> as ProvideRuntimeApi<Block>>::Api as sp_api::ApiExt<Block>>::StateBackend:
sp_api::StateBackend<BlakeTwo256>,
Client: ProvideRuntimeApi<Block>,
Client::Api: RuntimeApiCollection<Extrinsic>,
<Client::Api as ApiExt<Block>>::StateBackend: StateBackend<HashFor<Block>>,
Extrinsic: codec::Codec + Send + Sync + 'static,
E: sc_client::CallExecutor<Block> + Clone + Send + Sync + 'static,
SP: Spawn + Clone + Send + Sync + 'static,
R: Send + Sync + 'static,
B: sc_client_api::Backend<Block> + 'static,
// Rust bug: https://github.com/rust-lang/rust/issues/24159
B::State: sp_api::StateBackend<BlakeTwo256>;
SP: Spawn + Clone + Send + Sync + 'static;
}
/// Parachain context needed for collation.
@@ -209,38 +200,40 @@ pub async fn collate<P>(
Ok(collation)
}
fn build_collator_service<S, P, Extrinsic>(
service: (S, polkadot_service::FullNodeHandles),
fn build_collator_service<SP, P, C, E, R, Extrinsic>(
spawner: SP,
handles: polkadot_service::FullNodeHandles,
client: Arc<C>,
para_id: ParaId,
key: Arc<CollatorPair>,
build_parachain_context: P,
) -> Result<S, polkadot_service::Error>
) -> Result<impl Future<Output = ()> + Send + 'static, polkadot_service::Error>
where
S: AbstractService<Block = service::Block>,
sc_client::Client<S::Backend, S::CallExecutor, service::Block, S::RuntimeApi>: ProvideRuntimeApi<Block>,
<sc_client::Client<S::Backend, S::CallExecutor, service::Block, S::RuntimeApi> as ProvideRuntimeApi<Block>>::Api:
RuntimeApiCollection<
C: ClientProvider<
service::Block,
service::TFullBackend<service::Block>,
service::TFullCallExecutor<service::Block, E>,
R
> + 'static,
R: ConstructRuntimeApi<service::Block, C> + Sync + Send,
<R as ConstructRuntimeApi<service::Block, C>>::RuntimeApi:
sp_api::ApiExt<
service::Block,
StateBackend = <service::TFullBackend<service::Block> as service::Backend<service::Block>>::State,
>
+ RuntimeApiCollection<
Extrinsic,
Error = sp_blockchain::Error,
StateBackend = sc_client_api::StateBackendFor<S::Backend, Block>
>,
// Rust bug: https://github.com/rust-lang/rust/issues/24159
S::Backend: service::Backend<service::Block>,
// Rust bug: https://github.com/rust-lang/rust/issues/24159
<S::Backend as service::Backend<service::Block>>::State:
sp_api::StateBackend<sp_runtime::traits::HashFor<Block>>,
// Rust bug: https://github.com/rust-lang/rust/issues/24159
S::CallExecutor: service::CallExecutor<service::Block>,
// Rust bug: https://github.com/rust-lang/rust/issues/24159
S::SelectChain: service::SelectChain<service::Block>,
StateBackend = <service::TFullBackend<service::Block> as service::Backend<service::Block>>::State,
>
+ Sync + Send,
E: sc_executor::NativeExecutionDispatch + 'static,
P: BuildParachainContext,
P::ParachainContext: Send + 'static,
<P::ParachainContext as ParachainContext>::ProduceCandidate: Send,
Extrinsic: service::Codec + Send + Sync + 'static,
SP: Spawn + Clone + Send + Sync + 'static,
{
let (service, handles) = service;
let spawner = service.spawn_task_handle();
let polkadot_network = handles.polkadot_network
.ok_or_else(|| "Collator cannot run when Polkadot-specific networking has not been started")?;
@@ -250,8 +243,6 @@ fn build_collator_service<S, P, Extrinsic>(
handles.validation_service_handle
.ok_or_else(|| "Collator cannot run when validation networking has not been started")?;
let client = service.client();
let parachain_context = match build_parachain_context.build(
client.clone(),
spawner,
@@ -334,9 +325,7 @@ fn build_collator_service<S, P, Extrinsic>(
}
}.boxed();
service.spawn_essential_task("collation", work);
Ok(service)
Ok(work)
}
/// Async function that will run the collator node with the given `RelayChainContext` and `ParachainContext`
@@ -348,29 +337,55 @@ pub async fn start_collator<P>(
config: Configuration,
) -> Result<(), polkadot_service::Error>
where
P: BuildParachainContext,
P: 'static + BuildParachainContext,
P::ParachainContext: Send + 'static,
<P::ParachainContext as ParachainContext>::ProduceCandidate: Send,
{
let is_kusama = config.chain_spec.is_kusama();
match (is_kusama, &config.role) {
(_, Role::Light) => return Err(
(_, Role::Light) => Err(
polkadot_service::Error::Other("light nodes are unsupported as collator".into())
).into(),
(true, _) =>
(true, _) => {
let (service, client, handlers) = service::kusama_new_full(
config,
Some((key.public(), para_id)),
None,
false,
6000,
None
)?;
let spawn_handle = service.spawn_task_handle();
build_collator_service(
service::kusama_new_full(config, Some((key.public(), para_id)), None, false, 6000, None)?,
spawn_handle,
handlers,
client,
para_id,
key,
build_parachain_context
)?.await;
Ok(())
},
(false, _) => {
let (service, client, handles) = service::polkadot_new_full(
config,
Some((key.public(), para_id)),
None,
false,
6000,
None
)?;
let spawn_handle = service.spawn_task_handle();
build_collator_service(
spawn_handle,
handles,
client,
para_id,
key,
build_parachain_context,
)?.await,
(false, _) =>
build_collator_service(
service::polkadot_new_full(config, Some((key.public(), para_id)), None, false, 6000, None)?,
para_id,
key,
build_parachain_context,
)?.await,
)?.await;
Ok(())
}
}
}
@@ -413,9 +428,9 @@ mod tests {
impl BuildParachainContext for BuildDummyParachainContext {
type ParachainContext = DummyParachainContext;
fn build<B, E, R, SP, Extrinsic>(
fn build<C, SP, Extrinsic>(
self,
_: Arc<PolkadotClient<B, E, R>>,
_: Arc<C>,
_: SP,
_: impl Network + Clone + 'static,
) -> Result<Self::ParachainContext, ()> {
-1
View File
@@ -23,7 +23,6 @@ futures = "0.3.4"
log = "0.4.8"
exit-future = "0.2.0"
futures-timer = "2.0"
sc-client = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
wasm-timer = "0.2.4"
+2 -1
View File
@@ -10,10 +10,11 @@ log = "0.4.8"
parking_lot = "0.10.0"
futures = "0.3.1"
rand = "0.7.2"
sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-service = { git = "https://github.com/paritytech/substrate", features = ["test-helpers"], branch = "master" }
sc-network-test = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-client = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
+14 -5
View File
@@ -34,8 +34,8 @@ use sc_client_api::{
client::BlockBackend,
backend::{TransactionFor, AuxStore, Backend, Finalizer},
};
use sc_consensus::LongestChain;
use sc_block_builder::{BlockBuilder, BlockBuilderProvider};
use sc_client::LongestChain;
use sp_consensus::block_validation::DefaultBlockAnnounceValidator;
use sp_consensus::import_queue::{
BasicQueue, BoxJustificationImport, Verifier, BoxFinalityProofImport,
@@ -53,14 +53,23 @@ use sp_runtime::generic::BlockId;
use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor};
use sp_runtime::Justification;
pub use sc_network_test::PassThroughVerifier;
use sc_service::client::Client;
pub use polkadot_test_runtime_client::runtime::{Block, Extrinsic, Hash};
pub use polkadot_test_runtime_client::{TestClient, TestClientBuilder, TestClientBuilderExt};
pub type PeersFullClient =
sc_client::Client<polkadot_test_runtime_client::Backend, polkadot_test_runtime_client::Executor, Block, polkadot_test_runtime_client::runtime::RuntimeApi>;
pub type PeersLightClient =
sc_client::Client<polkadot_test_runtime_client::LightBackend, polkadot_test_runtime_client::LightExecutor, Block, polkadot_test_runtime_client::runtime::RuntimeApi>;
pub type PeersFullClient = Client<
polkadot_test_runtime_client::Backend,
polkadot_test_runtime_client::Executor,
Block,
polkadot_test_runtime_client::runtime::RuntimeApi
>;
pub type PeersLightClient = Client<
polkadot_test_runtime_client::LightBackend,
polkadot_test_runtime_client::LightExecutor,
Block,
polkadot_test_runtime_client::runtime::RuntimeApi
>;
#[derive(Clone)]
pub enum PeersClient {
@@ -10,7 +10,6 @@ parachain = { package = "polkadot-parachain", path = "../../.." }
collator = { package = "polkadot-collator", path = "../../../../collator" }
primitives = { package = "polkadot-primitives", path = "../../../../primitives" }
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
client = { package = "sc-client", git = "https://github.com/paritytech/substrate", branch = "master" }
client-api = { package = "sc-client-api", git = "https://github.com/paritytech/substrate", branch = "master" }
parking_lot = "0.10.0"
codec = { package = "parity-scale-codec", version = "1.2.0" }
@@ -101,9 +101,9 @@ impl ParachainContext for AdderContext {
impl BuildParachainContext for AdderContext {
type ParachainContext = Self;
fn build<B, E, R, SP, Extrinsic>(
fn build<Client, SP, Extrinsic>(
self,
_: Arc<collator::PolkadotClient<B, E, R>>,
_: Arc<Client>,
_: SP,
network: impl Network + Clone + 'static,
) -> Result<Self::ParachainContext, ()> {
+2 -1
View File
@@ -5,9 +5,10 @@ authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
[dependencies]
client = { package = "sc-client", git = "https://github.com/paritytech/substrate", branch = "master" }
jsonrpc-core = "14.0.3"
polkadot-primitives = { path = "../primitives" }
sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" }
+6 -4
View File
@@ -23,6 +23,8 @@ use std::sync::Arc;
use polkadot_primitives::{Block, AccountId, Nonce, Balance};
use sp_api::ProvideRuntimeApi;
use txpool_api::TransactionPool;
use sp_blockchain::HeaderBackend;
use sc_client_api::light::{Fetcher, RemoteBlockchain};
/// A type representing all RPC extensions.
pub type RpcExtension = jsonrpc_core::IoHandler<sc_rpc::Metadata>;
@@ -30,7 +32,7 @@ pub type RpcExtension = jsonrpc_core::IoHandler<sc_rpc::Metadata>;
/// Instantiate all RPC extensions.
pub fn create_full<C, P, UE>(client: Arc<C>, pool: Arc<P>) -> RpcExtension where
C: ProvideRuntimeApi<Block>,
C: client::blockchain::HeaderBackend<Block>,
C: HeaderBackend<Block>,
C: Send + Sync + 'static,
C::Api: frame_rpc_system::AccountNonceApi<Block, AccountId, Nonce>,
C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<Block, Balance, UE>,
@@ -53,18 +55,18 @@ pub fn create_full<C, P, UE>(client: Arc<C>, pool: Arc<P>) -> RpcExtension where
/// Instantiate all RPC extensions for light node.
pub fn create_light<C, P, F, UE>(
client: Arc<C>,
remote_blockchain: Arc<dyn client::light::blockchain::RemoteBlockchain<Block>>,
remote_blockchain: Arc<dyn RemoteBlockchain<Block>>,
fetcher: Arc<F>,
pool: Arc<P>,
) -> RpcExtension
where
C: ProvideRuntimeApi<Block>,
C: client::blockchain::HeaderBackend<Block>,
C: HeaderBackend<Block>,
C: Send + Sync + 'static,
C::Api: frame_rpc_system::AccountNonceApi<Block, AccountId, Nonce>,
C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<Block, Balance, UE>,
P: TransactionPool + Sync + Send + 'static,
F: client::light::fetcher::Fetcher<Block> + 'static,
F: Fetcher<Block> + 'static,
UE: codec::Codec + Send + Sync + 'static,
{
use frame_rpc_system::{LightSystem, SystemApi};
@@ -7,6 +7,8 @@ license = "GPL-3.0"
[dependencies]
sc-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-service = { git = "https://github.com/paritytech/substrate", branch = "master", features = ["test-helpers"], default-features = false }
substrate-test-client = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
polkadot-test-runtime = { path = ".." }
@@ -17,6 +19,5 @@ sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
codec = { package = "parity-scale-codec", version = "1.0.0" }
sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-client = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master" }
futures = "0.3.1"
+31 -18
View File
@@ -22,16 +22,19 @@ use std::sync::Arc;
use std::collections::BTreeMap;
pub use substrate_test_client::*;
pub use polkadot_test_runtime as runtime;
pub use sc_client::LongestChain;
use sp_core::{sr25519, ChangesTrieConfiguration, map, twox_128};
use sp_core::storage::{ChildInfo, Storage, StorageChild};
use polkadot_test_runtime::genesismap::GenesisConfig;
use sp_runtime::traits::{Block as BlockT, Header as HeaderT, Hash as HashT, HashFor};
use sc_client::{
light::fetcher::{
RemoteCallRequest, RemoteBodyRequest,
use sc_consensus::LongestChain;
use sc_client_api::light::{RemoteCallRequest, RemoteBodyRequest};
use sc_service::client::{
light::{
call_executor::GenesisCallExecutor, backend as light_backend,
new_light_blockchain, new_light_backend,
},
genesis, Client as SubstrateClient, LocalCallExecutor
};
/// A prelude to import in tests.
@@ -57,7 +60,7 @@ sc_executor::native_executor_instance! {
pub type Backend = substrate_test_client::Backend<polkadot_test_runtime::Block>;
/// Test client executor.
pub type Executor = sc_client::LocalCallExecutor<
pub type Executor = LocalCallExecutor<
Backend,
NativeExecutor<LocalExecutor>,
>;
@@ -66,10 +69,10 @@ pub type Executor = sc_client::LocalCallExecutor<
pub type LightBackend = substrate_test_client::LightBackend<polkadot_test_runtime::Block>;
/// Test client light executor.
pub type LightExecutor = sc_client::light::call_executor::GenesisCallExecutor<
pub type LightExecutor = GenesisCallExecutor<
LightBackend,
sc_client::LocalCallExecutor<
sc_client::light::backend::Backend<
LocalCallExecutor<
light_backend::Backend<
sc_client_db::light::LightStorage<polkadot_test_runtime::Block>,
HashFor<polkadot_test_runtime::Block>
>,
@@ -120,7 +123,7 @@ impl substrate_test_client::GenesisInit for GenesisParameters {
let state_root = <<<runtime::Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
storage.top.clone().into_iter().chain(child_roots).collect()
);
let block: runtime::Block = sc_client::genesis::construct_genesis_block(state_root);
let block: runtime::Block = genesis::construct_genesis_block(state_root);
storage.top.extend(additional_storage_with_genesis(&block));
storage
@@ -136,9 +139,9 @@ pub type TestClientBuilder<E, B> = substrate_test_client::TestClientBuilder<
>;
/// Test client type with `LocalExecutor` and generic Backend.
pub type Client<B> = sc_client::Client<
pub type Client<B> = SubstrateClient<
B,
sc_client::LocalCallExecutor<B, sc_executor::NativeExecutor<LocalExecutor>>,
LocalCallExecutor<B, sc_executor::NativeExecutor<LocalExecutor>>,
polkadot_test_runtime::Block,
polkadot_test_runtime::RuntimeApi,
>;
@@ -212,21 +215,21 @@ pub trait TestClientBuilderExt<B>: Sized {
}
/// Build the test client and longest chain selector.
fn build_with_longest_chain(self) -> (Client<B>, sc_client::LongestChain<B, polkadot_test_runtime::Block>);
fn build_with_longest_chain(self) -> (Client<B>, LongestChain<B, polkadot_test_runtime::Block>);
/// Build the test client and the backend.
fn build_with_backend(self) -> (Client<B>, Arc<B>);
}
impl TestClientBuilderExt<Backend> for TestClientBuilder<
sc_client::LocalCallExecutor<Backend, sc_executor::NativeExecutor<LocalExecutor>>,
LocalCallExecutor<Backend, sc_executor::NativeExecutor<LocalExecutor>>,
Backend
> {
fn genesis_init_mut(&mut self) -> &mut GenesisParameters {
Self::genesis_init_mut(self)
}
fn build_with_longest_chain(self) -> (Client<Backend>, sc_client::LongestChain<Backend, polkadot_test_runtime::Block>) {
fn build_with_longest_chain(self) -> (Client<Backend>, LongestChain<Backend, polkadot_test_runtime::Block>) {
self.build_with_native_executor(None)
}
@@ -277,15 +280,25 @@ pub fn new() -> Client<Backend> {
/// Creates new light client instance used for tests.
pub fn new_light() -> (
sc_client::Client<LightBackend, LightExecutor, polkadot_test_runtime::Block, polkadot_test_runtime::RuntimeApi>,
SubstrateClient<
LightBackend,
LightExecutor,
polkadot_test_runtime::Block,
polkadot_test_runtime::RuntimeApi
>,
Arc<LightBackend>,
) {
let storage = sc_client_db::light::LightStorage::new_test();
let blockchain = Arc::new(sc_client::light::blockchain::Blockchain::new(storage));
let backend = Arc::new(LightBackend::new(blockchain.clone()));
let blockchain =new_light_blockchain(storage);
let backend = new_light_backend(blockchain.clone());
let executor = new_native_executor();
let local_call_executor = sc_client::LocalCallExecutor::new(backend.clone(), executor, sp_core::tasks::executor(), Default::default(),);
let local_call_executor = LocalCallExecutor::new(
backend.clone(),
executor,
sp_core::tasks::executor(),
Default::default()
);
let call_executor = LightExecutor::new(
backend.clone(),
local_call_executor,
+2 -1
View File
@@ -25,11 +25,11 @@ sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-client = { 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-chain-spec = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-executor = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" }
consensus_common = { package = "sp-consensus", git = "https://github.com/paritytech/substrate", branch = "master" }
grandpa = { package = "sc-finality-grandpa", git = "https://github.com/paritytech/substrate", branch = "master" }
@@ -37,6 +37,7 @@ grandpa_primitives = { package = "sp-finality-grandpa", git = "https://github.co
inherents = { package = "sp-inherents", 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" }
sc-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
+2 -2
View File
@@ -48,9 +48,9 @@ const DEFAULT_PROTOCOL_ID: &str = "dot";
#[serde(rename_all = "camelCase")]
pub struct Extensions {
/// Block numbers with known hashes.
pub fork_blocks: sc_client::ForkBlocks<polkadot_primitives::Block>,
pub fork_blocks: sc_client_api::ForkBlocks<polkadot_primitives::Block>,
/// Known bad block hashes.
pub bad_blocks: sc_client::BadBlocks<polkadot_primitives::Block>,
pub bad_blocks: sc_client_api::BadBlocks<polkadot_primitives::Block>,
}
/// The `ChainSpec parametrised for polkadot runtime`.
+408 -456
View File
@@ -19,7 +19,6 @@
pub mod chain_spec;
mod grandpa_support;
use sc_client::LongestChain;
use std::sync::Arc;
use std::time::Duration;
use polkadot_primitives::{parachain, Hash, BlockId, AccountId, Nonce, Balance};
@@ -27,21 +26,20 @@ use polkadot_primitives::{parachain, Hash, BlockId, AccountId, Nonce, Balance};
use polkadot_network::{legacy::gossip::Known, protocol as network_protocol};
use service::{error::Error as ServiceError, ServiceBuilder};
use grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider};
use inherents::InherentDataProviders;
use sc_executor::native_executor_instance;
use log::info;
pub use service::{
AbstractService, Role, PruningMode, TransactionPoolOptions, Error, RuntimeGenesis,
TFullClient, TLightClient, TFullBackend, TLightBackend, TFullCallExecutor, TLightCallExecutor,
Configuration, ChainSpec, ServiceBuilderCommand,
Configuration, ChainSpec, ServiceBuilderCommand, ClientProvider,
};
pub use service::config::{DatabaseConfig, PrometheusConfig};
pub use sc_executor::NativeExecutionDispatch;
pub use sc_client::{ExecutionStrategy, CallExecutor, Client};
pub use sc_client_api::backend::Backend;
pub use sc_client_api::{Backend, ExecutionStrategy, CallExecutor};
pub use sc_consensus::LongestChain;
pub use sp_api::{Core as CoreApi, ConstructRuntimeApi, ProvideRuntimeApi, StateBackend};
pub use sp_runtime::traits::{HashFor, NumberFor};
pub use consensus_common::SelectChain;
pub use consensus_common::{SelectChain, BlockImport, block_validation::Chain};
pub use polkadot_primitives::parachain::{CollatorId, ParachainHost};
pub use polkadot_primitives::Block;
pub use sp_runtime::traits::{Block as BlockT, self as runtime_traits, BlakeTwo256};
@@ -76,7 +74,7 @@ native_executor_instance!(
);
/// A set of APIs that polkadot-like runtimes must implement.
pub trait RuntimeApiCollection<Extrinsic: codec::Codec + Send + Sync + 'static> :
pub trait RuntimeApiCollection<Extrinsic: codec::Codec + Send + Sync + 'static>:
sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
+ sp_api::ApiExt<Block, Error = sp_blockchain::Error>
+ babe_primitives::BabeApi<Block>
@@ -156,7 +154,7 @@ macro_rules! new_full_start {
Block, $runtime, $executor
>($config)?
.with_select_chain(|_, backend| {
Ok(sc_client::LongestChain::new(backend.clone()))
Ok(sc_consensus::LongestChain::new(backend.clone()))
})?
.with_transaction_pool(|config, client, _fetcher, prometheus_registry| {
let pool_api = sc_transaction_pool::FullChainApi::new(client.clone());
@@ -209,6 +207,352 @@ macro_rules! new_full_start {
}}
}
/// Builds a new service for a full client.
#[macro_export]
macro_rules! new_full {
(
$config:expr,
$collating_for:expr,
$max_block_data_size:expr,
$authority_discovery_enabled:expr,
$slot_duration:expr,
$grandpa_pause:expr,
$runtime:ty,
$dispatch:ty
) => {{
use sc_network::Event;
use sc_client_api::ExecutorProvider;
use futures::stream::StreamExt;
let is_collator = $collating_for.is_some();
let role = $config.role.clone();
let is_authority = role.is_authority() && !is_collator;
let force_authoring = $config.force_authoring;
let max_block_data_size = $max_block_data_size;
let db_path = match $config.database.path() {
Some(path) => std::path::PathBuf::from(path),
None => return Err("Starting a Polkadot service with a custom database isn't supported".to_string().into()),
};
let disable_grandpa = $config.disable_grandpa;
let name = $config.network.node_name.clone();
let authority_discovery_enabled = $authority_discovery_enabled;
let slot_duration = $slot_duration;
let (builder, mut import_setup, inherent_data_providers) = new_full_start!($config, $runtime, $dispatch);
let backend = builder.backend().clone();
let service = builder
.with_finality_proof_provider(|client, backend| {
let provider = client as Arc<dyn grandpa::StorageAndProofProvider<_, _>>;
Ok(Arc::new(GrandpaFinalityProofProvider::new(backend, provider)) as _)
})?
.build()?;
let (block_import, link_half, babe_link) = import_setup.take()
.expect("Link Half and Block Import are present for Full Services or setup failed before. qed");
let client = service.client();
let known_oracle = client.clone();
let mut handles = FullNodeHandles::default();
let select_chain = if let Some(select_chain) = service.select_chain() {
select_chain
} else {
info!("The node cannot start as an authority because it can't select chain.");
return Ok((service, client, handles));
};
let gossip_validator_select_chain = select_chain.clone();
let is_known = move |block_hash: &Hash| {
use consensus_common::BlockStatus;
match known_oracle.block_status(&BlockId::hash(*block_hash)) {
Err(_) | Ok(BlockStatus::Unknown) | Ok(BlockStatus::Queued) => None,
Ok(BlockStatus::KnownBad) => Some(Known::Bad),
Ok(BlockStatus::InChainWithState) | Ok(BlockStatus::InChainPruned) => {
match gossip_validator_select_chain.leaves() {
Err(_) => None,
Ok(leaves) => if leaves.contains(block_hash) {
Some(Known::Leaf)
} else {
Some(Known::Old)
},
}
}
}
};
let polkadot_network_service = network_protocol::start(
service.network(),
network_protocol::Config {
collating_for: $collating_for,
},
(is_known, client.clone()),
client.clone(),
service.spawn_task_handle(),
).map_err(|e| format!("Could not spawn network worker: {:?}", e))?;
let authority_handles = if is_collator || role.is_authority() {
let availability_store = {
use std::path::PathBuf;
let mut path = PathBuf::from(db_path);
path.push("availability");
#[cfg(not(target_os = "unknown"))]
{
av_store::Store::new(
::av_store::Config {
cache_size: None,
path,
},
polkadot_network_service.clone(),
)?
}
#[cfg(target_os = "unknown")]
av_store::Store::new_in_memory(gossip)
};
polkadot_network_service.register_availability_store(availability_store.clone());
let (validation_service_handle, validation_service) = consensus::ServiceBuilder {
client: client.clone(),
network: polkadot_network_service.clone(),
collators: polkadot_network_service.clone(),
spawner: service.spawn_task_handle(),
availability_store: availability_store.clone(),
select_chain: select_chain.clone(),
keystore: service.keystore(),
max_block_data_size,
}.build();
service.spawn_essential_task("validation-service", Box::pin(validation_service));
handles.validation_service_handle = Some(validation_service_handle.clone());
Some((validation_service_handle, availability_store))
} else {
None
};
if role.is_authority() {
let (validation_service_handle, availability_store) = authority_handles
.clone()
.expect("Authority handles are set for authority nodes; qed");
let proposer = consensus::ProposerFactory::new(
client.clone(),
service.transaction_pool(),
validation_service_handle,
slot_duration,
backend,
);
let select_chain = service.select_chain().ok_or(ServiceError::SelectChainRequired)?;
let can_author_with =
consensus_common::CanAuthorWithNativeVersion::new(client.executor().clone());
let block_import = availability_store.block_import(
block_import,
client.clone(),
service.spawn_task_handle(),
service.keystore(),
)?;
let babe_config = babe::BabeParams {
keystore: service.keystore(),
client: client.clone(),
select_chain,
block_import,
env: proposer,
sync_oracle: service.network(),
inherent_data_providers: inherent_data_providers.clone(),
force_authoring,
babe_link,
can_author_with,
};
let babe = babe::start_babe(babe_config)?;
service.spawn_essential_task("babe", babe);
}
if matches!(role, Role::Authority{..} | Role::Sentry{..}) {
if authority_discovery_enabled {
let (sentries, authority_discovery_role) = match role {
Role::Authority { ref sentry_nodes } => (
sentry_nodes.clone(),
authority_discovery::Role::Authority (
service.keystore(),
),
),
Role::Sentry {..} => (
vec![],
authority_discovery::Role::Sentry,
),
_ => unreachable!("Due to outer matches! constraint; qed."),
};
let network = service.network();
let network_event_stream = network.event_stream("authority-discovery");
let dht_event_stream = network_event_stream.filter_map(|e| async move { match e {
Event::Dht(e) => Some(e),
_ => None,
}}).boxed();
let authority_discovery = authority_discovery::AuthorityDiscovery::new(
service.client(),
network,
sentries,
dht_event_stream,
authority_discovery_role,
service.prometheus_registry(),
);
service.spawn_task("authority-discovery", authority_discovery);
}
}
// if the node isn't actively participating in consensus then it doesn't
// need a keystore, regardless of which protocol we use below.
let keystore = if is_authority {
Some(service.keystore())
} else {
None
};
let config = grandpa::Config {
// FIXME substrate#1578 make this available through chainspec
gossip_duration: Duration::from_millis(1000),
justification_period: 512,
name: Some(name),
observer_enabled: false,
keystore,
is_authority: role.is_network_authority(),
};
let enable_grandpa = !disable_grandpa;
if enable_grandpa {
// start the full GRANDPA voter
// NOTE: unlike in substrate we are currently running the full
// GRANDPA voter protocol for all full nodes (regardless of whether
// they're validators or not). at this point the full voter should
// provide better guarantees of block and vote data availability than
// the observer.
// add a custom voting rule to temporarily stop voting for new blocks
// after the given pause block is finalized and restarting after the
// given delay.
let voting_rule = match $grandpa_pause {
Some((block, delay)) => {
info!("GRANDPA scheduled voting pause set for block #{} with a duration of {} blocks.",
block,
delay,
);
grandpa::VotingRulesBuilder::default()
.add(grandpa_support::PauseAfterBlockFor(block, delay))
.build()
},
None =>
grandpa::VotingRulesBuilder::default()
.build(),
};
let grandpa_config = grandpa::GrandpaParams {
config,
link: link_half,
network: service.network(),
inherent_data_providers: inherent_data_providers.clone(),
telemetry_on_connect: Some(service.telemetry_on_connect_stream()),
voting_rule,
prometheus_registry: service.prometheus_registry(),
};
service.spawn_essential_task(
"grandpa-voter",
grandpa::run_grandpa_voter(grandpa_config)?
);
} else {
grandpa::setup_disabled_grandpa(
client.clone(),
&inherent_data_providers,
service.network(),
)?;
}
handles.polkadot_network = Some(polkadot_network_service);
(service, client, handles)
}}
}
/// Builds a new service for a light client.
#[macro_export]
macro_rules! new_light {
($config:expr, $runtime:ty, $dispatch:ty) => {{
crate::set_prometheus_registry(&mut $config)?;
let inherent_data_providers = inherents::InherentDataProviders::new();
ServiceBuilder::new_light::<Block, $runtime, $dispatch>($config)?
.with_select_chain(|_, backend| {
Ok(sc_consensus::LongestChain::new(backend.clone()))
})?
.with_transaction_pool(|config, client, fetcher, prometheus_registry| {
let fetcher = fetcher
.ok_or_else(|| "Trying to start light transaction pool without active fetcher")?;
let pool_api = sc_transaction_pool::LightChainApi::new(client.clone(), fetcher.clone());
let pool = sc_transaction_pool::BasicPool::with_revalidation_type(
config, Arc::new(pool_api), prometheus_registry, sc_transaction_pool::RevalidationType::Light,
);
Ok(pool)
})?
.with_import_queue_and_fprb(|_config, client, backend, fetcher, _select_chain, _| {
let fetch_checker = fetcher
.map(|fetcher| fetcher.checker().clone())
.ok_or_else(|| "Trying to start light import queue without active fetch checker")?;
let grandpa_block_import = grandpa::light_block_import(
client.clone(), backend, &(client.clone() as Arc<_>), Arc::new(fetch_checker)
)?;
let finality_proof_import = grandpa_block_import.clone();
let finality_proof_request_builder =
finality_proof_import.create_finality_proof_request_builder();
let (babe_block_import, babe_link) = babe::block_import(
babe::Config::get_or_compute(&*client)?,
grandpa_block_import,
client.clone(),
)?;
// FIXME: pruning task isn't started since light client doesn't do `AuthoritySetup`.
let import_queue = babe::import_queue(
babe_link,
babe_block_import,
None,
Some(Box::new(finality_proof_import)),
client,
inherent_data_providers.clone(),
)?;
Ok((import_queue, finality_proof_request_builder))
})?
.with_finality_proof_provider(|client, backend| {
let provider = client as Arc<dyn grandpa::StorageAndProofProvider<_, _>>;
Ok(Arc::new(grandpa::FinalityProofProvider::new(backend, provider)) as _)
})?
.with_rpc_extensions(|builder|
-> Result<polkadot_rpc::RpcExtension, _> {
let fetcher = builder.fetcher()
.ok_or_else(|| "Trying to start node RPC without active fetcher")?;
let remote_blockchain = builder.remote_backend()
.ok_or_else(|| "Trying to start node RPC without active remote blockchain")?;
Ok(polkadot_rpc::create_light(builder.client().clone(), remote_blockchain, fetcher, builder.pool()))
})?
.build()
}}
}
/// Builds a new object suitable for chain operations.
pub fn new_chain_ops<Runtime, Dispatch, Extrinsic>(mut config: Configuration)
-> Result<impl ServiceBuilderCommand<Block=Block>, ServiceError>
@@ -227,7 +571,7 @@ where
/// Create a new Polkadot service for a full node.
#[cfg(feature = "full-node")]
pub fn polkadot_new_full(
config: Configuration,
mut config: Configuration,
collating_for: Option<(CollatorId, parachain::Id)>,
max_block_data_size: Option<u64>,
authority_discovery_enabled: bool,
@@ -235,61 +579,69 @@ pub fn polkadot_new_full(
grandpa_pause: Option<(u32, u32)>,
)
-> Result<(
impl AbstractService<
Block = Block,
RuntimeApi = polkadot_runtime::RuntimeApi,
Backend = TFullBackend<Block>,
SelectChain = LongestChain<TFullBackend<Block>, Block>,
CallExecutor = TFullCallExecutor<Block, PolkadotExecutor>,
>,
impl AbstractService,
Arc<impl ClientProvider<
Block,
TFullBackend<Block>,
TFullCallExecutor<Block, PolkadotExecutor>,
polkadot_runtime::RuntimeApi
>>,
FullNodeHandles,
), ServiceError>
{
new_full(
let (service, client, handles) = new_full!(
config,
collating_for,
max_block_data_size,
authority_discovery_enabled,
slot_duration,
grandpa_pause,
)
polkadot_runtime::RuntimeApi,
PolkadotExecutor
);
Ok((service, client, handles))
}
/// Create a new Kusama service for a full node.
#[cfg(feature = "full-node")]
pub fn kusama_new_full(
config: Configuration,
mut config: Configuration,
collating_for: Option<(CollatorId, parachain::Id)>,
max_block_data_size: Option<u64>,
authority_discovery_enabled: bool,
slot_duration: u64,
grandpa_pause: Option<(u32, u32)>,
)
-> Result<(
impl AbstractService<
Block = Block,
RuntimeApi = kusama_runtime::RuntimeApi,
Backend = TFullBackend<Block>,
SelectChain = LongestChain<TFullBackend<Block>, Block>,
CallExecutor = TFullCallExecutor<Block, KusamaExecutor>,
) -> Result<(
impl AbstractService,
Arc<impl ClientProvider<
Block,
TFullBackend<Block>,
TFullCallExecutor<Block, KusamaExecutor>,
kusama_runtime::RuntimeApi
>
>,
FullNodeHandles,
FullNodeHandles
), ServiceError>
{
new_full(
let (service, client, handles) = new_full!(
config,
collating_for,
max_block_data_size,
authority_discovery_enabled,
slot_duration,
grandpa_pause,
)
kusama_runtime::RuntimeApi,
KusamaExecutor
);
Ok((service, client, handles))
}
/// Create a new Kusama service for a full node.
#[cfg(feature = "full-node")]
pub fn westend_new_full(
config: Configuration,
mut config: Configuration,
collating_for: Option<(CollatorId, parachain::Id)>,
max_block_data_size: Option<u64>,
authority_discovery_enabled: bool,
@@ -297,24 +649,28 @@ pub fn westend_new_full(
grandpa_pause: Option<(u32, u32)>,
)
-> Result<(
impl AbstractService<
Block = Block,
RuntimeApi = westend_runtime::RuntimeApi,
Backend = TFullBackend<Block>,
SelectChain = LongestChain<TFullBackend<Block>, Block>,
CallExecutor = TFullCallExecutor<Block, KusamaExecutor>,
>,
impl AbstractService,
Arc<impl ClientProvider<
Block,
TFullBackend<Block>,
TFullCallExecutor<Block, KusamaExecutor>,
westend_runtime::RuntimeApi
>>,
FullNodeHandles,
), ServiceError>
{
new_full(
let (service, client, handles) = new_full!(
config,
collating_for,
max_block_data_size,
authority_discovery_enabled,
slot_duration,
grandpa_pause,
)
westend_runtime::RuntimeApi,
KusamaExecutor
);
Ok((service, client, handles))
}
/// Handles to other sub-services that full nodes instantiate, which consumers
@@ -328,305 +684,9 @@ pub struct FullNodeHandles {
pub validation_service_handle: Option<consensus::ServiceHandle>,
}
/// Builds a new service for a full client.
#[cfg(feature = "full-node")]
pub fn new_full<Runtime, Dispatch, Extrinsic>(
mut config: Configuration,
collating_for: Option<(CollatorId, parachain::Id)>,
max_block_data_size: Option<u64>,
authority_discovery_enabled: bool,
slot_duration: u64,
grandpa_pause: Option<(u32, u32)>,
)
-> Result<(
impl AbstractService<
Block = Block,
RuntimeApi = Runtime,
Backend = TFullBackend<Block>,
SelectChain = LongestChain<TFullBackend<Block>, Block>,
CallExecutor = TFullCallExecutor<Block, Dispatch>,
>,
FullNodeHandles,
), ServiceError>
where
Runtime: ConstructRuntimeApi<Block, service::TFullClient<Block, Runtime, Dispatch>> + Send + Sync + 'static,
Runtime::RuntimeApi:
RuntimeApiCollection<Extrinsic, StateBackend = sc_client_api::StateBackendFor<TFullBackend<Block>, Block>>,
Dispatch: NativeExecutionDispatch + 'static,
Extrinsic: RuntimeExtrinsic,
// Rust bug: https://github.com/rust-lang/rust/issues/24159
<Runtime::RuntimeApi as sp_api::ApiExt<Block>>::StateBackend: sp_api::StateBackend<BlakeTwo256>,
{
use sc_network::Event;
use sc_client_api::ExecutorProvider;
use futures::stream::StreamExt;
let is_collator = collating_for.is_some();
let role = config.role.clone();
let is_authority = role.is_authority() && !is_collator;
let force_authoring = config.force_authoring;
let max_block_data_size = max_block_data_size;
let db_path = match config.database.path() {
Some(path) => std::path::PathBuf::from(path),
None => return Err("Starting a Polkadot service with a custom database isn't supported".to_string().into()),
};
let disable_grandpa = config.disable_grandpa;
let name = config.network.node_name.clone();
let authority_discovery_enabled = authority_discovery_enabled;
let slot_duration = slot_duration;
let (builder, mut import_setup, inherent_data_providers) = new_full_start!(config, Runtime, Dispatch);
let backend = builder.backend().clone();
let service = builder
.with_finality_proof_provider(|client, backend| {
let provider = client as Arc<dyn grandpa::StorageAndProofProvider<_, _>>;
Ok(Arc::new(GrandpaFinalityProofProvider::new(backend, provider)) as _)
})?
.build()?;
let (block_import, link_half, babe_link) = import_setup.take()
.expect("Link Half and Block Import are present for Full Services or setup failed before. qed");
let client = service.client();
let known_oracle = client.clone();
let mut handles = FullNodeHandles::default();
let select_chain = if let Some(select_chain) = service.select_chain() {
select_chain
} else {
info!("The node cannot start as an authority because it can't select chain.");
return Ok((service, handles));
};
let gossip_validator_select_chain = select_chain.clone();
let is_known = move |block_hash: &Hash| {
use consensus_common::BlockStatus;
match known_oracle.block_status(&BlockId::hash(*block_hash)) {
Err(_) | Ok(BlockStatus::Unknown) | Ok(BlockStatus::Queued) => None,
Ok(BlockStatus::KnownBad) => Some(Known::Bad),
Ok(BlockStatus::InChainWithState) | Ok(BlockStatus::InChainPruned) => {
match gossip_validator_select_chain.leaves() {
Err(_) => None,
Ok(leaves) => if leaves.contains(block_hash) {
Some(Known::Leaf)
} else {
Some(Known::Old)
},
}
}
}
};
let polkadot_network_service = network_protocol::start(
service.network(),
network_protocol::Config {
collating_for,
},
(is_known, client.clone()),
client.clone(),
service.spawn_task_handle(),
).map_err(|e| format!("Could not spawn network worker: {:?}", e))?;
let authority_handles = if is_collator || role.is_authority() {
let availability_store = {
use std::path::PathBuf;
let mut path = PathBuf::from(db_path);
path.push("availability");
#[cfg(not(target_os = "unknown"))]
{
av_store::Store::new(
::av_store::Config {
cache_size: None,
path,
},
polkadot_network_service.clone(),
)?
}
#[cfg(target_os = "unknown")]
av_store::Store::new_in_memory(gossip)
};
polkadot_network_service.register_availability_store(availability_store.clone());
let (validation_service_handle, validation_service) = consensus::ServiceBuilder {
client: client.clone(),
network: polkadot_network_service.clone(),
collators: polkadot_network_service.clone(),
spawner: service.spawn_task_handle(),
availability_store: availability_store.clone(),
select_chain: select_chain.clone(),
keystore: service.keystore(),
max_block_data_size,
}.build();
service.spawn_essential_task("validation-service", Box::pin(validation_service));
handles.validation_service_handle = Some(validation_service_handle.clone());
Some((validation_service_handle, availability_store))
} else {
None
};
if role.is_authority() {
let (validation_service_handle, availability_store) = authority_handles
.clone()
.expect("Authority handles are set for authority nodes; qed");
let proposer = consensus::ProposerFactory::new(
client.clone(),
service.transaction_pool(),
validation_service_handle,
slot_duration,
backend,
);
let select_chain = service.select_chain().ok_or(ServiceError::SelectChainRequired)?;
let can_author_with =
consensus_common::CanAuthorWithNativeVersion::new(client.executor().clone());
let block_import = availability_store.block_import(
block_import,
client.clone(),
service.spawn_task_handle(),
service.keystore(),
)?;
let babe_config = babe::BabeParams {
keystore: service.keystore(),
client,
select_chain,
block_import,
env: proposer,
sync_oracle: service.network(),
inherent_data_providers: inherent_data_providers.clone(),
force_authoring,
babe_link,
can_author_with,
};
let babe = babe::start_babe(babe_config)?;
service.spawn_essential_task("babe", babe);
}
if matches!(role, Role::Authority{..} | Role::Sentry{..}) {
if authority_discovery_enabled {
let (sentries, authority_discovery_role) = match role {
Role::Authority { ref sentry_nodes } => (
sentry_nodes.clone(),
authority_discovery::Role::Authority (
service.keystore(),
),
),
Role::Sentry {..} => (
vec![],
authority_discovery::Role::Sentry,
),
_ => unreachable!("Due to outer matches! constraint; qed."),
};
let network = service.network();
let network_event_stream = network.event_stream("authority-discovery");
let dht_event_stream = network_event_stream.filter_map(|e| async move { match e {
Event::Dht(e) => Some(e),
_ => None,
}}).boxed();
let authority_discovery = authority_discovery::AuthorityDiscovery::new(
service.client(),
network,
sentries,
dht_event_stream,
authority_discovery_role,
service.prometheus_registry(),
);
service.spawn_task("authority-discovery", authority_discovery);
}
}
// if the node isn't actively participating in consensus then it doesn't
// need a keystore, regardless of which protocol we use below.
let keystore = if is_authority {
Some(service.keystore())
} else {
None
};
let config = grandpa::Config {
// FIXME substrate#1578 make this available through chainspec
gossip_duration: Duration::from_millis(1000),
justification_period: 512,
name: Some(name),
observer_enabled: false,
keystore,
is_authority: role.is_network_authority(),
};
let enable_grandpa = !disable_grandpa;
if enable_grandpa {
// start the full GRANDPA voter
// NOTE: unlike in substrate we are currently running the full
// GRANDPA voter protocol for all full nodes (regardless of whether
// they're validators or not). at this point the full voter should
// provide better guarantees of block and vote data availability than
// the observer.
// add a custom voting rule to temporarily stop voting for new blocks
// after the given pause block is finalized and restarting after the
// given delay.
let voting_rule = match grandpa_pause {
Some((block, delay)) => {
info!("GRANDPA scheduled voting pause set for block #{} with a duration of {} blocks.",
block,
delay,
);
grandpa::VotingRulesBuilder::default()
.add(grandpa_support::PauseAfterBlockFor(block, delay))
.build()
},
None =>
grandpa::VotingRulesBuilder::default()
.build(),
};
let grandpa_config = grandpa::GrandpaParams {
config,
link: link_half,
network: service.network(),
inherent_data_providers: inherent_data_providers.clone(),
telemetry_on_connect: Some(service.telemetry_on_connect_stream()),
voting_rule,
prometheus_registry: service.prometheus_registry(),
};
service.spawn_essential_task(
"grandpa-voter",
grandpa::run_grandpa_voter(grandpa_config)?
);
} else {
grandpa::setup_disabled_grandpa(
service.client(),
&inherent_data_providers,
service.network(),
)?;
}
handles.polkadot_network = Some(polkadot_network_service);
Ok((service, handles))
}
/// Create a new Polkadot service for a light client.
pub fn polkadot_new_light(
config: Configuration,
)
-> Result<impl AbstractService<
pub fn polkadot_new_light(mut config: Configuration) -> Result<
impl AbstractService<
Block = Block,
RuntimeApi = polkadot_runtime::RuntimeApi,
Backend = TLightBackend<Block>,
@@ -634,14 +694,12 @@ pub fn polkadot_new_light(
CallExecutor = TLightCallExecutor<Block, PolkadotExecutor>,
>, ServiceError>
{
new_light(config)
new_light!(config, polkadot_runtime::RuntimeApi, PolkadotExecutor)
}
/// Create a new Kusama service for a light client.
pub fn kusama_new_light(
config: Configuration,
)
-> Result<impl AbstractService<
pub fn kusama_new_light(mut config: Configuration) -> Result<
impl AbstractService<
Block = Block,
RuntimeApi = kusama_runtime::RuntimeApi,
Backend = TLightBackend<Block>,
@@ -649,125 +707,19 @@ pub fn kusama_new_light(
CallExecutor = TLightCallExecutor<Block, KusamaExecutor>,
>, ServiceError>
{
new_light(config)
new_light!(config, kusama_runtime::RuntimeApi, KusamaExecutor)
}
/// Create a new Westend service for a light client.
pub fn westend_new_light(
config: Configuration,
)
-> Result<impl AbstractService<
pub fn westend_new_light(mut config: Configuration, ) -> Result<
impl AbstractService<
Block = Block,
RuntimeApi = westend_runtime::RuntimeApi,
Backend = TLightBackend<Block>,
SelectChain = LongestChain<TLightBackend<Block>, Block>,
CallExecutor = TLightCallExecutor<Block, KusamaExecutor>,
>, ServiceError>
CallExecutor = TLightCallExecutor<Block, KusamaExecutor>
>,
ServiceError>
{
new_light(config)
}
// We can't use service::TLightClient due to
// Rust bug: https://github.com/rust-lang/rust/issues/43580
type TLocalLightClient<Runtime, Dispatch> = Client<
sc_client::light::backend::Backend<sc_client_db::light::LightStorage<Block>, BlakeTwo256>,
sc_client::light::call_executor::GenesisCallExecutor<
sc_client::light::backend::Backend<sc_client_db::light::LightStorage<Block>, BlakeTwo256>,
sc_client::LocalCallExecutor<
sc_client::light::backend::Backend<
sc_client_db::light::LightStorage<Block>,
BlakeTwo256
>,
sc_executor::NativeExecutor<Dispatch>
>
>,
Block,
Runtime
>;
/// Builds a new service for a light client.
pub fn new_light<Runtime, Dispatch, Extrinsic>(
mut config: Configuration,
)
-> Result<impl AbstractService<
Block = Block,
RuntimeApi = Runtime,
Backend = TLightBackend<Block>,
SelectChain = LongestChain<TLightBackend<Block>, Block>,
CallExecutor = TLightCallExecutor<Block, Dispatch>,
>, ServiceError>
where
Runtime: Send + Sync + 'static,
Runtime::RuntimeApi: RuntimeApiCollection<
Extrinsic,
StateBackend = sc_client_api::StateBackendFor<TLightBackend<Block>, Block>
>,
Dispatch: NativeExecutionDispatch + 'static,
Extrinsic: RuntimeExtrinsic,
Runtime: sp_api::ConstructRuntimeApi<
Block,
TLocalLightClient<Runtime, Dispatch>,
>,
{
set_prometheus_registry(&mut config)?;
let inherent_data_providers = InherentDataProviders::new();
ServiceBuilder::new_light::<Block, Runtime, Dispatch>(config)?
.with_select_chain(|_, backend| {
Ok(LongestChain::new(backend.clone()))
})?
.with_transaction_pool(|config, client, fetcher, prometheus_registry| {
let fetcher = fetcher
.ok_or_else(|| "Trying to start light transaction pool without active fetcher")?;
let pool_api = sc_transaction_pool::LightChainApi::new(client.clone(), fetcher.clone());
let pool = sc_transaction_pool::BasicPool::with_revalidation_type(
config, Arc::new(pool_api), prometheus_registry, sc_transaction_pool::RevalidationType::Light,
);
Ok(pool)
})?
.with_import_queue_and_fprb(|_config, client, backend, fetcher, _select_chain, _| {
let fetch_checker = fetcher
.map(|fetcher| fetcher.checker().clone())
.ok_or_else(|| "Trying to start light import queue without active fetch checker")?;
let grandpa_block_import = grandpa::light_block_import(
client.clone(), backend, &(client.clone() as Arc<_>), Arc::new(fetch_checker)
)?;
let finality_proof_import = grandpa_block_import.clone();
let finality_proof_request_builder =
finality_proof_import.create_finality_proof_request_builder();
let (babe_block_import, babe_link) = babe::block_import(
babe::Config::get_or_compute(&*client)?,
grandpa_block_import,
client.clone(),
)?;
// FIXME: pruning task isn't started since light client doesn't do `AuthoritySetup`.
let import_queue = babe::import_queue(
babe_link,
babe_block_import,
None,
Some(Box::new(finality_proof_import)),
client,
inherent_data_providers.clone(),
)?;
Ok((import_queue, finality_proof_request_builder))
})?
.with_finality_proof_provider(|client, backend| {
let provider = client as Arc<dyn grandpa::StorageAndProofProvider<_, _>>;
Ok(Arc::new(GrandpaFinalityProofProvider::new(backend, provider)) as _)
})?
.with_rpc_extensions(|builder|
-> Result<polkadot_rpc::RpcExtension, _> {
let fetcher = builder.fetcher()
.ok_or_else(|| "Trying to start node RPC without active fetcher")?;
let remote_blockchain = builder.remote_backend()
.ok_or_else(|| "Trying to start node RPC without active remote blockchain")?;
Ok(polkadot_rpc::create_light(builder.client().clone(), remote_blockchain, fetcher, builder.pool()))
})?
.build()
new_light!(config, westend_runtime::RuntimeApi, KusamaExecutor)
}