Use tokio runtime handle instead of TaskExecutor abstraction (#9737)

* Use tokio runtime handle instead of TaskExecutor abstraction

Before this pr we had the `TaskExecutor` abstraction which theoretically
allowed that any futures executor could have been used. However, this
was never tested and is currently not really required. Anyone running a
node currently only used tokio and nothing else (because this was hard
coded in CLI). So, this pr removes the `TaskExecutor` abstraction and
relies directly on the tokio runtime handle.

Besides this changes, this pr also makes sure that the http and ws rpc
server use the same tokio runtime. This fixes a panic that occurred when
you drop the rpc servers inside an async function (tokio doesn't like
that a tokio runtime is dropped in the async context of another tokio
runtime).

As we don't use any custom runtime in the http rpc server anymore, this
pr also removes the `rpc-http-threads` cli argument. If external parties
complain that there aren't enough threads for the rpc server, we could
bring support for increasing the thread count of the tokio runtime.

* FMT

* Fix try runtime

* Fix integration tests and some other optimizations

* Remove warnings
This commit is contained in:
Bastian Köcher
2021-09-12 14:29:11 +02:00
committed by GitHub
parent be69e4d2b2
commit c09d52ead7
31 changed files with 197 additions and 302 deletions
+2 -17
View File
@@ -36,18 +36,9 @@ fn parse_knobs(
let attrs = &input.attrs;
let vis = input.vis;
if sig.inputs.len() != 1 {
let msg = "the test function accepts only one argument of type sc_service::TaskExecutor";
return Err(syn::Error::new_spanned(&sig, msg))
if !sig.inputs.is_empty() {
return Err(syn::Error::new_spanned(&sig, "No arguments expected for tests."))
}
let (task_executor_name, task_executor_type) = match sig.inputs.pop().map(|x| x.into_value()) {
Some(syn::FnArg::Typed(x)) => (x.pat, x.ty),
_ => {
let msg =
"the test function accepts only one argument of type sc_service::TaskExecutor";
return Err(syn::Error::new_spanned(&sig, msg))
},
};
let crate_name = match crate_name("substrate-test-utils") {
Ok(FoundCrate::Itself) => syn::Ident::new("substrate_test_utils", Span::call_site().into()),
@@ -65,12 +56,6 @@ fn parse_knobs(
#header
#(#attrs)*
#vis #sig {
use #crate_name::futures::future::FutureExt;
let #task_executor_name: #task_executor_type = (|fut, _| {
#crate_name::tokio::spawn(fut).map(drop)
})
.into();
if #crate_name::tokio::time::timeout(
std::time::Duration::from_secs(
std::env::var("SUBSTRATE_TEST_TIMEOUT")
+2 -5
View File
@@ -19,8 +19,7 @@
#[doc(hidden)]
pub use futures;
/// Marks async function to be executed by an async runtime and provide a `TaskExecutor`,
/// suitable to test environment.
/// Marks async function to be executed by an async runtime suitable to test environment.
///
/// # Requirements
///
@@ -30,10 +29,8 @@ pub use futures;
///
/// ```
/// #[substrate_test_utils::test]
/// async fn basic_test(task_executor: TaskExecutor) {
/// async fn basic_test() {
/// assert!(true);
/// // create your node in here and use task_executor
/// // then don't forget to gracefully shutdown your node before exit
/// }
/// ```
pub use substrate_test_utils_derive::test;
+1 -1
View File
@@ -18,7 +18,7 @@
#[cfg(test)]
#[test_utils::test]
async fn basic_test(_: sc_service::TaskExecutor) {
async fn basic_test() {
assert!(true);
}
@@ -29,7 +29,7 @@ use sc_client_api::backend::Backend;
use sc_executor::NativeElseWasmExecutor;
use sc_service::{
build_network, new_full_parts, spawn_tasks, BuildNetworkParams, ChainSpec, Configuration,
SpawnTasksParams, TFullBackend, TFullClient, TaskExecutor, TaskManager,
SpawnTasksParams, TFullBackend, TFullClient, TaskManager,
};
use sc_transaction_pool::BasicPool;
use sc_transaction_pool_api::TransactionPool;
@@ -74,7 +74,7 @@ pub enum ConfigOrChainSpec {
/// Configuration object
Config(Configuration),
/// Chain spec object
ChainSpec(Box<dyn ChainSpec>, TaskExecutor),
ChainSpec(Box<dyn ChainSpec>, tokio::runtime::Handle),
}
/// Creates all the client parts you need for [`Node`](crate::node::Node)
pub fn client_parts<T>(
@@ -103,8 +103,8 @@ where
use sp_consensus_babe::AuthorityId;
let config = match config_or_chain_spec {
ConfigOrChainSpec::Config(config) => config,
ConfigOrChainSpec::ChainSpec(chain_spec, task_executor) =>
default_config(task_executor, chain_spec),
ConfigOrChainSpec::ChainSpec(chain_spec, tokio_handle) =>
default_config(tokio_handle, chain_spec),
};
let executor = NativeElseWasmExecutor::<T::ExecutorDispatch>::new(
+3 -19
View File
@@ -16,7 +16,6 @@
// 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 futures::FutureExt;
use sc_client_api::execution_extensions::ExecutionStrategies;
use sc_executor::WasmExecutionMethod;
use sc_informant::OutputFormat;
@@ -26,7 +25,7 @@ use sc_network::{
};
use sc_service::{
config::KeystoreConfig, BasePath, ChainSpec, Configuration, DatabaseSource, KeepBlocks,
TaskExecutor, TaskType, TransactionStorageMode,
TransactionStorageMode,
};
use sp_keyring::sr25519::Keyring::Alice;
use tokio::runtime::Handle;
@@ -43,10 +42,7 @@ pub fn base_path() -> BasePath {
}
/// Produces a default configuration object, suitable for use with most set ups.
pub fn default_config(
task_executor: TaskExecutor,
mut chain_spec: Box<dyn ChainSpec>,
) -> Configuration {
pub fn default_config(tokio_handle: Handle, mut chain_spec: Box<dyn ChainSpec>) -> Configuration {
let base_path = base_path();
let root_path = base_path.path().to_path_buf().join("chains").join(chain_spec.id());
@@ -75,7 +71,7 @@ pub fn default_config(
impl_name: "test-node".to_string(),
impl_version: "0.1".to_string(),
role: Role::Authority,
task_executor: task_executor.into(),
tokio_handle,
transaction_pool: Default::default(),
network: network_config,
keystore: KeystoreConfig::Path { path: root_path.join("key"), password: None },
@@ -95,7 +91,6 @@ pub fn default_config(
rpc_ws: None,
rpc_ipc: None,
rpc_ws_max_connections: None,
rpc_http_threads: None,
rpc_cors: None,
rpc_methods: Default::default(),
rpc_max_payload: None,
@@ -120,14 +115,3 @@ pub fn default_config(
transaction_storage: TransactionStorageMode::BlockBody,
}
}
/// Produce a task executor given a handle to a tokio runtime
pub fn task_executor(handle: Handle) -> TaskExecutor {
let task_executor = move |fut, task_type| match task_type {
TaskType::Async => handle.spawn(fut).map(drop),
TaskType::Blocking =>
handle.spawn_blocking(move || futures::executor::block_on(fut)).map(drop),
};
task_executor.into()
}
+4 -13
View File
@@ -16,28 +16,19 @@
// 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 sc_service::{TaskExecutor, TaskType};
#[substrate_test_utils::test]
async fn basic_test(_: TaskExecutor) {
async fn basic_test() {
assert!(true);
}
#[substrate_test_utils::test]
#[should_panic(expected = "boo!")]
async fn panicking_test(_: TaskExecutor) {
async fn panicking_test() {
panic!("boo!");
}
#[substrate_test_utils::test(flavor = "multi_thread", worker_threads = 1)]
async fn basic_test_with_args(_: TaskExecutor) {
assert!(true);
}
#[substrate_test_utils::test]
async fn rename_argument(ex: TaskExecutor) {
let ex2 = ex.clone();
ex2.spawn(Box::pin(async { () }), TaskType::Blocking);
async fn basic_test_with_args() {
assert!(true);
}
@@ -47,7 +38,7 @@ async fn rename_argument(ex: TaskExecutor) {
#[substrate_test_utils::test]
#[should_panic(expected = "test took too long")]
#[ignore]
async fn timeout(_: TaskExecutor) {
async fn timeout() {
tokio::time::sleep(std::time::Duration::from_secs(
std::env::var("SUBSTRATE_TEST_TIMEOUT")
.expect("env var SUBSTRATE_TEST_TIMEOUT has been provided by the user")
-1
View File
@@ -19,6 +19,5 @@
#[test]
fn substrate_test_utils_derive_trybuild() {
let t = trybuild::TestCases::new();
t.compile_fail("tests/ui/missing-func-parameter.rs");
t.compile_fail("tests/ui/too-many-func-parameters.rs");
}
@@ -1,24 +0,0 @@
// This file is part of Substrate.
// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#[substrate_test_utils::test]
async fn missing_func_parameter() {
assert!(true);
}
fn main() {}
@@ -1,5 +0,0 @@
error: the test function accepts only one argument of type sc_service::TaskExecutor
--> $DIR/missing-func-parameter.rs:20:1
|
20 | async fn missing_func_parameter() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -16,11 +16,8 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#[allow(unused_imports)]
use sc_service::TaskExecutor;
#[substrate_test_utils::test]
async fn too_many_func_parameters(task_executor_1: TaskExecutor, task_executor_2: TaskExecutor) {
async fn too_many_func_parameters(_: u32) {
assert!(true);
}
@@ -1,5 +1,5 @@
error: the test function accepts only one argument of type sc_service::TaskExecutor
--> $DIR/too-many-func-parameters.rs:23:1
error: No arguments expected for tests.
--> $DIR/too-many-func-parameters.rs:20:1
|
23 | async fn too_many_func_parameters(task_executor_1: TaskExecutor, task_executor_2: TaskExecutor) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
20 | async fn too_many_func_parameters(_: u32) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^