,
+ /// Transaction pool instance.
+ pub pool: Arc,
+ /// Remote access to the blockchain (async).
+ pub remote_blockchain: Arc>,
+ /// Fetcher instance.
+ pub fetcher: Arc,
+}
+
+/// Extra dependencies for BABE.
+pub struct BabeDeps {
+ /// BABE protocol config.
+ pub babe_config: Config,
+ /// BABE pending epoch changes.
+ pub shared_epoch_changes: SharedEpochChanges,
+ /// The keystore that manages the keys of the node.
+ pub keystore: KeyStorePtr,
+}
+
+/// Extra dependencies for GRANDPA
+pub struct GrandpaDeps {
+ /// Voting round info.
+ pub shared_voter_state: SharedVoterState,
+ /// Authority set info.
+ pub shared_authority_set: SharedAuthoritySet,
+}
+
+/// Full client dependencies.
+pub struct FullDeps {
+ /// The client instance to use.
+ pub client: Arc,
+ /// Transaction pool instance.
+ pub pool: Arc,
+ /// The SelectChain Strategy
+ pub select_chain: SC,
+ /// Whether to deny unsafe calls
+ pub deny_unsafe: DenyUnsafe,
+ /// BABE specific dependencies.
+ pub babe: BabeDeps,
+ /// GRANDPA specific dependencies.
+ pub grandpa: GrandpaDeps,
+}
+
+/// Instantiate all Full RPC extensions.
+pub fn create_full(deps: FullDeps) -> jsonrpc_core::IoHandler
+where
+ C: ProvideRuntimeApi,
+ C: HeaderBackend + HeaderMetadata + 'static,
+ C: Send + Sync + 'static,
+ C::Api: substrate_frame_rpc_system::AccountNonceApi,
+ C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<
+ Block,
+ Balance,
+ UncheckedExtrinsic,
+ >,
+ C::Api: BabeApi,
+ C::Api: BlockBuilder,
+ P: TransactionPool + 'static,
+ M: jsonrpc_core::Metadata + Default,
+ SC: SelectChain + 'static,
+{
+ use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi};
+ use substrate_frame_rpc_system::{FullSystem, SystemApi};
+
+ let mut io = jsonrpc_core::IoHandler::default();
+ let FullDeps {
+ client,
+ pool,
+ select_chain,
+ deny_unsafe,
+ babe,
+ grandpa,
+ } = deps;
+ let BabeDeps {
+ keystore,
+ babe_config,
+ shared_epoch_changes,
+ } = babe;
+ let GrandpaDeps {
+ shared_voter_state,
+ shared_authority_set,
+ } = grandpa;
+
+ io.extend_with(SystemApi::to_delegate(FullSystem::new(
+ client.clone(),
+ pool,
+ deny_unsafe,
+ )));
+ // Making synchronous calls in light client freezes the browser currently,
+ // more context: https://github.com/paritytech/substrate/pull/3480
+ // These RPCs should use an asynchronous caller instead.
+ io.extend_with(TransactionPaymentApi::to_delegate(TransactionPayment::new(
+ client.clone(),
+ )));
+ io.extend_with(sc_consensus_babe_rpc::BabeApi::to_delegate(
+ BabeRpcHandler::new(
+ client,
+ shared_epoch_changes,
+ keystore,
+ babe_config,
+ select_chain,
+ deny_unsafe,
+ ),
+ ));
+ io.extend_with(sc_finality_grandpa_rpc::GrandpaApi::to_delegate(
+ GrandpaRpcHandler::new(shared_authority_set, shared_voter_state),
+ ));
+
+ io
+}
+
+/// Instantiate all Light RPC extensions.
+pub fn create_light(deps: LightDeps) -> jsonrpc_core::IoHandler
+where
+ C: sp_blockchain::HeaderBackend,
+ C: Send + Sync + 'static,
+ F: sc_client_api::light::Fetcher + 'static,
+ P: TransactionPool + 'static,
+ M: jsonrpc_core::Metadata + Default,
+{
+ use substrate_frame_rpc_system::{LightSystem, SystemApi};
+
+ let LightDeps {
+ client,
+ pool,
+ remote_blockchain,
+ fetcher,
+ } = deps;
+ let mut io = jsonrpc_core::IoHandler::default();
+ io.extend_with(SystemApi::::to_delegate(
+ LightSystem::new(client, remote_blockchain, fetcher, pool),
+ ));
+
+ io
+}
diff --git a/node/src/proposals_config.rs b/node/src/proposals_config.rs
new file mode 100644
index 0000000000..aa394123ba
--- /dev/null
+++ b/node/src/proposals_config.rs
@@ -0,0 +1,17 @@
+use node_runtime::ProposalsConfigParameters;
+
+/// Development chain config. 0 grace period for all proposals, ie.
+/// proposals executed immediatly. Short voting period.
+pub fn development() -> ProposalsConfigParameters {
+ ProposalsConfigParameters::with_grace_and_voting_periods(0, 200)
+}
+
+/// Staging chain config. Shorter grace periods and voting periods than default.
+pub fn staging() -> ProposalsConfigParameters {
+ ProposalsConfigParameters::with_grace_and_voting_periods(200, 600)
+}
+
+/// The default configuration as defined in the runtime module
+pub fn default() -> ProposalsConfigParameters {
+ ProposalsConfigParameters::default()
+}
diff --git a/node/src/service.rs b/node/src/service.rs
index 703bb6f5f2..e9343e1ade 100644
--- a/node/src/service.rs
+++ b/node/src/service.rs
@@ -16,107 +16,141 @@
#![warn(unused_extern_crates)]
-// Clippy linter warning.
-#![allow(clippy::type_complexity)] // disable it because this is foreign code and can be changed any time
-
-// Clippy linter warning.
-#![allow(clippy::redundant_closure_call)] // disable it because of the substrate lib design
-
-//! Service and ServiceFactory implementation. Specialized wrapper over substrate service.
-
-use client_db::Backend;
-use grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider};
-use inherents::InherentDataProviders;
-use network::{construct_simple_protocol, NetworkService};
-use node_runtime::{self, opaque::Block, GenesisConfig, RuntimeApi};
-use offchain::OffchainWorkers;
-use primitives::Blake2Hasher;
-use runtime_primitives::traits::Block as BlockT;
-use std::sync::Arc;
-use substrate_client::{Client, LocalCallExecutor, LongestChain};
-pub use substrate_executor::{native_executor_instance, NativeExecutor};
-use substrate_service::{
- error::Error as ServiceError, AbstractService, Configuration, NetworkStatus, Service,
- ServiceBuilder,
-};
-use transaction_pool::{self, txpool::Pool as TransactionPool};
+// Substrate implementation issue.
+#![allow(clippy::redundant_closure_call)]
-construct_simple_protocol! {
- /// Demo protocol attachment for substrate.
- pub struct NodeProtocol where Block = Block { }
-}
+//! Service implementation. Specialized wrapper over substrate service.
-// Declare an instance of the native executor named `Executor`. Include the wasm binary as the
-// equivalent wasm code.
-native_executor_instance!(
- pub Executor,
- node_runtime::api::dispatch,
- node_runtime::native_version
-);
+use node_runtime::opaque::Block;
+use node_runtime::RuntimeApi;
+use sc_consensus::LongestChain;
+use sc_finality_grandpa::{
+ self as grandpa, FinalityProofProvider as GrandpaFinalityProofProvider, StorageAndProofProvider,
+};
+use sc_service::{
+ config::Configuration, error::Error as ServiceError, AbstractService, ServiceBuilder,
+};
+use sp_inherents::InherentDataProviders;
+use std::sync::Arc;
+
+use crate::node_executor;
+use crate::node_rpc;
/// 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_export]
macro_rules! new_full_start {
($config:expr) => {{
- // type RpcExtension = jsonrpc_core::IoHandler;
+ use std::sync::Arc;
+
let mut import_setup = None;
- let inherent_data_providers = inherents::InherentDataProviders::new();
+ let mut rpc_setup = None;
+ let inherent_data_providers = sp_inherents::InherentDataProviders::new();
- let builder = substrate_service::ServiceBuilder::new_full::<
- node_runtime::opaque::Block,
- node_runtime::RuntimeApi,
- crate::service::Executor,
+ let builder = sc_service::ServiceBuilder::new_full::<
+ Block,
+ RuntimeApi,
+ node_executor::Executor,
>($config)?
- .with_select_chain(|_config, backend| {
- Ok(substrate_client::LongestChain::new(backend.clone()))
- })?
- .with_transaction_pool(|config, client| {
- Ok(transaction_pool::txpool::Pool::new(
- config,
- transaction_pool::FullChainApi::new(client),
+ .with_select_chain(|_config, backend| Ok(sc_consensus::LongestChain::new(backend.clone())))?
+ .with_transaction_pool(|builder| {
+ let pool_api = sc_transaction_pool::FullChainApi::new(builder.client().clone());
+ let config = builder.config();
+
+ Ok(sc_transaction_pool::BasicPool::new(
+ config.transaction_pool.clone(),
+ std::sync::Arc::new(pool_api),
+ builder.prometheus_registry(),
))
})?
- .with_import_queue(|_config, client, mut select_chain, _transaction_pool| {
- let select_chain = select_chain
- .take()
- .ok_or_else(|| substrate_service::Error::SelectChainRequired)?;
- let (grandpa_block_import, grandpa_link) =
- grandpa::block_import::<_, _, _, node_runtime::RuntimeApi, _>(
+ .with_import_queue(
+ |_config,
+ client,
+ mut select_chain,
+ _transaction_pool,
+ spawn_task_handle,
+ prometheus_registry| {
+ let select_chain = select_chain
+ .take()
+ .ok_or_else(|| sc_service::Error::SelectChainRequired)?;
+ let (grandpa_block_import, grandpa_link) = grandpa::block_import(
client.clone(),
- &*client,
+ &(client.clone() as Arc<_>),
select_chain,
)?;
- let justification_import = grandpa_block_import.clone();
-
- let (block_import, babe_link) = babe::block_import(
- babe::Config::get_or_compute(&*client)?,
- grandpa_block_import,
- client.clone(),
- client.clone(),
- )?;
-
- let import_queue = babe::import_queue(
- babe_link.clone(),
- block_import.clone(),
- Some(Box::new(justification_import)),
- None,
- client.clone(),
- client,
- inherent_data_providers.clone(),
- )?;
-
- import_setup = Some((block_import, grandpa_link, babe_link));
- Ok(import_queue)
+ let justification_import = grandpa_block_import.clone();
+
+ let (block_import, babe_link) = sc_consensus_babe::block_import(
+ sc_consensus_babe::Config::get_or_compute(&*client)?,
+ grandpa_block_import,
+ client.clone(),
+ )?;
+
+ let import_queue = sc_consensus_babe::import_queue(
+ babe_link.clone(),
+ block_import.clone(),
+ Some(Box::new(justification_import)),
+ None,
+ client,
+ inherent_data_providers.clone(),
+ spawn_task_handle,
+ prometheus_registry,
+ )?;
+
+ import_setup = Some((block_import, grandpa_link, babe_link));
+ Ok(import_queue)
+ },
+ )?
+ .with_rpc_extensions_builder(|builder| {
+ let grandpa_link = import_setup
+ .as_ref()
+ .map(|s| &s.1)
+ .expect("GRANDPA LinkHalf is present for full services or set up failed; qed.");
+
+ let shared_authority_set = grandpa_link.shared_authority_set().clone();
+ let shared_voter_state = grandpa::SharedVoterState::empty();
+
+ rpc_setup = Some((shared_voter_state.clone()));
+
+ let babe_link = import_setup
+ .as_ref()
+ .map(|s| &s.2)
+ .expect("BabeLink is present for full services or set up failed; qed.");
+
+ let babe_config = babe_link.config().clone();
+ let shared_epoch_changes = babe_link.epoch_changes().clone();
+
+ let client = builder.client().clone();
+ let pool = builder.pool().clone();
+ let select_chain = builder
+ .select_chain()
+ .cloned()
+ .expect("SelectChain is present for full services or set up failed; qed.");
+ let keystore = builder.keystore().clone();
+
+ Ok(move |deny_unsafe| {
+ let deps = node_rpc::FullDeps {
+ client: client.clone(),
+ pool: pool.clone(),
+ select_chain: select_chain.clone(),
+ deny_unsafe,
+ babe: node_rpc::BabeDeps {
+ babe_config: babe_config.clone(),
+ shared_epoch_changes: shared_epoch_changes.clone(),
+ keystore: keystore.clone(),
+ },
+ grandpa: node_rpc::GrandpaDeps {
+ shared_voter_state: shared_voter_state.clone(),
+ shared_authority_set: shared_authority_set.clone(),
+ },
+ };
+
+ node_rpc::create_full(deps)
+ })
})?;
- // We don't have any custom rpc commands...
- // .with_rpc_extensions(|client, pool| -> RpcExtension {
- // node_rpc::create(client, pool)
- // })?;
- (builder, import_setup, inherent_data_providers)
+ (builder, import_setup, inherent_data_providers, rpc_setup)
}};
}
@@ -126,58 +160,57 @@ macro_rules! new_full_start {
/// concrete types instead.
macro_rules! new_full {
($config:expr, $with_startup_data: expr) => {{
- use futures::sync::mpsc;
- use network::DhtEvent;
+ use futures::prelude::*;
+ use sc_network::Event;
+ use sc_client_api::ExecutorProvider;
+ use sp_core::traits::BareCryptoStorePtr;
let (
- is_authority,
+ role,
force_authoring,
name,
- disable_grandpa
+ disable_grandpa,
) = (
- $config.roles.is_authority(),
+ $config.role.clone(),
$config.force_authoring,
- $config.name.clone(),
- $config.disable_grandpa
+ $config.network.node_name.clone(),
+ $config.disable_grandpa,
);
- // sentry nodes announce themselves as authorities to the network
- // and should run the same protocols authorities do, but it should
- // never actively participate in any consensus process.
- let participates_in_consensus = is_authority && !$config.sentry_mode;
-
- let (builder, mut import_setup, inherent_data_providers) = new_full_start!($config);
-
- // Dht event channel from the network to the authority discovery module. Use bounded channel to ensure
- // back-pressure. Authority discovery is triggering one event per authority within the current authority set.
- // This estimates the authority set size to be somewhere below 10 000 thereby setting the channel buffer size to
- // 10 000.
- let (dht_event_tx, _dht_event_rx) =
- mpsc::channel::(10_000);
+ let (builder, mut import_setup, inherent_data_providers, mut rpc_setup) =
+ new_full_start!($config);
- let service = builder.with_network_protocol(|_| Ok(crate::service::NodeProtocol::new()))?
- .with_finality_proof_provider(|client, backend|
- Ok(Arc::new(grandpa::FinalityProofProvider::new(backend, client)) as _)
- )?
- .with_dht_event_tx(dht_event_tx)?
- .build()?;
+ let service = builder
+ .with_finality_proof_provider(|client, backend| {
+ // GenesisAuthoritySetProvider is implemented for StorageAndProofProvider
+ let provider = client as Arc>;
+ Ok(Arc::new(grandpa::FinalityProofProvider::new(backend, provider)) as _)
+ })?
+ .build_full()?;
let (block_import, grandpa_link, babe_link) = import_setup.take()
- .expect("Link Half and Block Import are present for Full Services or setup failed before. qed");
+ .expect("Link Half and Block Import are present for Full Services or setup failed before. qed");
+
+ let shared_voter_state = rpc_setup.take()
+ .expect("The SharedVoterState is present for Full Services or setup failed before. qed");
($with_startup_data)(&block_import, &babe_link);
- if participates_in_consensus {
- let proposer = substrate_basic_authorship::ProposerFactory {
- client: service.client(),
- transaction_pool: service.transaction_pool(),
- };
+ if let sc_service::config::Role::Authority { .. } = &role {
+ let proposer = sc_basic_authorship::ProposerFactory::new(
+ service.client(),
+ service.transaction_pool(),
+ service.prometheus_registry().as_ref(),
+ );
let client = service.client();
let select_chain = service.select_chain()
- .ok_or(substrate_service::Error::SelectChainRequired)?;
+ .ok_or(sc_service::Error::SelectChainRequired)?;
+
+ let can_author_with =
+ sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone());
- let babe_config = babe::BabeParams {
+ let babe_config = sc_consensus_babe::BabeParams {
keystore: service.keystore(),
client,
select_chain,
@@ -187,62 +220,95 @@ macro_rules! new_full {
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);
- }
+ let babe = sc_consensus_babe::start_babe(babe_config)?;
+ service.spawn_essential_task_handle().spawn_blocking("babe-proposer", babe);
+ }
+
+ // Spawn authority discovery module.
+ if matches!(role, sc_service::config::Role::Authority{..} | sc_service::config::Role::Sentry {..}) {
+ let (sentries, authority_discovery_role) = match role {
+ sc_service::config::Role::Authority { ref sentry_nodes } => (
+ sentry_nodes.clone(),
+ sc_authority_discovery::Role::Authority (
+ service.keystore(),
+ ),
+ ),
+ sc_service::config::Role::Sentry {..} => (
+ vec![],
+ sc_authority_discovery::Role::Sentry,
+ ),
+ _ => unreachable!("Due to outer matches! constraint; qed.")
+ };
+
+ let network = service.network();
+ let dht_event_stream = network.event_stream("authority-discovery").filter_map(|e| async move { match e {
+ Event::Dht(e) => Some(e),
+ _ => None,
+ }}).boxed();
+ let authority_discovery = sc_authority_discovery::AuthorityDiscovery::new(
+ service.client(),
+ network,
+ sentries,
+ dht_event_stream,
+ authority_discovery_role,
+ service.prometheus_registry(),
+ );
+
+ service.spawn_task_handle().spawn("authority-discovery", authority_discovery);
+ }
- // if the node isn't actively participating in consensus then it doesn't
+ // 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 participates_in_consensus {
- Some(service.keystore())
+ let keystore = if role.is_authority() {
+ Some(service.keystore() as BareCryptoStorePtr)
} else {
None
- };
-
- let config = grandpa::Config {
- // FIXME #1578 make this available through chainspec
- gossip_duration: std::time::Duration::from_millis(333),
- justification_period: 512,
- name: Some(name),
- observer_enabled: true,
- keystore,
- is_authority,
- };
-
- match (is_authority, disable_grandpa) {
- (false, false) => {
- // start the lightweight GRANDPA observer
- service.spawn_task(Box::new(grandpa::run_grandpa_observer(
- config,
- grandpa_link,
- service.network(),
- service.on_exit(),
- )?));
- },
- (true, false) => {
- // start the full GRANDPA voter
- let grandpa_config = grandpa::GrandpaParams {
- config: config,
- link: grandpa_link,
- network: service.network(),
- inherent_data_providers: inherent_data_providers.clone(),
- on_exit: service.on_exit(),
- telemetry_on_connect: Some(service.telemetry_on_connect_stream()),
- voting_rule: grandpa::VotingRulesBuilder::default().build(),
- };
- // 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(),
- )?;
- },
+ };
+
+ let config = grandpa::Config {
+ // FIXME #1578 make this available through chainspec
+ gossip_duration: std::time::Duration::from_millis(333),
+ 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: non-authorities could run the GRANDPA observer protocol, but at
+ // this point the full voter should provide better guarantees of block
+ // and vote data availability than the observer. The observer has not
+ // been tested extensively yet and having most nodes in a network run it
+ // could lead to finality stalls.
+ let grandpa_config = grandpa::GrandpaParams {
+ config,
+ link: grandpa_link,
+ network: service.network(),
+ inherent_data_providers: inherent_data_providers.clone(),
+ telemetry_on_connect: Some(service.telemetry_on_connect_stream()),
+ voting_rule: grandpa::VotingRulesBuilder::default().build(),
+ prometheus_registry: service.prometheus_registry(),
+ shared_voter_state,
+ };
+
+ // the GRANDPA voter task is considered infallible, i.e.
+ // if it fails we take down the service with it.
+ service.spawn_essential_task_handle().spawn_blocking(
+ "grandpa-voter",
+ grandpa::run_grandpa_voter(grandpa_config)?
+ );
+ } else {
+ grandpa::setup_disabled_grandpa(
+ service.client(),
+ &inherent_data_providers,
+ service.network(),
+ )?;
}
Ok((service, inherent_data_providers))
@@ -252,70 +318,49 @@ macro_rules! new_full {
}}
}
-#[allow(dead_code)]
-type ConcreteBlock = node_runtime::opaque::Block;
-#[allow(dead_code)]
-type ConcreteClient = Client<
- Backend,
- LocalCallExecutor, NativeExecutor>,
- ConcreteBlock,
- node_runtime::RuntimeApi,
->;
-#[allow(dead_code)]
-type ConcreteBackend = Backend;
-
-/// A specialized configuration object for setting up the node..
-pub type NodeConfiguration =
- Configuration;
-
/// Builds a new service for a full client.
-pub fn new_full(config: NodeConfiguration)
--> Result<
- Service<
- ConcreteBlock,
- ConcreteClient,
- LongestChain,
- NetworkStatus,
- NetworkService::Hash>,
- TransactionPool>,
- OffchainWorkers<
- ConcreteClient,
- >::OffchainStorage,
- ConcreteBlock,
- >
- >,
- ServiceError,
->
-{
+pub fn new_full(config: Configuration) -> Result {
new_full!(config).map(|(service, _)| service)
}
/// Builds a new service for a light client.
-pub fn new_light(
- config: NodeConfiguration,
-) -> Result {
- // type RpcExtension = jsonrpc_core::IoHandler;
+pub fn new_light(config: Configuration) -> Result {
let inherent_data_providers = InherentDataProviders::new();
- let service = ServiceBuilder::new_light::(config)?
+ let service = ServiceBuilder::new_light::(config)?
.with_select_chain(|_config, backend| Ok(LongestChain::new(backend.clone())))?
- .with_transaction_pool(|config, client| {
- Ok(TransactionPool::new(
- config,
- transaction_pool::FullChainApi::new(client),
- ))
+ .with_transaction_pool(|builder| {
+ let fetcher = builder
+ .fetcher()
+ .ok_or_else(|| "Trying to start light transaction pool without active fetcher")?;
+ let pool_api =
+ sc_transaction_pool::LightChainApi::new(builder.client().clone(), fetcher);
+ let pool = sc_transaction_pool::BasicPool::with_revalidation_type(
+ builder.config().transaction_pool.clone(),
+ Arc::new(pool_api),
+ builder.prometheus_registry(),
+ sc_transaction_pool::RevalidationType::Light,
+ );
+ Ok(pool)
})?
.with_import_queue_and_fprb(
- |_config, client, backend, fetcher, _select_chain, _tx_pool| {
+ |_config,
+ client,
+ backend,
+ fetcher,
+ _select_chain,
+ _tx_pool,
+ spawn_task_handle,
+ registry| {
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::<_, _, _, RuntimeApi>(
+ let grandpa_block_import = grandpa::light_block_import(
client.clone(),
backend,
- &*client,
+ &(client.clone() as Arc<_>),
Arc::new(fetch_checker),
)?;
@@ -323,35 +368,297 @@ pub fn new_light(
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)?,
+ let (babe_block_import, babe_link) = sc_consensus_babe::block_import(
+ sc_consensus_babe::Config::get_or_compute(&*client)?,
grandpa_block_import,
client.clone(),
- client.clone(),
)?;
- let import_queue = babe::import_queue(
+ let import_queue = sc_consensus_babe::import_queue(
babe_link,
babe_block_import,
None,
Some(Box::new(finality_proof_import)),
- client.clone(),
client,
inherent_data_providers.clone(),
+ spawn_task_handle,
+ registry,
)?;
Ok((import_queue, finality_proof_request_builder))
},
)?
- .with_network_protocol(|_| Ok(NodeProtocol::new()))?
.with_finality_proof_provider(|client, backend| {
- Ok(Arc::new(GrandpaFinalityProofProvider::new(backend, client)) as _)
+ // GenesisAuthoritySetProvider is implemented for StorageAndProofProvider
+ let provider = client as Arc>;
+ Ok(Arc::new(GrandpaFinalityProofProvider::new(backend, provider)) as _)
})?
- // We don't have any custom rpc extensions
- // .with_rpc_extensions(|client, pool| -> RpcExtension {
- // node_rpc::create(client, pool)
- // })?
- .build()?;
+ .with_rpc_extensions(|builder| {
+ 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")?;
+
+ let light_deps = node_rpc::LightDeps {
+ remote_blockchain,
+ fetcher,
+ client: builder.client().clone(),
+ pool: builder.pool(),
+ };
+
+ Ok(node_rpc::create_light(light_deps))
+ })?
+ .build_light()?;
Ok(service)
}
+
+// Tests are commented out until we find a solution to why
+// building dependencies for the tests are taking so long on Travis CI
+
+// #[cfg(test)]
+// mod tests {
+// use crate::node_executor;
+// use crate::node_rpc;
+// use crate::service::{new_full, new_light};
+// use codec::{Decode, Encode};
+// use node_runtime::RuntimeApi;
+// use node_runtime::{currency::CENTS, SLOT_DURATION};
+// use node_runtime::{opaque::Block, AccountId, DigestItem, Signature};
+// use node_runtime::{BalancesCall, Call, UncheckedExtrinsic};
+// use sc_consensus_babe::{BabeIntermediate, CompatibleDigestItem, INTERMEDIATE_KEY};
+// use sc_consensus_epochs::descendent_query;
+// use sc_finality_grandpa::{self as grandpa};
+// use sc_service::AbstractService;
+// use sp_consensus::{
+// BlockImport, BlockImportParams, BlockOrigin, Environment, ForkChoiceStrategy, Proposer,
+// RecordProof,
+// };
+// use sp_core::{crypto::Pair as CryptoPair, H256};
+// use sp_finality_tracker;
+// use sp_keyring::AccountKeyring;
+// use sp_runtime::traits::IdentifyAccount;
+// use sp_runtime::{
+// generic::{BlockId, Digest, Era, SignedPayload},
+// traits::Verify,
+// traits::{Block as BlockT, Header as HeaderT},
+// OpaqueExtrinsic,
+// };
+// use sp_timestamp;
+// use sp_transaction_pool::{ChainEvent, MaintainedTransactionPool};
+// use std::{any::Any, borrow::Cow, sync::Arc};
+
+// type AccountPublic = ::Signer;
+
+// // Long running test. Run it locally only after the node changes.
+// #[test]
+// // It is "ignored", but the node-cli ignored tests are running on the CI.
+// // This can be run locally with `cargo test --release -p node-cli test_sync -- --ignored`.
+// #[ignore]
+// fn test_sync() {
+// let keystore_path = tempfile::tempdir().expect("Creates keystore path");
+// let keystore =
+// sc_keystore::Store::open(keystore_path.path(), None).expect("Creates keystore");
+// let alice = keystore
+// .write()
+// .insert_ephemeral_from_seed::("//Alice")
+// .expect("Creates authority pair");
+
+// let chain_spec = crate::chain_spec::tests::integration_test_config_with_single_authority();
+
+// // For the block factory
+// let mut slot_num = 1u64;
+
+// // For the extrinsics factory
+// let bob = Arc::new(AccountKeyring::Bob.pair());
+// let charlie = Arc::new(AccountKeyring::Charlie.pair());
+// let mut index = 0;
+
+// sc_service_test::sync(
+// chain_spec,
+// |config| {
+// let mut setup_handles = None;
+// new_full!(
+// config,
+// |block_import: &sc_consensus_babe::BabeBlockImport,
+// babe_link: &sc_consensus_babe::BabeLink| {
+// setup_handles = Some((block_import.clone(), babe_link.clone()));
+// }
+// )
+// .map(move |(node, x)| (node, (x, setup_handles.unwrap())))
+// },
+// |config| new_light(config),
+// |service, &mut (ref inherent_data_providers, (ref mut block_import, ref babe_link))| {
+// let mut inherent_data = inherent_data_providers
+// .create_inherent_data()
+// .expect("Creates inherent data.");
+// inherent_data.replace_data(sp_finality_tracker::INHERENT_IDENTIFIER, &1u64);
+
+// let parent_id = BlockId::number(service.client().chain_info().best_number);
+// let parent_header = service.client().header(&parent_id).unwrap().unwrap();
+// let parent_hash = parent_header.hash();
+// let parent_number = *parent_header.number();
+
+// futures::executor::block_on(service.transaction_pool().maintain(
+// ChainEvent::NewBlock {
+// is_new_best: true,
+// hash: parent_header.hash(),
+// tree_route: None,
+// header: parent_header.clone(),
+// },
+// ));
+
+// let mut proposer_factory = sc_basic_authorship::ProposerFactory::new(
+// service.client(),
+// service.transaction_pool(),
+// None,
+// );
+
+// let epoch_descriptor = babe_link
+// .epoch_changes()
+// .lock()
+// .epoch_descriptor_for_child_of(
+// descendent_query(&*service.client()),
+// &parent_hash,
+// parent_number,
+// slot_num,
+// )
+// .unwrap()
+// .unwrap();
+
+// let mut digest = Digest::::default();
+
+// // even though there's only one authority some slots might be empty,
+// // so we must keep trying the next slots until we can claim one.
+// let babe_pre_digest = loop {
+// inherent_data.replace_data(
+// sp_timestamp::INHERENT_IDENTIFIER,
+// &(slot_num * SLOT_DURATION),
+// );
+// if let Some(babe_pre_digest) = sc_consensus_babe::test_helpers::claim_slot(
+// slot_num,
+// &parent_header,
+// &*service.client(),
+// &keystore,
+// &babe_link,
+// ) {
+// break babe_pre_digest;
+// }
+
+// slot_num += 1;
+// };
+
+// digest.push(::babe_pre_digest(
+// babe_pre_digest,
+// ));
+
+// let new_block = futures::executor::block_on(async move {
+// let proposer = proposer_factory.init(&parent_header).await;
+// proposer
+// .unwrap()
+// .propose(
+// inherent_data,
+// digest,
+// std::time::Duration::from_secs(1),
+// RecordProof::Yes,
+// )
+// .await
+// })
+// .expect("Error making test block")
+// .block;
+
+// let (new_header, new_body) = new_block.deconstruct();
+// let pre_hash = new_header.hash();
+// // sign the pre-sealed hash of the block and then
+// // add it to a digest item.
+// let to_sign = pre_hash.encode();
+// let signature = alice.sign(&to_sign[..]);
+// let item = ::babe_seal(signature.into());
+// slot_num += 1;
+
+// let mut params = BlockImportParams::new(BlockOrigin::File, new_header);
+// params.post_digests.push(item);
+// params.body = Some(new_body);
+// params.intermediates.insert(
+// Cow::from(INTERMEDIATE_KEY),
+// Box::new(BabeIntermediate:: { epoch_descriptor }) as Box,
+// );
+// params.fork_choice = Some(ForkChoiceStrategy::LongestChain);
+
+// block_import
+// .import_block(params, Default::default())
+// .expect("error importing test block");
+// },
+// |service, _| {
+// let amount = 5 * CENTS;
+// let to: AccountId = AccountPublic::from(bob.public()).into_account().into();
+// let from: AccountId = AccountPublic::from(charlie.public()).into_account().into();
+// let genesis_hash = service.client().block_hash(0).unwrap().unwrap();
+// let best_block_id = BlockId::number(service.client().chain_info().best_number);
+// let (spec_version, transaction_version) = {
+// let version = service.client().runtime_version_at(&best_block_id).unwrap();
+// (version.spec_version, version.transaction_version)
+// };
+// let signer = charlie.clone();
+
+// let function = Call::Balances(BalancesCall::transfer(to.into(), amount));
+
+// let check_spec_version = frame_system::CheckSpecVersion::new();
+// let check_tx_version = frame_system::CheckTxVersion::new();
+// let check_genesis = frame_system::CheckGenesis::new();
+// let check_era = frame_system::CheckEra::from(Era::Immortal);
+// let check_nonce = frame_system::CheckNonce::from(index);
+// let check_weight = frame_system::CheckWeight::new();
+// let payment = pallet_transaction_payment::ChargeTransactionPayment::from(0);
+// let validate_grandpa_equivocation =
+// pallet_grandpa::ValidateEquivocationReport::new();
+// let extra = (
+// check_spec_version,
+// check_tx_version,
+// check_genesis,
+// check_era,
+// check_nonce,
+// check_weight,
+// payment,
+// validate_grandpa_equivocation,
+// );
+// let raw_payload = SignedPayload::from_raw(
+// function,
+// extra,
+// (
+// spec_version,
+// transaction_version,
+// genesis_hash,
+// genesis_hash,
+// (),
+// (),
+// (),
+// (),
+// ),
+// );
+// let signature = raw_payload.using_encoded(|payload| signer.sign(payload));
+// let (function, extra, _) = raw_payload.deconstruct();
+// let xt =
+// UncheckedExtrinsic::new_signed(function, from.into(), signature.into(), extra)
+// .encode();
+// let v: Vec