Run cargo fmt on the whole code base (#9394)

* Run cargo fmt on the whole code base

* Second run

* Add CI check

* Fix compilation

* More unnecessary braces

* Handle weights

* Use --all

* Use correct attributes...

* Fix UI tests

* AHHHHHHHHH

* 🤦

* Docs

* Fix compilation

* 🤷

* Please stop

* 🤦 x 2

* More

* make rustfmt.toml consistent with polkadot

Co-authored-by: André Silva <andrerfosilva@gmail.com>
This commit is contained in:
Bastian Köcher
2021-07-21 16:32:32 +02:00
committed by GitHub
parent d451c38c1c
commit 7b56ab15b4
1010 changed files with 53339 additions and 51208 deletions
+285 -292
View File
@@ -17,65 +17,52 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::{
error::Error, MallocSizeOfWasm, RpcHandlers,
start_rpc_servers, build_network_future, TransactionPoolAdapter, TaskManager, SpawnTaskHandle,
metrics::MetricsService,
build_network_future,
client::{light, Client, ClientConfig},
config::{Configuration, KeystoreConfig, PrometheusConfig, TransactionStorageMode},
error::Error,
metrics::MetricsService,
start_rpc_servers, MallocSizeOfWasm, RpcHandlers, SpawnTaskHandle, TaskManager,
TransactionPoolAdapter,
};
use sc_client_api::{
light::RemoteBlockchain, ForkBlocks, BadBlocks, UsageProvider, ExecutorProvider,
};
use sp_utils::mpsc::{tracing_unbounded, TracingUnboundedSender};
use futures::{channel::oneshot, future::ready, FutureExt, StreamExt};
use jsonrpc_pubsub::manager::SubscriptionManager;
use log::info;
use prometheus_endpoint::Registry;
use sc_chain_spec::get_extension;
use sc_client_api::{
execution_extensions::ExecutionExtensions, light::RemoteBlockchain,
proof_provider::ProofProvider, BadBlocks, BlockBackend, BlockchainEvents, ExecutorProvider,
ForkBlocks, StorageProvider, UsageProvider,
};
use sc_client_db::{Backend, DatabaseSettings};
use sc_executor::{NativeExecutionDispatch, NativeExecutor, RuntimeInfo};
use sc_keystore::LocalKeystore;
use sc_network::{
block_request_handler::{self, BlockRequestHandler},
config::{OnDemand, Role, SyncMode},
light_client_requests::{self, handler::LightClientRequestHandler},
state_request_handler::{self, StateRequestHandler},
NetworkService,
};
use sc_telemetry::{telemetry, ConnectionMessage, Telemetry, TelemetryHandle, SUBSTRATE_INFO};
use sc_transaction_pool_api::MaintainedTransactionPool;
use sp_api::{CallApiAt, ProvideRuntimeApi};
use sp_blockchain::{HeaderBackend, HeaderMetadata};
use sp_consensus::{
block_validation::{BlockAnnounceValidator, DefaultBlockAnnounceValidator, Chain},
block_validation::{BlockAnnounceValidator, Chain, DefaultBlockAnnounceValidator},
import_queue::ImportQueue,
};
use jsonrpc_pubsub::manager::SubscriptionManager;
use futures::{
FutureExt, StreamExt,
future::ready,
channel::oneshot,
};
use sc_keystore::LocalKeystore;
use log::info;
use sc_network::config::{Role, OnDemand, SyncMode};
use sc_network::NetworkService;
use sc_network::block_request_handler::{self, BlockRequestHandler};
use sc_network::state_request_handler::{self, StateRequestHandler};
use sc_network::light_client_requests::{self, handler::LightClientRequestHandler};
use sp_runtime::generic::BlockId;
use sp_runtime::traits::{
Block as BlockT, HashFor, Zero, BlockIdTo,
};
use sp_api::{ProvideRuntimeApi, CallApiAt};
use sc_executor::{NativeExecutor, NativeExecutionDispatch, RuntimeInfo};
use std::{sync::Arc, str::FromStr};
use wasm_timer::SystemTime;
use sc_telemetry::{
telemetry,
ConnectionMessage,
Telemetry,
TelemetryHandle,
SUBSTRATE_INFO,
};
use sc_transaction_pool_api::MaintainedTransactionPool;
use prometheus_endpoint::Registry;
use sc_client_db::{Backend, DatabaseSettings};
use sp_core::traits::{
CodeExecutor,
SpawnNamed,
};
use sp_core::traits::{CodeExecutor, SpawnNamed};
use sp_keystore::{CryptoStore, SyncCryptoStore, SyncCryptoStorePtr};
use sp_runtime::BuildStorage;
use sc_client_api::{
BlockBackend, BlockchainEvents,
StorageProvider,
proof_provider::ProofProvider,
execution_extensions::ExecutionExtensions
use sp_runtime::{
generic::BlockId,
traits::{Block as BlockT, BlockIdTo, HashFor, Zero},
BuildStorage,
};
use sp_blockchain::{HeaderMetadata, HeaderBackend};
use sp_utils::mpsc::{tracing_unbounded, TracingUnboundedSender};
use std::{str::FromStr, sync::Arc};
use wasm_timer::SystemTime;
/// A utility trait for building an RPC extension given a `DenyUnsafe` instance.
/// This is useful since at service definition time we don't know whether the
@@ -95,7 +82,8 @@ pub trait RpcExtensionBuilder {
) -> Self::Output;
}
impl<F, R> RpcExtensionBuilder for F where
impl<F, R> RpcExtensionBuilder for F
where
F: Fn(sc_rpc::DenyUnsafe, sc_rpc::SubscriptionTaskExecutor) -> R,
R: sc_rpc::RpcExtension<sc_rpc::Metadata>,
{
@@ -115,7 +103,8 @@ impl<F, R> RpcExtensionBuilder for F where
/// `DenyUnsafe` instance and return a static `RpcExtension` instance.
pub struct NoopRpcExtensionBuilder<R>(pub R);
impl<R> RpcExtensionBuilder for NoopRpcExtensionBuilder<R> where
impl<R> RpcExtensionBuilder for NoopRpcExtensionBuilder<R>
where
R: Clone + sc_rpc::RpcExtension<sc_rpc::Metadata>,
{
type Output = R;
@@ -129,7 +118,8 @@ impl<R> RpcExtensionBuilder for NoopRpcExtensionBuilder<R> where
}
}
impl<R> From<R> for NoopRpcExtensionBuilder<R> where
impl<R> From<R> for NoopRpcExtensionBuilder<R>
where
R: sc_rpc::RpcExtension<sc_rpc::Metadata>,
{
fn from(e: R) -> NoopRpcExtensionBuilder<R> {
@@ -137,58 +127,37 @@ impl<R> From<R> for NoopRpcExtensionBuilder<R> where
}
}
/// Full client type.
pub type TFullClient<TBl, TRtApi, TExecDisp> = Client<
TFullBackend<TBl>,
TFullCallExecutor<TBl, TExecDisp>,
TBl,
TRtApi,
>;
pub type TFullClient<TBl, TRtApi, TExecDisp> =
Client<TFullBackend<TBl>, TFullCallExecutor<TBl, TExecDisp>, TBl, TRtApi>;
/// Full client backend type.
pub type TFullBackend<TBl> = sc_client_db::Backend<TBl>;
/// Full client call executor type.
pub type TFullCallExecutor<TBl, TExecDisp> = crate::client::LocalCallExecutor<
TBl,
sc_client_db::Backend<TBl>,
NativeExecutor<TExecDisp>,
>;
pub type TFullCallExecutor<TBl, TExecDisp> =
crate::client::LocalCallExecutor<TBl, sc_client_db::Backend<TBl>, NativeExecutor<TExecDisp>>;
/// Light client type.
pub type TLightClient<TBl, TRtApi, TExecDisp> = TLightClientWithBackend<
TBl, TRtApi, TExecDisp, TLightBackend<TBl>
>;
pub type TLightClient<TBl, TRtApi, TExecDisp> =
TLightClientWithBackend<TBl, TRtApi, TExecDisp, TLightBackend<TBl>>;
/// Light client backend type.
pub type TLightBackend<TBl> = sc_light::Backend<
sc_client_db::light::LightStorage<TBl>,
HashFor<TBl>,
>;
pub type TLightBackend<TBl> =
sc_light::Backend<sc_client_db::light::LightStorage<TBl>, HashFor<TBl>>;
/// Light call executor type.
pub type TLightCallExecutor<TBl, TExecDisp> = sc_light::GenesisCallExecutor<
sc_light::Backend<
sc_client_db::light::LightStorage<TBl>,
HashFor<TBl>
>,
sc_light::Backend<sc_client_db::light::LightStorage<TBl>, HashFor<TBl>>,
crate::client::LocalCallExecutor<
TBl,
sc_light::Backend<
sc_client_db::light::LightStorage<TBl>,
HashFor<TBl>
>,
NativeExecutor<TExecDisp>
sc_light::Backend<sc_client_db::light::LightStorage<TBl>, HashFor<TBl>>,
NativeExecutor<TExecDisp>,
>,
>;
type TFullParts<TBl, TRtApi, TExecDisp> = (
TFullClient<TBl, TRtApi, TExecDisp>,
Arc<TFullBackend<TBl>>,
KeystoreContainer,
TaskManager,
);
type TFullParts<TBl, TRtApi, TExecDisp> =
(TFullClient<TBl, TRtApi, TExecDisp>, Arc<TFullBackend<TBl>>, KeystoreContainer, TaskManager);
type TLightParts<TBl, TRtApi, TExecDisp> = (
Arc<TLightClient<TBl, TRtApi, TExecDisp>>,
@@ -199,10 +168,8 @@ type TLightParts<TBl, TRtApi, TExecDisp> = (
);
/// Light client backend type with a specific hash type.
pub type TLightBackendWithHash<TBl, THash> = sc_light::Backend<
sc_client_db::light::LightStorage<TBl>,
THash,
>;
pub type TLightBackendWithHash<TBl, THash> =
sc_light::Backend<sc_client_db::light::LightStorage<TBl>, THash>;
/// Light client type with a specific backend.
pub type TLightClientWithBackend<TBl, TRtApi, TExecDisp, TBackend> = Client<
@@ -220,7 +187,10 @@ trait AsCryptoStoreRef {
fn sync_keystore_ref(&self) -> Arc<dyn SyncCryptoStore>;
}
impl<T> AsCryptoStoreRef for Arc<T> where T: CryptoStore + SyncCryptoStore + 'static {
impl<T> AsCryptoStoreRef for Arc<T>
where
T: CryptoStore + SyncCryptoStore + 'static,
{
fn keystore_ref(&self) -> Arc<dyn CryptoStore> {
self.clone()
}
@@ -239,14 +209,12 @@ impl KeystoreContainer {
/// Construct KeystoreContainer
pub fn new(config: &KeystoreConfig) -> Result<Self, Error> {
let keystore = Arc::new(match config {
KeystoreConfig::Path { path, password } => LocalKeystore::open(
path.clone(),
password.clone(),
)?,
KeystoreConfig::Path { path, password } =>
LocalKeystore::open(path.clone(), password.clone())?,
KeystoreConfig::InMemory => LocalKeystore::in_memory(),
});
Ok(Self{remote: Default::default(), local: keystore})
Ok(Self { remote: Default::default(), local: keystore })
}
/// Set the remote keystore.
@@ -255,7 +223,8 @@ impl KeystoreContainer {
/// does not reset any references previously handed out - they will
/// stick around.
pub fn set_remote_keystore<T>(&mut self, remote: Arc<T>)
where T: CryptoStore + SyncCryptoStore + 'static
where
T: CryptoStore + SyncCryptoStore + 'static,
{
self.remote = Some(Box::new(remote))
}
@@ -295,7 +264,8 @@ impl KeystoreContainer {
pub fn new_full_client<TBl, TRtApi, TExecDisp>(
config: &Configuration,
telemetry: Option<TelemetryHandle>,
) -> Result<TFullClient<TBl, TRtApi, TExecDisp>, Error> where
) -> Result<TFullClient<TBl, TRtApi, TExecDisp>, Error>
where
TBl: BlockT,
TExecDisp: NativeExecutionDispatch + 'static,
TBl::Hash: FromStr,
@@ -307,7 +277,8 @@ pub fn new_full_client<TBl, TRtApi, TExecDisp>(
pub fn new_full_parts<TBl, TRtApi, TExecDisp>(
config: &Configuration,
telemetry: Option<TelemetryHandle>,
) -> Result<TFullParts<TBl, TRtApi, TExecDisp>, Error> where
) -> Result<TFullParts<TBl, TRtApi, TExecDisp>, Error>
where
TBl: BlockT,
TExecDisp: NativeExecutionDispatch + 'static,
TBl::Hash: FromStr,
@@ -337,15 +308,13 @@ pub fn new_full_parts<TBl, TRtApi, TExecDisp>(
let (client, backend) = {
let db_config = sc_client_db::DatabaseSettings {
state_cache_size: config.state_cache_size,
state_cache_child_ratio:
config.state_cache_child_ratio.map(|v| (v, 100)),
state_cache_child_ratio: config.state_cache_child_ratio.map(|v| (v, 100)),
state_pruning: config.state_pruning.clone(),
source: config.database.clone(),
keep_blocks: config.keep_blocks.clone(),
transaction_storage: config.transaction_storage.clone(),
};
let backend = new_db_backend(db_config)?;
let extensions = sc_client_api::execution_extensions::ExecutionExtensions::new(
@@ -354,15 +323,20 @@ pub fn new_full_parts<TBl, TRtApi, TExecDisp>(
sc_offchain::OffchainDb::factory_from_backend(&*backend),
);
let wasm_runtime_substitutes = config.chain_spec.code_substitutes().into_iter().map(|(h, c)| {
let hash = TBl::Hash::from_str(&h)
.map_err(|_|
Error::Application(Box::from(
format!("Failed to parse `{}` as block hash for code substitutes.", h)
))
)?;
Ok((hash, c))
}).collect::<Result<std::collections::HashMap<_, _>, Error>>()?;
let wasm_runtime_substitutes = config
.chain_spec
.code_substitutes()
.into_iter()
.map(|(h, c)| {
let hash = TBl::Hash::from_str(&h).map_err(|_| {
Error::Application(Box::from(format!(
"Failed to parse `{}` as block hash for code substitutes.",
h
)))
})?;
Ok((hash, c))
})
.collect::<Result<std::collections::HashMap<_, _>, Error>>()?;
let client = new_client(
backend.clone(),
@@ -375,10 +349,13 @@ pub fn new_full_parts<TBl, TRtApi, TExecDisp>(
config.prometheus_config.as_ref().map(|config| config.registry.clone()),
telemetry,
ClientConfig {
offchain_worker_enabled : config.offchain_worker.enabled,
offchain_worker_enabled: config.offchain_worker.enabled,
offchain_indexing_api: config.offchain_worker.indexing_enabled,
wasm_runtime_overrides: config.wasm_runtime_overrides.clone(),
no_genesis: matches!(config.network.sync_mode, sc_network::config::SyncMode::Fast {..}),
no_genesis: matches!(
config.network.sync_mode,
sc_network::config::SyncMode::Fast { .. }
),
wasm_runtime_substitutes,
},
)?;
@@ -386,19 +363,15 @@ pub fn new_full_parts<TBl, TRtApi, TExecDisp>(
(client, backend)
};
Ok((
client,
backend,
keystore_container,
task_manager,
))
Ok((client, backend, keystore_container, task_manager))
}
/// Create the initial parts of a light node.
pub fn new_light_parts<TBl, TRtApi, TExecDisp>(
config: &Configuration,
telemetry: Option<TelemetryHandle>,
) -> Result<TLightParts<TBl, TRtApi, TExecDisp>, Error> where
) -> Result<TLightParts<TBl, TRtApi, TExecDisp>, Error>
where
TBl: BlockT,
TExecDisp: NativeExecutionDispatch + 'static,
{
@@ -417,8 +390,7 @@ pub fn new_light_parts<TBl, TRtApi, TExecDisp>(
let db_storage = {
let db_settings = sc_client_db::DatabaseSettings {
state_cache_size: config.state_cache_size,
state_cache_child_ratio:
config.state_cache_child_ratio.map(|v| (v, 100)),
state_cache_child_ratio: config.state_cache_child_ratio.map(|v| (v, 100)),
state_pruning: config.state_pruning.clone(),
source: config.database.clone(),
keep_blocks: config.keep_blocks.clone(),
@@ -427,13 +399,11 @@ pub fn new_light_parts<TBl, TRtApi, TExecDisp>(
sc_client_db::light::LightStorage::new(db_settings)?
};
let light_blockchain = sc_light::new_light_blockchain(db_storage);
let fetch_checker = Arc::new(
sc_light::new_fetch_checker::<_, TBl, _>(
light_blockchain.clone(),
executor.clone(),
Box::new(task_manager.spawn_handle()),
),
);
let fetch_checker = Arc::new(sc_light::new_fetch_checker::<_, TBl, _>(
light_blockchain.clone(),
executor.clone(),
Box::new(task_manager.spawn_handle()),
));
let on_demand = Arc::new(sc_network::config::OnDemand::new(fetch_checker));
let backend = sc_light::new_light_backend(light_blockchain);
let client = Arc::new(light::new_light(
@@ -451,7 +421,8 @@ pub fn new_light_parts<TBl, TRtApi, TExecDisp>(
/// Create an instance of default DB-backend backend.
pub fn new_db_backend<Block>(
settings: DatabaseSettings,
) -> Result<Arc<Backend<Block>>, sp_blockchain::Error> where
) -> Result<Arc<Backend<Block>>, sp_blockchain::Error>
where
Block: BlockT,
{
const CANONICALIZATION_DELAY: u64 = 4096;
@@ -480,11 +451,16 @@ pub fn new_client<E, Block, RA>(
>,
sp_blockchain::Error,
>
where
Block: BlockT,
E: CodeExecutor + RuntimeInfo,
where
Block: BlockT,
E: CodeExecutor + RuntimeInfo,
{
let executor = crate::client::LocalCallExecutor::new(backend.clone(), executor, spawn_handle, config.clone())?;
let executor = crate::client::LocalCallExecutor::new(
backend.clone(),
executor,
spawn_handle,
config.clone(),
)?;
Ok(crate::client::Client::new(
backend,
executor,
@@ -534,10 +510,10 @@ pub fn build_offchain_workers<TBl, TCl>(
client: Arc<TCl>,
network: Arc<NetworkService<TBl, <TBl as BlockT>::Hash>>,
) -> Option<Arc<sc_offchain::OffchainWorkers<TCl, TBl>>>
where
TBl: BlockT,
TCl: Send + Sync + ProvideRuntimeApi<TBl> + BlockchainEvents<TBl> + 'static,
<TCl as ProvideRuntimeApi<TBl>>::Api: sc_offchain::OffchainWorkerApi<TBl>,
where
TBl: BlockT,
TCl: Send + Sync + ProvideRuntimeApi<TBl> + BlockchainEvents<TBl> + 'static,
<TCl as ProvideRuntimeApi<TBl>>::Api: sc_offchain::OffchainWorkerApi<TBl>,
{
let offchain_workers = Some(Arc::new(sc_offchain::OffchainWorkers::new(client.clone())));
@@ -551,7 +527,7 @@ pub fn build_offchain_workers<TBl, TCl>(
offchain,
Clone::clone(&spawn_handle),
network.clone(),
)
),
);
}
@@ -562,22 +538,32 @@ pub fn build_offchain_workers<TBl, TCl>(
pub fn spawn_tasks<TBl, TBackend, TExPool, TRpc, TCl>(
params: SpawnTasksParams<TBl, TCl, TExPool, TRpc, TBackend>,
) -> Result<RpcHandlers, Error>
where
TCl: ProvideRuntimeApi<TBl> + HeaderMetadata<TBl, Error=sp_blockchain::Error> + Chain<TBl> +
BlockBackend<TBl> + BlockIdTo<TBl, Error=sp_blockchain::Error> + ProofProvider<TBl> +
HeaderBackend<TBl> + BlockchainEvents<TBl> + ExecutorProvider<TBl> + UsageProvider<TBl> +
StorageProvider<TBl, TBackend> + CallApiAt<TBl> + Send + 'static,
<TCl as ProvideRuntimeApi<TBl>>::Api:
sp_api::Metadata<TBl> +
sc_offchain::OffchainWorkerApi<TBl> +
sp_transaction_pool::runtime_api::TaggedTransactionQueue<TBl> +
sp_session::SessionKeys<TBl> +
sp_api::ApiExt<TBl, StateBackend = TBackend::State>,
TBl: BlockT,
TBackend: 'static + sc_client_api::backend::Backend<TBl> + Send,
TExPool: MaintainedTransactionPool<Block=TBl, Hash = <TBl as BlockT>::Hash> +
MallocSizeOfWasm + 'static,
TRpc: sc_rpc::RpcExtension<sc_rpc::Metadata>
where
TCl: ProvideRuntimeApi<TBl>
+ HeaderMetadata<TBl, Error = sp_blockchain::Error>
+ Chain<TBl>
+ BlockBackend<TBl>
+ BlockIdTo<TBl, Error = sp_blockchain::Error>
+ ProofProvider<TBl>
+ HeaderBackend<TBl>
+ BlockchainEvents<TBl>
+ ExecutorProvider<TBl>
+ UsageProvider<TBl>
+ StorageProvider<TBl, TBackend>
+ CallApiAt<TBl>
+ Send
+ 'static,
<TCl as ProvideRuntimeApi<TBl>>::Api: sp_api::Metadata<TBl>
+ sc_offchain::OffchainWorkerApi<TBl>
+ sp_transaction_pool::runtime_api::TaggedTransactionQueue<TBl>
+ sp_session::SessionKeys<TBl>
+ sp_api::ApiExt<TBl, StateBackend = TBackend::State>,
TBl: BlockT,
TBackend: 'static + sc_client_api::backend::Backend<TBl> + Send,
TExPool: MaintainedTransactionPool<Block = TBl, Hash = <TBl as BlockT>::Hash>
+ MallocSizeOfWasm
+ 'static,
TRpc: sc_rpc::RpcExtension<sc_rpc::Metadata>,
{
let SpawnTasksParams {
mut config,
@@ -600,17 +586,11 @@ pub fn spawn_tasks<TBl, TBackend, TExPool, TRpc, TCl>(
client.clone(),
&BlockId::Hash(chain_info.best_hash),
config.dev_key_seed.clone().map(|s| vec![s]).unwrap_or_default(),
).map_err(|e| Error::Application(Box::new(e)))?;
)
.map_err(|e| Error::Application(Box::new(e)))?;
let telemetry = telemetry
.map(|telemetry| {
init_telemetry(
&mut config,
network.clone(),
client.clone(),
telemetry,
)
})
.map(|telemetry| init_telemetry(&mut config, network.clone(), client.clone(), telemetry))
.transpose()?;
info!("📦 Highest known block at #{}", chain_info.best_number);
@@ -625,63 +605,69 @@ pub fn spawn_tasks<TBl, TBackend, TExPool, TRpc, TCl>(
spawn_handle.spawn(
"on-transaction-imported",
transaction_notifications(
transaction_pool.clone(),
network.clone(),
telemetry.clone(),
),
transaction_notifications(transaction_pool.clone(), network.clone(), telemetry.clone()),
);
// Prometheus metrics.
let metrics_service = if let Some(PrometheusConfig { port, registry }) =
config.prometheus_config.clone()
{
// Set static metrics.
let metrics = MetricsService::with_prometheus(telemetry.clone(), &registry, &config)?;
spawn_handle.spawn(
"prometheus-endpoint",
prometheus_endpoint::init_prometheus(port, registry).map(drop)
);
let metrics_service =
if let Some(PrometheusConfig { port, registry }) = config.prometheus_config.clone() {
// Set static metrics.
let metrics = MetricsService::with_prometheus(telemetry.clone(), &registry, &config)?;
spawn_handle.spawn(
"prometheus-endpoint",
prometheus_endpoint::init_prometheus(port, registry).map(drop),
);
metrics
} else {
MetricsService::new(telemetry.clone())
};
metrics
} else {
MetricsService::new(telemetry.clone())
};
// Periodically updated metrics and telemetry updates.
spawn_handle.spawn("telemetry-periodic-send",
metrics_service.run(
client.clone(),
transaction_pool.clone(),
network.clone(),
)
spawn_handle.spawn(
"telemetry-periodic-send",
metrics_service.run(client.clone(), transaction_pool.clone(), network.clone()),
);
// RPC
let gen_handler = |
deny_unsafe: sc_rpc::DenyUnsafe,
rpc_middleware: sc_rpc_server::RpcMiddleware
| gen_handler(
deny_unsafe, rpc_middleware, &config, task_manager.spawn_handle(),
client.clone(), transaction_pool.clone(), keystore.clone(),
on_demand.clone(), remote_blockchain.clone(), &*rpc_extensions_builder,
backend.offchain_storage(), system_rpc_tx.clone()
);
let gen_handler = |deny_unsafe: sc_rpc::DenyUnsafe,
rpc_middleware: sc_rpc_server::RpcMiddleware| {
gen_handler(
deny_unsafe,
rpc_middleware,
&config,
task_manager.spawn_handle(),
client.clone(),
transaction_pool.clone(),
keystore.clone(),
on_demand.clone(),
remote_blockchain.clone(),
&*rpc_extensions_builder,
backend.offchain_storage(),
system_rpc_tx.clone(),
)
};
let rpc_metrics = sc_rpc_server::RpcMetrics::new(config.prometheus_registry())?;
let rpc = start_rpc_servers(&config, gen_handler, rpc_metrics.clone())?;
// This is used internally, so don't restrict access to unsafe RPC
let rpc_handlers = RpcHandlers(Arc::new(gen_handler(
sc_rpc::DenyUnsafe::No,
sc_rpc_server::RpcMiddleware::new(rpc_metrics, "inbrowser")
).into()));
let rpc_handlers = RpcHandlers(Arc::new(
gen_handler(
sc_rpc::DenyUnsafe::No,
sc_rpc_server::RpcMiddleware::new(rpc_metrics, "inbrowser"),
)
.into(),
));
// Spawn informant task
spawn_handle.spawn("informant", sc_informant::build(
client.clone(),
network.clone(),
transaction_pool.clone(),
config.informant_output_format,
));
spawn_handle.spawn(
"informant",
sc_informant::build(
client.clone(),
network.clone(),
transaction_pool.clone(),
config.informant_output_format,
),
);
task_manager.keep_alive((config.base_path, rpc, rpc_handlers.clone()));
@@ -692,10 +678,9 @@ async fn transaction_notifications<TBl, TExPool>(
transaction_pool: Arc<TExPool>,
network: Arc<NetworkService<TBl, <TBl as BlockT>::Hash>>,
telemetry: Option<TelemetryHandle>,
)
where
TBl: BlockT,
TExPool: MaintainedTransactionPool<Block=TBl, Hash = <TBl as BlockT>::Hash>,
) where
TBl: BlockT,
TExPool: MaintainedTransactionPool<Block = TBl, Hash = <TBl as BlockT>::Hash>,
{
// transaction notifications
transaction_pool
@@ -730,9 +715,11 @@ fn init_telemetry<TBl: BlockT, TCl: BlockBackend<TBl>>(
chain: config.chain_spec.name().to_owned(),
genesis_hash: format!("{:?}", genesis_hash),
authority: config.role.is_authority(),
startup_time: SystemTime::UNIX_EPOCH.elapsed()
startup_time: SystemTime::UNIX_EPOCH
.elapsed()
.map(|dur| dur.as_millis())
.unwrap_or(0).to_string(),
.unwrap_or(0)
.to_string(),
network_id: network.local_peer_id().to_base58(),
};
@@ -753,22 +740,28 @@ fn gen_handler<TBl, TBackend, TExPool, TRpc, TCl>(
remote_blockchain: Option<Arc<dyn RemoteBlockchain<TBl>>>,
rpc_extensions_builder: &(dyn RpcExtensionBuilder<Output = TRpc> + Send),
offchain_storage: Option<<TBackend as sc_client_api::backend::Backend<TBl>>::OffchainStorage>,
system_rpc_tx: TracingUnboundedSender<sc_rpc::system::Request<TBl>>
system_rpc_tx: TracingUnboundedSender<sc_rpc::system::Request<TBl>>,
) -> sc_rpc_server::RpcHandler<sc_rpc::Metadata>
where
TBl: BlockT,
TCl: ProvideRuntimeApi<TBl> + BlockchainEvents<TBl> + HeaderBackend<TBl> +
HeaderMetadata<TBl, Error=sp_blockchain::Error> + ExecutorProvider<TBl> +
CallApiAt<TBl> + ProofProvider<TBl> +
StorageProvider<TBl, TBackend> + BlockBackend<TBl> + Send + Sync + 'static,
TExPool: MaintainedTransactionPool<Block=TBl, Hash = <TBl as BlockT>::Hash> + 'static,
TBackend: sc_client_api::backend::Backend<TBl> + 'static,
TRpc: sc_rpc::RpcExtension<sc_rpc::Metadata>,
<TCl as ProvideRuntimeApi<TBl>>::Api:
sp_session::SessionKeys<TBl> +
sp_api::Metadata<TBl>,
where
TBl: BlockT,
TCl: ProvideRuntimeApi<TBl>
+ BlockchainEvents<TBl>
+ HeaderBackend<TBl>
+ HeaderMetadata<TBl, Error = sp_blockchain::Error>
+ ExecutorProvider<TBl>
+ CallApiAt<TBl>
+ ProofProvider<TBl>
+ StorageProvider<TBl, TBackend>
+ BlockBackend<TBl>
+ Send
+ Sync
+ 'static,
TExPool: MaintainedTransactionPool<Block = TBl, Hash = <TBl as BlockT>::Hash> + 'static,
TBackend: sc_client_api::backend::Backend<TBl> + 'static,
TRpc: sc_rpc::RpcExtension<sc_rpc::Metadata>,
<TCl as ProvideRuntimeApi<TBl>>::Api: sp_session::SessionKeys<TBl> + sp_api::Metadata<TBl>,
{
use sc_rpc::{chain, state, author, system, offchain};
use sc_rpc::{author, chain, offchain, state, system};
let system_info = sc_rpc::system::SystemInfo {
chain_name: config.chain_spec.name().into(),
@@ -781,43 +774,37 @@ fn gen_handler<TBl, TBackend, TExPool, TRpc, TCl>(
let task_executor = sc_rpc::SubscriptionTaskExecutor::new(spawn_handle);
let subscriptions = SubscriptionManager::new(Arc::new(task_executor.clone()));
let (chain, state, child_state) = if let (Some(remote_blockchain), Some(on_demand)) =
(remote_blockchain, on_demand) {
// Light clients
let chain = sc_rpc::chain::new_light(
client.clone(),
subscriptions.clone(),
remote_blockchain.clone(),
on_demand.clone(),
);
let (state, child_state) = sc_rpc::state::new_light(
client.clone(),
subscriptions.clone(),
remote_blockchain.clone(),
on_demand,
deny_unsafe,
);
(chain, state, child_state)
let (chain, state, child_state) =
if let (Some(remote_blockchain), Some(on_demand)) = (remote_blockchain, on_demand) {
// Light clients
let chain = sc_rpc::chain::new_light(
client.clone(),
subscriptions.clone(),
remote_blockchain.clone(),
on_demand.clone(),
);
let (state, child_state) = sc_rpc::state::new_light(
client.clone(),
subscriptions.clone(),
remote_blockchain.clone(),
on_demand,
deny_unsafe,
);
(chain, state, child_state)
} else {
// Full nodes
let chain = sc_rpc::chain::new_full(client.clone(), subscriptions.clone());
let (state, child_state) = sc_rpc::state::new_full(
client.clone(),
subscriptions.clone(),
deny_unsafe,
config.rpc_max_payload,
);
(chain, state, child_state)
};
} else {
// Full nodes
let chain = sc_rpc::chain::new_full(client.clone(), subscriptions.clone());
let (state, child_state) = sc_rpc::state::new_full(
client.clone(),
subscriptions.clone(),
deny_unsafe,
config.rpc_max_payload,
);
(chain, state, child_state)
};
let author = sc_rpc::author::Author::new(
client,
transaction_pool,
subscriptions,
keystore,
deny_unsafe,
);
let author =
sc_rpc::author::Author::new(client, transaction_pool, subscriptions, keystore, deny_unsafe);
let system = system::System::new(system_info, system_rpc_tx, deny_unsafe);
let maybe_offchain_rpc = offchain_storage.map(|storage| {
@@ -835,7 +822,7 @@ fn gen_handler<TBl, TBackend, TExPool, TRpc, TCl>(
system::SystemApi::to_delegate(system),
rpc_extensions_builder.build(deny_unsafe, task_executor),
),
rpc_middleware
rpc_middleware,
)
}
@@ -854,32 +841,42 @@ pub struct BuildNetworkParams<'a, TBl: BlockT, TExPool, TImpQu, TCl> {
/// An optional, shared data fetcher for light clients.
pub on_demand: Option<Arc<OnDemand<TBl>>>,
/// A block announce validator builder.
pub block_announce_validator_builder: Option<Box<
dyn FnOnce(Arc<TCl>) -> Box<dyn BlockAnnounceValidator<TBl> + Send> + Send
>>,
pub block_announce_validator_builder:
Option<Box<dyn FnOnce(Arc<TCl>) -> Box<dyn BlockAnnounceValidator<TBl> + Send> + Send>>,
}
/// Build the network service, the network status sinks and an RPC sender.
pub fn build_network<TBl, TExPool, TImpQu, TCl>(
params: BuildNetworkParams<TBl, TExPool, TImpQu, TCl>
params: BuildNetworkParams<TBl, TExPool, TImpQu, TCl>,
) -> Result<
(
Arc<NetworkService<TBl, <TBl as BlockT>::Hash>>,
TracingUnboundedSender<sc_rpc::system::Request<TBl>>,
NetworkStarter,
),
Error
Error,
>
where
TBl: BlockT,
TCl: ProvideRuntimeApi<TBl> + HeaderMetadata<TBl, Error=sp_blockchain::Error> + Chain<TBl> +
BlockBackend<TBl> + BlockIdTo<TBl, Error=sp_blockchain::Error> + ProofProvider<TBl> +
HeaderBackend<TBl> + BlockchainEvents<TBl> + 'static,
TExPool: MaintainedTransactionPool<Block=TBl, Hash = <TBl as BlockT>::Hash> + 'static,
TImpQu: ImportQueue<TBl> + 'static,
where
TBl: BlockT,
TCl: ProvideRuntimeApi<TBl>
+ HeaderMetadata<TBl, Error = sp_blockchain::Error>
+ Chain<TBl>
+ BlockBackend<TBl>
+ BlockIdTo<TBl, Error = sp_blockchain::Error>
+ ProofProvider<TBl>
+ HeaderBackend<TBl>
+ BlockchainEvents<TBl>
+ 'static,
TExPool: MaintainedTransactionPool<Block = TBl, Hash = <TBl as BlockT>::Hash> + 'static,
TImpQu: ImportQueue<TBl> + 'static,
{
let BuildNetworkParams {
config, client, transaction_pool, spawn_handle, import_queue, on_demand,
config,
client,
transaction_pool,
spawn_handle,
import_queue,
on_demand,
block_announce_validator_builder,
} = params;
@@ -906,8 +903,8 @@ pub fn build_network<TBl, TExPool, TImpQu, TCl>(
let (handler, protocol_config) = BlockRequestHandler::new(
&protocol_id,
client.clone(),
config.network.default_peers_set.in_peers as usize
+ config.network.default_peers_set.out_peers as usize,
config.network.default_peers_set.in_peers as usize +
config.network.default_peers_set.out_peers as usize,
);
spawn_handle.spawn("block_request_handler", handler.run());
protocol_config
@@ -923,8 +920,8 @@ pub fn build_network<TBl, TExPool, TImpQu, TCl>(
let (handler, protocol_config) = StateRequestHandler::new(
&protocol_id,
client.clone(),
config.network.default_peers_set.in_peers as usize
+ config.network.default_peers_set.out_peers as usize,
config.network.default_peers_set.in_peers as usize +
config.network.default_peers_set.out_peers as usize,
);
spawn_handle.spawn("state_request_handler", handler.run());
protocol_config
@@ -937,10 +934,8 @@ pub fn build_network<TBl, TExPool, TImpQu, TCl>(
light_client_requests::generate_protocol_config(&protocol_id)
} else {
// Allow both outgoing and incoming requests.
let (handler, protocol_config) = LightClientRequestHandler::new(
&protocol_id,
client.clone(),
);
let (handler, protocol_config) =
LightClientRequestHandler::new(&protocol_id, client.clone());
spawn_handle.spawn("light_client_request_handler", handler.run());
protocol_config
}
@@ -962,7 +957,7 @@ pub fn build_network<TBl, TExPool, TImpQu, TCl>(
},
network_config: config.network.clone(),
chain: client.clone(),
on_demand: on_demand,
on_demand,
transaction_pool: transaction_pool_adapter as _,
import_queue: Box::new(import_queue),
protocol_id,
@@ -976,10 +971,8 @@ pub fn build_network<TBl, TExPool, TImpQu, TCl>(
// Storage chains don't keep full block history and can't be synced in full mode.
// Force fast sync when storage chain mode is enabled.
if matches!(config.transaction_storage, TransactionStorageMode::StorageChain) {
network_params.network_config.sync_mode = SyncMode::Fast {
storage_chain_mode: true,
skip_proofs: false,
};
network_params.network_config.sync_mode =
SyncMode::Fast { storage_chain_mode: true, skip_proofs: false };
}
let has_bootnodes = !network_params.network_config.boot_nodes.is_empty();
@@ -1028,7 +1021,7 @@ pub fn build_network<TBl, TExPool, TImpQu, TCl>(
);
// This `return` might seem unnecessary, but we don't want to make it look like
// everything is working as normal even though the user is clearly misusing the API.
return;
return
}
future.await
@@ -17,22 +17,20 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::error::Error;
use futures::{future, prelude::*};
use sp_runtime::traits::Block as BlockT;
use sp_runtime::generic::BlockId;
use codec::Encode;
use sp_consensus::import_queue::ImportQueue;
use futures::{future, prelude::*};
use sc_client_api::{BlockBackend, UsageProvider};
use sp_consensus::import_queue::ImportQueue;
use sp_runtime::{generic::BlockId, traits::Block as BlockT};
use std::pin::Pin;
use std::sync::Arc;
use crate::chain_ops::import_blocks;
use std::{pin::Pin, sync::Arc};
/// Re-validate known block.
pub fn check_block<B, IQ, C>(
client: Arc<C>,
import_queue: IQ,
block_id: BlockId<B>
block_id: BlockId<B>,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send>>
where
C: BlockBackend<B> + UsageProvider<B> + Send + Sync + 'static,
@@ -46,7 +44,7 @@ where
block.encode_to(&mut buf);
let reader = std::io::Cursor::new(buf);
import_blocks(client, import_queue, reader, true, true)
}
},
Ok(None) => Box::pin(future::err("Unknown block".into())),
Err(e) => Box::pin(future::err(format!("Error reading block: {:?}", e).into())),
}
@@ -17,18 +17,16 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::error::Error;
use log::info;
use futures::{future, prelude::*};
use sp_runtime::traits::{
Block as BlockT, NumberFor, One, Zero, SaturatedConversion
};
use sp_runtime::generic::BlockId;
use codec::Encode;
use futures::{future, prelude::*};
use log::info;
use sp_runtime::{
generic::BlockId,
traits::{Block as BlockT, NumberFor, One, SaturatedConversion, Zero},
};
use std::{io::Write, pin::Pin};
use sc_client_api::{BlockBackend, UsageProvider};
use std::sync::Arc;
use std::task::Poll;
use std::{io::Write, pin::Pin, sync::Arc, task::Poll};
/// Performs the blocks export.
pub fn export_blocks<B, C>(
@@ -36,7 +34,7 @@ pub fn export_blocks<B, C>(
mut output: impl Write + 'static,
from: NumberFor<B>,
to: Option<NumberFor<B>>,
binary: bool
binary: bool,
) -> Pin<Box<dyn Future<Output = Result<(), Error>>>>
where
C: BlockBackend<B> + UsageProvider<B> + 'static,
@@ -63,7 +61,7 @@ where
let client = &client;
if last < block {
return Poll::Ready(Err("Invalid block range specified".into()));
return Poll::Ready(Err("Invalid block range specified".into()))
}
if !wrote_header {
@@ -78,14 +76,13 @@ where
}
match client.block(&BlockId::number(block))? {
Some(block) => {
Some(block) =>
if binary {
output.write_all(&block.encode())?;
} else {
serde_json::to_writer(&mut output, &block)
.map_err(|e| format!("Error writing JSON: {}", e))?;
}
},
},
// Reached end of the chain.
None => return Poll::Ready(Ok(())),
}
@@ -93,7 +90,7 @@ where
info!("#{}", block);
}
if block == last {
return Poll::Ready(Ok(()));
return Poll::Ready(Ok(()))
}
block += One::one();
@@ -17,10 +17,9 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::error::Error;
use sp_runtime::traits::Block as BlockT;
use sp_runtime::generic::BlockId;
use sp_core::storage::{StorageKey, well_known_keys, ChildInfo, Storage, StorageChild, StorageMap};
use sc_client_api::{StorageProvider, UsageProvider};
use sp_core::storage::{well_known_keys, ChildInfo, Storage, StorageChild, StorageKey, StorageMap};
use sp_runtime::{generic::BlockId, traits::Block as BlockT};
use std::{collections::HashMap, sync::Arc};
@@ -35,9 +34,7 @@ where
B: BlockT,
BA: sc_client_api::backend::Backend<B>,
{
let block = block.unwrap_or_else(
|| BlockId::Hash(client.usage_info().chain.best_hash)
);
let block = block.unwrap_or_else(|| BlockId::Hash(client.usage_info().chain.best_hash));
let empty_key = StorageKey(Vec::new());
let mut top_storage = client.storage_pairs(&block, &empty_key)?;
@@ -47,12 +44,12 @@ where
// pairs.
while let Some(pos) = top_storage
.iter()
.position(|(k, _)| k.0.starts_with(well_known_keys::DEFAULT_CHILD_STORAGE_KEY_PREFIX)) {
.position(|(k, _)| k.0.starts_with(well_known_keys::DEFAULT_CHILD_STORAGE_KEY_PREFIX))
{
let (key, _) = top_storage.swap_remove(pos);
let key = StorageKey(
key.0[well_known_keys::DEFAULT_CHILD_STORAGE_KEY_PREFIX.len()..].to_vec(),
);
let key =
StorageKey(key.0[well_known_keys::DEFAULT_CHILD_STORAGE_KEY_PREFIX.len()..].to_vec());
let child_info = ChildInfo::new_default(&key.0);
let keys = client.child_storage_keys(&block, &child_info, &empty_key)?;
@@ -16,29 +16,31 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::error;
use crate::error::Error;
use sc_chain_spec::ChainSpec;
use log::{warn, info};
use futures::{future, prelude::*};
use sp_runtime::traits::{
Block as BlockT, NumberFor, Zero, Header, MaybeSerializeDeserialize,
};
use sp_runtime::generic::SignedBlock;
use crate::{error, error::Error};
use codec::{Decode, IoReader as CodecIoReader};
use futures::{future, prelude::*};
use log::{info, warn};
use sc_chain_spec::ChainSpec;
use sp_consensus::{
import_queue::{BlockImportError, BlockImportResult, ImportQueue, IncomingBlock, Link},
BlockOrigin,
import_queue::{IncomingBlock, Link, BlockImportError, BlockImportResult, ImportQueue},
};
use sp_runtime::{
generic::SignedBlock,
traits::{Block as BlockT, Header, MaybeSerializeDeserialize, NumberFor, Zero},
};
use std::{io::{Read, Seek}, pin::Pin};
use std::time::{Duration, Instant};
use futures_timer::Delay;
use std::task::Poll;
use serde_json::{de::IoRead as JsonIoRead, Deserializer, StreamDeserializer};
use std::convert::{TryFrom, TryInto};
use sp_runtime::traits::{CheckedDiv, Saturating};
use sc_client_api::UsageProvider;
use serde_json::{de::IoRead as JsonIoRead, Deserializer, StreamDeserializer};
use sp_runtime::traits::{CheckedDiv, Saturating};
use std::{
convert::{TryFrom, TryInto},
io::{Read, Seek},
pin::Pin,
task::Poll,
time::{Duration, Instant},
};
/// Number of blocks we will add to the queue before waiting for the queue to catch up.
const MAX_PENDING_BLOCKS: u64 = 1_024;
@@ -56,11 +58,11 @@ pub fn build_spec(spec: &dyn ChainSpec, raw: bool) -> error::Result<String> {
spec.as_json(raw).map_err(Into::into)
}
/// Helper enum that wraps either a binary decoder (from parity-scale-codec), or a JSON decoder
/// (from serde_json). Implements the Iterator Trait, calling `next()` will decode the next
/// SignedBlock and return it.
enum BlockIter<R, B> where
enum BlockIter<R, B>
where
R: std::io::Read + std::io::Seek,
{
Binary {
@@ -79,7 +81,8 @@ enum BlockIter<R, B> where
},
}
impl<R, B> BlockIter<R, B> where
impl<R, B> BlockIter<R, B>
where
R: Read + Seek + 'static,
B: BlockT + MaybeSerializeDeserialize,
{
@@ -90,40 +93,32 @@ impl<R, B> BlockIter<R, B> where
// of blocks that are going to be decoded. We read it and add it to our enum struct.
let num_expected_blocks: u64 = Decode::decode(&mut reader)
.map_err(|e| format!("Failed to decode the number of blocks: {:?}", e))?;
Ok(BlockIter::Binary {
num_expected_blocks,
read_block_count: 0,
reader,
})
Ok(BlockIter::Binary { num_expected_blocks, read_block_count: 0, reader })
} else {
let stream_deser = Deserializer::from_reader(input)
.into_iter::<SignedBlock<B>>();
Ok(BlockIter::Json {
reader: stream_deser,
read_block_count: 0,
})
let stream_deser = Deserializer::from_reader(input).into_iter::<SignedBlock<B>>();
Ok(BlockIter::Json { reader: stream_deser, read_block_count: 0 })
}
}
/// Returns the number of blocks read thus far.
fn read_block_count(&self) -> u64 {
match self {
BlockIter::Binary { read_block_count, .. }
| BlockIter::Json { read_block_count, .. }
=> *read_block_count,
BlockIter::Binary { read_block_count, .. } |
BlockIter::Json { read_block_count, .. } => *read_block_count,
}
}
/// Returns the total number of blocks to be imported, if possible.
fn num_expected_blocks(&self) -> Option<u64> {
match self {
BlockIter::Binary { num_expected_blocks, ..} => Some(*num_expected_blocks),
BlockIter::Json {..} => None
BlockIter::Binary { num_expected_blocks, .. } => Some(*num_expected_blocks),
BlockIter::Json { .. } => None,
}
}
}
impl<R, B> Iterator for BlockIter<R, B> where
impl<R, B> Iterator for BlockIter<R, B>
where
R: Read + Seek + 'static,
B: BlockT + MaybeSerializeDeserialize,
{
@@ -133,20 +128,20 @@ impl<R, B> Iterator for BlockIter<R, B> where
match self {
BlockIter::Binary { num_expected_blocks, read_block_count, reader } => {
if read_block_count < num_expected_blocks {
let block_result: Result<SignedBlock::<B>, _> = SignedBlock::<B>::decode(reader)
.map_err(|e| e.to_string());
let block_result: Result<SignedBlock<B>, _> =
SignedBlock::<B>::decode(reader).map_err(|e| e.to_string());
*read_block_count += 1;
Some(block_result)
} else {
// `read_block_count` == `num_expected_blocks` so we've read enough blocks.
None
}
}
},
BlockIter::Json { reader, read_block_count } => {
let res = Some(reader.next()?.map_err(|e| e.to_string()));
*read_block_count += 1;
res
}
},
}
}
}
@@ -155,7 +150,7 @@ impl<R, B> Iterator for BlockIter<R, B> where
fn import_block_to_queue<TBl, TImpQu>(
signed_block: SignedBlock<TBl>,
queue: &mut TImpQu,
force: bool
force: bool,
) where
TBl: BlockT + MaybeSerializeDeserialize,
TImpQu: 'static + ImportQueue<TBl>,
@@ -163,8 +158,9 @@ fn import_block_to_queue<TBl, TImpQu>(
let (header, extrinsics) = signed_block.block.deconstruct();
let hash = header.hash();
// import queue handles verification and importing it into the client.
queue.import_blocks(BlockOrigin::File, vec![
IncomingBlock::<TBl> {
queue.import_blocks(
BlockOrigin::File,
vec![IncomingBlock::<TBl> {
hash,
header: Some(header),
body: Some(extrinsics),
@@ -175,15 +171,15 @@ fn import_block_to_queue<TBl, TImpQu>(
import_existing: force,
state: None,
skip_execution: false,
}
]);
}],
);
}
/// Returns true if we have imported every block we were supposed to import, else returns false.
fn importing_is_done(
num_expected_blocks: Option<u64>,
read_block_count: u64,
imported_blocks: u64
imported_blocks: u64,
) -> bool {
if let Some(num_expected_blocks) = num_expected_blocks {
imported_blocks >= num_expected_blocks
@@ -209,7 +205,7 @@ impl<B: BlockT> Speedometer<B> {
}
}
/// Calculates `(best_number - last_number) / (now - last_update)` and
/// Calculates `(best_number - last_number) / (now - last_update)` and
/// logs the speed of import.
fn display_speed(&self) {
// Number of milliseconds elapsed since last time.
@@ -223,24 +219,28 @@ impl<B: BlockT> Speedometer<B> {
// Number of blocks that have been imported since last time.
let diff = match self.last_number {
None => return,
Some(n) => self.best_number.saturating_sub(n)
Some(n) => self.best_number.saturating_sub(n),
};
if let Ok(diff) = TryInto::<u128>::try_into(diff) {
// If the number of blocks can be converted to a regular integer, then it's easy: just
// do the math and turn it into a `f64`.
let speed = diff.saturating_mul(10_000).checked_div(u128::from(elapsed_ms))
.map_or(0.0, |s| s as f64) / 10.0;
let speed = diff
.saturating_mul(10_000)
.checked_div(u128::from(elapsed_ms))
.map_or(0.0, |s| s as f64) /
10.0;
info!("📦 Current best block: {} ({:4.1} bps)", self.best_number, speed);
} else {
// If the number of blocks can't be converted to a regular integer, then we need a more
// algebraic approach and we stay within the realm of integers.
let one_thousand = NumberFor::<B>::from(1_000u32);
let elapsed = NumberFor::<B>::from(
<u32 as TryFrom<_>>::try_from(elapsed_ms).unwrap_or(u32::MAX)
);
let elapsed =
NumberFor::<B>::from(<u32 as TryFrom<_>>::try_from(elapsed_ms).unwrap_or(u32::MAX));
let speed = diff.saturating_mul(one_thousand).checked_div(&elapsed)
let speed = diff
.saturating_mul(one_thousand)
.checked_div(&elapsed)
.unwrap_or_else(Zero::zero);
info!("📦 Current best block: {} ({} bps)", self.best_number, speed)
}
@@ -265,22 +265,23 @@ impl<B: BlockT> Speedometer<B> {
}
/// Different State that the `import_blocks` future could be in.
enum ImportState<R, B> where
enum ImportState<R, B>
where
R: Read + Seek + 'static,
B: BlockT + MaybeSerializeDeserialize,
{
/// We are reading from the BlockIter structure, adding those blocks to the queue if possible.
Reading{block_iter: BlockIter<R, B>},
Reading { block_iter: BlockIter<R, B> },
/// The queue is full (contains at least MAX_PENDING_BLOCKS blocks) and we are waiting for it to
/// catch up.
WaitingForImportQueueToCatchUp{
WaitingForImportQueueToCatchUp {
block_iter: BlockIter<R, B>,
delay: Delay,
block: SignedBlock<B>
block: SignedBlock<B>,
},
// We have added all the blocks to the queue but they are still being processed.
WaitingForImportQueueToFinish{
num_expected_blocks: Option<u64>,
WaitingForImportQueueToFinish {
num_expected_blocks: Option<u64>,
read_block_count: u64,
delay: Delay,
},
@@ -306,10 +307,7 @@ where
impl WaitLink {
fn new() -> WaitLink {
WaitLink {
imported_blocks: 0,
has_error: false,
}
WaitLink { imported_blocks: 0, has_error: false }
}
}
@@ -318,7 +316,7 @@ where
&mut self,
imported: usize,
_num_expected_blocks: usize,
results: Vec<(Result<BlockImportResult<NumberFor<B>>, BlockImportError>, B::Hash)>
results: Vec<(Result<BlockImportResult<NumberFor<B>>, BlockImportError>, B::Hash)>,
) {
self.imported_blocks += imported as u64;
@@ -326,7 +324,7 @@ where
if let (Err(err), hash) = result {
warn!("There was an error importing block with hash {:?}: {:?}", hash, err);
self.has_error = true;
break;
break
}
}
}
@@ -338,13 +336,13 @@ where
let block_iter = match block_iter_res {
Ok(block_iter) => block_iter,
Err(e) => {
// We've encountered an error while creating the block iterator
// We've encountered an error while creating the block iterator
// so we can just return a future that returns an error.
return future::ready(Err(Error::Other(e))).boxed()
}
},
};
let mut state = Some(ImportState::Reading{block_iter});
let mut state = Some(ImportState::Reading { block_iter });
let mut speedometer = Speedometer::<B>::new();
// Importing blocks is implemented as a future, because we want the operation to be
@@ -358,7 +356,7 @@ where
let client = &client;
let queue = &mut import_queue;
match state.take().expect("state should never be None; qed") {
ImportState::Reading{mut block_iter} => {
ImportState::Reading { mut block_iter } => {
match block_iter.next() {
None => {
// The iterator is over: we now need to wait for the import queue to finish.
@@ -366,7 +364,9 @@ where
let read_block_count = block_iter.read_block_count();
let delay = Delay::new(Duration::from_millis(DELAY_TIME));
state = Some(ImportState::WaitingForImportQueueToFinish {
num_expected_blocks, read_block_count, delay
num_expected_blocks,
read_block_count,
delay,
});
},
Some(block_result) => {
@@ -378,32 +378,35 @@ where
// until the queue has made some progress.
let delay = Delay::new(Duration::from_millis(DELAY_TIME));
state = Some(ImportState::WaitingForImportQueueToCatchUp {
block_iter, delay, block
block_iter,
delay,
block,
});
} else {
// Queue is not full, we can keep on adding blocks to the queue.
import_block_to_queue(block, queue, force);
state = Some(ImportState::Reading{block_iter});
state = Some(ImportState::Reading { block_iter });
}
}
Err(e) => {
return Poll::Ready(
Err(Error::Other(
format!("Error reading block #{}: {}", read_block_count, e)
)))
}
},
Err(e) =>
return Poll::Ready(Err(Error::Other(format!(
"Error reading block #{}: {}",
read_block_count, e
)))),
}
}
},
}
},
ImportState::WaitingForImportQueueToCatchUp{block_iter, mut delay, block} => {
ImportState::WaitingForImportQueueToCatchUp { block_iter, mut delay, block } => {
let read_block_count = block_iter.read_block_count();
if read_block_count - link.imported_blocks >= MAX_PENDING_BLOCKS {
// Queue is still full, so wait until there is room to insert our block.
match Pin::new(&mut delay).poll(cx) {
Poll::Pending => {
state = Some(ImportState::WaitingForImportQueueToCatchUp {
block_iter, delay, block
block_iter,
delay,
block,
});
return Poll::Pending
},
@@ -412,25 +415,30 @@ where
},
}
state = Some(ImportState::WaitingForImportQueueToCatchUp {
block_iter, delay, block
block_iter,
delay,
block,
});
} else {
// Queue is no longer full, so we can add our block to the queue.
import_block_to_queue(block, queue, force);
// Switch back to Reading state.
state = Some(ImportState::Reading{block_iter});
state = Some(ImportState::Reading { block_iter });
}
},
ImportState::WaitingForImportQueueToFinish {
num_expected_blocks, read_block_count, mut delay
num_expected_blocks,
read_block_count,
mut delay,
} => {
// All the blocks have been added to the queue, which doesn't mean they
// All the blocks have been added to the queue, which doesn't mean they
// have all been properly imported.
if importing_is_done(num_expected_blocks, read_block_count, link.imported_blocks) {
// Importing is done, we can log the result and return.
info!(
"🎉 Imported {} blocks. Best: #{}",
read_block_count, client.usage_info().chain.best_number
read_block_count,
client.usage_info().chain.best_number
);
return Poll::Ready(Ok(()))
} else {
@@ -439,7 +447,9 @@ where
match Pin::new(&mut delay).poll(cx) {
Poll::Pending => {
state = Some(ImportState::WaitingForImportQueueToFinish {
num_expected_blocks, read_block_count, delay
num_expected_blocks,
read_block_count,
delay,
});
return Poll::Pending
},
@@ -449,10 +459,12 @@ where
}
state = Some(ImportState::WaitingForImportQueueToFinish {
num_expected_blocks, read_block_count, delay
num_expected_blocks,
read_block_count,
delay,
});
}
}
},
}
queue.poll_actions(cx, &mut link);
@@ -461,11 +473,10 @@ where
speedometer.notify_user(best_number);
if link.has_error {
return Poll::Ready(Err(
Error::Other(
format!("Stopping after #{} blocks because of an error", link.imported_blocks)
)
))
return Poll::Ready(Err(Error::Other(format!(
"Stopping after #{} blocks because of an error",
link.imported_blocks
))))
}
cx.waker().wake_by_ref();
@@ -18,15 +18,15 @@
use crate::error::Error;
use log::info;
use sp_runtime::traits::{Block as BlockT, NumberFor, Zero};
use sc_client_api::{Backend, UsageProvider};
use sp_runtime::traits::{Block as BlockT, NumberFor, Zero};
use std::sync::Arc;
/// Performs a revert of `blocks` blocks.
pub fn revert_chain<B, BA, C>(
client: Arc<C>,
backend: Arc<BA>,
blocks: NumberFor<B>
blocks: NumberFor<B>,
) -> Result<(), Error>
where
B: BlockT,
@@ -20,11 +20,9 @@
use std::collections::{HashMap, HashSet};
use sp_runtime::{
traits::{Block as BlockT, NumberFor},
};
use sp_runtime::traits::{Block as BlockT, NumberFor};
use sc_client_api::{ForkBlocks, BadBlocks};
use sc_client_api::{BadBlocks, ForkBlocks};
/// Chain specification rules lookup result.
pub enum LookupResult<B: BlockT> {
@@ -33,7 +31,7 @@ pub enum LookupResult<B: BlockT> {
/// The block is known to be bad and should not be imported
KnownBad,
/// There is a specified canonical block hash for the given height
Expected(B::Hash)
Expected(B::Hash),
}
/// Chain-specific block filtering rules.
@@ -47,10 +45,7 @@ pub struct BlockRules<B: BlockT> {
impl<B: BlockT> BlockRules<B> {
/// New block rules with provided black and white lists.
pub fn new(
fork_blocks: ForkBlocks<B>,
bad_blocks: BadBlocks<B>,
) -> Self {
pub fn new(fork_blocks: ForkBlocks<B>, bad_blocks: BadBlocks<B>) -> Self {
Self {
bad: bad_blocks.unwrap_or_else(|| HashSet::new()),
forks: fork_blocks.unwrap_or_else(|| vec![]).into_iter().collect(),
@@ -66,7 +61,7 @@ impl<B: BlockT> BlockRules<B> {
pub fn lookup(&self, number: NumberFor<B>, hash: &B::Hash) -> LookupResult<B> {
if let Some(hash_for_height) = self.forks.get(&number) {
if hash_for_height != hash {
return LookupResult::Expected(hash_for_height.clone());
return LookupResult::Expected(hash_for_height.clone())
}
}
@@ -16,23 +16,25 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use std::{sync::Arc, panic::UnwindSafe, result, cell::RefCell};
use codec::{Encode, Decode};
use super::{client::ClientConfig, wasm_override::WasmOverride, wasm_substitutes::WasmSubstitutes};
use codec::{Decode, Encode};
use sc_client_api::{backend, call_executor::CallExecutor};
use sc_executor::{NativeVersion, RuntimeInfo, RuntimeVersion};
use sp_api::{ProofRecorder, StorageTransactionCache};
use sp_core::{
traits::{CodeExecutor, RuntimeCode, SpawnNamed},
NativeOrEncoded, NeverNativeValue,
};
use sp_externalities::Extensions;
use sp_runtime::{
generic::BlockId, traits::{Block as BlockT, HashFor, NumberFor},
generic::BlockId,
traits::{Block as BlockT, HashFor, NumberFor},
};
use sp_state_machine::{
self, OverlayedChanges, Ext, ExecutionManager, StateMachine, ExecutionStrategy,
backend::Backend as _, StorageProof,
self, backend::Backend as _, ExecutionManager, ExecutionStrategy, Ext, OverlayedChanges,
StateMachine, StorageProof,
};
use sc_executor::{RuntimeVersion, RuntimeInfo, NativeVersion};
use sp_externalities::Extensions;
use sp_core::{
NativeOrEncoded, NeverNativeValue, traits::{CodeExecutor, SpawnNamed, RuntimeCode},
};
use sp_api::{ProofRecorder, StorageTransactionCache};
use sc_client_api::{backend, call_executor::CallExecutor};
use super::{client::ClientConfig, wasm_override::WasmOverride, wasm_substitutes::WasmSubstitutes};
use std::{cell::RefCell, panic::UnwindSafe, result, sync::Arc};
/// Call executor that executes methods locally, querying all required
/// data from local backend.
@@ -57,7 +59,8 @@ where
spawn_handle: Box<dyn SpawnNamed>,
client_config: ClientConfig<Block>,
) -> sp_blockchain::Result<Self> {
let wasm_override = client_config.wasm_runtime_overrides
let wasm_override = client_config
.wasm_runtime_overrides
.as_ref()
.map(|p| WasmOverride::new(p.clone(), executor.clone()))
.transpose()?;
@@ -91,10 +94,12 @@ where
B: backend::Backend<Block>,
{
let spec = self.runtime_version(id)?.spec_version;
let code = if let Some(d) = self.wasm_override
let code = if let Some(d) = self
.wasm_override
.as_ref()
.map(|o| o.get(&spec, onchain_code.heap_pages))
.flatten() {
.flatten()
{
log::debug!(target: "wasm_overrides", "using WASM override for block {}", id);
d
} else if let Some(s) = self.wasm_substitutes.get(spec, onchain_code.heap_pages, id) {
@@ -113,7 +118,10 @@ where
}
}
impl<Block: BlockT, B, E> Clone for LocalCallExecutor<Block, B, E> where E: Clone {
impl<Block: BlockT, B, E> Clone for LocalCallExecutor<Block, B, E>
where
E: Clone,
{
fn clone(&self) -> Self {
LocalCallExecutor {
backend: self.backend.clone(),
@@ -145,13 +153,12 @@ where
extensions: Option<Extensions>,
) -> sp_blockchain::Result<Vec<u8>> {
let mut changes = OverlayedChanges::default();
let changes_trie = backend::changes_tries_state_at_block(
id, self.backend.changes_trie_storage()
)?;
let changes_trie =
backend::changes_tries_state_at_block(id, self.backend.changes_trie_storage())?;
let state = self.backend.state_at(*id)?;
let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&state);
let runtime_code = state_runtime_code.runtime_code()
.map_err(sp_blockchain::Error::RuntimeCode)?;
let runtime_code =
state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?;
let runtime_code = self.check_override(runtime_code, id)?;
let return_data = StateMachine::new(
@@ -164,7 +171,8 @@ where
extensions.unwrap_or_default(),
&runtime_code,
self.spawn_handle.clone(),
).execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>(
)
.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>(
strategy.get_manager(),
None,
)?;
@@ -175,7 +183,7 @@ where
fn contextual_call<
EM: Fn(
Result<NativeOrEncoded<R>, Self::Error>,
Result<NativeOrEncoded<R>, Self::Error>
Result<NativeOrEncoded<R>, Self::Error>,
) -> Result<NativeOrEncoded<R>, Self::Error>,
R: Encode + Decode + PartialEq,
NC: FnOnce() -> result::Result<R, sp_api::ApiError> + UnwindSafe,
@@ -185,15 +193,17 @@ where
method: &str,
call_data: &[u8],
changes: &RefCell<OverlayedChanges>,
storage_transaction_cache: Option<&RefCell<
StorageTransactionCache<Block, B::State>
>>,
storage_transaction_cache: Option<&RefCell<StorageTransactionCache<Block, B::State>>>,
execution_manager: ExecutionManager<EM>,
native_call: Option<NC>,
recorder: &Option<ProofRecorder<Block>>,
extensions: Option<Extensions>,
) -> Result<NativeOrEncoded<R>, sp_blockchain::Error> where ExecutionManager<EM>: Clone {
let changes_trie_state = backend::changes_tries_state_at_block(at, self.backend.changes_trie_storage())?;
) -> Result<NativeOrEncoded<R>, sp_blockchain::Error>
where
ExecutionManager<EM>: Clone,
{
let changes_trie_state =
backend::changes_tries_state_at_block(at, self.backend.changes_trie_storage())?;
let mut storage_transaction_cache = storage_transaction_cache.map(|c| c.borrow_mut());
let mut state = self.backend.state_at(*at)?;
@@ -202,16 +212,17 @@ where
match recorder {
Some(recorder) => {
let trie_state = state.as_trie_backend()
.ok_or_else(||
Box::new(sp_state_machine::ExecutionError::UnableToGenerateProof) as Box<dyn sp_state_machine::Error>
)?;
let trie_state = state.as_trie_backend().ok_or_else(|| {
Box::new(sp_state_machine::ExecutionError::UnableToGenerateProof)
as Box<dyn sp_state_machine::Error>
})?;
let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(trie_state);
let state_runtime_code =
sp_state_machine::backend::BackendRuntimeCode::new(trie_state);
// It is important to extract the runtime code here before we create the proof
// recorder.
let runtime_code = state_runtime_code.runtime_code()
.map_err(sp_blockchain::Error::RuntimeCode)?;
let runtime_code =
state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?;
let runtime_code = self.check_override(runtime_code, at)?;
let backend = sp_state_machine::ProvingBackend::new_with_recorder(
@@ -239,8 +250,8 @@ where
},
None => {
let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&state);
let runtime_code = state_runtime_code.runtime_code()
.map_err(sp_blockchain::Error::RuntimeCode)?;
let runtime_code =
state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?;
let runtime_code = self.check_override(runtime_code, at)?;
let mut state_machine = StateMachine::new(
@@ -253,34 +264,31 @@ where
extensions.unwrap_or_default(),
&runtime_code,
self.spawn_handle.clone(),
).with_storage_transaction_cache(storage_transaction_cache.as_mut().map(|c| &mut **c));
)
.with_storage_transaction_cache(
storage_transaction_cache.as_mut().map(|c| &mut **c),
);
state_machine.execute_using_consensus_failure_handler(
execution_manager,
native_call.map(|n| || (n)().map_err(|e| Box::new(e) as Box<_>)),
)
}
}.map_err(Into::into)
},
}
.map_err(Into::into)
}
fn runtime_version(&self, id: &BlockId<Block>) -> sp_blockchain::Result<RuntimeVersion> {
let mut overlay = OverlayedChanges::default();
let changes_trie_state = backend::changes_tries_state_at_block(
id,
self.backend.changes_trie_storage(),
)?;
let changes_trie_state =
backend::changes_tries_state_at_block(id, self.backend.changes_trie_storage())?;
let state = self.backend.state_at(*id)?;
let mut cache = StorageTransactionCache::<Block, B::State>::default();
let mut ext = Ext::new(
&mut overlay,
&mut cache,
&state,
changes_trie_state,
None,
);
let mut ext = Ext::new(&mut overlay, &mut cache, &state, changes_trie_state, None);
let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&state);
let runtime_code = state_runtime_code.runtime_code()
.map_err(sp_blockchain::Error::RuntimeCode)?;
self.executor.runtime_version(&mut ext, &runtime_code)
let runtime_code =
state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?;
self.executor
.runtime_version(&mut ext, &runtime_code)
.map_err(|e| sp_blockchain::Error::VersionInvalid(format!("{:?}", e)).into())
}
@@ -289,11 +297,11 @@ where
trie_state: &sp_state_machine::TrieBackend<S, HashFor<Block>>,
overlay: &mut OverlayedChanges,
method: &str,
call_data: &[u8]
call_data: &[u8],
) -> Result<(Vec<u8>, StorageProof), sp_blockchain::Error> {
let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(trie_state);
let runtime_code = state_runtime_code.runtime_code()
.map_err(sp_blockchain::Error::RuntimeCode)?;
let runtime_code =
state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?;
sp_state_machine::prove_execution_on_trie_backend::<_, _, NumberFor<Block>, _, _>(
trie_state,
overlay,
@@ -312,19 +320,16 @@ where
}
impl<Block, B, E> sp_version::GetRuntimeVersion<Block> for LocalCallExecutor<Block, B, E>
where
B: backend::Backend<Block>,
E: CodeExecutor + RuntimeInfo + Clone + 'static,
Block: BlockT,
where
B: backend::Backend<Block>,
E: CodeExecutor + RuntimeInfo + Clone + 'static,
Block: BlockT,
{
fn native_version(&self) -> &sp_version::NativeVersion {
self.executor.native_version()
}
fn runtime_version(
&self,
at: &BlockId<Block>,
) -> Result<sp_version::RuntimeVersion, String> {
fn runtime_version(&self, at: &BlockId<Block>) -> Result<sp_version::RuntimeVersion, String> {
CallExecutor::runtime_version(self, at).map_err(|e| format!("{:?}", e))
}
}
@@ -332,10 +337,13 @@ impl<Block, B, E> sp_version::GetRuntimeVersion<Block> for LocalCallExecutor<Blo
#[cfg(test)]
mod tests {
use super::*;
use substrate_test_runtime_client::{LocalExecutor, GenesisInit, runtime};
use sc_executor::{NativeExecutor, WasmExecutionMethod};
use sp_core::{traits::{WrappedRuntimeCode, FetchRuntimeCode}, testing::TaskExecutor};
use sc_client_api::in_mem;
use sc_executor::{NativeExecutor, WasmExecutionMethod};
use sp_core::{
testing::TaskExecutor,
traits::{FetchRuntimeCode, WrappedRuntimeCode},
};
use substrate_test_runtime_client::{runtime, GenesisInit, LocalExecutor};
#[test]
fn should_get_override_if_exists() {
@@ -372,7 +380,8 @@ mod tests {
None,
None,
Default::default(),
).expect("Creates a client");
)
.expect("Creates a client");
let call_executor = LocalCallExecutor {
backend: backend.clone(),
@@ -384,10 +393,12 @@ mod tests {
Default::default(),
executor.clone(),
backend.clone(),
).unwrap(),
)
.unwrap(),
};
let check = call_executor.check_override(onchain_code, &BlockId::Number(Default::default()))
let check = call_executor
.check_override(onchain_code, &BlockId::Number(Default::default()))
.expect("RuntimeCode override");
assert_eq!(Some(vec![2, 2, 2, 2, 2, 2, 2, 2]), check.fetch_runtime_code().map(Into::into));
File diff suppressed because it is too large Load Diff
+6 -11
View File
@@ -18,17 +18,12 @@
//! Tool for creating the genesis block.
use sp_runtime::traits::{Block as BlockT, Header as HeaderT, Hash as HashT, Zero};
use sp_runtime::traits::{Block as BlockT, Hash as HashT, Header as HeaderT, Zero};
/// Create a genesis block, given the initial storage.
pub fn construct_genesis_block<
Block: BlockT
> (
state_root: Block::Hash
) -> Block {
let extrinsics_root = <<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
Vec::new(),
);
pub fn construct_genesis_block<Block: BlockT>(state_root: Block::Hash) -> Block {
let extrinsics_root =
<<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(Vec::new());
Block::new(
<<Block as BlockT>::Header as HeaderT>::new(
@@ -36,8 +31,8 @@ pub fn construct_genesis_block<
extrinsics_root,
state_root,
Default::default(),
Default::default()
Default::default(),
),
Default::default()
Default::default(),
)
}
+26 -21
View File
@@ -20,15 +20,20 @@
use std::sync::Arc;
use sc_executor::RuntimeInfo;
use sp_core::traits::{CodeExecutor, SpawnNamed};
use sc_telemetry::TelemetryHandle;
use sp_runtime::BuildStorage;
use sp_runtime::traits::{Block as BlockT, HashFor};
use sp_blockchain::Result as ClientResult;
use prometheus_endpoint::Registry;
use sc_executor::RuntimeInfo;
use sc_telemetry::TelemetryHandle;
use sp_blockchain::Result as ClientResult;
use sp_core::traits::{CodeExecutor, SpawnNamed};
use sp_runtime::{
traits::{Block as BlockT, HashFor},
BuildStorage,
};
use super::{call_executor::LocalCallExecutor, client::{Client, ClientConfig}};
use super::{
call_executor::LocalCallExecutor,
client::{Client, ClientConfig},
};
use sc_client_api::light::Storage as BlockchainStorage;
use sc_light::{Backend, GenesisCallExecutor};
@@ -41,26 +46,26 @@ pub fn new_light<B, S, RA, E>(
prometheus_registry: Option<Registry>,
telemetry: Option<TelemetryHandle>,
) -> ClientResult<
Client<
Client<
Backend<S, HashFor<B>>,
GenesisCallExecutor<
Backend<S, HashFor<B>>,
GenesisCallExecutor<
Backend<S, HashFor<B>>,
LocalCallExecutor<B, Backend<S, HashFor<B>>, E>
>,
B,
RA
>
>
where
B: BlockT,
S: BlockchainStorage<B> + 'static,
E: CodeExecutor + RuntimeInfo + Clone + 'static,
LocalCallExecutor<B, Backend<S, HashFor<B>>, E>,
>,
B,
RA,
>,
>
where
B: BlockT,
S: BlockchainStorage<B> + 'static,
E: CodeExecutor + RuntimeInfo + Clone + 'static,
{
let local_executor = LocalCallExecutor::new(
backend.clone(),
code_executor,
spawn_handle.clone(),
ClientConfig::default()
ClientConfig::default(),
)?;
let executor = GenesisCallExecutor::new(backend.clone(), local_executor);
Client::new(
+5 -5
View File
@@ -45,11 +45,11 @@
//! the ways in which the runtime can interface with the outside. Any code that builds a `Client`
//! is responsible for putting the right marker.
pub mod genesis;
pub mod light;
mod block_rules;
mod call_executor;
mod client;
mod block_rules;
pub mod genesis;
pub mod light;
mod wasm_override;
mod wasm_substitutes;
@@ -58,5 +58,5 @@ pub use self::{
client::{Client, ClientConfig},
};
#[cfg(feature="test-helpers")]
pub use self::client::{new_with_backend, new_in_mem};
#[cfg(feature = "test-helpers")]
pub use self::client::{new_in_mem, new_with_backend};
@@ -35,18 +35,17 @@
//! A custom WASM blob will override on-chain WASM if the spec version matches. If it is
//! required to overrides multiple runtimes, multiple WASM blobs matching each of the spec versions
//! needed must be provided in the given directory.
//!
use std::{
fs, collections::{HashMap, hash_map::DefaultHasher},
path::{Path, PathBuf},
hash::Hasher as _,
};
use sp_core::traits::FetchRuntimeCode;
use sp_state_machine::BasicExternalities;
use sp_blockchain::Result;
use sc_executor::RuntimeInfo;
use sp_blockchain::Result;
use sp_core::traits::{FetchRuntimeCode, RuntimeCode};
use sp_state_machine::BasicExternalities;
use sp_version::RuntimeVersion;
use sp_core::traits::RuntimeCode;
use std::{
collections::{hash_map::DefaultHasher, HashMap},
fs,
hash::Hasher as _,
path::{Path, PathBuf},
};
#[derive(Clone, Debug, PartialEq)]
/// Auxiliary structure that holds a wasm blob and its hash.
@@ -62,11 +61,7 @@ impl WasmBlob {
}
fn runtime_code(&self, heap_pages: Option<u64>) -> RuntimeCode {
RuntimeCode {
code_fetcher: self,
hash: self.hash.clone(),
heap_pages,
}
RuntimeCode { code_fetcher: self, hash: self.hash.clone(), heap_pages }
}
}
@@ -117,7 +112,7 @@ pub struct WasmOverride<E> {
impl<E> WasmOverride<E>
where
E: RuntimeInfo + Clone + 'static
E: RuntimeInfo + Clone + 'static,
{
pub fn new<P>(path: P, executor: E) -> Result<Self>
where
@@ -130,26 +125,19 @@ where
/// Gets an override by it's runtime spec version.
///
/// Returns `None` if an override for a spec version does not exist.
pub fn get<'a, 'b: 'a>(
&'b self,
spec: &u32,
pages: Option<u64>,
) -> Option<RuntimeCode<'a>> {
self.overrides
.get(spec)
.map(|w| w.runtime_code(pages))
pub fn get<'a, 'b: 'a>(&'b self, spec: &u32, pages: Option<u64>) -> Option<RuntimeCode<'a>> {
self.overrides.get(spec).map(|w| w.runtime_code(pages))
}
/// Scrapes a folder for WASM runtimes.
/// Returns a hashmap of the runtime version and wasm runtime code.
fn scrape_overrides(dir: &Path, executor: &E) -> Result<HashMap<u32, WasmBlob>> {
let handle_err = |e: std::io::Error | -> sp_blockchain::Error {
let handle_err = |e: std::io::Error| -> sp_blockchain::Error {
WasmOverrideError::Io(dir.to_owned(), e).into()
};
if !dir.is_dir() {
return Err(WasmOverrideError::NotADirectory(dir.to_owned()).into());
return Err(WasmOverrideError::NotADirectory(dir.to_owned()).into())
}
let mut overrides = HashMap::new();
@@ -176,13 +164,13 @@ where
);
duplicates.push(format!("{}", path.display()));
}
}
_ => ()
},
_ => (),
}
}
if !duplicates.is_empty() {
return Err(WasmOverrideError::DuplicateRuntime(duplicates).into());
return Err(WasmOverrideError::DuplicateRuntime(duplicates).into())
}
Ok(overrides)
@@ -194,7 +182,8 @@ where
heap_pages: Option<u64>,
) -> Result<RuntimeVersion> {
let mut ext = BasicExternalities::default();
executor.runtime_version(&mut ext, &code.runtime_code(heap_pages))
executor
.runtime_version(&mut ext, &code.runtime_code(heap_pages))
.map_err(|e| WasmOverrideError::VersionInvalid(format!("{:?}", e)).into())
}
}
@@ -203,28 +192,25 @@ where
#[cfg(test)]
pub fn dummy_overrides<E>(executor: &E) -> WasmOverride<E>
where
E: RuntimeInfo + Clone + 'static
E: RuntimeInfo + Clone + 'static,
{
let mut overrides = HashMap::new();
overrides.insert(0, WasmBlob::new(vec![0, 0, 0, 0, 0, 0, 0, 0]));
overrides.insert(1, WasmBlob::new(vec![1, 1, 1, 1, 1, 1, 1, 1]));
overrides.insert(2, WasmBlob::new(vec![2, 2, 2, 2, 2, 2, 2, 2]));
WasmOverride {
overrides,
executor: executor.clone()
}
WasmOverride { overrides, executor: executor.clone() }
}
#[cfg(test)]
mod tests {
use super::*;
use sc_executor::{NativeExecutor, WasmExecutionMethod};
use substrate_test_runtime_client::LocalExecutor;
use std::fs::{self, File};
use substrate_test_runtime_client::LocalExecutor;
fn wasm_test<F>(fun: F)
where
F: Fn(&Path, &[u8], &NativeExecutor::<LocalExecutor>)
F: Fn(&Path, &[u8], &NativeExecutor<LocalExecutor>),
{
let exec = NativeExecutor::<substrate_test_runtime_client::LocalExecutor>::new(
WasmExecutionMethod::Interpreted,
@@ -252,8 +238,8 @@ mod tests {
fn should_scrape_wasm() {
wasm_test(|dir, wasm_bytes, exec| {
fs::write(dir.join("test.wasm"), wasm_bytes).expect("Create test file");
let overrides = WasmOverride::scrape_overrides(dir, exec)
.expect("HashMap of u32 and WasmBlob");
let overrides =
WasmOverride::scrape_overrides(dir, exec).expect("HashMap of u32 and WasmBlob");
let wasm = overrides.get(&2).expect("WASM binary");
assert_eq!(wasm.code, substrate_test_runtime::wasm_binary_unwrap().to_vec())
});
@@ -272,10 +258,10 @@ mod tests {
Some(WasmOverrideError::DuplicateRuntime(duplicates)) => {
assert_eq!(duplicates.len(), 1);
},
_ => panic!("Test should end with Msg Error Variant")
_ => panic!("Test should end with Msg Error Variant"),
}
},
_ => panic!("Test should end in error")
_ => panic!("Test should end in error"),
}
});
}
@@ -286,8 +272,8 @@ mod tests {
File::create(dir.join("README.md")).expect("Create test file");
File::create(dir.join("LICENSE")).expect("Create a test file");
fs::write(dir.join("test0.wasm"), wasm_bytes).expect("Create test file");
let scraped = WasmOverride::scrape_overrides(dir, exec)
.expect("HashMap of u32 and WasmBlob");
let scraped =
WasmOverride::scrape_overrides(dir, exec).expect("HashMap of u32 and WasmBlob");
assert_eq!(scraped.len(), 1);
});
}
@@ -18,15 +18,22 @@
//! # WASM substitutes
use std::{collections::{HashMap, hash_map::DefaultHasher}, hash::Hasher as _, sync::Arc};
use sp_core::traits::{FetchRuntimeCode, RuntimeCode};
use sp_state_machine::BasicExternalities;
use sp_blockchain::{Result, HeaderBackend};
use sc_executor::RuntimeInfo;
use sp_version::RuntimeVersion;
use sc_client_api::backend;
use sp_runtime::{traits::{NumberFor, Block as BlockT}, generic::BlockId};
use parking_lot::RwLock;
use sc_client_api::backend;
use sc_executor::RuntimeInfo;
use sp_blockchain::{HeaderBackend, Result};
use sp_core::traits::{FetchRuntimeCode, RuntimeCode};
use sp_runtime::{
generic::BlockId,
traits::{Block as BlockT, NumberFor},
};
use sp_state_machine::BasicExternalities;
use sp_version::RuntimeVersion;
use std::{
collections::{hash_map::DefaultHasher, HashMap},
hash::Hasher as _,
sync::Arc,
};
/// A wasm substitute for the on chain wasm.
#[derive(Debug)]
@@ -51,11 +58,7 @@ impl<Block: BlockT> WasmSubstitute<Block> {
}
fn runtime_code(&self, heap_pages: Option<u64>) -> RuntimeCode {
RuntimeCode {
code_fetcher: self,
hash: self.hash.clone(),
heap_pages,
}
RuntimeCode { code_fetcher: self, hash: self.hash.clone(), heap_pages }
}
/// Returns `true` when the substitute matches for the given `block_id`.
@@ -82,7 +85,8 @@ impl<Block: BlockT> WasmSubstitute<Block> {
block_number
};
let requested_block_number = backend.blockchain().block_number_from_id(&block_id).ok().flatten();
let requested_block_number =
backend.blockchain().block_number_from_id(&block_id).ok().flatten();
Some(block_number) <= requested_block_number
}
@@ -145,11 +149,14 @@ where
executor: Executor,
backend: Arc<Backend>,
) -> Result<Self> {
let substitutes = substitutes.into_iter().map(|(parent_block_hash, code)| {
let substitute = WasmSubstitute::new(code, parent_block_hash, &*backend)?;
let version = Self::runtime_version(&executor, &substitute)?;
Ok((version.spec_version, substitute))
}).collect::<Result<HashMap<_, _>>>()?;
let substitutes = substitutes
.into_iter()
.map(|(parent_block_hash, code)| {
let substitute = WasmSubstitute::new(code, parent_block_hash, &*backend)?;
let version = Self::runtime_version(&executor, &substitute)?;
Ok((version.spec_version, substitute))
})
.collect::<Result<HashMap<_, _>>>()?;
Ok(Self { executor, substitutes: Arc::new(substitutes), backend })
}
@@ -172,8 +179,8 @@ where
code: &WasmSubstitute<Block>,
) -> Result<RuntimeVersion> {
let mut ext = BasicExternalities::default();
executor.runtime_version(&mut ext, &code.runtime_code(None))
executor
.runtime_version(&mut ext, &code.runtime_code(None))
.map_err(|e| WasmSubstituteError::VersionInvalid(format!("{:?}", e)).into())
}
}
+31 -22
View File
@@ -18,25 +18,34 @@
//! Service configuration.
pub use sc_client_api::execution_extensions::{ExecutionStrategies, ExecutionStrategy};
pub use sc_client_db::{
Database, PruningMode, DatabaseSettingsSrc as DatabaseConfig,
KeepBlocks, TransactionStorageMode
};
pub use sc_network::Multiaddr;
pub use sc_network::config::{
ExtTransport, MultiaddrWithPeerId, NetworkConfiguration, Role, NodeKeyConfig,
SetConfig, NonDefaultSetConfig, TransportConfig,
RequestResponseConfig, IncomingRequest, OutgoingResponse,
Database, DatabaseSettingsSrc as DatabaseConfig, KeepBlocks, PruningMode,
TransactionStorageMode,
};
pub use sc_executor::WasmExecutionMethod;
pub use sc_client_api::execution_extensions::{ExecutionStrategies, ExecutionStrategy};
pub use sc_network::{
config::{
ExtTransport, IncomingRequest, MultiaddrWithPeerId, NetworkConfiguration, NodeKeyConfig,
NonDefaultSetConfig, OutgoingResponse, RequestResponseConfig, Role, SetConfig,
TransportConfig,
},
Multiaddr,
};
use std::{io, future::Future, path::{PathBuf, Path}, pin::Pin, net::SocketAddr, sync::Arc};
pub use sc_transaction_pool::Options as TransactionPoolOptions;
use sc_chain_spec::ChainSpec;
use sp_core::crypto::SecretString;
pub use sc_telemetry::TelemetryEndpoints;
use prometheus_endpoint::Registry;
use sc_chain_spec::ChainSpec;
pub use sc_telemetry::TelemetryEndpoints;
pub use sc_transaction_pool::Options as TransactionPoolOptions;
use sp_core::crypto::SecretString;
use std::{
future::Future,
io,
net::SocketAddr,
path::{Path, PathBuf},
pin::Pin,
sync::Arc,
};
#[cfg(not(target_os = "unknown"))]
use tempfile::TempDir;
@@ -153,7 +162,7 @@ pub enum KeystoreConfig {
/// The path of the keystore.
path: PathBuf,
/// Node keystore's password.
password: Option<SecretString>
password: Option<SecretString>,
},
/// In-memory keystore. Recommended for in-browser nodes.
InMemory,
@@ -194,7 +203,7 @@ impl PrometheusConfig {
Self {
port,
registry: Registry::new_custom(Some("substrate".into()), None)
.expect("this can only fail if the prefix is empty")
.expect("this can only fail if the prefix is empty"),
}
}
}
@@ -215,11 +224,13 @@ impl Configuration {
let protocol_id_full = match self.chain_spec.protocol_id() {
Some(pid) => pid,
None => {
log::warn!("Using default protocol ID {:?} because none is configured in the \
chain specs", crate::DEFAULT_PROTOCOL_ID
log::warn!(
"Using default protocol ID {:?} because none is configured in the \
chain specs",
crate::DEFAULT_PROTOCOL_ID
);
crate::DEFAULT_PROTOCOL_ID
}
},
};
sc_network::config::ProtocolId::from(protocol_id_full)
}
@@ -261,9 +272,7 @@ impl BasePath {
/// instance is dropped.
#[cfg(not(target_os = "unknown"))]
pub fn new_temp_dir() -> io::Result<BasePath> {
Ok(BasePath::Temporary(
tempfile::Builder::new().prefix("substrate").tempdir()?,
))
Ok(BasePath::Temporary(tempfile::Builder::new().prefix("substrate").tempdir()?))
}
/// Create a `BasePath` instance based on an existing path on disk.
+2 -2
View File
@@ -18,10 +18,10 @@
//! Errors that can occur during the service operation.
use sc_network;
use sc_keystore;
use sp_consensus;
use sc_network;
use sp_blockchain;
use sp_consensus;
/// Service Result typedef.
pub type Result<T> = std::result::Result<T, Error>;
+137 -122
View File
@@ -22,65 +22,62 @@
#![warn(missing_docs)]
#![recursion_limit = "1024"]
pub mod config;
pub mod chain_ops;
pub mod config;
pub mod error;
mod metrics;
mod builder;
#[cfg(feature = "test-helpers")]
pub mod client;
#[cfg(not(feature = "test-helpers"))]
mod client;
mod metrics;
mod task_manager;
use std::{io, pin::Pin};
use std::net::SocketAddr;
use std::collections::HashMap;
use std::task::Poll;
use std::{collections::HashMap, io, net::SocketAddr, pin::Pin, task::Poll};
use futures::{Future, FutureExt, Stream, StreamExt, stream, compat::*};
use sc_network::PeerId;
use log::{warn, debug, error};
use codec::{Encode, Decode};
use sp_runtime::generic::BlockId;
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
use codec::{Decode, Encode};
use futures::{compat::*, stream, Future, FutureExt, Stream, StreamExt};
use log::{debug, error, warn};
use parity_util_mem::MallocSizeOf;
use sc_network::PeerId;
use sp_runtime::{
generic::BlockId,
traits::{Block as BlockT, Header as HeaderT},
};
use sp_utils::mpsc::TracingUnboundedReceiver;
pub use self::error::Error;
pub use self::builder::{
new_full_client, new_db_backend, new_client, new_full_parts, new_light_parts,
spawn_tasks, build_network, build_offchain_workers,
BuildNetworkParams, KeystoreContainer, NetworkStarter, SpawnTasksParams, TFullClient, TLightClient,
TFullBackend, TLightBackend, TLightBackendWithHash, TLightClientWithBackend,
TFullCallExecutor, TLightCallExecutor, RpcExtensionBuilder, NoopRpcExtensionBuilder,
pub use self::{
builder::{
build_network, build_offchain_workers, new_client, new_db_backend, new_full_client,
new_full_parts, new_light_parts, spawn_tasks, BuildNetworkParams, KeystoreContainer,
NetworkStarter, NoopRpcExtensionBuilder, RpcExtensionBuilder, SpawnTasksParams,
TFullBackend, TFullCallExecutor, TFullClient, TLightBackend, TLightBackendWithHash,
TLightCallExecutor, TLightClient, TLightClientWithBackend,
},
client::{ClientConfig, LocalCallExecutor},
error::Error,
};
pub use config::{
BasePath, Configuration, DatabaseConfig, PruningMode, Role, RpcMethods, TaskExecutor, TaskType,
KeepBlocks, TransactionStorageMode,
BasePath, Configuration, DatabaseConfig, KeepBlocks, PruningMode, Role, RpcMethods,
TaskExecutor, TaskType, TransactionStorageMode,
};
pub use sc_chain_spec::{
ChainSpec, GenericChainSpec, Properties, RuntimeGenesis, Extension as ChainSpecExtension,
NoExtension, ChainType,
ChainSpec, ChainType, Extension as ChainSpecExtension, GenericChainSpec, NoExtension,
Properties, RuntimeGenesis,
};
pub use sc_transaction_pool_api::{TransactionPool, InPoolTransaction, error::IntoPoolError};
pub use sc_transaction_pool::Options as TransactionPoolOptions;
pub use sc_rpc::Metadata as RpcMetadata;
use sc_client_api::{blockchain::HeaderBackend, BlockchainEvents};
pub use sc_executor::NativeExecutionDispatch;
#[doc(hidden)]
pub use std::{ops::Deref, result::Result, sync::Arc};
#[doc(hidden)]
pub use sc_network::config::{
OnDemand, TransactionImport,
TransactionImportFuture,
};
pub use sc_network::config::{OnDemand, TransactionImport, TransactionImportFuture};
pub use sc_rpc::Metadata as RpcMetadata;
pub use sc_tracing::TracingReceiver;
pub use task_manager::SpawnTaskHandle;
pub use task_manager::TaskManager;
pub use sc_transaction_pool::Options as TransactionPoolOptions;
pub use sc_transaction_pool_api::{error::IntoPoolError, InPoolTransaction, TransactionPool};
pub use sp_consensus::import_queue::ImportQueue;
pub use self::client::{LocalCallExecutor, ClientConfig};
use sc_client_api::{blockchain::HeaderBackend, BlockchainEvents};
#[doc(hidden)]
pub use std::{ops::Deref, result::Result, sync::Arc};
pub use task_manager::{SpawnTaskHandle, TaskManager};
const DEFAULT_PROTOCOL_ID: &str = "sup";
@@ -96,7 +93,9 @@ impl<T> MallocSizeOfWasm for T {}
/// RPC handlers that can perform RPC queries.
#[derive(Clone)]
pub struct RpcHandlers(Arc<jsonrpc_core::MetaIoHandler<sc_rpc::Metadata, sc_rpc_server::RpcMiddleware>>);
pub struct RpcHandlers(
Arc<jsonrpc_core::MetaIoHandler<sc_rpc::Metadata, sc_rpc_server::RpcMiddleware>>,
);
impl RpcHandlers {
/// Starts an RPC query.
@@ -108,17 +107,22 @@ impl RpcHandlers {
///
/// If the request subscribes you to events, the `Sender` in the `RpcSession` object is used to
/// send back spontaneous events.
pub fn rpc_query(&self, mem: &RpcSession, request: &str)
-> Pin<Box<dyn Future<Output = Option<String>> + Send>> {
self.0.handle_request(request, mem.metadata.clone())
pub fn rpc_query(
&self,
mem: &RpcSession,
request: &str,
) -> Pin<Box<dyn Future<Output = Option<String>> + Send>> {
self.0
.handle_request(request, mem.metadata.clone())
.compat()
.map(|res| res.expect("this should never fail"))
.boxed()
}
/// Provides access to the underlying `MetaIoHandler`
pub fn io_handler(&self)
-> Arc<jsonrpc_core::MetaIoHandler<sc_rpc::Metadata, sc_rpc_server::RpcMiddleware>> {
pub fn io_handler(
&self,
) -> Arc<jsonrpc_core::MetaIoHandler<sc_rpc::Metadata, sc_rpc_server::RpcMiddleware>> {
self.0.clone()
}
}
@@ -149,8 +153,8 @@ pub struct PartialComponents<Client, Backend, SelectChain, ImportQueue, Transact
async fn build_network_future<
B: BlockT,
C: BlockchainEvents<B> + HeaderBackend<B>,
H: sc_network::ExHashT
> (
H: sc_network::ExHashT,
>(
role: Role,
mut network: sc_network::NetworkWorker<B, H>,
client: Arc<C>,
@@ -171,7 +175,9 @@ async fn build_network_future<
// ready. This way, we only get the latest finalized block.
stream::poll_fn(move |cx| {
let mut last = None;
while let Poll::Ready(Some(item)) = Pin::new(&mut finality_notification_stream).poll_next(cx) {
while let Poll::Ready(Some(item)) =
Pin::new(&mut finality_notification_stream).poll_next(cx)
{
last = Some(item);
}
if let Some(last) = last {
@@ -179,11 +185,12 @@ async fn build_network_future<
} else {
Poll::Pending
}
}).fuse()
})
.fuse()
};
loop {
futures::select!{
futures::select! {
// List of blocks that the client has imported.
notification = imported_blocks_stream.next() => {
let notification = match notification {
@@ -338,79 +345,90 @@ mod waiting {
/// Starts RPC servers that run in their own thread, and returns an opaque object that keeps them alive.
#[cfg(not(target_os = "unknown"))]
fn start_rpc_servers<
H: FnMut(sc_rpc::DenyUnsafe, sc_rpc_server::RpcMiddleware)
-> sc_rpc_server::RpcHandler<sc_rpc::Metadata>
H: FnMut(
sc_rpc::DenyUnsafe,
sc_rpc_server::RpcMiddleware,
) -> sc_rpc_server::RpcHandler<sc_rpc::Metadata>,
>(
config: &Configuration,
mut gen_handler: H,
rpc_metrics: sc_rpc_server::RpcMetrics,
) -> Result<Box<dyn std::any::Any + Send + Sync>, error::Error> {
fn maybe_start_server<T, F>(address: Option<SocketAddr>, mut start: F) -> Result<Option<T>, io::Error>
where F: FnMut(&SocketAddr) -> Result<T, io::Error>,
{
address.map(|mut address| start(&address)
.or_else(|e| match e.kind() {
io::ErrorKind::AddrInUse |
io::ErrorKind::PermissionDenied => {
fn maybe_start_server<T, F>(
address: Option<SocketAddr>,
mut start: F,
) -> Result<Option<T>, io::Error>
where
F: FnMut(&SocketAddr) -> Result<T, io::Error>,
{
address
.map(|mut address| {
start(&address).or_else(|e| match e.kind() {
io::ErrorKind::AddrInUse | io::ErrorKind::PermissionDenied => {
warn!("Unable to bind RPC server to {}. Trying random port.", address);
address.set_port(0);
start(&address)
},
_ => Err(e),
}
) ).transpose()
}
})
})
.transpose()
}
fn deny_unsafe(addr: &SocketAddr, methods: &RpcMethods) -> sc_rpc::DenyUnsafe {
let is_exposed_addr = !addr.ip().is_loopback();
match (is_exposed_addr, methods) {
| (_, RpcMethods::Unsafe)
| (false, RpcMethods::Auto) => sc_rpc::DenyUnsafe::No,
_ => sc_rpc::DenyUnsafe::Yes
| (_, RpcMethods::Unsafe) | (false, RpcMethods::Auto) => sc_rpc::DenyUnsafe::No,
_ => sc_rpc::DenyUnsafe::Yes,
}
}
Ok(Box::new((
config.rpc_ipc.as_ref().map(|path| sc_rpc_server::start_ipc(
&*path, gen_handler(
sc_rpc::DenyUnsafe::No,
sc_rpc_server::RpcMiddleware::new(rpc_metrics.clone(), "ipc")
config.rpc_ipc.as_ref().map(|path| {
sc_rpc_server::start_ipc(
&*path,
gen_handler(
sc_rpc::DenyUnsafe::No,
sc_rpc_server::RpcMiddleware::new(rpc_metrics.clone(), "ipc"),
),
)
)),
maybe_start_server(
config.rpc_http,
|address| sc_rpc_server::start_http(
}),
maybe_start_server(config.rpc_http, |address| {
sc_rpc_server::start_http(
address,
config.rpc_http_threads,
config.rpc_cors.as_ref(),
gen_handler(
deny_unsafe(&address, &config.rpc_methods),
sc_rpc_server::RpcMiddleware::new(rpc_metrics.clone(), "http")
sc_rpc_server::RpcMiddleware::new(rpc_metrics.clone(), "http"),
),
config.rpc_max_payload
),
)?.map(|s| waiting::HttpServer(Some(s))),
maybe_start_server(
config.rpc_ws,
|address| sc_rpc_server::start_ws(
config.rpc_max_payload,
)
})?
.map(|s| waiting::HttpServer(Some(s))),
maybe_start_server(config.rpc_ws, |address| {
sc_rpc_server::start_ws(
address,
config.rpc_ws_max_connections,
config.rpc_cors.as_ref(),
gen_handler(
deny_unsafe(&address, &config.rpc_methods),
sc_rpc_server::RpcMiddleware::new(rpc_metrics.clone(), "ws")
sc_rpc_server::RpcMiddleware::new(rpc_metrics.clone(), "ws"),
),
config.rpc_max_payload
),
)?.map(|s| waiting::WsServer(Some(s))),
config.rpc_max_payload,
)
})?
.map(|s| waiting::WsServer(Some(s))),
)))
}
/// Starts RPC servers that run in their own thread, and returns an opaque object that keeps them alive.
#[cfg(target_os = "unknown")]
fn start_rpc_servers<
H: FnMut(sc_rpc::DenyUnsafe, sc_rpc_server::RpcMiddleware)
-> sc_rpc_server::RpcHandler<sc_rpc::Metadata>
H: FnMut(
sc_rpc::DenyUnsafe,
sc_rpc_server::RpcMiddleware,
) -> sc_rpc_server::RpcHandler<sc_rpc::Metadata>,
>(
_: &Configuration,
_: H,
@@ -434,9 +452,7 @@ impl RpcSession {
///
/// The `RpcSession` must be kept alive in order to receive messages on the sender.
pub fn new(sender: futures01::sync::mpsc::Sender<String>) -> RpcSession {
RpcSession {
metadata: sender.into(),
}
RpcSession { metadata: sender.into() }
}
}
@@ -450,10 +466,9 @@ pub struct TransactionPoolAdapter<C, P> {
/// Get transactions for propagation.
///
/// Function extracted to simplify the test and prevent creating `ServiceFactory`.
fn transactions_to_propagate<Pool, B, H, E>(pool: &Pool)
-> Vec<(H, B::Extrinsic)>
fn transactions_to_propagate<Pool, B, H, E>(pool: &Pool) -> Vec<(H, B::Extrinsic)>
where
Pool: TransactionPool<Block=B, Hash=H, Error=E>,
Pool: TransactionPool<Block = B, Hash = H, Error = E>,
B: BlockT,
H: std::hash::Hash + Eq + sp_runtime::traits::Member + sp_runtime::traits::MaybeSerialize,
E: IntoPoolError + From<sc_transaction_pool_api::error::Error>,
@@ -468,11 +483,10 @@ where
.collect()
}
impl<B, H, C, Pool, E> sc_network::config::TransactionPool<H, B> for
TransactionPoolAdapter<C, Pool>
impl<B, H, C, Pool, E> sc_network::config::TransactionPool<H, B> for TransactionPoolAdapter<C, Pool>
where
C: sc_network::config::Client<B> + Send + Sync,
Pool: 'static + TransactionPool<Block=B, Hash=H, Error=E>,
Pool: 'static + TransactionPool<Block = B, Hash = H, Error = E>,
B: BlockT,
H: std::hash::Hash + Eq + sp_runtime::traits::Member + sp_runtime::traits::MaybeSerialize,
E: 'static + IntoPoolError + From<sc_transaction_pool_api::error::Error>,
@@ -485,10 +499,7 @@ where
self.pool.hash_of(transaction)
}
fn import(
&self,
transaction: B::Extrinsic,
) -> TransactionImportFuture {
fn import(&self, transaction: B::Extrinsic) -> TransactionImportFuture {
if !self.imports_external_transactions {
debug!("Transaction rejected");
Box::pin(futures::future::ready(TransactionImport::None));
@@ -499,28 +510,33 @@ where
Ok(uxt) => uxt,
Err(e) => {
debug!("Transaction invalid: {:?}", e);
return Box::pin(futures::future::ready(TransactionImport::Bad));
}
return Box::pin(futures::future::ready(TransactionImport::Bad))
},
};
let best_block_id = BlockId::hash(self.client.info().best_hash);
let import_future = self.pool.submit_one(&best_block_id, sc_transaction_pool_api::TransactionSource::External, uxt);
let import_future = self.pool.submit_one(
&best_block_id,
sc_transaction_pool_api::TransactionSource::External,
uxt,
);
Box::pin(async move {
match import_future.await {
Ok(_) => TransactionImport::NewGood,
Err(e) => match e.into_pool_error() {
Ok(sc_transaction_pool_api::error::Error::AlreadyImported(_)) => TransactionImport::KnownGood,
Ok(sc_transaction_pool_api::error::Error::AlreadyImported(_)) =>
TransactionImport::KnownGood,
Ok(e) => {
debug!("Error adding transaction to the pool: {:?}", e);
TransactionImport::Bad
}
},
Err(e) => {
debug!("Error converting pool error: {:?}", e);
// it is not bad at least, just some internal node logic error, so peer is innocent.
TransactionImport::KnownGood
}
}
},
},
}
})
}
@@ -530,11 +546,10 @@ where
}
fn transaction(&self, hash: &H) -> Option<B::Extrinsic> {
self.pool.ready_transaction(hash)
.and_then(
// Only propagable transactions should be resolved for network service.
|tx| if tx.is_propagable() { Some(tx.data().clone()) } else { None }
)
self.pool.ready_transaction(hash).and_then(
// Only propagable transactions should be resolved for network service.
|tx| if tx.is_propagable() { Some(tx.data().clone()) } else { None },
)
}
}
@@ -542,10 +557,13 @@ where
mod tests {
use super::*;
use futures::executor::block_on;
use sc_transaction_pool::BasicPool;
use sp_consensus::SelectChain;
use sp_runtime::traits::BlindCheckable;
use substrate_test_runtime_client::{prelude::*, runtime::{Extrinsic, Transfer}};
use sc_transaction_pool::BasicPool;
use substrate_test_runtime_client::{
prelude::*,
runtime::{Extrinsic, Transfer},
};
#[test]
fn should_not_propagate_transactions_that_are_marked_as_such() {
@@ -553,13 +571,8 @@ mod tests {
let (client, longest_chain) = TestClientBuilder::new().build_with_longest_chain();
let client = Arc::new(client);
let spawner = sp_core::testing::TaskExecutor::new();
let pool = BasicPool::new_full(
Default::default(),
true.into(),
None,
spawner,
client.clone(),
);
let pool =
BasicPool::new_full(Default::default(), true.into(), None, spawner, client.clone());
let source = sp_runtime::transaction_validity::TransactionSource::External;
let best = block_on(longest_chain.best_chain()).unwrap();
let transaction = Transfer {
@@ -569,12 +582,14 @@ mod tests {
to: Default::default(),
}
.into_signed_tx();
block_on(pool.submit_one(&BlockId::hash(best.hash()), source, transaction.clone()))
.unwrap();
block_on(pool.submit_one(
&BlockId::hash(best.hash()), source, transaction.clone()),
).unwrap();
block_on(pool.submit_one(
&BlockId::hash(best.hash()), source, Extrinsic::IncludeData(vec![1])),
).unwrap();
&BlockId::hash(best.hash()),
source,
Extrinsic::IncludeData(vec![1]),
))
.unwrap();
assert_eq!(pool.status().ready, 2);
// when
+86 -75
View File
@@ -20,16 +20,15 @@ use std::{convert::TryFrom, time::SystemTime};
use crate::config::Configuration;
use futures_timer::Delay;
use prometheus_endpoint::{register, Gauge, U64, Registry, PrometheusError, Opts, GaugeVec};
use sc_telemetry::{telemetry, TelemetryHandle, SUBSTRATE_INFO};
use sp_api::ProvideRuntimeApi;
use sp_runtime::traits::{NumberFor, Block, SaturatedConversion, UniqueSaturatedInto};
use sc_transaction_pool_api::{PoolStatus, MaintainedTransactionPool};
use sp_utils::metrics::register_globals;
use prometheus_endpoint::{register, Gauge, GaugeVec, Opts, PrometheusError, Registry, U64};
use sc_client_api::{ClientInfo, UsageProvider};
use sc_network::{config::Role, NetworkStatus, NetworkService};
use std::sync::Arc;
use std::time::Duration;
use sc_network::{config::Role, NetworkService, NetworkStatus};
use sc_telemetry::{telemetry, TelemetryHandle, SUBSTRATE_INFO};
use sc_transaction_pool_api::{MaintainedTransactionPool, PoolStatus};
use sp_api::ProvideRuntimeApi;
use sp_runtime::traits::{Block, NumberFor, SaturatedConversion, UniqueSaturatedInto};
use sp_utils::metrics::register_globals;
use std::{sync::Arc, time::Duration};
use wasm_timer::Instant;
struct PrometheusMetrics {
@@ -51,54 +50,74 @@ impl PrometheusMetrics {
version: &str,
roles: u64,
) -> Result<Self, PrometheusError> {
register(Gauge::<U64>::with_opts(
Opts::new(
"build_info",
"A metric with a constant '1' value labeled by name, version"
)
register(
Gauge::<U64>::with_opts(
Opts::new(
"build_info",
"A metric with a constant '1' value labeled by name, version",
)
.const_label("name", name)
.const_label("version", version)
)?, &registry)?.set(1);
.const_label("version", version),
)?,
&registry,
)?
.set(1);
register(Gauge::<U64>::new(
"node_roles", "The roles the node is running as",
)?, &registry)?.set(roles);
register(Gauge::<U64>::new("node_roles", "The roles the node is running as")?, &registry)?
.set(roles);
register_globals(registry)?;
let start_time_since_epoch = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)
.unwrap_or_default();
register(Gauge::<U64>::new(
"process_start_time_seconds",
"Number of seconds between the UNIX epoch and the moment the process started",
)?, registry)?.set(start_time_since_epoch.as_secs());
let start_time_since_epoch =
SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap_or_default();
register(
Gauge::<U64>::new(
"process_start_time_seconds",
"Number of seconds between the UNIX epoch and the moment the process started",
)?,
registry,
)?
.set(start_time_since_epoch.as_secs());
Ok(Self {
// generic internals
block_height: register(GaugeVec::new(
Opts::new("block_height", "Block height info of the chain"),
&["status"]
)?, registry)?,
block_height: register(
GaugeVec::new(
Opts::new("block_height", "Block height info of the chain"),
&["status"],
)?,
registry,
)?,
number_leaves: register(Gauge::new(
"number_leaves", "Number of known chain leaves (aka forks)",
)?, registry)?,
number_leaves: register(
Gauge::new("number_leaves", "Number of known chain leaves (aka forks)")?,
registry,
)?,
ready_transactions_number: register(Gauge::new(
"ready_transactions_number", "Number of transactions in the ready queue",
)?, registry)?,
ready_transactions_number: register(
Gauge::new(
"ready_transactions_number",
"Number of transactions in the ready queue",
)?,
registry,
)?,
// I/ O
database_cache: register(Gauge::new(
"database_cache_bytes", "RocksDB cache size in bytes",
)?, registry)?,
state_cache: register(Gauge::new(
"state_cache_bytes", "State cache size in bytes",
)?, registry)?,
state_db: register(GaugeVec::new(
Opts::new("state_db_cache_bytes", "State DB cache in bytes"),
&["subtype"]
)?, registry)?,
database_cache: register(
Gauge::new("database_cache_bytes", "RocksDB cache size in bytes")?,
registry,
)?,
state_cache: register(
Gauge::new("state_cache_bytes", "State cache size in bytes")?,
registry,
)?,
state_db: register(
GaugeVec::new(
Opts::new("state_db_cache_bytes", "State DB cache in bytes"),
&["subtype"],
)?,
registry,
)?,
})
}
}
@@ -179,11 +198,7 @@ impl MetricsService {
let net_status = network.status().await.ok();
// Update / Send the metrics.
self.update(
&client.usage_info(),
&transactions.status(),
net_status,
);
self.update(&client.usage_info(), &transactions.status(), net_status);
// Schedule next tick.
timer.reset(timer_interval);
@@ -220,14 +235,8 @@ impl MetricsService {
);
if let Some(metrics) = self.metrics.as_ref() {
metrics
.block_height
.with_label_values(&["finalized"])
.set(finalized_number);
metrics
.block_height
.with_label_values(&["best"])
.set(best_number);
metrics.block_height.with_label_values(&["finalized"]).set(finalized_number);
metrics.block_height.with_label_values(&["best"]).set(best_number);
if let Ok(leaves) = u64::try_from(info.chain.number_leaves) {
metrics.number_leaves.set(leaves);
@@ -239,15 +248,17 @@ impl MetricsService {
metrics.database_cache.set(info.memory.database_cache.as_bytes() as u64);
metrics.state_cache.set(info.memory.state_cache.as_bytes() as u64);
metrics.state_db.with_label_values(&["non_canonical"]).set(
info.memory.state_db.non_canonical.as_bytes() as u64,
);
metrics
.state_db
.with_label_values(&["non_canonical"])
.set(info.memory.state_db.non_canonical.as_bytes() as u64);
if let Some(pruning) = info.memory.state_db.pruning {
metrics.state_db.with_label_values(&["pruning"]).set(pruning.as_bytes() as u64);
}
metrics.state_db.with_label_values(&["pinned"]).set(
info.memory.state_db.pinned.as_bytes() as u64,
);
metrics
.state_db
.with_label_values(&["pinned"])
.set(info.memory.state_db.pinned.as_bytes() as u64);
}
}
@@ -259,14 +270,13 @@ impl MetricsService {
let diff_bytes_inbound = total_bytes_inbound - self.last_total_bytes_inbound;
let diff_bytes_outbound = total_bytes_outbound - self.last_total_bytes_outbound;
let (avg_bytes_per_sec_inbound, avg_bytes_per_sec_outbound) =
if elapsed > 0 {
self.last_total_bytes_inbound = total_bytes_inbound;
self.last_total_bytes_outbound = total_bytes_outbound;
(diff_bytes_inbound / elapsed, diff_bytes_outbound / elapsed)
} else {
(diff_bytes_inbound, diff_bytes_outbound)
};
let (avg_bytes_per_sec_inbound, avg_bytes_per_sec_outbound) = if elapsed > 0 {
self.last_total_bytes_inbound = total_bytes_inbound;
self.last_total_bytes_outbound = total_bytes_outbound;
(diff_bytes_inbound / elapsed, diff_bytes_outbound / elapsed)
} else {
(diff_bytes_inbound, diff_bytes_outbound)
};
telemetry!(
self.telemetry;
@@ -278,9 +288,10 @@ impl MetricsService {
);
if let Some(metrics) = self.metrics.as_ref() {
let best_seen_block: Option<u64> = net_status
.best_seen_block
.map(|num: NumberFor<T>| UniqueSaturatedInto::<u64>::unique_saturated_into(num));
let best_seen_block: Option<u64> =
net_status.best_seen_block.map(|num: NumberFor<T>| {
UniqueSaturatedInto::<u64>::unique_saturated_into(num)
});
if let Some(best_seen_block) = best_seen_block {
metrics.block_height.with_label_values(&["sync_target"]).set(best_seen_block);
@@ -18,22 +18,24 @@
//! Substrate service tasks management module.
use std::{panic, result::Result, pin::Pin};
use crate::{
config::{JoinFuture, TaskExecutor, TaskType},
Error,
};
use exit_future::Signal;
use log::{debug, error};
use futures::{
Future, FutureExt, StreamExt,
future::{select, Either, BoxFuture, join_all, try_join_all, pending},
future::{join_all, pending, select, try_join_all, BoxFuture, Either},
sink::SinkExt,
Future, FutureExt, StreamExt,
};
use log::{debug, error};
use prometheus_endpoint::{
exponential_buckets, register,
PrometheusError,
CounterVec, HistogramOpts, HistogramVec, Opts, Registry, U64
exponential_buckets, register, CounterVec, HistogramOpts, HistogramVec, Opts, PrometheusError,
Registry, U64,
};
use sp_utils::mpsc::{TracingUnboundedSender, TracingUnboundedReceiver, tracing_unbounded};
use sp_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender};
use std::{panic, pin::Pin, result::Result};
use tracing_futures::Instrument;
use crate::{config::{TaskExecutor, TaskType, JoinFuture}, Error};
mod prometheus_future;
#[cfg(test)]
@@ -62,7 +64,11 @@ impl SpawnTaskHandle {
}
/// Spawns the blocking task with the given name. See also `spawn`.
pub fn spawn_blocking(&self, name: &'static str, task: impl Future<Output = ()> + Send + 'static) {
pub fn spawn_blocking(
&self,
name: &'static str,
task: impl Future<Output = ()> + Send + 'static,
) {
self.spawn_inner(name, task, TaskType::Blocking)
}
@@ -75,7 +81,7 @@ impl SpawnTaskHandle {
) {
if self.task_notifier.is_closed() {
debug!("Attempt to spawn a new task has been prevented: {}", name);
return;
return
}
let on_exit = self.on_exit.clone();
@@ -95,7 +101,8 @@ impl SpawnTaskHandle {
let task = {
let poll_duration = metrics.poll_duration.with_label_values(&[name]);
let poll_start = metrics.poll_start.with_label_values(&[name]);
let inner = prometheus_future::with_poll_durations(poll_duration, poll_start, task);
let inner =
prometheus_future::with_poll_durations(poll_duration, poll_start, task);
// The logic of `AssertUnwindSafe` here is ok considering that we throw
// away the `Future` after it has panicked.
panic::AssertUnwindSafe(inner).catch_unwind()
@@ -106,16 +113,15 @@ impl SpawnTaskHandle {
Either::Right((Err(payload), _)) => {
metrics.tasks_ended.with_label_values(&[name, "panic"]).inc();
panic::resume_unwind(payload)
}
},
Either::Right((Ok(()), _)) => {
metrics.tasks_ended.with_label_values(&[name, "finished"]).inc();
}
},
Either::Left(((), _)) => {
// The `on_exit` has triggered.
metrics.tasks_ended.with_label_values(&[name, "interrupted"]).inc();
}
},
}
} else {
futures::pin_mut!(task);
let _ = select(on_exit, task).await;
@@ -162,10 +168,7 @@ impl SpawnEssentialTaskHandle {
essential_failed_tx: TracingUnboundedSender<()>,
spawn_task_handle: SpawnTaskHandle,
) -> SpawnEssentialTaskHandle {
SpawnEssentialTaskHandle {
essential_failed_tx,
inner: spawn_task_handle,
}
SpawnEssentialTaskHandle { essential_failed_tx, inner: spawn_task_handle }
}
/// Spawns the given task with the given name.
@@ -193,12 +196,10 @@ impl SpawnEssentialTaskHandle {
task_type: TaskType,
) {
let essential_failed = self.essential_failed_tx.clone();
let essential_task = std::panic::AssertUnwindSafe(task)
.catch_unwind()
.map(move |_| {
log::error!("Essential task `{}` failed. Shutting down service.", name);
let _ = essential_failed.close_channel();
});
let essential_task = std::panic::AssertUnwindSafe(task).catch_unwind().map(move |_| {
log::error!("Essential task `{}` failed. Shutting down service.", name);
let _ = essential_failed.close_channel();
});
let _ = self.inner.spawn_inner(name, essential_task, task_type);
}
@@ -260,10 +261,8 @@ impl TaskManager {
// NOTE: for_each_concurrent will await on all the JoinHandle futures at the same time. It
// is possible to limit this but it's actually better for the memory foot print to await
// them all to not accumulate anything on that stream.
let completion_future = executor.spawn(
Box::pin(background_tasks.for_each_concurrent(None, |x| x)),
TaskType::Async,
);
let completion_future = executor
.spawn(Box::pin(background_tasks.for_each_concurrent(None, |x| x)), TaskType::Async);
Ok(Self {
on_exit,
@@ -323,16 +322,21 @@ impl TaskManager {
///
/// This function will not wait until the end of the remaining task. You must call and await
/// `clean_shutdown()` after this.
pub fn future<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'a>> {
pub fn future<'a>(
&'a mut self,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'a>> {
Box::pin(async move {
let mut t1 = self.essential_failed_rx.next().fuse();
let mut t2 = self.on_exit.clone().fuse();
let mut t3 = try_join_all(
self.children.iter_mut().map(|x| x.future())
self.children
.iter_mut()
.map(|x| x.future())
// Never end this future if there is no error because if there is no children,
// it must not stop
.chain(std::iter::once(pending().boxed()))
).fuse();
.chain(std::iter::once(pending().boxed())),
)
.fuse();
futures::select! {
_ = t1 => Err(Error::Other("Essential task failed.".into())),
@@ -20,20 +20,20 @@
use futures::prelude::*;
use prometheus_endpoint::{Counter, Histogram, U64};
use std::{fmt, pin::Pin, task::{Context, Poll}};
use std::{
fmt,
pin::Pin,
task::{Context, Poll},
};
/// Wraps around a `Future`. Report the polling duration to the `Histogram` and when the polling
/// starts to the `Counter`.
pub fn with_poll_durations<T>(
poll_duration: Histogram,
poll_start: Counter<U64>,
inner: T
inner: T,
) -> PrometheusFuture<T> {
PrometheusFuture {
inner,
poll_duration,
poll_start,
}
PrometheusFuture { inner, poll_duration, poll_start }
}
/// Wraps around `Future` and adds diagnostics to it.
@@ -16,8 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::config::TaskExecutor;
use crate::task_manager::TaskManager;
use crate::{config::TaskExecutor, task_manager::TaskManager};
use futures::{future::FutureExt, pin_mut, select};
use parking_lot::Mutex;
use std::{any::Any, sync::Arc, time::Duration};
@@ -205,7 +204,9 @@ fn ensure_task_manager_future_ends_with_error_when_essential_task_fails() {
runtime.block_on(async { tokio::time::delay_for(Duration::from_secs(1)).await });
assert_eq!(drop_tester, 2);
spawn_essential_handle.spawn("task3", async { panic!("task failed") });
runtime.block_on(task_manager.future()).expect_err("future()'s Result must be Err");
runtime
.block_on(task_manager.future())
.expect_err("future()'s Result must be Err");
assert_eq!(drop_tester, 2);
runtime.block_on(task_manager.clean_shutdown());
assert_eq!(drop_tester, 0);
@@ -265,7 +266,9 @@ fn ensure_task_manager_future_ends_with_error_when_childs_essential_task_fails()
runtime.block_on(async { tokio::time::delay_for(Duration::from_secs(1)).await });
assert_eq!(drop_tester, 4);
spawn_essential_handle_child_1.spawn("task5", async { panic!("task failed") });
runtime.block_on(task_manager.future()).expect_err("future()'s Result must be Err");
runtime
.block_on(task_manager.future())
.expect_err("future()'s Result must be Err");
assert_eq!(drop_tester, 4);
runtime.block_on(task_manager.clean_shutdown());
assert_eq!(drop_tester, 0);