mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 12:51:02 +00:00
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:
@@ -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" }
|
||||
|
||||
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user