mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-26 15:47:58 +00:00
5b8ebf7baf
* Move Service::new to a macro * Move function calls to macros * Extract offchain_workers and start_rpc in separate function In follow-up commits, we want to be able to directly call maintain_transaction_pool, offchain_workers, and start_rpc, without having to implement the Components trait. This commit is a preliminary step: we extract the code to freestanding functions. * Introduce an AbstractService trait * Introduce NewService as an implementation detail of Service * Implement traits on NewService instead Instead of implementing AbstractService, Future, and Executor on Service, we implement them on NewService instead. The implementations of AbstractService, Future, and Executor on Service still exist, but they just wrap to the respective implementations for NewService. * Move components creation back to macro invocation Instead of having multiple $build_ parameters passed to the macro, let's group them all into one. This change is necessary for the follow-up commits, because we are going to call new_impl! only after all the components have already been built. * Add a $block parameter to new_impl This makes it possible to be explicit as what the generic parameter of the NewServiceis, without relying on type inference. * Introduce the ServiceBuilder struct Introduces a new builder-like ServiceBuilder struct that creates a NewService. * Macro-ify import_blocks, export_blocks and revert_chain Similar to the introduction of new_impl!, we extract the actual code into a macro, letting us get rid of the Components and Factory traits * Add export_blocks, import_blocks and revert_chain methods on ServiceBuilder Can be used as a replacement for the chain_ops::* methods * Add run_with_builder Instead of just run, adds run_with_builder to ParseAndPrepareExport/Import/Revert. This lets you run these operations with a ServiceBuilder instead of a ServiceFactory. * Transition node and node-template to ServiceBuilder * Transition transaction-factory to the new service factory This is technically a breaking change, but the transaction-factory crate is only ever used from within substrate-node, which this commit updates as well. * Remove old service factory * Adjust the AbstractService trait to be more usable We slightly change the trait bounds in order to make all the methods usable. * Make substrate-service-test compile * Fix the node-cli tests * Remove the old API * Remove the components module * Fix indentation on chain_ops * Line widths * Fix bad line widths commit * Line widths again 🤦 * Fix the sync test * Apply suggestions from code review Co-Authored-By: Gavin Wood <i@gavwood.com> * Address some concerns * Remove TelemetryOnConnect * Remove informant::start * Update jsonrpc * Rename factory to builder * Line widths 😩
232 lines
7.6 KiB
Rust
232 lines
7.6 KiB
Rust
//! Service and ServiceFactory implementation. Specialized wrapper over substrate service.
|
|
|
|
use std::sync::Arc;
|
|
use std::time::Duration;
|
|
use substrate_client::LongestChain;
|
|
use babe::{import_queue, start_babe, Config};
|
|
use grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider};
|
|
use futures::prelude::*;
|
|
use node_template_runtime::{self, GenesisConfig, opaque::Block, RuntimeApi, WASM_BINARY};
|
|
use substrate_service::{error::{Error as ServiceError}, AbstractService, Configuration, ServiceBuilder};
|
|
use transaction_pool::{self, txpool::{Pool as TransactionPool}};
|
|
use inherents::InherentDataProviders;
|
|
use network::construct_simple_protocol;
|
|
use substrate_executor::native_executor_instance;
|
|
pub use substrate_executor::NativeExecutor;
|
|
|
|
// Our native executor instance.
|
|
native_executor_instance!(
|
|
pub Executor,
|
|
node_template_runtime::api::dispatch,
|
|
node_template_runtime::native_version,
|
|
WASM_BINARY
|
|
);
|
|
|
|
construct_simple_protocol! {
|
|
/// Demo protocol attachment for substrate.
|
|
pub struct NodeProtocol where Block = Block { }
|
|
}
|
|
|
|
/// Starts a `ServiceBuilder` for a full service.
|
|
///
|
|
/// Use this macro if you don't actually need the full service, but just the builder in order to
|
|
/// be able to perform chain operations.
|
|
macro_rules! new_full_start {
|
|
($config:expr) => {{
|
|
let mut import_setup = None;
|
|
let inherent_data_providers = inherents::InherentDataProviders::new();
|
|
let mut tasks_to_spawn = None;
|
|
|
|
let builder = substrate_service::ServiceBuilder::new_full::<
|
|
node_template_runtime::opaque::Block, node_template_runtime::RuntimeApi, crate::service::Executor
|
|
>($config)?
|
|
.with_select_chain(|_config, client| {
|
|
#[allow(deprecated)]
|
|
Ok(substrate_client::LongestChain::new(client.backend().clone()))
|
|
})?
|
|
.with_transaction_pool(|config, client|
|
|
Ok(transaction_pool::txpool::Pool::new(config, transaction_pool::ChainApi::new(client)))
|
|
)?
|
|
.with_import_queue(|_config, client, mut select_chain, transaction_pool| {
|
|
let select_chain = select_chain.take()
|
|
.ok_or_else(|| substrate_service::Error::SelectChainRequired)?;
|
|
let (block_import, link_half) =
|
|
grandpa::block_import::<_, _, _, node_template_runtime::RuntimeApi, _, _>(
|
|
client.clone(), client.clone(), select_chain
|
|
)?;
|
|
let justification_import = block_import.clone();
|
|
|
|
let (import_queue, babe_link, babe_block_import, pruning_task) = babe::import_queue(
|
|
babe::Config::get_or_compute(&*client)?,
|
|
block_import,
|
|
Some(Box::new(justification_import)),
|
|
None,
|
|
client.clone(),
|
|
client,
|
|
inherent_data_providers.clone(),
|
|
Some(transaction_pool)
|
|
)?;
|
|
|
|
import_setup = Some((babe_block_import.clone(), link_half, babe_link));
|
|
tasks_to_spawn = Some(vec![Box::new(pruning_task)]);
|
|
|
|
Ok(import_queue)
|
|
})?;
|
|
|
|
(builder, import_setup, inherent_data_providers, tasks_to_spawn)
|
|
}}
|
|
}
|
|
|
|
/// Builds a new service for a full client.
|
|
pub fn new_full<C: Send + Default + 'static>(config: Configuration<C, GenesisConfig>)
|
|
-> Result<impl AbstractService, ServiceError>
|
|
{
|
|
|
|
let (builder, mut import_setup, inherent_data_providers, mut tasks_to_spawn) = new_full_start!(config);
|
|
|
|
let service = builder.with_network_protocol(|_| Ok(NodeProtocol::new()))?
|
|
.with_finality_proof_provider(|client|
|
|
Ok(Arc::new(GrandpaFinalityProofProvider::new(client.clone(), client)) 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");
|
|
|
|
// spawn any futures that were created in the previous setup steps
|
|
if let Some(tasks) = tasks_to_spawn.take() {
|
|
for task in tasks {
|
|
service.spawn_task(
|
|
task.select(service.on_exit())
|
|
.map(|_| ())
|
|
.map_err(|_| ())
|
|
);
|
|
}
|
|
}
|
|
|
|
if service.config().roles.is_authority() {
|
|
let proposer = basic_authorship::ProposerFactory {
|
|
client: service.client(),
|
|
transaction_pool: service.transaction_pool(),
|
|
};
|
|
|
|
let client = service.client();
|
|
let select_chain = service.select_chain()
|
|
.ok_or(ServiceError::SelectChainRequired)?;
|
|
|
|
let babe_config = babe::BabeParams {
|
|
config: Config::get_or_compute(&*client)?,
|
|
keystore: service.keystore(),
|
|
client,
|
|
select_chain,
|
|
block_import,
|
|
env: proposer,
|
|
sync_oracle: service.network(),
|
|
inherent_data_providers: inherent_data_providers.clone(),
|
|
force_authoring: service.config().force_authoring,
|
|
time_source: babe_link,
|
|
};
|
|
|
|
let babe = start_babe(babe_config)?;
|
|
let select = babe.select(service.on_exit()).then(|_| Ok(()));
|
|
|
|
// the BABE authoring task is considered infallible, i.e. if it
|
|
// fails we take down the service with it.
|
|
service.spawn_essential_task(select);
|
|
}
|
|
|
|
let config = grandpa::Config {
|
|
// FIXME #1578 make this available through chainspec
|
|
gossip_duration: Duration::from_millis(333),
|
|
justification_period: 4096,
|
|
name: Some(service.config().name.clone()),
|
|
keystore: Some(service.keystore()),
|
|
};
|
|
|
|
match (service.config().roles.is_authority(), service.config().disable_grandpa) {
|
|
(false, false) => {
|
|
// start the lightweight GRANDPA observer
|
|
service.spawn_task(Box::new(grandpa::run_grandpa_observer(
|
|
config,
|
|
link_half,
|
|
service.network(),
|
|
service.on_exit(),
|
|
)?));
|
|
},
|
|
(true, false) => {
|
|
// start the full GRANDPA voter
|
|
let grandpa_config = grandpa::GrandpaParams {
|
|
config: config,
|
|
link: link_half,
|
|
network: service.network(),
|
|
inherent_data_providers: inherent_data_providers.clone(),
|
|
on_exit: service.on_exit(),
|
|
telemetry_on_connect: Some(service.telemetry_on_connect_stream()),
|
|
};
|
|
|
|
// the GRANDPA voter task is considered infallible, i.e.
|
|
// if it fails we take down the service with it.
|
|
service.spawn_essential_task(grandpa::run_grandpa_voter(grandpa_config)?);
|
|
},
|
|
(_, true) => {
|
|
grandpa::setup_disabled_grandpa(
|
|
service.client(),
|
|
&inherent_data_providers,
|
|
service.network(),
|
|
)?;
|
|
},
|
|
}
|
|
|
|
Ok(service)
|
|
}
|
|
|
|
/// Builds a new service for a light client.
|
|
pub fn new_light<C: Send + Default + 'static>(config: Configuration<C, GenesisConfig>)
|
|
-> Result<impl AbstractService, ServiceError>
|
|
{
|
|
let inherent_data_providers = InherentDataProviders::new();
|
|
|
|
ServiceBuilder::new_light::<Block, RuntimeApi, Executor>(config)?
|
|
.with_select_chain(|_config, client| {
|
|
#[allow(deprecated)]
|
|
Ok(LongestChain::new(client.backend().clone()))
|
|
})?
|
|
.with_transaction_pool(|config, client|
|
|
Ok(TransactionPool::new(config, transaction_pool::ChainApi::new(client)))
|
|
)?
|
|
.with_import_queue_and_fprb(|_config, client, _select_chain, transaction_pool| {
|
|
#[allow(deprecated)]
|
|
let fetch_checker = client.backend().blockchain().fetcher()
|
|
.upgrade()
|
|
.map(|fetcher| fetcher.checker().clone())
|
|
.ok_or_else(|| "Trying to start light import queue without active fetch checker")?;
|
|
let block_import = grandpa::light_block_import::<_, _, _, RuntimeApi, _>(
|
|
client.clone(), Arc::new(fetch_checker), client.clone()
|
|
)?;
|
|
|
|
let finality_proof_import = block_import.clone();
|
|
let finality_proof_request_builder =
|
|
finality_proof_import.create_finality_proof_request_builder();
|
|
|
|
// FIXME: pruning task isn't started since light client doesn't do `AuthoritySetup`.
|
|
let (import_queue, ..) = import_queue(
|
|
Config::get_or_compute(&*client)?,
|
|
block_import,
|
|
None,
|
|
Some(Box::new(finality_proof_import)),
|
|
client.clone(),
|
|
client,
|
|
inherent_data_providers.clone(),
|
|
Some(transaction_pool)
|
|
)?;
|
|
|
|
Ok((import_queue, finality_proof_request_builder))
|
|
})?
|
|
.with_network_protocol(|_| Ok(NodeProtocol::new()))?
|
|
.with_finality_proof_provider(|client|
|
|
Ok(Arc::new(GrandpaFinalityProofProvider::new(client.clone(), client)) as _)
|
|
)?
|
|
.build()
|
|
}
|