Files
pezkuwi-subxt/substrate/bin/node/cli/src/service.rs
T
Cecile Tonglet 27274c42cf Fix telemetry span not entering properly attempt 3 (#8043)
* Fix tracing tests (#8022)

* Fix tracing tests

The tests were not working properly.

1. Some test was setting a global subscriber, this could lead to racy
conditions with other tests.

2. A logging test called `process::exit` which is completly wrong.

* Update client/tracing/src/lib.rs

Co-authored-by: David <dvdplm@gmail.com>

* Review comments

Co-authored-by: David <dvdplm@gmail.com>

* Fix tracing spans are not being forwarded to spawned task (#8009)

* Fix tracing spans are not being forwarded to spawned task

There is a bug that tracing spans are not forwarded to spawned task. The
problem was that only the telemetry span was forwarded. The solution to
this is to use the tracing provided `in_current_span` to capture the
current active span and pass the telemetry span explictely. We will now
always enter the span when the future is polled. This is essentially the
same strategy as tracing is doing with its `Instrumented`, but now
extended for our use case with having multiple spans active.

* More tests

* Proper test for telemetry and prefix span

* WIP

* Fix test (need to create & enter the span at the same time)

* WIP

* Remove telemtry_span from sc_service config

* CLEANUP

* Update comment

* Incorrect indent

* More meaningful name

* Dedent

* Naming XD

* Attempt to make a more complete test

* lint

* Missing licenses

* Remove user data

* CLEANUP

* Apply suggestions from code review

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>

* CLEANUP

* Apply suggestion

* Update bin/node/cli/tests/telemetry.rs

Co-authored-by: David <dvdplm@gmail.com>

* Wrapping lines

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
Co-authored-by: David <dvdplm@gmail.com>
2021-02-17 07:44:25 +00:00

719 lines
23 KiB
Rust

// This file is part of Substrate.
// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#![warn(unused_extern_crates)]
//! Service implementation. Specialized wrapper over substrate service.
use std::sync::Arc;
use sc_consensus_babe;
use node_primitives::Block;
use node_runtime::RuntimeApi;
use sc_service::{
config::{Configuration}, error::{Error as ServiceError},
RpcHandlers, TaskManager,
};
use sp_inherents::InherentDataProviders;
use sc_network::{Event, NetworkService};
use sp_runtime::traits::Block as BlockT;
use futures::prelude::*;
use sc_client_api::{ExecutorProvider, RemoteBackend};
use node_executor::Executor;
use sc_telemetry::{TelemetryConnectionNotifier, TelemetrySpan};
type FullClient = sc_service::TFullClient<Block, RuntimeApi, Executor>;
type FullBackend = sc_service::TFullBackend<Block>;
type FullSelectChain = sc_consensus::LongestChain<FullBackend, Block>;
type FullGrandpaBlockImport =
grandpa::GrandpaBlockImport<FullBackend, Block, FullClient, FullSelectChain>;
type LightClient = sc_service::TLightClient<Block, RuntimeApi, Executor>;
pub fn new_partial(config: &Configuration) -> Result<sc_service::PartialComponents<
FullClient, FullBackend, FullSelectChain,
sp_consensus::DefaultImportQueue<Block, FullClient>,
sc_transaction_pool::FullPool<Block, FullClient>,
(
impl Fn(
node_rpc::DenyUnsafe,
sc_rpc::SubscriptionTaskExecutor,
) -> node_rpc::IoHandler,
(
sc_consensus_babe::BabeBlockImport<Block, FullClient, FullGrandpaBlockImport>,
grandpa::LinkHalf<Block, FullClient, FullSelectChain>,
sc_consensus_babe::BabeLink<Block>,
),
grandpa::SharedVoterState,
)
>, ServiceError> {
let (client, backend, keystore_container, task_manager) =
sc_service::new_full_parts::<Block, RuntimeApi, Executor>(&config)?;
let client = Arc::new(client);
let select_chain = sc_consensus::LongestChain::new(backend.clone());
let transaction_pool = sc_transaction_pool::BasicPool::new_full(
config.transaction_pool.clone(),
config.role.is_authority().into(),
config.prometheus_registry(),
task_manager.spawn_handle(),
client.clone(),
);
let (grandpa_block_import, grandpa_link) = grandpa::block_import(
client.clone(), &(client.clone() as Arc<_>), select_chain.clone(),
)?;
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 inherent_data_providers = sp_inherents::InherentDataProviders::new();
let import_queue = sc_consensus_babe::import_queue(
babe_link.clone(),
block_import.clone(),
Some(Box::new(justification_import)),
client.clone(),
select_chain.clone(),
inherent_data_providers.clone(),
&task_manager.spawn_handle(),
config.prometheus_registry(),
sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()),
)?;
let import_setup = (block_import, grandpa_link, babe_link);
let (rpc_extensions_builder, rpc_setup) = {
let (_, grandpa_link, babe_link) = &import_setup;
let justification_stream = grandpa_link.justification_stream();
let shared_authority_set = grandpa_link.shared_authority_set().clone();
let shared_voter_state = grandpa::SharedVoterState::empty();
let rpc_setup = shared_voter_state.clone();
let finality_proof_provider = grandpa::FinalityProofProvider::new_for_service(
backend.clone(),
Some(shared_authority_set.clone()),
);
let babe_config = babe_link.config().clone();
let shared_epoch_changes = babe_link.epoch_changes().clone();
let client = client.clone();
let pool = transaction_pool.clone();
let select_chain = select_chain.clone();
let keystore = keystore_container.sync_keystore();
let chain_spec = config.chain_spec.cloned_box();
let rpc_extensions_builder = move |deny_unsafe, subscription_executor| {
let deps = node_rpc::FullDeps {
client: client.clone(),
pool: pool.clone(),
select_chain: select_chain.clone(),
chain_spec: chain_spec.cloned_box(),
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(),
justification_stream: justification_stream.clone(),
subscription_executor,
finality_provider: finality_proof_provider.clone(),
},
};
node_rpc::create_full(deps)
};
(rpc_extensions_builder, rpc_setup)
};
Ok(sc_service::PartialComponents {
client,
backend,
task_manager,
keystore_container,
select_chain,
import_queue,
transaction_pool,
inherent_data_providers,
other: (rpc_extensions_builder, import_setup, rpc_setup),
})
}
pub struct NewFullBase {
pub task_manager: TaskManager,
pub inherent_data_providers: InherentDataProviders,
pub client: Arc<FullClient>,
pub network: Arc<NetworkService<Block, <Block as BlockT>::Hash>>,
pub network_status_sinks: sc_service::NetworkStatusSinks<Block>,
pub transaction_pool: Arc<sc_transaction_pool::FullPool<Block, FullClient>>,
}
/// Creates a full service from the configuration.
pub fn new_full_base(
mut config: Configuration,
with_startup_data: impl FnOnce(
&sc_consensus_babe::BabeBlockImport<Block, FullClient, FullGrandpaBlockImport>,
&sc_consensus_babe::BabeLink<Block>,
)
) -> Result<NewFullBase, ServiceError> {
let sc_service::PartialComponents {
client,
backend,
mut task_manager,
import_queue,
keystore_container,
select_chain,
transaction_pool,
inherent_data_providers,
other: (rpc_extensions_builder, import_setup, rpc_setup),
} = new_partial(&config)?;
let shared_voter_state = rpc_setup;
config.network.extra_sets.push(grandpa::grandpa_peers_set_config());
#[cfg(feature = "cli")]
config.network.request_response_protocols.push(sc_finality_grandpa_warp_sync::request_response_config_for_chain(
&config, task_manager.spawn_handle(), backend.clone(),
));
let (network, network_status_sinks, system_rpc_tx, network_starter) =
sc_service::build_network(sc_service::BuildNetworkParams {
config: &config,
client: client.clone(),
transaction_pool: transaction_pool.clone(),
spawn_handle: task_manager.spawn_handle(),
import_queue,
on_demand: None,
block_announce_validator_builder: None,
})?;
if config.offchain_worker.enabled {
sc_service::build_offchain_workers(
&config, backend.clone(), task_manager.spawn_handle(), client.clone(), network.clone(),
);
}
let role = config.role.clone();
let force_authoring = config.force_authoring;
let backoff_authoring_blocks =
Some(sc_consensus_slots::BackoffAuthoringOnFinalizedHeadLagging::default());
let name = config.network.node_name.clone();
let enable_grandpa = !config.disable_grandpa;
let prometheus_registry = config.prometheus_registry().cloned();
let telemetry_span = TelemetrySpan::new();
let _telemetry_span_entered = telemetry_span.enter();
let (_rpc_handlers, telemetry_connection_notifier) = sc_service::spawn_tasks(
sc_service::SpawnTasksParams {
config,
backend: backend.clone(),
client: client.clone(),
keystore: keystore_container.sync_keystore(),
network: network.clone(),
rpc_extensions_builder: Box::new(rpc_extensions_builder),
transaction_pool: transaction_pool.clone(),
task_manager: &mut task_manager,
on_demand: None,
remote_blockchain: None,
network_status_sinks: network_status_sinks.clone(),
system_rpc_tx,
telemetry_span: Some(telemetry_span.clone()),
},
)?;
let (block_import, grandpa_link, babe_link) = import_setup;
(with_startup_data)(&block_import, &babe_link);
if let sc_service::config::Role::Authority { .. } = &role {
let proposer = sc_basic_authorship::ProposerFactory::new(
task_manager.spawn_handle(),
client.clone(),
transaction_pool.clone(),
prometheus_registry.as_ref(),
);
let can_author_with =
sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone());
let babe_config = sc_consensus_babe::BabeParams {
keystore: keystore_container.sync_keystore(),
client: client.clone(),
select_chain,
env: proposer,
block_import,
sync_oracle: network.clone(),
inherent_data_providers: inherent_data_providers.clone(),
force_authoring,
backoff_authoring_blocks,
babe_link,
can_author_with,
};
let babe = sc_consensus_babe::start_babe(babe_config)?;
task_manager.spawn_essential_handle().spawn_blocking("babe-proposer", babe);
}
// Spawn authority discovery module.
if role.is_authority() {
let authority_discovery_role = sc_authority_discovery::Role::PublishAndDiscover(
keystore_container.keystore(),
);
let dht_event_stream = network.event_stream("authority-discovery")
.filter_map(|e| async move { match e {
Event::Dht(e) => Some(e),
_ => None,
}});
let (authority_discovery_worker, _service) = sc_authority_discovery::new_worker_and_service(
client.clone(),
network.clone(),
Box::pin(dht_event_stream),
authority_discovery_role,
prometheus_registry.clone(),
);
task_manager.spawn_handle().spawn("authority-discovery-worker", authority_discovery_worker.run());
}
// 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 role.is_authority() {
Some(keystore_container.sync_keystore())
} 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: false,
keystore,
is_authority: role.is_authority(),
};
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: network.clone(),
telemetry_on_connect: telemetry_connection_notifier.map(|x| x.on_connect_stream()),
voting_rule: grandpa::VotingRulesBuilder::default().build(),
prometheus_registry,
shared_voter_state,
};
// the GRANDPA voter task is considered infallible, i.e.
// if it fails we take down the service with it.
task_manager.spawn_essential_handle().spawn_blocking(
"grandpa-voter",
grandpa::run_grandpa_voter(grandpa_config)?
);
}
network_starter.start_network();
Ok(NewFullBase {
task_manager,
inherent_data_providers,
client,
network,
network_status_sinks,
transaction_pool,
})
}
/// Builds a new service for a full client.
pub fn new_full(config: Configuration)
-> Result<TaskManager, ServiceError> {
new_full_base(config, |_, _| ()).map(|NewFullBase { task_manager, .. }| {
task_manager
})
}
pub fn new_light_base(mut config: Configuration) -> Result<(
TaskManager, RpcHandlers, Option<TelemetryConnectionNotifier>, Arc<LightClient>,
Arc<NetworkService<Block, <Block as BlockT>::Hash>>,
Arc<sc_transaction_pool::LightPool<Block, LightClient, sc_network::config::OnDemand<Block>>>
), ServiceError> {
let (client, backend, keystore_container, mut task_manager, on_demand) =
sc_service::new_light_parts::<Block, RuntimeApi, Executor>(&config)?;
config.network.extra_sets.push(grandpa::grandpa_peers_set_config());
let select_chain = sc_consensus::LongestChain::new(backend.clone());
let transaction_pool = Arc::new(sc_transaction_pool::BasicPool::new_light(
config.transaction_pool.clone(),
config.prometheus_registry(),
task_manager.spawn_handle(),
client.clone(),
on_demand.clone(),
));
let (grandpa_block_import, _) = grandpa::block_import(
client.clone(),
&(client.clone() as Arc<_>),
select_chain.clone(),
)?;
let justification_import = grandpa_block_import.clone();
let (babe_block_import, babe_link) = sc_consensus_babe::block_import(
sc_consensus_babe::Config::get_or_compute(&*client)?,
grandpa_block_import,
client.clone(),
)?;
let inherent_data_providers = sp_inherents::InherentDataProviders::new();
let import_queue = sc_consensus_babe::import_queue(
babe_link,
babe_block_import,
Some(Box::new(justification_import)),
client.clone(),
select_chain.clone(),
inherent_data_providers.clone(),
&task_manager.spawn_handle(),
config.prometheus_registry(),
sp_consensus::NeverCanAuthor,
)?;
let (network, network_status_sinks, system_rpc_tx, network_starter) =
sc_service::build_network(sc_service::BuildNetworkParams {
config: &config,
client: client.clone(),
transaction_pool: transaction_pool.clone(),
spawn_handle: task_manager.spawn_handle(),
import_queue,
on_demand: Some(on_demand.clone()),
block_announce_validator_builder: None,
})?;
network_starter.start_network();
if config.offchain_worker.enabled {
sc_service::build_offchain_workers(
&config, backend.clone(), task_manager.spawn_handle(), client.clone(), network.clone(),
);
}
let light_deps = node_rpc::LightDeps {
remote_blockchain: backend.remote_blockchain(),
fetcher: on_demand.clone(),
client: client.clone(),
pool: transaction_pool.clone(),
};
let rpc_extensions = node_rpc::create_light(light_deps);
let telemetry_span = TelemetrySpan::new();
let _telemetry_span_entered = telemetry_span.enter();
let (rpc_handlers, telemetry_connection_notifier) =
sc_service::spawn_tasks(sc_service::SpawnTasksParams {
on_demand: Some(on_demand),
remote_blockchain: Some(backend.remote_blockchain()),
rpc_extensions_builder: Box::new(sc_service::NoopRpcExtensionBuilder(rpc_extensions)),
client: client.clone(),
transaction_pool: transaction_pool.clone(),
keystore: keystore_container.sync_keystore(),
config, backend, network_status_sinks, system_rpc_tx,
network: network.clone(),
task_manager: &mut task_manager,
telemetry_span: Some(telemetry_span.clone()),
})?;
Ok((
task_manager,
rpc_handlers,
telemetry_connection_notifier,
client,
network,
transaction_pool,
))
}
/// Builds a new service for a light client.
pub fn new_light(config: Configuration) -> Result<TaskManager, ServiceError> {
new_light_base(config).map(|(task_manager, _, _, _, _, _)| {
task_manager
})
}
#[cfg(test)]
mod tests {
use std::{sync::Arc, borrow::Cow, any::Any, convert::TryInto};
use sc_consensus_babe::{CompatibleDigestItem, BabeIntermediate, INTERMEDIATE_KEY};
use sc_consensus_epochs::descendent_query;
use sp_consensus::{
Environment, Proposer, BlockImportParams, BlockOrigin, ForkChoiceStrategy, BlockImport,
RecordProof,
};
use node_primitives::{Block, DigestItem, Signature};
use node_runtime::{BalancesCall, Call, UncheckedExtrinsic, Address};
use node_runtime::constants::{currency::CENTS, time::SLOT_DURATION};
use codec::Encode;
use sp_core::{
crypto::Pair as CryptoPair,
H256,
Public
};
use sp_keystore::{SyncCryptoStorePtr, SyncCryptoStore};
use sp_runtime::{
generic::{BlockId, Era, Digest, SignedPayload},
traits::{Block as BlockT, Header as HeaderT},
traits::Verify,
};
use sp_timestamp;
use sp_keyring::AccountKeyring;
use sc_service_test::TestNetNode;
use crate::service::{new_full_base, new_light_base, NewFullBase};
use sp_runtime::{key_types::BABE, traits::IdentifyAccount, RuntimeAppPublic};
use sp_transaction_pool::{MaintainedTransactionPool, ChainEvent};
use sc_client_api::BlockBackend;
use sc_keystore::LocalKeystore;
type AccountPublic = <Signature as Verify>::Signer;
#[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: SyncCryptoStorePtr = Arc::new(LocalKeystore::open(keystore_path.path(), None)
.expect("Creates keystore"));
let alice: sp_consensus_babe::AuthorityId = SyncCryptoStore::sr25519_generate_new(&*keystore, BABE, Some("//Alice"))
.expect("Creates authority pair").into();
let chain_spec = crate::chain_spec::tests::integration_test_config_with_single_authority();
// For the block factory
let mut slot = 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;
let NewFullBase {
task_manager, inherent_data_providers, client, network, transaction_pool, ..
} = new_full_base(config,
|
block_import: &sc_consensus_babe::BabeBlockImport<Block, _, _>,
babe_link: &sc_consensus_babe::BabeLink<Block>,
| {
setup_handles = Some((block_import.clone(), babe_link.clone()));
}
)?;
let node = sc_service_test::TestNetComponents::new(
task_manager, client, network, transaction_pool
);
Ok((node, (inherent_data_providers, setup_handles.unwrap())))
},
|config| {
let (keep_alive, _, _, client, network, transaction_pool) = new_light_base(config)?;
Ok(sc_service_test::TestNetComponents::new(keep_alive, client, network, transaction_pool))
},
|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.");
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::NewBestBlock {
hash: parent_header.hash(),
tree_route: None,
},
)
);
let mut proposer_factory = sc_basic_authorship::ProposerFactory::new(
service.spawn_handle(),
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.into(),
).unwrap().unwrap();
let mut digest = Digest::<H256>::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 * SLOT_DURATION));
if let Some(babe_pre_digest) = sc_consensus_babe::test_helpers::claim_slot(
slot.into(),
&parent_header,
&*service.client(),
keystore.clone(),
&babe_link,
) {
break babe_pre_digest;
}
slot += 1;
};
digest.push(<DigestItem as CompatibleDigestItem>::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 = SyncCryptoStore::sign_with(
&*keystore,
sp_consensus_babe::AuthorityId::ID,
&alice.to_public_crypto_pair(),
&to_sign,
).unwrap()
.try_into()
.unwrap();
let item = <DigestItem as CompatibleDigestItem>::babe_seal(
signature,
);
slot += 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::<Block> { epoch_descriptor }) as Box<dyn Any>,
);
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: Address = AccountPublic::from(bob.public()).into_account().into();
let from: Address = 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 extra = (
check_spec_version,
check_tx_version,
check_genesis,
check_era,
check_nonce,
check_weight,
payment,
);
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();
index += 1;
UncheckedExtrinsic::new_signed(
function,
from.into(),
signature.into(),
extra,
).into()
},
);
}
#[test]
#[ignore]
fn test_consensus() {
sc_service_test::consensus(
crate::chain_spec::tests::integration_test_config_with_two_authorities(),
|config| {
let NewFullBase { task_manager, client, network, transaction_pool, .. }
= new_full_base(config,|_, _| ())?;
Ok(sc_service_test::TestNetComponents::new(task_manager, client, network, transaction_pool))
},
|config| {
let (keep_alive, _, _, client, network, transaction_pool) = new_light_base(config)?;
Ok(sc_service_test::TestNetComponents::new(keep_alive, client, network, transaction_pool))
},
vec![
"//Alice".into(),
"//Bob".into(),
],
)
}
}