From 21e9162dc600192c1e3a769742e8ef81358ebae2 Mon Sep 17 00:00:00 2001 From: Ashley Date: Wed, 18 Dec 2019 17:21:33 +0100 Subject: [PATCH 01/26] Switch service to futures03 --- Cargo.lock | 4 +- bin/node/cli/src/cli.rs | 3 - bin/node/cli/src/service.rs | 23 ++-- client/cli/src/informant.rs | 7 +- client/finality-grandpa/src/lib.rs | 8 +- client/rpc-api/src/subscriptions.rs | 10 +- client/rpc/src/author/mod.rs | 5 +- client/service/Cargo.toml | 8 +- client/service/src/builder.rs | 80 +++++------- client/service/src/chain_ops.rs | 19 ++- client/service/src/lib.rs | 186 ++++++++++++---------------- client/service/src/status_sinks.rs | 49 ++++---- client/service/test/Cargo.toml | 2 +- client/service/test/src/lib.rs | 2 +- 14 files changed, 175 insertions(+), 231 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f8afee75dc34e..360457baa5c0b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5587,6 +5587,7 @@ dependencies = [ "exit-future 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-timer 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "grafana-data-source 2.0.0", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5625,8 +5626,7 @@ dependencies = [ "sysinfo 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "tracing 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/bin/node/cli/src/cli.rs b/bin/node/cli/src/cli.rs index 6e8afc613336a..78cbdb23b7f1e 100644 --- a/bin/node/cli/src/cli.rs +++ b/bin/node/cli/src/cli.rs @@ -194,9 +194,6 @@ where let service_res = { let exit = e.into_exit(); - let service = service - .map_err(|err| error::Error::Service(err)) - .compat(); let select = select(service, exit) .map(|_| Ok(())) .compat(); diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index 1403393866fdd..4b81f98bee81a 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -113,12 +113,11 @@ macro_rules! new_full_start { /// concrete types instead. macro_rules! new_full { ($config:expr, $with_startup_data: expr) => {{ - use futures01::sync::mpsc; use sc_network::DhtEvent; use futures::{ - compat::Stream01CompatExt, + compat::{Stream01CompatExt, Future01CompatExt}, stream::StreamExt, - future::{FutureExt, TryFutureExt}, + future::{TryFutureExt, FutureExt}, }; let ( @@ -147,7 +146,7 @@ macro_rules! new_full { // This estimates the authority set size to be somewhere below 10 000 thereby setting the channel buffer size to // 10 000. let (dht_event_tx, dht_event_rx) = - mpsc::channel::(10_000); + futures::channel::mpsc::channel::(10_000); let service = builder.with_network_protocol(|_| Ok(crate::service::NodeProtocol::new()))? .with_finality_proof_provider(|client, backend| @@ -187,22 +186,18 @@ macro_rules! new_full { can_author_with, }; - let babe = sc_consensus_babe::start_babe(babe_config)?; + let babe = sc_consensus_babe::start_babe(babe_config)?.compat().map(drop); service.spawn_essential_task(babe); - let future03_dht_event_rx = dht_event_rx.compat() - .map(|x| x.expect(" never returns an error; qed")) - .boxed(); let authority_discovery = sc_authority_discovery::AuthorityDiscovery::new( service.client(), service.network(), sentry_nodes, service.keystore(), - future03_dht_event_rx, + dht_event_rx.boxed(), ); - let future01_authority_discovery = authority_discovery.map(|x| Ok(x)).compat(); - service.spawn_task(future01_authority_discovery); + service.spawn_task(authority_discovery); } // if the node isn't actively participating in consensus then it doesn't @@ -232,7 +227,7 @@ macro_rules! new_full { service.network(), service.on_exit(), service.spawn_task_handle(), - )?); + )?.compat().map(drop)); }, (true, false) => { // start the full GRANDPA voter @@ -248,7 +243,9 @@ macro_rules! new_full { }; // the GRANDPA voter task is considered infallible, i.e. // if it fails we take down the service with it. - service.spawn_essential_task(grandpa::run_grandpa_voter(grandpa_config)?); + service.spawn_essential_task( + grandpa::run_grandpa_voter(grandpa_config)?.compat().map(drop) + ); }, (_, true) => { grandpa::setup_disabled_grandpa( diff --git a/client/cli/src/informant.rs b/client/cli/src/informant.rs index be896e180dfff..42a8525148214 100644 --- a/client/cli/src/informant.rs +++ b/client/cli/src/informant.rs @@ -17,7 +17,7 @@ //! Console informant. Prints sync progress and block events. Runs on the calling thread. use sc_client_api::BlockchainEvents; -use futures::{StreamExt, TryStreamExt, FutureExt, future, compat::Stream01CompatExt}; +use futures::{StreamExt, FutureExt, future}; use log::{info, warn}; use sp_runtime::traits::Header; use sc_service::AbstractService; @@ -33,11 +33,10 @@ pub fn build(service: &impl AbstractService) -> impl futures::Future, N, RA, SC, VR, X, Sp> { /// Handle to a future that will resolve on exit. pub on_exit: X, /// If supplied, can be used to hook on telemetry connection established events. - pub telemetry_on_connect: Option>, + pub telemetry_on_connect: Option>, /// A voting rule used to potentially restrict target votes. pub voting_rule: VR, /// How to spawn background tasks. @@ -605,9 +606,10 @@ pub fn run_grandpa_voter, N, RA, SC, VR, X, Sp>( .expect("authorities is always at least an empty vector; elements are always of type string") } ); - Ok(()) + ready(()) }) - .then(|_| -> Result<(), ()> { Ok(()) }); + .unit_error() + .compat(); futures::future::Either::A(events) } else { futures::future::Either::B(futures::future::empty()) diff --git a/client/rpc-api/src/subscriptions.rs b/client/rpc-api/src/subscriptions.rs index d5ca74fa60bc7..5907bd7db7896 100644 --- a/client/rpc-api/src/subscriptions.rs +++ b/client/rpc-api/src/subscriptions.rs @@ -22,11 +22,12 @@ use jsonrpc_pubsub::{SubscriptionId, typed::{Sink, Subscriber}}; use parking_lot::Mutex; use jsonrpc_core::futures::sync::oneshot; use jsonrpc_core::futures::{Future, future}; +use futures::{task::{Spawn, SpawnExt}, FutureExt, compat::Future01CompatExt}; type Id = u64; /// Alias for a an implementation of `futures::future::Executor`. -pub type TaskExecutor = Arc + Send>> + Send + Sync>; +pub type TaskExecutor = Arc; /// Generate unique ids for subscriptions. #[derive(Clone, Debug)] @@ -92,11 +93,12 @@ impl Subscriptions { let (tx, rx) = oneshot::channel(); let future = into_future(sink) .into_future() - .select(rx.map_err(|e| warn!("Error timeing out: {:?}", e))) - .then(|_| Ok(())); + .select(rx.map_err(|e| warn!("Error timing out: {:?}", e))) + .compat() + .map(drop); self.active_subscriptions.lock().insert(id, tx); - if self.executor.execute(Box::new(future)).is_err() { + if self.executor.spawn(Box::new(future)).is_err() { error!("Failed to spawn RPC subscription task"); } } diff --git a/client/rpc/src/author/mod.rs b/client/rpc/src/author/mod.rs index 1cdbda5904c85..98957f890f812 100644 --- a/client/rpc/src/author/mod.rs +++ b/client/rpc/src/author/mod.rs @@ -42,6 +42,7 @@ use sp_transaction_pool::{ BlockHash, TxHash, TransactionFor, error::IntoPoolError, }; use sp_session::SessionKeys; +use futures::task::SpawnExt; /// Re-export the API for backward compatibility. pub use sc_rpc_api::author::*; @@ -193,9 +194,7 @@ impl AuthorApi for Author Box + Send>; + ) -> Box> + Send>; /// Performs the blocks export. fn export_blocks( @@ -677,7 +675,7 @@ pub trait ServiceBuilderCommand { from: NumberFor, to: Option>, json: bool - ) -> Box>; + ) -> Box>>; /// Performs a revert of `blocks` blocks. fn revert_chain( @@ -689,7 +687,7 @@ pub trait ServiceBuilderCommand { fn check_block( self, block: BlockId - ) -> Box + Send>; + ) -> Box> + Send>; } impl @@ -731,6 +729,7 @@ ServiceBuilder< + TransactionPool::Hash> + TransactionPoolMaintainer::Hash>, TRpc: sc_rpc::RpcExtension + Clone, + ::Extrinsic: Unpin, { /// Builds the service. pub fn build(self) -> Result + Send>>(); + mpsc::unbounded:: + Send + Unpin>>(); // A side-channel for essential tasks to communicate shutdown. let (essential_failed_tx, essential_failed_rx) = mpsc::unbounded(); @@ -858,7 +857,6 @@ ServiceBuilder< let is_validator = config.roles.is_authority(); let events = client.import_notification_stream() - .map(|v| Ok::<_, ()>(v)).compat() .for_each(move |notification| { let number = *notification.header.number(); let txpool = txpool.upgrade(); @@ -867,22 +865,19 @@ ServiceBuilder< let future = txpool.maintain( &BlockId::hash(notification.hash), ¬ification.retracted, - ).map(|_| Ok(())).compat(); + ); let _ = to_spawn_tx_.unbounded_send(Box::new(future)); } let offchain = offchain.as_ref().and_then(|o| o.upgrade()); if let Some(offchain) = offchain { - let future = offchain.on_block_imported(&number, network_state_info.clone(), is_validator) - .map(|()| Ok(())); - let _ = to_spawn_tx_.unbounded_send(Box::new(Compat::new(future))); + let future = offchain.on_block_imported(&number, network_state_info.clone(), is_validator); + let _ = to_spawn_tx_.unbounded_send(Box::new(future)); } - Ok(()) - }) - .select(exit.clone().map(Ok).compat()) - .then(|_| Ok(())); - let _ = to_spawn_tx.unbounded_send(Box::new(events)); + ready(()) + }); + let _ = to_spawn_tx.unbounded_send(Box::new(select(events, exit.clone()).map(drop))); } { @@ -890,7 +885,6 @@ ServiceBuilder< let network = Arc::downgrade(&network); let transaction_pool_ = transaction_pool.clone(); let events = transaction_pool.import_notification_stream() - .map(|v| Ok::<_, ()>(v)).compat() .for_each(move |_| { if let Some(network) = network.upgrade() { network.trigger_repropagate(); @@ -900,12 +894,10 @@ ServiceBuilder< "ready" => status.ready, "future" => status.future ); - Ok(()) - }) - .select(exit.clone().map(Ok).compat()) - .then(|_| Ok(())); + ready(()) + }); - let _ = to_spawn_tx.unbounded_send(Box::new(events)); + let _ = to_spawn_tx.unbounded_send(Box::new(select(events, exit.clone()).map(drop))); } // Periodically notify the telemetry. @@ -966,9 +958,9 @@ ServiceBuilder< "used_state_cache_size" => used_state_cache_size, ); - Ok(()) - }).select(exit.clone().map(Ok).compat()).then(|_| Ok(())); - let _ = to_spawn_tx.unbounded_send(Box::new(tel_task)); + ready(()) + }); + let _ = to_spawn_tx.unbounded_send(Box::new(select(tel_task, exit.clone()).map(drop))); // Periodically send the network state to the telemetry. let (netstat_tx, netstat_rx) = mpsc::unbounded::<(NetworkStatus<_>, NetworkState)>(); @@ -979,12 +971,12 @@ ServiceBuilder< "system.network_state"; "state" => network_state, ); - Ok(()) - }).select(exit.clone().map(Ok).compat()).then(|_| Ok(())); - let _ = to_spawn_tx.unbounded_send(Box::new(tel_task_2)); + ready(()) + }); + let _ = to_spawn_tx.unbounded_send(Box::new(select(tel_task_2, exit.clone()).map(drop))); // RPC - let (system_rpc_tx, system_rpc_rx) = futures03::channel::mpsc::unbounded(); + let (system_rpc_tx, system_rpc_rx) = mpsc::unbounded(); let gen_handler = || { use sc_rpc::{chain, state, author, system}; @@ -1044,7 +1036,7 @@ ServiceBuilder< let rpc = start_rpc_servers(&config, gen_handler)?; - let _ = to_spawn_tx.unbounded_send(Box::new(build_network_future( + let _ = to_spawn_tx.unbounded_send(Box::new(select(build_network_future( config.roles, network_mut, client.clone(), @@ -1052,10 +1044,7 @@ ServiceBuilder< system_rpc_rx, has_bootnodes, dht_event_tx, - ) - .map_err(|_| ()) - .select(exit.clone().map(Ok).compat()) - .then(|_| Ok(())))); + ), exit.clone()).map(drop))); let telemetry_connection_sinks: Arc>>> = Default::default(); @@ -1076,8 +1065,6 @@ ServiceBuilder< .map(|dur| dur.as_millis()) .unwrap_or(0); let future = telemetry.clone() - .map(|ev| Ok::<_, ()>(ev)) - .compat() .for_each(move |event| { // Safe-guard in case we add more events in the future. let sc_telemetry::TelemetryEvent::Connected = event; @@ -1096,11 +1083,11 @@ ServiceBuilder< telemetry_connection_sinks_.lock().retain(|sink| { sink.unbounded_send(()).is_ok() }); - Ok(()) + ready(()) }); - let _ = to_spawn_tx.unbounded_send(Box::new(future - .select(exit.clone().map(Ok).compat()) - .then(|_| Ok(())))); + let _ = to_spawn_tx.unbounded_send(Box::new(select( + future, exit.clone() + ).map(drop))); telemetry }); @@ -1109,10 +1096,7 @@ ServiceBuilder< let future = select( grafana_data_source::run_server(port).boxed(), exit.clone() - ).map(|either| match either { - Either::Left((result, _)) => result.map_err(|_| ()), - Either::Right(_) => Ok(()) - }).compat(); + ).map(drop); let _ = to_spawn_tx.unbounded_send(Box::new(future)); } diff --git a/client/service/src/chain_ops.rs b/client/service/src/chain_ops.rs index fb62cd3399b41..b0aa30ab9e4d1 100644 --- a/client/service/src/chain_ops.rs +++ b/client/service/src/chain_ops.rs @@ -21,10 +21,7 @@ use crate::builder::{ServiceBuilderCommand, ServiceBuilder}; use crate::error::Error; use sc_chain_spec::{ChainSpec, RuntimeGenesis, Extension}; use log::{warn, info}; -use futures::{future, prelude::*}; -use futures03::{ - TryFutureExt as _, -}; +use futures::{future, Future}; use sp_core::{Blake2Hasher, Hasher}; use sp_runtime::traits::{ Block as BlockT, NumberFor, One, Zero, Header, SaturatedConversion @@ -69,7 +66,7 @@ impl< self, input: impl Read + Seek + Send + 'static, force: bool, - ) -> Box + Send> { + ) -> Box> + Send> { struct WaitLink { imported_blocks: u64, has_error: bool, @@ -118,7 +115,7 @@ impl< // queue, the `Future` re-schedules itself and returns `Poll::Pending`. // This makes it possible either to interleave other operations in-between the block imports, // or to stop the operation completely. - let import = futures03::future::poll_fn(move |cx| { + let import = future::poll_fn(move |cx| { // Start by reading the number of blocks if not done so already. let count = match count { Some(c) => c, @@ -206,7 +203,7 @@ impl< return std::task::Poll::Pending; } }); - Box::new(import.compat()) + Box::new(import) } fn export_blocks( @@ -215,7 +212,7 @@ impl< from: NumberFor, to: Option>, json: bool - ) -> Box> { + ) -> Box>> { let client = self.client; let mut block = from; @@ -234,7 +231,7 @@ impl< // `Poll::Pending`. // This makes it possible either to interleave other operations in-between the block exports, // or to stop the operation completely. - let export = futures03::future::poll_fn(move |cx| { + let export = future::poll_fn(move |cx| { if last < block { return std::task::Poll::Ready(Err("Invalid block range specified".into())); } @@ -275,7 +272,7 @@ impl< std::task::Poll::Pending }); - Box::new(export.compat()) + Box::new(export) } fn revert_chain( @@ -296,7 +293,7 @@ impl< fn check_block( self, block_id: BlockId - ) -> Box + Send> { + ) -> Box> + Send> { match self.client.block(&block_id) { Ok(Some(block)) => { let mut buf = Vec::new(); diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index d23e2a988c588..08476a302ab5e 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -32,15 +32,18 @@ use std::marker::PhantomData; use std::net::SocketAddr; use std::collections::HashMap; use std::time::{Duration, Instant}; -use futures::sync::mpsc; +use std::pin::Pin; +use std::task::{Poll, Context}; use parking_lot::Mutex; use sc_client::Client; use exit_future::Signal; -use futures::prelude::*; -use futures03::{ - future::{ready, FutureExt as _, TryFutureExt as _}, - stream::{StreamExt as _, TryStreamExt as _}, +use futures::{ + Future, FutureExt, Stream, StreamExt, + future::select, channel::mpsc, + compat::*, + sink::SinkExt, + task::{Spawn, SpawnExt, FutureObj, SpawnError}, }; use sc_network::{ NetworkService, NetworkState, specialization::NetworkSpecialization, @@ -64,8 +67,6 @@ pub use sc_rpc::Metadata as RpcMetadata; pub use std::{ops::Deref, result::Result, sync::Arc}; #[doc(hidden)] pub use sc_network::{FinalityProofProvider, OnDemand, config::BoxFinalityProofRequestBuilder}; -#[doc(hidden)] -pub use futures::future::Executor; const DEFAULT_PROTOCOL_ID: &str = "sup"; @@ -89,13 +90,13 @@ pub struct Service { /// A receiver for spawned essential-tasks concluding. essential_failed_rx: mpsc::UnboundedReceiver<()>, /// Sender for futures that must be spawned as background tasks. - to_spawn_tx: mpsc::UnboundedSender + Send>>, + to_spawn_tx: mpsc::UnboundedSender + Send + Unpin>>, /// Receiver for futures that must be spawned as background tasks. - to_spawn_rx: mpsc::UnboundedReceiver + Send>>, + to_spawn_rx: mpsc::UnboundedReceiver + Send + Unpin>>, /// List of futures to poll from `poll`. /// If spawning a background task is not possible, we instead push the task into this `Vec`. /// The elements must then be polled manually. - to_poll: Vec + Send>>, + to_poll: Vec + Send + Unpin>>, rpc_handlers: sc_rpc_server::RpcHandler, _rpc: Box, _telemetry: Option, @@ -106,42 +107,27 @@ pub struct Service { } /// Alias for a an implementation of `futures::future::Executor`. -pub type TaskExecutor = Arc + Send>> + Send + Sync>; +pub type TaskExecutor = Arc; /// An handle for spawning tasks in the service. #[derive(Clone)] pub struct SpawnTaskHandle { - sender: mpsc::UnboundedSender + Send>>, + sender: mpsc::UnboundedSender + Send + Unpin>>, on_exit: exit_future::Exit, } -impl Executor + Send>> for SpawnTaskHandle { - fn execute( - &self, - future: Box + Send>, - ) -> Result<(), futures::future::ExecuteError + Send>>> { - let exit = self.on_exit.clone().map(Ok).compat(); - let future = Box::new(future.select(exit).then(|_| Ok(()))); - if let Err(err) = self.sender.unbounded_send(future) { - let kind = futures::future::ExecuteErrorKind::Shutdown; - Err(futures::future::ExecuteError::new(kind, err.into_inner())) - } else { - Ok(()) - } - } -} - -impl futures03::task::Spawn for SpawnTaskHandle { - fn spawn_obj(&self, future: futures03::task::FutureObj<'static, ()>) - -> Result<(), futures03::task::SpawnError> { - self.execute(Box::new(futures03::compat::Compat::new(future.unit_error()))) - .map_err(|_| futures03::task::SpawnError::shutdown()) +impl Spawn for SpawnTaskHandle { + fn spawn_obj(&self, future: FutureObj<'static, ()>) + -> Result<(), SpawnError> { + let future = select(self.on_exit.clone(), future).map(drop); + self.sender.unbounded_send(Box::new(future)) + .map_err(|_| SpawnError::shutdown()) } } /// Abstraction over a Substrate service. -pub trait AbstractService: 'static + Future + - Executor + Send>> + Send { +pub trait AbstractService: 'static + Future> + + Spawn + Send + Unpin { /// Type of block of this chain. type Block: BlockT; /// Backend storage for the client. @@ -165,12 +151,12 @@ pub trait AbstractService: 'static + Future + fn telemetry(&self) -> Option; /// Spawns a task in the background that runs the future passed as parameter. - fn spawn_task(&self, task: impl Future + Send + 'static); + fn spawn_task(&self, task: impl Future + Send + Unpin + 'static); /// Spawns a task in the background that runs the future passed as /// parameter. The given task is considered essential, i.e. if it errors we /// trigger a service exit. - fn spawn_essential_task(&self, task: impl Future + Send + 'static); + fn spawn_essential_task(&self, task: impl Future + Send + Unpin + 'static); /// Returns a handle for spawning tasks. fn spawn_task_handle(&self) -> SpawnTaskHandle; @@ -187,7 +173,7 @@ pub trait AbstractService: 'static + Future + /// /// If the request subscribes you to events, the `Sender` in the `RpcSession` object is used to /// send back spontaneous events. - fn rpc_query(&self, mem: &RpcSession, request: &str) -> Box, Error = ()> + Send>; + fn rpc_query(&self, mem: &RpcSession, request: &str) -> Box> + Send>; /// Get shared client instance. fn client(&self) -> Arc>; @@ -212,11 +198,11 @@ impl AbstractService Service, TSc, NetworkStatus, NetworkService, TExPool, TOc> where - TBl: BlockT, + TBl: BlockT + Unpin, TBackend: 'static + sc_client_api::backend::Backend, TExec: 'static + sc_client::CallExecutor + Send + Sync + Clone, TRtApi: 'static + Send + Sync, - TSc: sp_consensus::SelectChain + 'static + Clone + Send, + TSc: sp_consensus::SelectChain + 'static + Clone + Send + Unpin, TExPool: 'static + TransactionPool + TransactionPoolMaintainer, TOc: 'static + Send + Sync, @@ -244,23 +230,20 @@ where self.keystore.clone() } - fn spawn_task(&self, task: impl Future + Send + 'static) { - let exit = self.on_exit().map(Ok).compat(); - let task = task.select(exit).then(|_| Ok(())); + fn spawn_task(&self, task: impl Future + Send + Unpin + 'static) { + let task = select(self.on_exit(), task).map(drop); let _ = self.to_spawn_tx.unbounded_send(Box::new(task)); } - fn spawn_essential_task(&self, task: impl Future + Send + 'static) { - let essential_failed = self.essential_failed_tx.clone(); + fn spawn_essential_task(&self, task: impl Future + Send + Unpin + 'static) { + let mut essential_failed = self.essential_failed_tx.clone(); let essential_task = std::panic::AssertUnwindSafe(task) .catch_unwind() - .then(move |_| { + .map(move |_| { error!("Essential task failed. Shutting down service."); let _ = essential_failed.send(()); - Ok(()) }); - let exit = self.on_exit().map(Ok::<_, ()>).compat(); - let task = essential_task.select(exit).then(|_| Ok(())); + let task = select(self.on_exit(), essential_task).map(drop); let _ = self.to_spawn_tx.unbounded_send(Box::new(task)); } @@ -272,8 +255,12 @@ where } } - fn rpc_query(&self, mem: &RpcSession, request: &str) -> Box, Error = ()> + Send> { - Box::new(self.rpc_handlers.handle_request(request, mem.metadata.clone())) + fn rpc_query(&self, mem: &RpcSession, request: &str) -> Box> + Send> { + Box::new( + self.rpc_handlers.handle_request(request, mem.metadata.clone()) + .compat() + .map(|res| res.expect("this should never fail")) + ) } fn client(&self) -> Arc> { @@ -303,57 +290,46 @@ where } } -impl Future for +impl Future for Service { - type Item = (); - type Error = Error; + type Output = Result<(), Error>; - fn poll(&mut self) -> Poll { - match self.essential_failed_rx.poll() { - Ok(Async::NotReady) => {}, - Ok(Async::Ready(_)) | Err(_) => { + fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { + let this = Pin::into_inner(self); + + match Pin::new(&mut this.essential_failed_rx).poll_next(cx) { + Poll::Pending => {}, + Poll::Ready(_) => { // Ready(None) should not be possible since we hold a live // sender. - return Err(Error::Other("Essential task failed.".into())); + return Poll::Ready(Err(Error::Other("Essential task failed.".into()))); } } - while let Ok(Async::Ready(Some(task_to_spawn))) = self.to_spawn_rx.poll() { - let executor = tokio_executor::DefaultExecutor::current(); - if let Err(err) = executor.execute(task_to_spawn) { - debug!( - target: "service", - "Failed to spawn background task: {:?}; falling back to manual polling", - err - ); - self.to_poll.push(err.into_future()); - } + while let Poll::Ready(Some(task_to_spawn)) = Pin::new(&mut this.to_spawn_rx).poll_next(cx) { + tokio::spawn(task_to_spawn); } // Polling all the `to_poll` futures. - while let Some(pos) = self.to_poll.iter_mut().position(|t| t.poll().map(|t| t.is_ready()).unwrap_or(true)) { - let _ = self.to_poll.remove(pos); + while let Some(pos) = this.to_poll.iter_mut().position(|t| Pin::new(t).poll(cx).is_ready()) { + let _ = this.to_poll.remove(pos); } // The service future never ends. - Ok(Async::NotReady) + Poll::Pending } } -impl Executor + Send>> for +impl Spawn for Service { - fn execute( + fn spawn_obj( &self, - future: Box + Send> - ) -> Result<(), futures::future::ExecuteError + Send>>> { - if let Err(err) = self.to_spawn_tx.unbounded_send(future) { - let kind = futures::future::ExecuteErrorKind::Shutdown; - Err(futures::future::ExecuteError::new(kind, err.into_inner())) - } else { - Ok(()) - } + future: FutureObj<'static, ()> + ) -> Result<(), SpawnError> { + self.to_spawn_tx.unbounded_send(Box::new(future)) + .map_err(|_| SpawnError::shutdown()) } } @@ -370,33 +346,27 @@ fn build_network_future< mut network: sc_network::NetworkWorker, client: Arc, status_sinks: Arc, NetworkState)>>>, - rpc_rx: futures03::channel::mpsc::UnboundedReceiver>, + mut rpc_rx: mpsc::UnboundedReceiver>, should_have_peers: bool, dht_event_tx: Option>, -) -> impl Future { - // Compatibility shim while we're transitioning to stable Futures. - // See https://github.com/paritytech/substrate/issues/3099 - let mut rpc_rx = futures03::compat::Compat::new(rpc_rx.map(|v| Ok::<_, ()>(v))); - - let mut imported_blocks_stream = client.import_notification_stream().fuse() - .map(|v| Ok::<_, ()>(v)).compat(); - let mut finality_notification_stream = client.finality_notification_stream().fuse() - .map(|v| Ok::<_, ()>(v)).compat(); +) -> impl Future { + let mut imported_blocks_stream = client.import_notification_stream().fuse(); + let mut finality_notification_stream = client.finality_notification_stream().fuse(); // Initializing a stream in order to obtain DHT events from the network. - let mut event_stream = network.service().event_stream(); + let mut event_stream = network.service().event_stream().compat(); - futures::future::poll_fn(move || { + futures::future::poll_fn(move |cx| { let before_polling = Instant::now(); // We poll `imported_blocks_stream`. - while let Ok(Async::Ready(Some(notification))) = imported_blocks_stream.poll() { + while let Poll::Ready(Some(notification)) = Pin::new(&mut imported_blocks_stream).poll_next(cx) { network.on_block_imported(notification.hash, notification.header, Vec::new(), notification.is_new_best); } // We poll `finality_notification_stream`, but we only take the last event. let mut last = None; - while let Ok(Async::Ready(Some(item))) = finality_notification_stream.poll() { + while let Poll::Ready(Some(item)) = Pin::new(&mut finality_notification_stream).poll_next(cx) { last = Some(item); } if let Some(notification) = last { @@ -404,7 +374,7 @@ fn build_network_future< } // Poll the RPC requests and answer them. - while let Ok(Async::Ready(Some(request))) = rpc_rx.poll() { + while let Poll::Ready(Some(request)) = Pin::new(&mut rpc_rx).poll_next(cx) { match request { sc_rpc::system::Request::Health(sender) => { let _ = sender.send(sc_rpc::system::Health { @@ -448,7 +418,7 @@ fn build_network_future< } // Interval report for the external API. - status_sinks.lock().poll(|| { + status_sinks.lock().poll(cx, || { let status = NetworkStatus { sync_state: network.sync_state(), best_seen_block: network.best_seen_block(), @@ -463,7 +433,7 @@ fn build_network_future< }); // Processing DHT events. - while let Ok(Async::Ready(Some(event))) = event_stream.poll() { + while let Poll::Ready(Some(Ok(event))) = Pin::new(&mut event_stream).poll_next(cx) { match event { Event::Dht(event) => { // Given that client/authority-discovery is the only upper stack consumer of Dht events at the moment, all Dht @@ -483,10 +453,10 @@ fn build_network_future< } // Main network polling. - if let Ok(Async::Ready(())) = network.poll().map_err(|err| { + if let Poll::Ready(Ok(())) = Pin::new(&mut (&mut network).compat()).poll(cx).map_err(|err| { warn!(target: "service", "Error in network: {:?}", err); }) { - return Ok(Async::Ready(())); + return Poll::Ready(()); } // Now some diagnostic for performances. @@ -498,7 +468,7 @@ fn build_network_future< polling_dur ); - Ok(Async::NotReady) + Poll::Pending }) } @@ -596,7 +566,7 @@ impl RpcSession { /// messages. /// /// The `RpcSession` must be kept alive in order to receive messages on the sender. - pub fn new(sender: mpsc::Sender) -> RpcSession { + pub fn new(sender: futures01::sync::mpsc::Sender) -> RpcSession { RpcSession { metadata: sender.into(), } @@ -668,7 +638,7 @@ where let best_block_id = BlockId::hash(self.client.info().chain.best_hash); let import_future = self.pool.submit_one(&best_block_id, uxt); let import_future = import_future - .then(move |import_result| { + .map(move |import_result| { match import_result { Ok(_) => report_handle.report_peer(who, reputation_change_good), Err(e) => match e.into_pool_error() { @@ -680,11 +650,9 @@ where Err(e) => debug!("Error converting pool error: {:?}", e), } } - ready(Ok(())) - }) - .compat(); + }); - if let Err(e) = self.executor.execute(Box::new(import_future)) { + if let Err(e) = self.executor.spawn(Box::new(import_future)) { warn!("Error scheduling extrinsic import: {:?}", e); } } @@ -700,7 +668,7 @@ where #[cfg(test)] mod tests { use super::*; - use futures03::executor::block_on; + use future::executor::block_on; use sp_consensus::SelectChain; use sp_runtime::traits::BlindCheckable; use substrate_test_runtime_client::{prelude::*, runtime::{Extrinsic, Transfer}}; diff --git a/client/service/src/status_sinks.rs b/client/service/src/status_sinks.rs index 8b8f859aa7d13..e42b9069a230b 100644 --- a/client/service/src/status_sinks.rs +++ b/client/service/src/status_sinks.rs @@ -14,11 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use futures::prelude::*; -use futures::sync::mpsc; -use futures::stream::futures_unordered::FuturesUnordered; -use std::time::{Duration, Instant}; -use tokio_timer::Delay; +use futures::{Stream, stream::futures_unordered::FuturesUnordered, channel::mpsc}; +use std::time::Duration; +use std::pin::Pin; +use std::task::{Poll, Context}; +use futures_timer::Delay; /// Holds a list of `UnboundedSender`s, each associated with a certain time period. Every time the /// period elapses, we push an element on the sender. @@ -29,7 +29,7 @@ pub struct StatusSinks { } struct YieldAfter { - delay: tokio_timer::Delay, + delay: Delay, interval: Duration, sender: Option>, } @@ -47,7 +47,7 @@ impl StatusSinks { /// The `interval` is the time period between two pushes on the sender. pub fn push(&mut self, interval: Duration, sender: mpsc::UnboundedSender) { self.entries.push(YieldAfter { - delay: Delay::new(Instant::now() + interval), + delay: Delay::new(interval), interval, sender: Some(sender), }) @@ -63,10 +63,10 @@ impl StatusSinks { /// # Panic /// /// Panics if not called within the context of a task. - pub fn poll(&mut self, mut status_grab: impl FnMut() -> T) { + pub fn poll(&mut self, cx: &mut Context, mut status_grab: impl FnMut() -> T) { loop { - match self.entries.poll() { - Ok(Async::Ready(Some((sender, interval)))) => { + match Pin::new(&mut self.entries).poll_next(cx) { + Poll::Ready(Some((sender, interval))) => { let status = status_grab(); if sender.unbounded_send(status).is_ok() { self.entries.push(YieldAfter { @@ -74,33 +74,32 @@ impl StatusSinks { // waken up and the moment it is polled, the period is actually not // `interval` but `interval + `. We ignore this problem in // practice. - delay: Delay::new(Instant::now() + interval), + delay: Delay::new( interval), interval, sender: Some(sender), }); } } - Err(()) | - Ok(Async::Ready(None)) | - Ok(Async::NotReady) => break, + Poll::Ready(None) | + Poll::Pending => break, } } } } -impl Future for YieldAfter { - type Item = (mpsc::UnboundedSender, Duration); - type Error = (); +impl futures::Future for YieldAfter { + type Output = (mpsc::UnboundedSender, Duration); - fn poll(&mut self) -> Poll { - match self.delay.poll() { - Ok(Async::NotReady) => Ok(Async::NotReady), - Ok(Async::Ready(())) => { - let sender = self.sender.take() + fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { + let this = Pin::into_inner(self); + + match Pin::new(&mut this.delay).poll(cx) { + Poll::Pending => Poll::Pending, + Poll::Ready(()) => { + let sender = this.sender.take() .expect("sender is always Some unless the future is finished; qed"); - Ok(Async::Ready((sender, self.interval))) - }, - Err(_) => Err(()), + Poll::Ready((sender, this.interval)) + } } } } diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index 2789bfda0fe19..432d9d4b98ed7 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -11,7 +11,7 @@ futures = "0.1.29" log = "0.4.8" env_logger = "0.7.0" fdlimit = "0.1.1" -futures03 = { package = "futures", version = "0.3.1", features = ["compat"] } +future = { package = "futures", version = "0.3.1", features = ["compat"] } sc-service = { version = "2.0.0", default-features = false, path = "../../service" } sc-network = { version = "0.8", path = "../../network" } sp-consensus = { version = "0.8", path = "../../../primitives/consensus/common" } diff --git a/client/service/test/src/lib.rs b/client/service/test/src/lib.rs index dae0f5604fcc8..10dba15522eaf 100644 --- a/client/service/test/src/lib.rs +++ b/client/service/test/src/lib.rs @@ -456,7 +456,7 @@ pub fn sync( let first_user_data = &network.full_nodes[0].2; let best_block = BlockId::number(first_service.get().client().info().chain.best_number); let extrinsic = extrinsic_factory(&first_service.get(), first_user_data); - futures03::executor::block_on(first_service.get().transaction_pool().submit_one(&best_block, extrinsic)).unwrap(); + future::executor::block_on(first_service.get().transaction_pool().submit_one(&best_block, extrinsic)).unwrap(); network.run_until_all_full( |_index, service| service.get().transaction_pool().ready().count() == 1, |_index, _service| true, From 3e705f655d1bd9910ffb484ba03c88b9270847ca Mon Sep 17 00:00:00 2001 From: Ashley Date: Wed, 18 Dec 2019 17:43:44 +0100 Subject: [PATCH 02/26] Fix tests --- Cargo.lock | 1 - client/service/Cargo.toml | 3 +-- client/service/src/lib.rs | 2 +- client/service/src/status_sinks.rs | 17 +++++++++-------- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 360457baa5c0b..f1111c31723aa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5625,7 +5625,6 @@ dependencies = [ "substrate-test-runtime-client 2.0.0", "sysinfo 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "tracing 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 59912d62a45de..98a6e4141a6f9 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -16,7 +16,7 @@ wasmtime = [ [dependencies] derive_more = "0.99.2" futures01 = { package = "futures", version = "0.1.29" } -futures = { version = "0.3.1" } +futures = "0.3.1" parking_lot = "0.9.0" lazy_static = "1.4.0" log = "0.4.8" @@ -60,4 +60,3 @@ substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/ru sp-consensus-babe = { version = "0.8", path = "../../primitives/consensus/babe" } grandpa = { version = "2.0.0", package = "sc-finality-grandpa", path = "../finality-grandpa" } grandpa-primitives = { version = "2.0.0", package = "sp-finality-grandpa", path = "../../primitives/finality-grandpa" } -tokio = "0.1" diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 08476a302ab5e..d44cf9899b324 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -668,7 +668,7 @@ where #[cfg(test)] mod tests { use super::*; - use future::executor::block_on; + use futures::executor::block_on; use sp_consensus::SelectChain; use sp_runtime::traits::BlindCheckable; use substrate_test_runtime_client::{prelude::*, runtime::{Extrinsic, Transfer}}; diff --git a/client/service/src/status_sinks.rs b/client/service/src/status_sinks.rs index e42b9069a230b..053ebb7e877e1 100644 --- a/client/service/src/status_sinks.rs +++ b/client/service/src/status_sinks.rs @@ -57,7 +57,7 @@ impl StatusSinks { /// pushes what it returns to the sender. /// /// This function doesn't return anything, but it should be treated as if it implicitly - /// returns `Ok(Async::NotReady)`. In particular, it should be called again when the task + /// returns `Poll::Pending`. In particular, it should be called again when the task /// is waken up. /// /// # Panic @@ -108,8 +108,9 @@ impl futures::Future for YieldAfter { mod tests { use super::StatusSinks; use futures::prelude::*; - use futures::sync::mpsc; + use futures::channel::mpsc; use std::time::Duration; + use std::task::Poll; #[test] fn works() { @@ -124,18 +125,18 @@ mod tests { let mut runtime = tokio::runtime::Runtime::new().unwrap(); let mut val_order = 5; - runtime.spawn(futures::future::poll_fn(move || { - status_sinks.poll(|| { val_order += 1; val_order }); - Ok(Async::NotReady) + runtime.spawn(futures::future::poll_fn(move |cx| { + status_sinks.poll(cx, || { val_order += 1; val_order }); + Poll::<()>::Pending })); let done = rx .into_future() - .and_then(|(item, rest)| { + .then(|(item, rest)| { assert_eq!(item, Some(6)); rest.into_future() }) - .and_then(|(item, rest)| { + .then(|(item, rest)| { assert_eq!(item, Some(7)); rest.into_future() }) @@ -143,6 +144,6 @@ mod tests { assert_eq!(item, Some(8)); }); - runtime.block_on(done).unwrap(); + runtime.block_on(done); } } From 566f190e57e03b45dc03b1a2374b6b1e3921d115 Mon Sep 17 00:00:00 2001 From: Ashley Date: Wed, 18 Dec 2019 18:38:06 +0100 Subject: [PATCH 03/26] Fix service test and cli --- Cargo.lock | 4 +- client/cli/Cargo.toml | 2 +- client/cli/src/lib.rs | 11 ++-- client/service/src/builder.rs | 6 +- client/service/src/chain_ops.rs | 6 +- client/service/test/Cargo.toml | 6 +- client/service/test/src/lib.rs | 110 +++++++++++++------------------- 7 files changed, 62 insertions(+), 83 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f1111c31723aa..f032f6ef25d06 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5633,9 +5633,9 @@ dependencies = [ name = "sc-service-test" version = "2.0.0" dependencies = [ + "async-std 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "sc-client 2.0.0", @@ -5646,7 +5646,7 @@ dependencies = [ "sp-runtime 2.0.0", "sp-transaction-pool 2.0.0", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 937135a8c30eb..d9bd93313086d 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -17,7 +17,7 @@ ansi_term = "0.12.1" lazy_static = "1.4.0" app_dirs = "1.2.1" tokio = "0.2.1" -futures = { version = "0.3.1", features = ["compat"] } +futures = "0.3.1" fdlimit = "0.1.1" serde_json = "1.0.41" sp-panic-handler = { version = "2.0.0", path = "../../primitives/panic-handler" } diff --git a/client/cli/src/lib.rs b/client/cli/src/lib.rs index c2e11b56ca49c..962a72b1dd36b 100644 --- a/client/cli/src/lib.rs +++ b/client/cli/src/lib.rs @@ -61,7 +61,7 @@ pub use traits::{GetLogFilter, AugmentClap}; use app_dirs::{AppInfo, AppDataType}; use log::info; use lazy_static::lazy_static; -use futures::{Future, compat::Future01CompatExt, executor::block_on}; +use futures::{Future, executor::block_on}; use sc_telemetry::TelemetryEndpoints; use sp_runtime::generic::BlockId; use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; @@ -405,8 +405,7 @@ impl<'a> ParseAndPrepareExport<'a> { }); let mut export_fut = builder(config)? - .export_blocks(file, from.into(), to, json) - .compat(); + .export_blocks(file, from.into(), to, json); let fut = futures::future::poll_fn(|cx| { if exit_recv.try_recv().is_ok() { return Poll::Ready(Ok(())); @@ -464,8 +463,7 @@ impl<'a> ParseAndPrepareImport<'a> { }); let mut import_fut = builder(config)? - .import_blocks(file, false) - .compat(); + .import_blocks(file, false); let fut = futures::future::poll_fn(|cx| { if exit_recv.try_recv().is_ok() { return Poll::Ready(Ok(())); @@ -516,8 +514,7 @@ impl<'a> CheckBlock<'a> { let start = std::time::Instant::now(); let check = builder(config)? - .check_block(block_id) - .compat(); + .check_block(block_id); let mut runtime = tokio::runtime::Runtime::new().unwrap(); runtime.block_on(check)?; println!("Completed in {} ms.", start.elapsed().as_millis()); diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index de679b8032a4e..e2ca2e91d3517 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -666,7 +666,7 @@ pub trait ServiceBuilderCommand { self, input: impl Read + Seek + Send + 'static, force: bool, - ) -> Box> + Send>; + ) -> Box> + Send + Unpin>; /// Performs the blocks export. fn export_blocks( @@ -675,7 +675,7 @@ pub trait ServiceBuilderCommand { from: NumberFor, to: Option>, json: bool - ) -> Box>>; + ) -> Box> + Unpin>; /// Performs a revert of `blocks` blocks. fn revert_chain( @@ -687,7 +687,7 @@ pub trait ServiceBuilderCommand { fn check_block( self, block: BlockId - ) -> Box> + Send>; + ) -> Box> + Send + Unpin>; } impl diff --git a/client/service/src/chain_ops.rs b/client/service/src/chain_ops.rs index b0aa30ab9e4d1..853b44fccbee6 100644 --- a/client/service/src/chain_ops.rs +++ b/client/service/src/chain_ops.rs @@ -66,7 +66,7 @@ impl< self, input: impl Read + Seek + Send + 'static, force: bool, - ) -> Box> + Send> { + ) -> Box> + Send + Unpin> { struct WaitLink { imported_blocks: u64, has_error: bool, @@ -212,7 +212,7 @@ impl< from: NumberFor, to: Option>, json: bool - ) -> Box>> { + ) -> Box> + Unpin> { let client = self.client; let mut block = from; @@ -293,7 +293,7 @@ impl< fn check_block( self, block_id: BlockId - ) -> Box> + Send> { + ) -> Box> + Send + Unpin> { match self.client.block(&block_id) { Ok(Some(block)) => { let mut buf = Vec::new(); diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index 432d9d4b98ed7..4be4831ba94ae 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -6,12 +6,12 @@ edition = "2018" [dependencies] tempfile = "3.1.0" -tokio = "0.1.22" -futures = "0.1.29" +tokio = { version = "0.2", features = ["rt-core"] } +futures = "0.3" +async-std = { version = "1", features = ["unstable"] } log = "0.4.8" env_logger = "0.7.0" fdlimit = "0.1.1" -future = { package = "futures", version = "0.3.1", features = ["compat"] } sc-service = { version = "2.0.0", default-features = false, path = "../../service" } sc-network = { version = "0.8", path = "../../network" } sp-consensus = { version = "0.8", path = "../../../primitives/consensus/common" } diff --git a/client/service/test/src/lib.rs b/client/service/test/src/lib.rs index 10dba15522eaf..cbc2e1e0b7136 100644 --- a/client/service/test/src/lib.rs +++ b/client/service/test/src/lib.rs @@ -20,11 +20,13 @@ use std::iter; use std::sync::{Arc, Mutex, MutexGuard}; use std::net::Ipv4Addr; use std::time::Duration; +use std::pin::Pin; +use std::task::{Poll, Context}; use log::info; -use futures::{Future, Stream, Poll}; +use futures::{Future, FutureExt, StreamExt, future::ready}; use tempfile::TempDir; -use tokio::{runtime::Runtime, prelude::FutureExt}; -use tokio::timer::Interval; +use tokio::runtime::Runtime; +use async_std::stream::interval; use sc_service::{ AbstractService, ChainSpec, @@ -38,9 +40,6 @@ use sc_network::config::{NetworkConfiguration, TransportConfig, NodeKeyConfig, S use sp_runtime::{generic::BlockId, traits::Block as BlockT}; use sp_transaction_pool::TransactionPool; -/// Maximum duration of single wait call. -const MAX_WAIT_TIME: Duration = Duration::from_secs(60 * 3); - struct TestNet { runtime: Runtime, authority_nodes: Vec<(usize, SyncService, U, Multiaddr)>, @@ -72,12 +71,11 @@ impl From for SyncService { } } -impl> Future for SyncService { - type Item = (); - type Error = sc_service::Error; +impl> + Unpin> Future for SyncService { + type Output = Result<(), sc_service::Error>; - fn poll(&mut self) -> Poll { - self.0.lock().unwrap().poll() + fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { + Pin::new(&mut *Pin::into_inner(self).0.lock().unwrap()).poll(cx) } } @@ -95,34 +93,24 @@ where F: Send + 'static, L: Send +'static, U: Clone + Send + 'static { let full_nodes = self.full_nodes.clone(); let light_nodes = self.light_nodes.clone(); - let interval = Interval::new_interval(Duration::from_millis(100)) - .map_err(|_| ()) + let interval = interval(Duration::from_millis(100)) .for_each(move |_| { let full_ready = full_nodes.iter().all(|&(ref id, ref service, _, _)| full_predicate(*id, service) ); if !full_ready { - return Ok(()); + return ready(()); } - let light_ready = light_nodes.iter().all(|&(ref id, ref service, _)| + let _ = light_nodes.iter().all(|&(ref id, ref service, _)| light_predicate(*id, service) ); - if !light_ready { - Ok(()) - } else { - Err(()) - } - }) - .timeout(MAX_WAIT_TIME); + ready(()) + }); - match self.runtime.block_on(interval) { - Ok(()) => unreachable!("interval always fails; qed"), - Err(ref err) if err.is_inner() => (), - Err(_) => panic!("Waited for too long"), - } + self.runtime.block_on(interval); } } @@ -245,7 +233,7 @@ impl TestNet where light: impl Iterator) -> Result>, authorities: impl Iterator) -> Result<(F, U), Error>)> ) { - let executor = self.runtime.executor(); + let executor = self.runtime.handle(); for (key, authority) in authorities { let node_config = node_config( @@ -260,7 +248,7 @@ impl TestNet where let (service, user_data) = authority(node_config).expect("Error creating test node service"); let service = SyncService::from(service); - executor.spawn(service.clone().map_err(|_| ())); + executor.spawn(service.clone().map(drop)); let addr = addr.with(multiaddr::Protocol::P2p(service.get().network().local_peer_id().into())); self.authority_nodes.push((self.nodes, service, user_data, addr)); self.nodes += 1; @@ -272,7 +260,7 @@ impl TestNet where let (service, user_data) = full(node_config).expect("Error creating test node service"); let service = SyncService::from(service); - executor.spawn(service.clone().map_err(|_| ())); + executor.spawn(service.clone().map(drop)); let addr = addr.with(multiaddr::Protocol::P2p(service.get().network().local_peer_id().into())); self.full_nodes.push((self.nodes, service, user_data, addr)); self.nodes += 1; @@ -283,7 +271,7 @@ impl TestNet where let addr = node_config.network.listen_addresses.iter().next().unwrap().clone(); let service = SyncService::from(light(node_config).expect("Error creating test node service")); - executor.spawn(service.clone().map_err(|_| ())); + executor.spawn(service.clone().map(drop)); let addr = addr.with(multiaddr::Protocol::P2p(service.get().network().local_peer_id().into())); self.light_nodes.push((self.nodes, service, addr)); self.nodes += 1; @@ -314,39 +302,33 @@ pub fn connectivity( { let temp = tempdir_with_prefix("substrate-connectivity-test"); - let runtime = { - let mut network = TestNet::new( - &temp, - spec.clone(), - (0..NUM_FULL_NODES).map(|_| { |cfg| full_builder(cfg).map(|s| (s, ())) }), - (0..NUM_LIGHT_NODES).map(|_| { |cfg| light_builder(cfg) }), - // Note: this iterator is empty but we can't just use `iter::empty()`, otherwise - // the type of the closure cannot be inferred. - (0..0).map(|_| (String::new(), { |cfg| full_builder(cfg).map(|s| (s, ())) })), - 30400, - ); - info!("Checking star topology"); - let first_address = network.full_nodes[0].3.clone(); - for (_, service, _, _) in network.full_nodes.iter().skip(1) { - service.get().network().add_reserved_peer(first_address.to_string()) - .expect("Error adding reserved peer"); - } - for (_, service, _) in network.light_nodes.iter() { - service.get().network().add_reserved_peer(first_address.to_string()) - .expect("Error adding reserved peer"); - } - - network.run_until_all_full( - move |_index, service| service.get().network().num_connected() - == expected_full_connections, - move |_index, service| service.get().network().num_connected() - == expected_light_connections, - ); - - network.runtime - }; + let mut network = TestNet::new( + &temp, + spec.clone(), + (0..NUM_FULL_NODES).map(|_| { |cfg| full_builder(cfg).map(|s| (s, ())) }), + (0..NUM_LIGHT_NODES).map(|_| { |cfg| light_builder(cfg) }), + // Note: this iterator is empty but we can't just use `iter::empty()`, otherwise + // the type of the closure cannot be inferred. + (0..0).map(|_| (String::new(), { |cfg| full_builder(cfg).map(|s| (s, ())) })), + 30400, + ); + info!("Checking star topology"); + let first_address = network.full_nodes[0].3.clone(); + for (_, service, _, _) in network.full_nodes.iter().skip(1) { + service.get().network().add_reserved_peer(first_address.to_string()) + .expect("Error adding reserved peer"); + } + for (_, service, _) in network.light_nodes.iter() { + service.get().network().add_reserved_peer(first_address.to_string()) + .expect("Error adding reserved peer"); + } - runtime.shutdown_now().wait().expect("Error shutting down runtime"); + network.run_until_all_full( + move |_index, service| service.get().network().num_connected() + == expected_full_connections, + move |_index, service| service.get().network().num_connected() + == expected_light_connections, + ); temp.close().expect("Error removing temp dir"); } @@ -456,7 +438,7 @@ pub fn sync( let first_user_data = &network.full_nodes[0].2; let best_block = BlockId::number(first_service.get().client().info().chain.best_number); let extrinsic = extrinsic_factory(&first_service.get(), first_user_data); - future::executor::block_on(first_service.get().transaction_pool().submit_one(&best_block, extrinsic)).unwrap(); + futures::executor::block_on(first_service.get().transaction_pool().submit_one(&best_block, extrinsic)).unwrap(); network.run_until_all_full( |_index, service| service.get().transaction_pool().ready().count() == 1, |_index, _service| true, From 3dd8ff4bf35c3f52fd630a19d064341a24c4a7a2 Mon Sep 17 00:00:00 2001 From: Ashley Date: Thu, 19 Dec 2019 11:04:39 +0100 Subject: [PATCH 04/26] Re-add Executor trait to SpawnTaskHandle --- client/rpc-api/src/subscriptions.rs | 10 ++++------ client/rpc/src/author/mod.rs | 5 +++-- client/service/src/lib.rs | 9 +++++++++ 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/client/rpc-api/src/subscriptions.rs b/client/rpc-api/src/subscriptions.rs index 5907bd7db7896..d5ca74fa60bc7 100644 --- a/client/rpc-api/src/subscriptions.rs +++ b/client/rpc-api/src/subscriptions.rs @@ -22,12 +22,11 @@ use jsonrpc_pubsub::{SubscriptionId, typed::{Sink, Subscriber}}; use parking_lot::Mutex; use jsonrpc_core::futures::sync::oneshot; use jsonrpc_core::futures::{Future, future}; -use futures::{task::{Spawn, SpawnExt}, FutureExt, compat::Future01CompatExt}; type Id = u64; /// Alias for a an implementation of `futures::future::Executor`. -pub type TaskExecutor = Arc; +pub type TaskExecutor = Arc + Send>> + Send + Sync>; /// Generate unique ids for subscriptions. #[derive(Clone, Debug)] @@ -93,12 +92,11 @@ impl Subscriptions { let (tx, rx) = oneshot::channel(); let future = into_future(sink) .into_future() - .select(rx.map_err(|e| warn!("Error timing out: {:?}", e))) - .compat() - .map(drop); + .select(rx.map_err(|e| warn!("Error timeing out: {:?}", e))) + .then(|_| Ok(())); self.active_subscriptions.lock().insert(id, tx); - if self.executor.spawn(Box::new(future)).is_err() { + if self.executor.execute(Box::new(future)).is_err() { error!("Failed to spawn RPC subscription task"); } } diff --git a/client/rpc/src/author/mod.rs b/client/rpc/src/author/mod.rs index 98957f890f812..1cdbda5904c85 100644 --- a/client/rpc/src/author/mod.rs +++ b/client/rpc/src/author/mod.rs @@ -42,7 +42,6 @@ use sp_transaction_pool::{ BlockHash, TxHash, TransactionFor, error::IntoPoolError, }; use sp_session::SessionKeys; -use futures::task::SpawnExt; /// Re-export the API for backward compatibility. pub use sc_rpc_api::author::*; @@ -194,7 +193,9 @@ impl AuthorApi for Author + Send + 'static>; + +impl futures01::future::Executor for SpawnTaskHandle { + fn execute(&self, future: Boxed01Future01) -> Result<(), futures01::future::ExecuteError>{ + self.spawn(future.compat().map(drop)); + Ok(()) + } +} + /// Abstraction over a Substrate service. pub trait AbstractService: 'static + Future> + Spawn + Send + Unpin { From be723198e1e33fbf57260b79038154aa46637f63 Mon Sep 17 00:00:00 2001 From: Ashley Date: Thu, 19 Dec 2019 11:17:17 +0100 Subject: [PATCH 05/26] Fix node-service --- bin/node-template/src/cli.rs | 5 +---- bin/node-template/src/service.rs | 7 ++++--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/bin/node-template/src/cli.rs b/bin/node-template/src/cli.rs index 16638c4af955d..98fa330fdb915 100644 --- a/bin/node-template/src/cli.rs +++ b/bin/node-template/src/cli.rs @@ -1,5 +1,5 @@ use crate::service; -use futures::{future::{select, Map}, FutureExt, TryFutureExt, channel::oneshot, compat::Future01CompatExt}; +use futures::{future::{select, Map}, FutureExt, TryFutureExt, channel::oneshot}; use std::cell::RefCell; use tokio::runtime::Runtime; pub use sc_cli::{VersionInfo, IntoExit, error}; @@ -87,9 +87,6 @@ where let service_res = { let exit = e.into_exit(); - let service = service - .map_err(|err| error::Error::Service(err)) - .compat(); let select = select(service, exit) .map(|_| Ok(())) .compat(); diff --git a/bin/node-template/src/service.rs b/bin/node-template/src/service.rs index e1379d2200354..c781025ba88af 100644 --- a/bin/node-template/src/service.rs +++ b/bin/node-template/src/service.rs @@ -12,6 +12,7 @@ pub use sc_executor::NativeExecutor; use sp_consensus_aura::sr25519::{AuthorityPair as AuraPair}; use grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider}; use sc_basic_authority; +use futures::{FutureExt, compat::Future01CompatExt}; // Our native executor instance. native_executor_instance!( @@ -125,7 +126,7 @@ pub fn new_full(config: Configuration(config: Configuration { // start the full GRANDPA voter @@ -176,7 +177,7 @@ pub fn new_full(config: Configuration { grandpa::setup_disabled_grandpa( From b260cfe263ec38e84acd7a47477a8c6c1278b8a6 Mon Sep 17 00:00:00 2001 From: Ashley Date: Thu, 19 Dec 2019 11:40:57 +0100 Subject: [PATCH 06/26] Update babe --- Cargo.lock | 3 +-- client/consensus/babe/Cargo.toml | 5 ++--- client/consensus/babe/src/lib.rs | 8 +++----- client/consensus/babe/src/tests.rs | 11 +++++------ client/network/test/src/lib.rs | 2 +- 5 files changed, 12 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f032f6ef25d06..9321df3e1552e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5175,7 +5175,6 @@ dependencies = [ "derive_more 0.99.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "fork-tree 2.0.0", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "futures-timer 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5214,7 +5213,7 @@ dependencies = [ "sp-version 2.0.0", "substrate-test-runtime-client 2.0.0", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index eb2875b3d37ff..3f04cf09b1833 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -29,8 +29,7 @@ sc-consensus-uncles = { version = "0.8", path = "../uncles" } sc-consensus-slots = { version = "0.8", path = "../slots" } sp-runtime = { version = "2.0.0", path = "../../../primitives/runtime" } fork-tree = { version = "2.0.0", path = "../../../utils/fork-tree" } -futures = { version = "0.3.1", features = ["compat"] } -futures01 = { package = "futures", version = "0.1" } +futures = { version = "0.3.1" } futures-timer = "0.4.0" parking_lot = "0.9.0" log = "0.4.8" @@ -48,7 +47,7 @@ sc-network-test = { version = "2.0.0", path = "../../network/test" } sc-service = { version = "2.0.0", path = "../../service" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } sc-block-builder = { version = "2.0.0", path = "../../block-builder" } -tokio = "0.1.22" +tokio = { version = "0.2", features = ["rt-core"] } env_logger = "0.7.0" tempfile = "3.1.0" diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index de06f638486ec..51f7cd6548d06 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -288,7 +288,7 @@ pub fn start_babe(BabeParams { babe_link, can_author_with, }: BabeParams) -> Result< - impl futures01::Future, + impl futures::Future, sp_consensus::Error, > where B: BlockT, @@ -324,7 +324,7 @@ pub fn start_babe(BabeParams { )?; babe_info!("Starting BABE Authorship worker"); - let slot_worker = sc_consensus_slots::start_slot_worker( + Ok(sc_consensus_slots::start_slot_worker( config.0, select_chain, worker, @@ -332,9 +332,7 @@ pub fn start_babe(BabeParams { inherent_data_providers, babe_link.time_source, can_author_with, - ); - - Ok(slot_worker.map(|_| Ok::<(), ()>(())).compat()) + )) } struct BabeWorker { diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index 8ee4ae22e248b..7ca48cd091b23 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -32,7 +32,7 @@ use sc_network_test::*; use sc_network_test::{Block as TestBlock, PeersClient}; use sc_network::config::{BoxFinalityProofRequestBuilder, ProtocolConfig}; use sp_runtime::{generic::DigestItem, traits::{Block as BlockT, DigestFor}}; -use tokio::runtime::current_thread; +use tokio::runtime::Runtime; use sc_client_api::BlockchainEvents; use log::debug; use std::{time::Duration, cell::RefCell}; @@ -347,7 +347,7 @@ fn run_one_test( let net = Arc::new(Mutex::new(net)); let mut import_notifications = Vec::new(); - let mut runtime = current_thread::Runtime::new().unwrap(); + let mut runtime = Runtime::new().unwrap(); let mut keystore_paths = Vec::new(); for (peer_id, seed) in peers { @@ -406,13 +406,12 @@ fn run_one_test( }).expect("Starts babe")); } - runtime.spawn(futures01::future::poll_fn(move || { + runtime.spawn(futures::future::poll_fn(move |_| { net.lock().poll(); - Ok::<_, ()>(futures01::Async::NotReady::<()>) + std::task::Poll::<()>::Pending })); - runtime.block_on(future::join_all(import_notifications) - .map(|_| Ok::<(), ()>(())).compat()).unwrap(); + runtime.block_on(future::join_all(import_notifications)); } #[test] diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index 8e598c95a3768..82675399fa9cc 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -217,7 +217,7 @@ pub struct Peer> { verifier: VerifierAdapter>, /// We keep a copy of the block_import so that we can invoke it for locally-generated blocks, /// instead of going through the import queue. - block_import: Box>, + block_import: Box + Send>, select_chain: Option>, backend: Option>, network: NetworkWorker::Hash>, From 07ba97d0946aeb29944d8ad077cf7d852ee6c49d Mon Sep 17 00:00:00 2001 From: Ashley Date: Thu, 19 Dec 2019 12:19:24 +0100 Subject: [PATCH 07/26] Fix browser node --- bin/node/cli/src/browser.rs | 7 +++++-- bin/node/cli/src/cli.rs | 2 +- bin/node/cli/src/service.rs | 6 +++--- client/service/src/lib.rs | 4 ++-- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/bin/node/cli/src/browser.rs b/bin/node/cli/src/browser.rs index cd1d453d8b266..94be576978c0e 100644 --- a/bin/node/cli/src/browser.rs +++ b/bin/node/cli/src/browser.rs @@ -21,6 +21,7 @@ use log::{debug, info}; use std::sync::Arc; use sc_service::{AbstractService, RpcSession, Roles as ServiceRoles, Configuration, config::DatabaseConfig}; use wasm_bindgen::prelude::*; +use futures::{FutureExt, TryFutureExt}; /// Starts the client. /// @@ -75,7 +76,9 @@ fn start_inner(wasm_ext: wasm_ext::ffi::Transport) -> Result { - let fut = service.rpc_query(&message.session, &message.rpc_json); + let fut = service.rpc_query(&message.session, &message.rpc_json) + .unit_error() + .compat(); let _ = message.send_back.send(Box::new(fut)); }, Ok(Async::NotReady) => break, @@ -84,7 +87,7 @@ fn start_inner(wasm_ext: wasm_ext::ffi::Transport) -> Result return Ok(Async::Ready(())), Async::NotReady => break } diff --git a/bin/node/cli/src/cli.rs b/bin/node/cli/src/cli.rs index 78cbdb23b7f1e..c482588dab79a 100644 --- a/bin/node/cli/src/cli.rs +++ b/bin/node/cli/src/cli.rs @@ -176,7 +176,7 @@ where T: AbstractService, E: IntoExit, { - use futures::{FutureExt, TryFutureExt, channel::oneshot, future::select, compat::Future01CompatExt}; + use futures::{FutureExt, TryFutureExt, channel::oneshot, future::select}; let (exit_send, exit) = oneshot::channel(); diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index 4b81f98bee81a..e3f51732015b0 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -115,9 +115,9 @@ macro_rules! new_full { ($config:expr, $with_startup_data: expr) => {{ use sc_network::DhtEvent; use futures::{ - compat::{Stream01CompatExt, Future01CompatExt}, + compat::Future01CompatExt, stream::StreamExt, - future::{TryFutureExt, FutureExt}, + future::FutureExt, }; let ( @@ -186,7 +186,7 @@ macro_rules! new_full { can_author_with, }; - let babe = sc_consensus_babe::start_babe(babe_config)?.compat().map(drop); + let babe = sc_consensus_babe::start_babe(babe_config)?; service.spawn_essential_task(babe); let authority_discovery = sc_authority_discovery::AuthorityDiscovery::new( diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 3089b80348ad3..3a03e26630776 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -182,7 +182,7 @@ pub trait AbstractService: 'static + Future> + /// /// If the request subscribes you to events, the `Sender` in the `RpcSession` object is used to /// send back spontaneous events. - fn rpc_query(&self, mem: &RpcSession, request: &str) -> Box> + Send>; + fn rpc_query(&self, mem: &RpcSession, request: &str) -> Box> + Send + Unpin>; /// Get shared client instance. fn client(&self) -> Arc>; @@ -264,7 +264,7 @@ where } } - fn rpc_query(&self, mem: &RpcSession, request: &str) -> Box> + Send> { + fn rpc_query(&self, mem: &RpcSession, request: &str) -> Box> + Send + Unpin> { Box::new( self.rpc_handlers.handle_request(request, mem.metadata.clone()) .compat() From 84032dd9c80b3c042a1b320af9e33e09f266e1d7 Mon Sep 17 00:00:00 2001 From: Ashley Date: Thu, 19 Dec 2019 12:30:20 +0100 Subject: [PATCH 08/26] Update aura --- Cargo.lock | 2 +- bin/node-template/src/service.rs | 2 +- client/consensus/aura/Cargo.toml | 2 +- client/consensus/aura/src/lib.rs | 15 +++++++-------- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9321df3e1552e..03902a589b454 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5165,7 +5165,7 @@ dependencies = [ "sp-version 2.0.0", "substrate-test-runtime-client 2.0.0", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/bin/node-template/src/service.rs b/bin/node-template/src/service.rs index c781025ba88af..4b4be2b83c3ee 100644 --- a/bin/node-template/src/service.rs +++ b/bin/node-template/src/service.rs @@ -126,7 +126,7 @@ pub fn new_full(config: Configuration( force_authoring: bool, keystore: KeyStorePtr, can_author_with: CAW, -) -> Result, sp_consensus::Error> where +) -> Result, sp_consensus::Error> where B: BlockT, C: ProvideRuntimeApi + BlockOf + ProvideCache + AuxStore + Send + Sync, C::Api: AuraApi>, @@ -192,7 +192,7 @@ pub fn start_aura( inherent_data_providers, AuraSlotCompatible, can_author_with, - ).map(|()| Ok::<(), ()>(())).compat()) + )) } struct AuraWorker { @@ -752,7 +752,7 @@ mod tests { use sp_runtime::traits::{Block as BlockT, DigestFor}; use sc_network::config::ProtocolConfig; use parking_lot::Mutex; - use tokio::runtime::current_thread; + use tokio::runtime::Runtime; use sp_keyring::sr25519::Keyring; use sc_client::BlockchainEvents; use sp_consensus_aura::sr25519::AuthorityPair; @@ -866,7 +866,7 @@ mod tests { let net = Arc::new(Mutex::new(net)); let mut import_notifications = Vec::new(); - let mut runtime = current_thread::Runtime::new().unwrap(); + let mut runtime = Runtime::new().unwrap(); let mut keystore_paths = Vec::new(); for (peer_id, key) in peers { let mut net = net.lock(); @@ -911,13 +911,12 @@ mod tests { runtime.spawn(aura); } - runtime.spawn(futures01::future::poll_fn(move || { + runtime.spawn(futures::future::poll_fn(move |_| { net.lock().poll(); - Ok::<_, ()>(futures01::Async::NotReady::<()>) + std::task::Poll::<()>::Pending })); - runtime.block_on(future::join_all(import_notifications) - .map(|_| Ok::<(), ()>(())).compat()).unwrap(); + runtime.block_on(future::join_all(import_notifications)); } #[test] From ae7dc83cb4f1a28ae2529fb7ffbafdcdadb5fe11 Mon Sep 17 00:00:00 2001 From: Ashley Date: Thu, 19 Dec 2019 14:32:44 +0100 Subject: [PATCH 09/26] Revert back to tokio-executor to fix runtime panic --- Cargo.lock | 2 +- client/service/Cargo.toml | 2 +- client/service/src/lib.rs | 13 +++++++++++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 03902a589b454..f361f1f9c6336 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5624,7 +5624,7 @@ dependencies = [ "substrate-test-runtime-client 2.0.0", "sysinfo 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "tracing 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 98a6e4141a6f9..e67bea356db1f 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -21,7 +21,7 @@ parking_lot = "0.9.0" lazy_static = "1.4.0" log = "0.4.8" slog = { version = "2.5.2", features = ["nested-values"] } -tokio = { version = "0.2", features = ["rt-core"] } +tokio-executor = "0.1.8" futures-timer = "2" exit-future = "0.2.0" serde = "1.0.101" diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 3a03e26630776..3ba265fbdfeba 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -39,7 +39,7 @@ use parking_lot::Mutex; use sc_client::Client; use exit_future::Signal; use futures::{ - Future, FutureExt, Stream, StreamExt, + Future, FutureExt, Stream, StreamExt, TryFutureExt, future::select, channel::mpsc, compat::*, sink::SinkExt, @@ -317,7 +317,16 @@ impl Future for } while let Poll::Ready(Some(task_to_spawn)) = Pin::new(&mut this.to_spawn_rx).poll_next(cx) { - tokio::spawn(task_to_spawn); + let executor = tokio_executor::DefaultExecutor::current(); + use futures01::future::Executor; + if let Err(err) = executor.execute(task_to_spawn.unit_error().compat()) { + debug!( + target: "service", + "Failed to spawn background task: {:?}; falling back to manual polling", + err + ); + this.to_poll.push(Box::new(err.into_future().compat().map(drop))); + } } // Polling all the `to_poll` futures. From b0308aa9ffe7aed608fc2ca4f1946d23476872e7 Mon Sep 17 00:00:00 2001 From: Ashley Date: Thu, 19 Dec 2019 14:36:21 +0100 Subject: [PATCH 10/26] Add todo item --- client/service/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 3ba265fbdfeba..31ee419543523 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -317,6 +317,7 @@ impl Future for } while let Poll::Ready(Some(task_to_spawn)) = Pin::new(&mut this.to_spawn_rx).poll_next(cx) { + // TODO: Update to tokio 0.2 when libp2p get switched to std futures (#4383) let executor = tokio_executor::DefaultExecutor::current(); use futures01::future::Executor; if let Err(err) = executor.execute(task_to_spawn.unit_error().compat()) { From ca1f5f2af01480f300c8ae615c0b0a15483600cb Mon Sep 17 00:00:00 2001 From: Ashley Date: Thu, 19 Dec 2019 14:53:07 +0100 Subject: [PATCH 11/26] Fix service tests again --- Cargo.lock | 1 + client/service/Cargo.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index f361f1f9c6336..79116a137061a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5624,6 +5624,7 @@ dependencies = [ "substrate-test-runtime-client 2.0.0", "sysinfo 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "tracing 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index e67bea356db1f..c417479511330 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -60,3 +60,4 @@ substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/ru sp-consensus-babe = { version = "0.8", path = "../../primitives/consensus/babe" } grandpa = { version = "2.0.0", package = "sc-finality-grandpa", path = "../finality-grandpa" } grandpa-primitives = { version = "2.0.0", package = "sp-finality-grandpa", path = "../../primitives/finality-grandpa" } +tokio = { version = "0.2", features = ["rt-core"] } From f650750500c4cfa557535a5f204d2d9e15c7e051 Mon Sep 17 00:00:00 2001 From: Ashley Date: Fri, 20 Dec 2019 14:54:45 +0100 Subject: [PATCH 12/26] Timeout test futures --- client/consensus/aura/src/lib.rs | 7 ++++++- client/consensus/babe/src/tests.rs | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index 8a0073cdbe016..df02ecdc5dd56 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -916,7 +916,12 @@ mod tests { std::task::Poll::<()>::Pending })); - runtime.block_on(future::join_all(import_notifications)); + let timed_out = future::select( + future::join_all(import_notifications), + futures_timer::Delay::new(std::time::Duration::from_secs(60)) + ); + + runtime.block_on(timed_out); } #[test] diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index 7ca48cd091b23..d00ad370620f9 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -411,7 +411,12 @@ fn run_one_test( std::task::Poll::<()>::Pending })); - runtime.block_on(future::join_all(import_notifications)); + let timed_out = future::select( + future::join_all(import_notifications), + futures_timer::Delay::new(std::time::Duration::from_secs(60)) + ).map(drop); + + runtime.block_on(timed_out); } #[test] From a3edd8669dea5f7e8cf44bc0f4abad5a75d48db6 Mon Sep 17 00:00:00 2001 From: Ashley Date: Fri, 20 Dec 2019 16:05:01 +0100 Subject: [PATCH 13/26] Fix tests --- Cargo.lock | 5 ++--- client/consensus/aura/Cargo.toml | 5 ++--- client/consensus/aura/src/lib.rs | 21 ++++++++++----------- client/consensus/babe/Cargo.toml | 4 ++-- client/consensus/babe/src/tests.rs | 16 ++++++---------- 5 files changed, 22 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 28c19f499ec55..b94f4dbecfd2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5137,7 +5137,6 @@ version = "0.8.0" dependencies = [ "derive_more 0.99.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "futures-timer 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5167,7 +5166,7 @@ dependencies = [ "sp-version 2.0.0", "substrate-test-runtime-client 2.0.0", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -5215,7 +5214,7 @@ dependencies = [ "sp-version 2.0.0", "substrate-test-runtime-client 2.0.0", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/client/consensus/aura/Cargo.toml b/client/consensus/aura/Cargo.toml index 2ccc8f7d7791f..e1f8284289f7c 100644 --- a/client/consensus/aura/Cargo.toml +++ b/client/consensus/aura/Cargo.toml @@ -14,8 +14,7 @@ sc-client-api = { version = "2.0.0", path = "../../api" } codec = { package = "parity-scale-codec", version = "1.0.0" } sp-consensus = { version = "0.8", path = "../../../primitives/consensus/common" } derive_more = "0.99.2" -futures = { version = "0.3.1", features = ["compat"] } -futures01 = { package = "futures", version = "0.1" } +futures = "0.3.1" futures-timer = "0.4.0" sp-inherents = { version = "2.0.0", path = "../../../primitives/inherents" } sc-keystore = { version = "2.0.0", path = "../../keystore" } @@ -38,6 +37,6 @@ sc-network = { version = "0.8", path = "../../network" } sc-network-test = { version = "2.0.0", path = "../../network/test" } sc-service = { version = "2.0.0", path = "../../service" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } -tokio = { version = "0.2", features = ["rt-core"] } +tokio = "0.1.22" env_logger = "0.7.0" tempfile = "3.1.0" diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index df02ecdc5dd56..b38716ed9e0d5 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -752,7 +752,7 @@ mod tests { use sp_runtime::traits::{Block as BlockT, DigestFor}; use sc_network::config::ProtocolConfig; use parking_lot::Mutex; - use tokio::runtime::Runtime; + use tokio::runtime::current_thread; use sp_keyring::sr25519::Keyring; use sc_client::BlockchainEvents; use sp_consensus_aura::sr25519::AuthorityPair; @@ -866,7 +866,7 @@ mod tests { let net = Arc::new(Mutex::new(net)); let mut import_notifications = Vec::new(); - let mut runtime = Runtime::new().unwrap(); + let mut runtime = current_thread::Runtime::new().unwrap(); let mut keystore_paths = Vec::new(); for (peer_id, key) in peers { let mut net = net.lock(); @@ -906,7 +906,10 @@ mod tests { false, keystore, sp_consensus::AlwaysCanAuthor, - ).expect("Starts aura"); + ) + .expect("Starts aura") + .unit_error() + .compat(); runtime.spawn(aura); } @@ -914,14 +917,10 @@ mod tests { runtime.spawn(futures::future::poll_fn(move |_| { net.lock().poll(); std::task::Poll::<()>::Pending - })); - - let timed_out = future::select( - future::join_all(import_notifications), - futures_timer::Delay::new(std::time::Duration::from_secs(60)) - ); - - runtime.block_on(timed_out); + }).unit_error().compat()); + + runtime.block_on(future::join_all(import_notifications) + .unit_error().compat()).unwrap(); } #[test] diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index 3f04cf09b1833..f68e9ddc29622 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -29,7 +29,7 @@ sc-consensus-uncles = { version = "0.8", path = "../uncles" } sc-consensus-slots = { version = "0.8", path = "../slots" } sp-runtime = { version = "2.0.0", path = "../../../primitives/runtime" } fork-tree = { version = "2.0.0", path = "../../../utils/fork-tree" } -futures = { version = "0.3.1" } +futures = "0.3.1" futures-timer = "0.4.0" parking_lot = "0.9.0" log = "0.4.8" @@ -47,7 +47,7 @@ sc-network-test = { version = "2.0.0", path = "../../network/test" } sc-service = { version = "2.0.0", path = "../../service" } substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } sc-block-builder = { version = "2.0.0", path = "../../block-builder" } -tokio = { version = "0.2", features = ["rt-core"] } +tokio = "0.1.22" env_logger = "0.7.0" tempfile = "3.1.0" diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index d00ad370620f9..7aa833e86217c 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -32,7 +32,7 @@ use sc_network_test::*; use sc_network_test::{Block as TestBlock, PeersClient}; use sc_network::config::{BoxFinalityProofRequestBuilder, ProtocolConfig}; use sp_runtime::{generic::DigestItem, traits::{Block as BlockT, DigestFor}}; -use tokio::runtime::Runtime; +use tokio::runtime::current_thread; use sc_client_api::BlockchainEvents; use log::debug; use std::{time::Duration, cell::RefCell}; @@ -347,7 +347,7 @@ fn run_one_test( let net = Arc::new(Mutex::new(net)); let mut import_notifications = Vec::new(); - let mut runtime = Runtime::new().unwrap(); + let mut runtime = current_thread::Runtime::new().unwrap(); let mut keystore_paths = Vec::new(); for (peer_id, seed) in peers { @@ -403,20 +403,16 @@ fn run_one_test( babe_link: data.link.clone(), keystore, can_author_with: sp_consensus::AlwaysCanAuthor, - }).expect("Starts babe")); + }).expect("Starts babe").unit_error().compat()); } runtime.spawn(futures::future::poll_fn(move |_| { net.lock().poll(); std::task::Poll::<()>::Pending - })); + }).unit_error().compat()); - let timed_out = future::select( - future::join_all(import_notifications), - futures_timer::Delay::new(std::time::Duration::from_secs(60)) - ).map(drop); - - runtime.block_on(timed_out); + runtime.block_on(future::join_all(import_notifications) + .unit_error().compat()).unwrap(); } #[test] From 326da2ae629f5e855ae9c6b76f9c9bb66af7b936 Mon Sep 17 00:00:00 2001 From: Ashley Date: Fri, 3 Jan 2020 15:29:42 +0100 Subject: [PATCH 14/26] nits --- client/cli/src/informant.rs | 2 +- client/consensus/aura/src/lib.rs | 2 +- client/service/src/builder.rs | 29 ++++++++++++++--------------- client/service/src/chain_ops.rs | 18 ++++++++---------- client/service/src/lib.rs | 26 +++++++++++++------------- client/service/src/status_sinks.rs | 2 +- 6 files changed, 38 insertions(+), 41 deletions(-) diff --git a/client/cli/src/informant.rs b/client/cli/src/informant.rs index 42a8525148214..09fc519495992 100644 --- a/client/cli/src/informant.rs +++ b/client/cli/src/informant.rs @@ -17,7 +17,7 @@ //! Console informant. Prints sync progress and block events. Runs on the calling thread. use sc_client_api::BlockchainEvents; -use futures::{StreamExt, FutureExt, future}; +use futures::prelude::*; use log::{info, warn}; use sp_runtime::traits::Header; use sc_service::AbstractService; diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index 6300120016b43..ea1858f11498d 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -148,7 +148,7 @@ pub fn start_aura( force_authoring: bool, keystore: KeyStorePtr, can_author_with: CAW, -) -> Result, sp_consensus::Error> where +) -> Result, sp_consensus::Error> where B: BlockT, C: ProvideRuntimeApi + BlockOf + ProvideCache + AuxStore + Send + Sync, C::Api: AuraApi>, diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 57c01d9080749..ff1fde00a6f73 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -46,7 +46,7 @@ use sp_runtime::traits::{ use sc_executor::{NativeExecutor, NativeExecutionDispatch}; use std::{ io::{Read, Write, Seek}, - marker::PhantomData, sync::Arc, time::SystemTime + marker::PhantomData, sync::Arc, time::SystemTime, pin::Pin }; use sysinfo::{get_current_pid, ProcessExt, System, SystemExt}; use sc_telemetry::{telemetry, SUBSTRATE_INFO}; @@ -666,7 +666,7 @@ pub trait ServiceBuilderCommand { self, input: impl Read + Seek + Send + 'static, force: bool, - ) -> Box> + Send + Unpin>; + ) -> Pin> + Send>>; /// Performs the blocks export. fn export_blocks( @@ -675,7 +675,7 @@ pub trait ServiceBuilderCommand { from: NumberFor, to: Option>, json: bool - ) -> Box> + Unpin>; + ) -> Pin>>>; /// Performs a revert of `blocks` blocks. fn revert_chain( @@ -687,7 +687,7 @@ pub trait ServiceBuilderCommand { fn check_block( self, block: BlockId - ) -> Box> + Send + Unpin>; + ) -> Pin> + Send>>; } impl @@ -729,7 +729,6 @@ ServiceBuilder< + TransactionPool::Hash> + TransactionPoolMaintainer::Hash>, TRpc: sc_rpc::RpcExtension + Clone, - ::Extrinsic: Unpin, { /// Builds the service. pub fn build(self) -> Result + Send + Unpin>>(); + mpsc::unbounded:: + Send>>>(); // A side-channel for essential tasks to communicate shutdown. let (essential_failed_tx, essential_failed_rx) = mpsc::unbounded(); @@ -866,18 +865,18 @@ ServiceBuilder< &BlockId::hash(notification.hash), ¬ification.retracted, ); - let _ = to_spawn_tx_.unbounded_send(Box::new(future)); + let _ = to_spawn_tx_.unbounded_send(Box::pin(future)); } let offchain = offchain.as_ref().and_then(|o| o.upgrade()); if let Some(offchain) = offchain { let future = offchain.on_block_imported(&number, network_state_info.clone(), is_validator); - let _ = to_spawn_tx_.unbounded_send(Box::new(future)); + let _ = to_spawn_tx_.unbounded_send(Box::pin(future)); } ready(()) }); - let _ = to_spawn_tx.unbounded_send(Box::new(select(events, exit.clone()).map(drop))); + let _ = to_spawn_tx.unbounded_send(Box::pin(select(events, exit.clone()).map(drop))); } { @@ -897,7 +896,7 @@ ServiceBuilder< ready(()) }); - let _ = to_spawn_tx.unbounded_send(Box::new(select(events, exit.clone()).map(drop))); + let _ = to_spawn_tx.unbounded_send(Box::pin(select(events, exit.clone()).map(drop))); } // Periodically notify the telemetry. @@ -960,7 +959,7 @@ ServiceBuilder< ready(()) }); - let _ = to_spawn_tx.unbounded_send(Box::new(select(tel_task, exit.clone()).map(drop))); + let _ = to_spawn_tx.unbounded_send(Box::pin(select(tel_task, exit.clone()).map(drop))); // Periodically send the network state to the telemetry. let (netstat_tx, netstat_rx) = mpsc::unbounded::<(NetworkStatus<_>, NetworkState)>(); @@ -973,7 +972,7 @@ ServiceBuilder< ); ready(()) }); - let _ = to_spawn_tx.unbounded_send(Box::new(select(tel_task_2, exit.clone()).map(drop))); + let _ = to_spawn_tx.unbounded_send(Box::pin(select(tel_task_2, exit.clone()).map(drop))); // RPC let (system_rpc_tx, system_rpc_rx) = mpsc::unbounded(); @@ -1036,7 +1035,7 @@ ServiceBuilder< let rpc = start_rpc_servers(&config, gen_handler)?; - let _ = to_spawn_tx.unbounded_send(Box::new(select(build_network_future( + let _ = to_spawn_tx.unbounded_send(Box::pin(select(build_network_future( config.roles, network_mut, client.clone(), @@ -1085,7 +1084,7 @@ ServiceBuilder< }); ready(()) }); - let _ = to_spawn_tx.unbounded_send(Box::new(select( + let _ = to_spawn_tx.unbounded_send(Box::pin(select( future, exit.clone() ).map(drop))); telemetry @@ -1098,7 +1097,7 @@ ServiceBuilder< exit.clone() ).map(drop); - let _ = to_spawn_tx.unbounded_send(Box::new(future)); + let _ = to_spawn_tx.unbounded_send(Box::pin(future)); } // Instrumentation diff --git a/client/service/src/chain_ops.rs b/client/service/src/chain_ops.rs index 853b44fccbee6..74609127c3d04 100644 --- a/client/service/src/chain_ops.rs +++ b/client/service/src/chain_ops.rs @@ -32,9 +32,7 @@ use sc_client::Client; use sp_consensus::import_queue::{IncomingBlock, Link, BlockImportError, BlockImportResult, ImportQueue}; use sp_consensus::BlockOrigin; -use std::{ - io::{Read, Write, Seek}, -}; +use std::{io::{Read, Write, Seek}, pin::Pin}; use sc_network::message; @@ -66,7 +64,7 @@ impl< self, input: impl Read + Seek + Send + 'static, force: bool, - ) -> Box> + Send + Unpin> { + ) -> Pin> + Send>> { struct WaitLink { imported_blocks: u64, has_error: bool, @@ -203,7 +201,7 @@ impl< return std::task::Poll::Pending; } }); - Box::new(import) + Box::pin(import) } fn export_blocks( @@ -212,7 +210,7 @@ impl< from: NumberFor, to: Option>, json: bool - ) -> Box> + Unpin> { + ) -> Pin>>> { let client = self.client; let mut block = from; @@ -272,7 +270,7 @@ impl< std::task::Poll::Pending }); - Box::new(export) + Box::pin(export) } fn revert_chain( @@ -293,7 +291,7 @@ impl< fn check_block( self, block_id: BlockId - ) -> Box> + Send + Unpin> { + ) -> Pin> + Send>> { match self.client.block(&block_id) { Ok(Some(block)) => { let mut buf = Vec::new(); @@ -302,8 +300,8 @@ impl< let reader = std::io::Cursor::new(buf); self.import_blocks(reader, true) } - Ok(None) => Box::new(future::err("Unknown block".into())), - Err(e) => Box::new(future::err(format!("Error reading block: {:?}", e).into())), + Ok(None) => Box::pin(future::err("Unknown block".into())), + Err(e) => Box::pin(future::err(format!("Error reading block: {:?}", e).into())), } } } diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 9ab8af6d887cc..64ab8cc1c7024 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -93,13 +93,13 @@ pub struct Service { /// A receiver for spawned essential-tasks concluding. essential_failed_rx: mpsc::UnboundedReceiver<()>, /// Sender for futures that must be spawned as background tasks. - to_spawn_tx: mpsc::UnboundedSender + Send + Unpin>>, + to_spawn_tx: mpsc::UnboundedSender + Send>>>, /// Receiver for futures that must be spawned as background tasks. - to_spawn_rx: mpsc::UnboundedReceiver + Send + Unpin>>, + to_spawn_rx: mpsc::UnboundedReceiver + Send>>>, /// List of futures to poll from `poll`. /// If spawning a background task is not possible, we instead push the task into this `Vec`. /// The elements must then be polled manually. - to_poll: Vec + Send + Unpin>>, + to_poll: Vec + Send>>>, rpc_handlers: sc_rpc_server::RpcHandler, _rpc: Box, _telemetry: Option, @@ -115,7 +115,7 @@ pub type TaskExecutor = Arc; /// An handle for spawning tasks in the service. #[derive(Clone)] pub struct SpawnTaskHandle { - sender: mpsc::UnboundedSender + Send + Unpin>>, + sender: mpsc::UnboundedSender + Send>>>, on_exit: exit_future::Exit, } @@ -123,7 +123,7 @@ impl Spawn for SpawnTaskHandle { fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> { let future = select(self.on_exit.clone(), future).map(drop); - self.sender.unbounded_send(Box::new(future)) + self.sender.unbounded_send(Box::pin(future)) .map_err(|_| SpawnError::shutdown()) } } @@ -139,7 +139,7 @@ impl futures01::future::Executor for SpawnTaskHandle { /// Abstraction over a Substrate service. pub trait AbstractService: 'static + Future> + - Spawn + Send + Unpin { + Spawn + Send { /// Type of block of this chain. type Block: BlockT; /// Backend storage for the client. @@ -185,7 +185,7 @@ pub trait AbstractService: 'static + Future> + /// /// If the request subscribes you to events, the `Sender` in the `RpcSession` object is used to /// send back spontaneous events. - fn rpc_query(&self, mem: &RpcSession, request: &str) -> Box> + Send + Unpin>; + fn rpc_query(&self, mem: &RpcSession, request: &str) -> Pin> + Send>>; /// Get shared client instance. fn client(&self) -> Arc>; @@ -244,7 +244,7 @@ where fn spawn_task(&self, task: impl Future + Send + Unpin + 'static) { let task = select(self.on_exit(), task).map(drop); - let _ = self.to_spawn_tx.unbounded_send(Box::new(task)); + let _ = self.to_spawn_tx.unbounded_send(Box::pin(task)); } fn spawn_essential_task(&self, task: impl Future + Send + Unpin + 'static) { @@ -257,7 +257,7 @@ where }); let task = select(self.on_exit(), essential_task).map(drop); - let _ = self.to_spawn_tx.unbounded_send(Box::new(task)); + let _ = self.to_spawn_tx.unbounded_send(Box::pin(task)); } fn spawn_task_handle(&self) -> SpawnTaskHandle { @@ -267,8 +267,8 @@ where } } - fn rpc_query(&self, mem: &RpcSession, request: &str) -> Box> + Send + Unpin> { - Box::new( + fn rpc_query(&self, mem: &RpcSession, request: &str) -> Pin> + Send>> { + Box::pin( self.rpc_handlers.handle_request(request, mem.metadata.clone()) .compat() .map(|res| res.expect("this should never fail")) @@ -329,7 +329,7 @@ impl Future for "Failed to spawn background task: {:?}; falling back to manual polling", err ); - this.to_poll.push(Box::new(err.into_future().compat().map(drop))); + this.to_poll.push(Box::pin(err.into_future().compat().map(drop))); } } @@ -350,7 +350,7 @@ impl Spawn for &self, future: FutureObj<'static, ()> ) -> Result<(), SpawnError> { - self.to_spawn_tx.unbounded_send(Box::new(future)) + self.to_spawn_tx.unbounded_send(Box::pin(future)) .map_err(|_| SpawnError::shutdown()) } } diff --git a/client/service/src/status_sinks.rs b/client/service/src/status_sinks.rs index 053ebb7e877e1..e2fa2b21c7b69 100644 --- a/client/service/src/status_sinks.rs +++ b/client/service/src/status_sinks.rs @@ -74,7 +74,7 @@ impl StatusSinks { // waken up and the moment it is polled, the period is actually not // `interval` but `interval + `. We ignore this problem in // practice. - delay: Delay::new( interval), + delay: Delay::new(interval), interval, sender: Some(sender), }); From 62e45b21079d38073cf3f210758743f0d67a2406 Mon Sep 17 00:00:00 2001 From: Ashley Date: Fri, 3 Jan 2020 15:42:20 +0100 Subject: [PATCH 15/26] Fix service test --- client/service/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 6bf8b99e19d53..5ea54d39940d4 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -139,7 +139,7 @@ impl futures01::future::Executor for SpawnTaskHandle { /// Abstraction over a Substrate service. pub trait AbstractService: 'static + Future> + - Spawn + Send { + Spawn + Send + Unpin { /// Type of block of this chain. type Block: BlockT; /// Backend storage for the client. From 5d0371947729cb26eb26c270b84cae41de2ac7c6 Mon Sep 17 00:00:00 2001 From: Ashley Date: Mon, 6 Jan 2020 12:07:58 +0100 Subject: [PATCH 16/26] Remove zstd patch --- Cargo.lock | 21 +++++++-------------- Cargo.toml | 3 --- 2 files changed, 7 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 90bfabf78a134..a0dba377722f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8099,30 +8099,24 @@ dependencies = [ [[package]] name = "zstd" version = "0.5.1+zstd.1.4.4" -source = "git+https://github.com/gyscos/zstd-rs#c0e8491d460311117bacd0262374f8b973ec8b69" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "zstd-safe 2.0.3+zstd.1.4.4 (git+https://github.com/gyscos/zstd-rs)", + "zstd-safe 2.0.3+zstd.1.4.4 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "zstd" -version = "0.5.1+zstd.1.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -replace = "zstd 0.5.1+zstd.1.4.4 (git+https://github.com/gyscos/zstd-rs)" - [[package]] name = "zstd-safe" version = "2.0.3+zstd.1.4.4" -source = "git+https://github.com/gyscos/zstd-rs#c0e8491d460311117bacd0262374f8b973ec8b69" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "zstd-sys 1.4.15+zstd.1.4.4 (git+https://github.com/gyscos/zstd-rs)", + "zstd-sys 1.4.15+zstd.1.4.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "zstd-sys" version = "1.4.15+zstd.1.4.4" -source = "git+https://github.com/gyscos/zstd-rs#c0e8491d460311117bacd0262374f8b973ec8b69" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -8699,7 +8693,6 @@ dependencies = [ "checksum zeroize 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "45af6a010d13e4cf5b54c94ba5a2b2eba5596b9e46bf5875612d332a1f2b3f86" "checksum zeroize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3cbac2ed2ba24cc90f5e06485ac8c7c1e5449fe8911aef4d8877218af021a5b8" "checksum zeroize_derive 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de251eec69fc7c1bc3923403d18ececb929380e016afe103da75f396704f8ca2" -"checksum zstd 0.5.1+zstd.1.4.4 (git+https://github.com/gyscos/zstd-rs)" = "" "checksum zstd 0.5.1+zstd.1.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5c5d978b793ae64375b80baf652919b148f6a496ac8802922d9999f5a553194f" -"checksum zstd-safe 2.0.3+zstd.1.4.4 (git+https://github.com/gyscos/zstd-rs)" = "" -"checksum zstd-sys 1.4.15+zstd.1.4.4 (git+https://github.com/gyscos/zstd-rs)" = "" +"checksum zstd-safe 2.0.3+zstd.1.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bee25eac9753cfedd48133fa1736cbd23b774e253d89badbeac7d12b23848d3f" +"checksum zstd-sys 1.4.15+zstd.1.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "89719b034dc22d240d5b407fb0a3fe6d29952c181cff9a9f95c0bd40b4f8f7d8" diff --git a/Cargo.toml b/Cargo.toml index 8fc76eeb5f6a2..505cd299d9c71 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -153,6 +153,3 @@ members = [ [profile.release] # Substrate runtime requires unwinding. panic = "unwind" - -[replace] -'zstd:0.5.1' = { git = "https://github.com/gyscos/zstd-rs" } From 9f570138816518c71147ad83591824403bf30723 Mon Sep 17 00:00:00 2001 From: Ashley Date: Mon, 6 Jan 2020 13:59:58 +0100 Subject: [PATCH 17/26] Re-add futures01 to aura and babe tests as a dev-dep --- Cargo.lock | 2 ++ client/consensus/aura/Cargo.toml | 1 + client/consensus/aura/src/lib.rs | 6 +++--- client/consensus/babe/Cargo.toml | 1 + client/consensus/babe/src/tests.rs | 6 +++--- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a0dba377722f3..3587d7fbd402a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5131,6 +5131,7 @@ version = "0.8.0" dependencies = [ "derive_more 0.99.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "futures-timer 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5170,6 +5171,7 @@ dependencies = [ "derive_more 0.99.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "fork-tree 2.0.0", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "futures-timer 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/client/consensus/aura/Cargo.toml b/client/consensus/aura/Cargo.toml index e1f8284289f7c..bcbf622cd3abc 100644 --- a/client/consensus/aura/Cargo.toml +++ b/client/consensus/aura/Cargo.toml @@ -40,3 +40,4 @@ substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils tokio = "0.1.22" env_logger = "0.7.0" tempfile = "3.1.0" +futures01 = { package = "futures", version = "0.1" } diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index d0d39d5954471..e74f5f086ad39 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -1002,10 +1002,10 @@ mod tests { runtime.spawn(aura); } - runtime.spawn(futures::future::poll_fn(move |_| { + runtime.spawn(futures01::future::poll_fn(move || { net.lock().poll(); - std::task::Poll::<()>::Pending - }).unit_error().compat()); + Ok::<_, ()>(futures01::Async::NotReady::<()>) + })); runtime.block_on(future::join_all(import_notifications) .unit_error().compat()).unwrap(); diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index f68e9ddc29622..53f60c76f909a 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -50,6 +50,7 @@ sc-block-builder = { version = "2.0.0", path = "../../block-builder" } tokio = "0.1.22" env_logger = "0.7.0" tempfile = "3.1.0" +futures01 = { package = "futures", version = "0.1" } [features] test-helpers = [] diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index 18fac95de501d..702f4942525d8 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -406,10 +406,10 @@ fn run_one_test( }).expect("Starts babe").unit_error().compat()); } - runtime.spawn(futures::future::poll_fn(move |_| { + runtime.spawn(futures01::future::poll_fn(move || { net.lock().poll(); - std::task::Poll::<()>::Pending - }).unit_error().compat()); + Ok::<_, ()>(futures01::Async::NotReady::<()>) + })); runtime.block_on(future::join_all(import_notifications) .unit_error().compat()).unwrap(); From 4a574191f4de2cf06cffd3ea624e0f07a423274b Mon Sep 17 00:00:00 2001 From: Ashley Date: Thu, 9 Jan 2020 16:37:36 +0100 Subject: [PATCH 18/26] Change failing test to tee --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 05834f11d1944..4b32f0a8c1c3d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -203,7 +203,7 @@ test-linux-stable-int: - echo "___Full log will be saved to the job artifacts only in case of failure.___" - WASM_BUILD_NO_COLOR=1 RUST_LOG=sync=trace,consensus=trace,client=trace,state-db=trace,db=trace,forks=trace,state_db=trace,storage_cache=trace time cargo test -p node-cli --release --verbose --locked -- --ignored - &> ${CI_COMMIT_SHORT_SHA}_int_failure.log + 2>&1 | tee ${CI_COMMIT_SHORT_SHA}_int_failure.log - sccache -s after_script: - awk '/FAILED|^error\[/,0' ${CI_COMMIT_SHORT_SHA}_int_failure.log From cd25fccd9b14d02e1fa23e158f357dfc1f916ea6 Mon Sep 17 00:00:00 2001 From: Ashley Date: Fri, 10 Jan 2020 13:05:12 +0100 Subject: [PATCH 19/26] Fix node --- Cargo.lock | 1 - bin/node/cli/Cargo.toml | 1 - bin/node/cli/src/service.rs | 4 ++-- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4f97cf70495a4..40e99c676461d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3025,7 +3025,6 @@ dependencies = [ "ctrlc 3.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "frame-support 2.0.0", "frame-system 2.0.0", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 14.0.5 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 1f7c90bc3a6c5..4f12775cc48fb 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -25,7 +25,6 @@ crate-type = ["cdylib", "rlib"] # third-party dependencies codec = { package = "parity-scale-codec", version = "1.0.6" } serde = { version = "1.0.102", features = ["derive"] } -futures01 = { package = "futures", version = "0.1.29" } futures = { version = "0.3.1", features = ["compat"] } hex-literal = "0.2.1" jsonrpc-core = "14.0.3" diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index 84bf90068ed32..2f53fb7637d64 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -113,8 +113,8 @@ macro_rules! new_full_start { macro_rules! new_full { ($config:expr, $with_startup_data: expr) => {{ use futures::{ - stream::StreamExt, - future::{self, FutureExt}, + prelude::*, + compat::Future01CompatExt }; use sc_network::Event; From 078992f1265dcd90a0461730f159e18876ff5a4f Mon Sep 17 00:00:00 2001 From: Ashley Date: Fri, 10 Jan 2020 14:58:41 +0100 Subject: [PATCH 20/26] Upgrade tokio --- Cargo.lock | 6 +++--- bin/node-template/Cargo.toml | 3 +-- bin/node-template/src/cli.rs | 28 +++++++++------------------- bin/node/cli/Cargo.toml | 2 +- bin/node/cli/src/cli.rs | 32 +++++++++++++------------------- client/cli/Cargo.toml | 2 +- 6 files changed, 28 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 40e99c676461d..4d19541afca28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3076,7 +3076,7 @@ dependencies = [ "structopt 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-build-script-utils 2.0.0", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-bindgen 0.2.57 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-bindgen-futures 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3216,7 +3216,6 @@ name = "node-template" version = "2.0.0" dependencies = [ "ctrlc 3.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "node-template-runtime 2.0.0", @@ -3240,7 +3239,7 @@ dependencies = [ "sp-runtime 2.0.0", "sp-transaction-pool 2.0.0", "substrate-build-script-utils 2.0.0", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "trie-root 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -7213,6 +7212,7 @@ dependencies = [ "bytes 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", "pin-project-lite 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/bin/node-template/Cargo.toml b/bin/node-template/Cargo.toml index aaaae647cf564..0333e887ec4b8 100644 --- a/bin/node-template/Cargo.toml +++ b/bin/node-template/Cargo.toml @@ -11,10 +11,9 @@ path = "src/main.rs" [dependencies] futures = "0.3.1" -futures01 = { package = "futures", version = "0.1.29" } ctrlc = { version = "3.1.3", features = ["termination"] } log = "0.4.8" -tokio = "0.1.22" +tokio = { version = "0.2", features = ["rt-threaded"] } parking_lot = "0.9.0" codec = { package = "parity-scale-codec", version = "1.0.0" } trie-root = "0.15.2" diff --git a/bin/node-template/src/cli.rs b/bin/node-template/src/cli.rs index 98fa330fdb915..44764e5c9db41 100644 --- a/bin/node-template/src/cli.rs +++ b/bin/node-template/src/cli.rs @@ -1,5 +1,5 @@ use crate::service; -use futures::{future::{select, Map}, FutureExt, TryFutureExt, channel::oneshot}; +use futures::{future::{select, Map, Either}, FutureExt, channel::oneshot}; use std::cell::RefCell; use tokio::runtime::Runtime; pub use sc_cli::{VersionInfo, IntoExit, error}; @@ -75,33 +75,23 @@ where let informant = informant::build(&service); - let future = select(exit, informant) - .map(|_| Ok(())) - .compat(); - - runtime.executor().spawn(future); + let handle = runtime.spawn(select(exit, informant)); // we eagerly drop the service so that the internal exit future is fired, // but we need to keep holding a reference to the global telemetry guard let _telemetry = service.telemetry(); - let service_res = { - let exit = e.into_exit(); - let select = select(service, exit) - .map(|_| Ok(())) - .compat(); - runtime.block_on(select) - }; + let exit = e.into_exit(); + let service_res = runtime.block_on(select(service, exit)); let _ = exit_send.send(()); - // TODO [andre]: timeout this future #1318 - - use futures01::Future; + runtime.block_on(handle); - let _ = runtime.shutdown_on_idle().wait(); - - service_res + match service_res { + Either::Left((res, _)) => res.map_err(error::Error::Service), + Either::Right((_, _)) => Ok(()) + } } // handles ctrl-c diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 4f12775cc48fb..ec54f5b374873 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -80,7 +80,7 @@ node-primitives = { version = "2.0.0", path = "../primitives" } node-executor = { version = "2.0.0", path = "../executor" } # CLI-specific dependencies -tokio = { version = "0.1.22", optional = true } +tokio = { version = "0.2", features = ["rt-threaded"], optional = true } sc-cli = { version = "2.0.0", optional = true, path = "../../../client/cli" } ctrlc = { version = "3.1.3", features = ["termination"], optional = true } node-transaction-factory = { version = "2.0.0", optional = true, path = "../transaction-factory" } diff --git a/bin/node/cli/src/cli.rs b/bin/node/cli/src/cli.rs index 823a4cc15b577..7a4321802cf36 100644 --- a/bin/node/cli/src/cli.rs +++ b/bin/node/cli/src/cli.rs @@ -15,7 +15,6 @@ // along with Substrate. If not, see . pub use sc_cli::VersionInfo; -use tokio::prelude::Future; use tokio::runtime::{Builder as RuntimeBuilder, Runtime}; use sc_cli::{IntoExit, NoCustom, SharedParams, ImportParams, error}; use sc_service::{AbstractService, Roles as ServiceRoles, Configuration}; @@ -25,6 +24,7 @@ use sc_cli::{display_role, parse_and_prepare, GetSharedParams, ParseAndPrepare}; use crate::{service, ChainSpec, load_spec}; use crate::factory_impl::FactoryState; use node_transaction_factory::RuntimeAdapter; +use futures::{channel::oneshot, future::{select, Either}}; /// Custom subcommands. #[derive(Clone, Debug, StructOpt)] @@ -105,7 +105,10 @@ pub fn run(args: I, exit: E, version: sc_cli::VersionInfo) -> error::Re info!("Chain specification: {}", config.chain_spec.name()); info!("Node name: {}", config.name); info!("Roles: {}", display_role(&config)); - let runtime = RuntimeBuilder::new().name_prefix("main-tokio-").build() + let runtime = RuntimeBuilder::new() + .thread_name("main-tokio-") + .threaded_scheduler() + .build() .map_err(|e| format!("{:?}", e))?; match config.roles { ServiceRoles::LIGHT => run_until_exit( @@ -172,34 +175,25 @@ where T: AbstractService, E: IntoExit, { - use futures::{FutureExt, TryFutureExt, channel::oneshot, future::select}; - let (exit_send, exit) = oneshot::channel(); let informant = sc_cli::informant::build(&service); - let future = select(informant, exit) - .map(|_| Ok(())) - .compat(); - - runtime.executor().spawn(future); + let handle = runtime.spawn(select(exit, informant)); // we eagerly drop the service so that the internal exit future is fired, // but we need to keep holding a reference to the global telemetry guard let _telemetry = service.telemetry(); - let service_res = { - let exit = e.into_exit(); - let select = select(service, exit) - .map(|_| Ok(())) - .compat(); - runtime.block_on(select) - }; + let exit = e.into_exit(); + let service_res = runtime.block_on(select(service, exit)); let _ = exit_send.send(()); - // TODO [andre]: timeout this future #1318 - let _ = runtime.shutdown_on_idle().wait(); + runtime.block_on(handle); - service_res + match service_res { + Either::Left((res, _)) => res.map_err(error::Error::Service), + Either::Right((_, _)) => Ok(()) + } } diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index a61f80d67dd00..b653f982e6694 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -16,7 +16,7 @@ time = "0.1.42" ansi_term = "0.12.1" lazy_static = "1.4.0" app_dirs = "1.2.1" -tokio = "0.2.1" +tokio = "0.2" futures = "0.3.1" fdlimit = "0.1.1" serde_json = "1.0.41" From 208291a2b10fc80eeb97c531ef9b992fd0242487 Mon Sep 17 00:00:00 2001 From: thiolliere Date: Fri, 10 Jan 2020 14:58:59 +0100 Subject: [PATCH 21/26] fix society --- frame/society/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/society/src/lib.rs b/frame/society/src/lib.rs index d5bf0bcf4e919..005746aeb4937 100644 --- a/frame/society/src/lib.rs +++ b/frame/society/src/lib.rs @@ -439,7 +439,7 @@ decl_storage! { /// Double map from Candidate -> Voter -> (Maybe) Vote. Votes: double_map hasher(twox_64_concat) T::AccountId, - twox_64_concat(T::AccountId) + hasher(twox_64_concat) T::AccountId => Option; /// The defending member currently being challenged. From 9c1976346237637effc07c13f7d0403daf5e71cf Mon Sep 17 00:00:00 2001 From: Ashley Date: Fri, 10 Jan 2020 15:14:44 +0100 Subject: [PATCH 22/26] Start switching grandpa to stable futures --- bin/node-template/src/service.rs | 5 ++--- bin/node/cli/src/service.rs | 9 +++------ client/finality-grandpa/src/lib.rs | 8 ++++---- client/finality-grandpa/src/observer.rs | 12 ++++++------ utils/prometheus/README.pdf | Bin 0 -> 34842 bytes 5 files changed, 15 insertions(+), 19 deletions(-) create mode 100644 utils/prometheus/README.pdf diff --git a/bin/node-template/src/service.rs b/bin/node-template/src/service.rs index 7f6ff67d282d1..92db95b5c7d89 100644 --- a/bin/node-template/src/service.rs +++ b/bin/node-template/src/service.rs @@ -12,7 +12,6 @@ pub use sc_executor::NativeExecutor; use sp_consensus_aura::sr25519::{AuthorityPair as AuraPair}; use grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider}; use sc_basic_authority; -use futures::{FutureExt, compat::Future01CompatExt}; // Our native executor instance. native_executor_instance!( @@ -164,7 +163,7 @@ pub fn new_full(config: Configuration { // start the full GRANDPA voter @@ -181,7 +180,7 @@ pub fn new_full(config: Configuration { grandpa::setup_disabled_grandpa( diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index 2f53fb7637d64..fa45ffd89bf4a 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -112,10 +112,7 @@ macro_rules! new_full_start { /// concrete types instead. macro_rules! new_full { ($config:expr, $with_startup_data: expr) => {{ - use futures::{ - prelude::*, - compat::Future01CompatExt - }; + use futures::prelude::*; use sc_network::Event; let ( @@ -222,7 +219,7 @@ macro_rules! new_full { service.network(), service.on_exit(), service.spawn_task_handle(), - )?.compat().map(drop)); + )?); }, (true, false) => { // start the full GRANDPA voter @@ -239,7 +236,7 @@ macro_rules! new_full { // the GRANDPA voter task is considered infallible, i.e. // if it fails we take down the service with it. service.spawn_essential_task( - grandpa::run_grandpa_voter(grandpa_config)?.compat().map(drop) + grandpa::run_grandpa_voter(grandpa_config)? ); }, (_, true) => { diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index dbecd9c9a4b7f..56d7b6498f547 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -547,7 +547,7 @@ pub struct GrandpaParams { /// block import worker that has already been instantiated with `block_import`. pub fn run_grandpa_voter( grandpa_params: GrandpaParams, -) -> sp_blockchain::Result + Send + 'static> where +) -> sp_blockchain::Result + Send + 'static> where Block::Hash: Ord, B: Backend + 'static, E: CallExecutor + Send + Sync + 'static, @@ -639,9 +639,9 @@ pub fn run_grandpa_voter( let telemetry_task = telemetry_task .then(|_| futures::future::empty::<(), ()>()); - use futures03::{FutureExt, TryFutureExt}; + use futures03::{FutureExt, TryFutureExt, future::select, compat::Future01CompatExt}; - Ok(voter_work.select(on_exit.map(Ok).compat()).select2(telemetry_task).then(|_| Ok(()))) + Ok(select(select(voter_work.compat(), telemetry_task.compat()), on_exit).map(drop)) } /// Future that powers the voter. @@ -885,7 +885,7 @@ where #[deprecated(since = "1.1.0", note = "Please switch to run_grandpa_voter.")] pub fn run_grandpa( grandpa_params: GrandpaParams, -) -> sp_blockchain::Result + Send + 'static> where +) -> sp_blockchain::Result + Send + 'static> where Block::Hash: Ord, B: Backend + 'static, E: CallExecutor + Send + Sync + 'static, diff --git a/client/finality-grandpa/src/observer.rs b/client/finality-grandpa/src/observer.rs index 3dbb2aff6a9cf..615cb72e0775f 100644 --- a/client/finality-grandpa/src/observer.rs +++ b/client/finality-grandpa/src/observer.rs @@ -156,7 +156,7 @@ pub fn run_grandpa_observer( network: N, on_exit: impl futures03::Future + Clone + Send + Unpin + 'static, executor: Sp, -) -> sp_blockchain::Result + Send + 'static> where +) -> sp_blockchain::Result + Send + 'static> where B: Backend + 'static, E: CallExecutor + Send + Sync + 'static, N: NetworkT + Send + Clone + 'static, @@ -195,9 +195,9 @@ pub fn run_grandpa_observer( warn!("GRANDPA Observer failed: {:?}", e); }); - use futures03::{FutureExt, TryFutureExt}; + use futures03::{FutureExt, future::select, compat::Future01CompatExt}; - Ok(observer_work.select(on_exit.map(Ok).compat()).map(|_| ()).map_err(|_| ())) + Ok(select(observer_work.compat(), on_exit).map(drop)) } /// Future that powers the observer. @@ -359,12 +359,12 @@ where } match self.voter_commands_rx.poll() { - Ok(Async::NotReady) => {} - Err(_) => { + Ok(Async::No{ // the `voter_commands_rx` stream should not fail. return Ok(Async::Ready(())) } - Ok(Async::Ready(None)) => { + Ok(Async::Ready(None)) => tReady) => {} + Err(_) => { // the `voter_commands_rx` stream should never conclude since it's never closed. return Ok(Async::Ready(())) } diff --git a/utils/prometheus/README.pdf b/utils/prometheus/README.pdf new file mode 100644 index 0000000000000000000000000000000000000000..8e8adbd1f8e01f1da040653bf9e2b97ba5de72eb GIT binary patch literal 34842 zcmeFZbyyrtvp0;pdkC_)+u|PF0>K@EySqaO7TldASRlB&Yw#qvL$DyhUEf`j-15kI z&iT&uUhhBOFvE2BR@YSZ^j3HOs(Psu#U+{8m^qNx0IUFeBP%2U0VEbxOBWkc0PXz) z9TJO}lc}MLz00k2DoA*^ zNU6Aho`l4rA_8!6as?;k0j$idKqMApLjW5yD@c5ipLY=%6@Zzcjq@Xop|drBMZwf3epAJ>JE|)X5IOB5vwtX>6)2C93yZXr6zPLGy)?m8r1{=)tZ=E{|%+*n-4I zV$rZPaj^ifaUrotn_8M%xI89BEnS=yO`XK-Z5==lw{rpTfCRL+v3F8&Ff;}=!5>dV zVtHzIZJcJko6eJ}0{B=OXLW2)D7#L_+csO`?@P&YgjEI1Mga8kZgo=cOi~>5~5z)|5 zQP99?FcWZfa4pb@f&h;Irud&74;>Jg2oM+$7|@X95Kx$q(3p@9JrJZ25RkASX~6>j zIv}B-VPN4vA|WAz2x>7v;zL72frN#HfdNtbf)i<^g+PfT1wQc7AzRz+1!T|-k#+t|d^ z%-q7#%Gt%$&E3P(>vd3YNNCub@c4wpq~w&;wDg?Zy!;OZg&&Kms%vWN>KhuHy1ILM z`}#i(41OJ-n4FrPnVnnxwzj^px%GW}=jiz4^z8iN^6DC_7bFDqPqqHg>>u>P1nC6@ zdIvD@V7(xr+(8#KCJZbY8yuF161<@!HaYMW0*+{0c4a3b1-tSgu94FhBs@xvRjMPf zYLA-z_Y@2K|D@R;iv6kA90Uq9B##i*n_BGJ#`=Zozt3~rksO}{ zo|a!)SiU9lw9P+SO2{8^VLELl*k_uNajJec|1BOU3#SZ(mv!$%5A>rxME~)$%wt+3 zqKl9;G=JPjivHPKfv>JwKSoB=e2Fm7nYTByZU>BG+`bMgyzsi){@ih=q}87>+g!|W zvR8ZASYE#3hm)V`>$&_cWv-Zia3Q66e08Jl-J6G5kPZ9w<@;sLz+Y3aRpa4d|7|PS z{@KEb*xA|t)l@vUw6jKHQ3lx$fDXt;0svgxoB#lj2b|*J2IwKNh}t`ufWG%StRViZ zpu7m+(L6sI8WCd`kfjA#9srA)vJ4XVAAr`v#l^vykA=nE-JRLk&e)9E(w^nf?EY!# zxc^gx>(oee!GD~(YpsX{1?N@=ask6PSlQGCLvw>};GDsM(I-o3=At)wHnqui2gYyi;tyYerK z{#ZfAmInZ~`HyV>Y{5s3!HVbr9^bMu=vDpd2#>AxTgP8Eob9J%e;9E|8_<~bPiEXB z^M~HcnDs(T|AQB+TM47a9R#sC(#`DrO5{{utt1D<5<@MRQ^vP9<3|M7cl#ga6%(^9 zzNhV5M(um)ahYB!si}&*I=DYPjoEqGuI7I6;^CwI=JHJebaDFqfw#J&p5>G}OL?gM zWPSH^_w@Zk_d$KPa^8~%KkutE2W~e0=ZOV3?WZ>P8b>=X?)?4t>4Y`>Z@eE)x`)j? zzMlbtxBdN}_$TdO`*ZFdJbTzaoIWUe`NDU(lIQ6|U9an;s~(ls@=Uba!`;?u|4R4s zwD5t?)z6EMw$-HshJ%Sn)#ZD-bJ9pQpNk7DPHVBtX5AF5?Jfutz1+HA{m%CkYcwRV zI(x6&B+h}IM$)STwmJZe^6YN%UptD?uR=h(p zP9_zsxlD(aJkJSr(Wq4q@9m+cIp;SbKaY~?bO*P0A;z6Y+jZ$tSJJ>(j+#;$1)PBz zF)fCHBBox5a5W?+{W!MCWFv^)n{x`&vUhex6rBw)2N_v&QFrL?9b{hDsF%#YH&#-w zgx2K2DaKiE8RYBe%Jx|H%Nss}Hqd+|t<|U1RUXoHVH~uQhQLGXrHAD$pF%cRRcx`Z z|7_{|i^`D&hxrZk?CSfA26W`mE|CL= kgT;>87DYpEIw}yBxcO_1L9DQ#tGb^Z zu#w`S1;1J{d=H-nBLC*w9E^7I$`G@~zRsHaN(llfl*7vxkB`gLbr}MWtCtz{NFj=j zt`C>XZ4%}!a0WJr_aJuTAa?O?ru`pE(0D;&TYTo9`_ajU1Od|JV4lgP1|210#kX3e zc@#NVZYN;R<^2U8=&||Gt>dpq_I!R(@sSeXb>3`JP;p_|Pkr);3co<|^AlPSEDEom zJc*g)d%}7v(0*Qf-Np?uCal_SogQ-6=5>G7AqFvBx_zPmq-hW6m%g3f5`T^coy(ZJ@jPj@2M$0Q@}Ce^E7B8g|pv zxUa(UE}Tq?buZ}?7h@}+XsN>+CE^*`9PM|(q9Lz7twiFXF3Rv9brdLDFWxDsKg-d}_4unuw;9JF=2%O#9_8V0i%&Pq?m1*4&eznT>y zn<#kyt=fZHG`P}Ho(&m`b}m}ygUTKshNw6XQdhBfD~IK4_6!&8{_h0OFjt7+z9Dn< z99XcH88rk!J7XW5Lr5c#u;2(jleR=%9IZyQcxO(!C&{Dv%5P*&E7g9D78+}WUWqMx zw~|my8$QKG?lK?UVTcwdrNxY*DOpsoiTuC~)m}FVIT}Z?s% zB!#0dN0`D=!zfH}0Rh=r=mDnIp~Ow6Bad7RdWKWaPBWZ|u`>w!!Hv$$%lw?NUjX0qn3gCOf>wJ1DoZYL zOh7(W^@cGdV?{r-00ZFzS+B#|UPRA^?%VE!T>`6k-LB{(e{Ow)r9$ira?O^#{Na8q z7hXS^wKcdem@3vh)hn0Cuyod`Ve@K%Ym!GW4wXIDqMC$!o#O-5$9}RalC&8{xdECV zq?HX-5?!qdq>mx@efJR*2W=q9ibk-asY+UpfN6jrNa&i(Hm+gwZfv&15eC-aR%)s) zJ*?5Du(8WoPx(HHgw$2?7D=`(QTlL`gO-D!H}pic*y@$OZUL;97@L$!R(z|;(k^ee zvl9b6&9CDz5CYV&77j6NR0j*ayAYa;<(17!5C{|E{czlZ5u9g^o*)G!MhdX;)8D7C zdMlct((SHOQaxd&qG6J1f+Ozh+D}hLbVd6htPI4fHc>Dq-l(Q_-b@v4qY8*`S*lmK zdV!Q*P8NlW9)7IJW^;pOK6Fnd)cGkL7D^-0_h~q_(vl5+da88&YFm|=-DQ{*bm?Zu zZjKxbHHsa)_&L{)A48(nq)O*RuQBXXM8f>LZtrm}5|`t*9L%?K&9i#*JCXE`6iCJm z`giRN=A6_JIUlTftV-JV@K8xuUZRPjVaW8JxxCa4-bg+>bnsssg{3dHu&%ZXEvPTw zKd>&YsMC6IxxCdQJG1Q{S=;>Z;;6BQe_up)h(Cvi!8D@!tB|95Uwq^JSG=v&wi=`% zrd^p#wJmJ($=MQqsm#!uIr?%qFxnWXU=bl$+7~=0)a^QbF6*}myWc=(^S;To2`A>&AzT6D5Qg|Aeb#{od+`q* zd5f2s)HS#Ts3~=6lL>~C^E|fQUcl-({DLzOXY7Kgi&{0!`4YJdt=1mPhI-jg?$Vg2 zj1e^jd-E*@S6tCg4O{GjDi;yfnlR0rC?Yo`3Hqa0^|`xd?1CH@5!f3s`{Z2;D>8%S$> zXAD|D2s$2emo1Mk&Z*A_v^0@e%$Yc?wq(-Q$PYJHws}p_fDGyLnmkX#fbg1|iW9}B z&1Dxjxna;=O9#=P*lpW}65zt7gJK;qmOg6s@%0~k_{3NF?1`$%1k3V3;=B-5K~g$`_i$dkQ!>63kVUNSwQ zu>nY4v`zZfOuZf(?DG#)J!^^%M2AzC#FEa%evJ+1EHIfci#_4J{5);%RArGK6 zLhZ9ew-eb%-obSf7`#U2<0)O`BxS1-$ch+J9{q7z`s66Z!Kj}u_qSPx-JivM_a0?4ad#?3@Fg`G4DkHAGi=NE3V4tNC30(y1$@_bML^#3(7dbMtn1Py%j2^E$&JpRQ?)6#a zqU){Ox?C|>$G@ryKL?OlyP0NZhR2KfM=J%8t(?+Rj!;5AjWuhIGGDmd2YgIpJFe=+ zP09O~ym&}eQ&~Y)QUdt~DQjG{s`v@}$)yFS)Q#9n0qHYNoSw0O;)}54604>2k%Vet zXH|DVP|zMtSB>`7rloOhMC^J@(V{|`py3CoD_zBb%4#J%Ji6w^C41oDD5L|TXEJ8L z^V{v9Fd(Tj&rs)Za4Ys?p@Xwfle-fPqFi>T82wA zP2H#)KytMdlWz7*O-{*lnNK^vMBXB%gd-T zwDac+fzyX8)DHI8CK9;IMLEw$rZu-T*?mTle8w7D<~gFFtQVQ*10urIR^#yigT5?l z*9DogqKdnTE|Kx?dKhi3H<)4(=I3xJd8VftU<_u%3%*#Zzo-s$Q&Txk{wCbpxVGxU z7eklA9qLDn9^D!p1OMLc2=SAV745qev9-rm|4^3N z7VZ<$FYgr5uRKxQ+;tc-L@bvJ#?T6yCIJ>$9^%|H7h=g#Uy`JT5uG%TRVM4vs(8roT~& zzhDUe1tP)D1psjJfc~-Z0zoNWp8pjf;oxL%YwBWQ>go)JBuwnx?QHA~P5u#^0D{-# zzn9OdKVgplLPR!JkYpS@Akc&j44QE8{_j8&b4wQsS0iR)ds~)2#rePyT-m7X1MbvHTr4;sN!$-|!I2Uw|VJRP-lW^r$je z6A)VT2#Vj;nwq2Be<_$0v5`O~~ z2ys4x4R{7cUi;%BRg3x^Nd?26Bi^JJo_1=S1+b^-!uT;I)F>*gk;@ zG3TV}TQrH8BHCi4wNCZK2XhX{mGQ_)@O?=ut1!Mad~Xg*41OMf{3Pb_j6zO=z^5m9 zJPGk#p>!vX8Vc7Om88~0X*z z?NvBJu`iG`E!Lz&@RSb6MJyuqzF2eV57fsAh0w$vI zjz1vj2@U0Id|~*o`>>THawxz&XFpM%fbFiQatOI7iCsrT$pt;ma{ zU4k4xp0M&lgOemqWba>mF_Zv+B$es=3a!c^Dg$PjFh`yfE-poo!iS#FN&!l4k>NvK zQ~qYj2xf`%$Wq4a50;)Tf3W=go8>T=r6ic8%0Ag|mMUMs+#gvI{A8(UA}~ey<~=zk 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 Date: Mon, 13 Jan 2020 16:32:01 +0100 Subject: [PATCH 23/26] Revert "Start switching grandpa to stable futures" This reverts commit 9c1976346237637effc07c13f7d0403daf5e71cf. --- bin/node-template/src/service.rs | 5 +++-- bin/node/cli/src/service.rs | 9 ++++++--- client/finality-grandpa/src/lib.rs | 8 ++++---- client/finality-grandpa/src/observer.rs | 12 ++++++------ utils/prometheus/README.pdf | Bin 34842 -> 0 bytes 5 files changed, 19 insertions(+), 15 deletions(-) delete mode 100644 utils/prometheus/README.pdf diff --git a/bin/node-template/src/service.rs b/bin/node-template/src/service.rs index 92db95b5c7d89..7f6ff67d282d1 100644 --- a/bin/node-template/src/service.rs +++ b/bin/node-template/src/service.rs @@ -12,6 +12,7 @@ pub use sc_executor::NativeExecutor; use sp_consensus_aura::sr25519::{AuthorityPair as AuraPair}; use grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider}; use sc_basic_authority; +use futures::{FutureExt, compat::Future01CompatExt}; // Our native executor instance. native_executor_instance!( @@ -163,7 +164,7 @@ pub fn new_full(config: Configuration { // start the full GRANDPA voter @@ -180,7 +181,7 @@ pub fn new_full(config: Configuration { grandpa::setup_disabled_grandpa( diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index fa45ffd89bf4a..2f53fb7637d64 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -112,7 +112,10 @@ macro_rules! new_full_start { /// concrete types instead. macro_rules! new_full { ($config:expr, $with_startup_data: expr) => {{ - use futures::prelude::*; + use futures::{ + prelude::*, + compat::Future01CompatExt + }; use sc_network::Event; let ( @@ -219,7 +222,7 @@ macro_rules! new_full { service.network(), service.on_exit(), service.spawn_task_handle(), - )?); + )?.compat().map(drop)); }, (true, false) => { // start the full GRANDPA voter @@ -236,7 +239,7 @@ macro_rules! new_full { // the GRANDPA voter task is considered infallible, i.e. // if it fails we take down the service with it. service.spawn_essential_task( - grandpa::run_grandpa_voter(grandpa_config)? + grandpa::run_grandpa_voter(grandpa_config)?.compat().map(drop) ); }, (_, true) => { diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index 56d7b6498f547..dbecd9c9a4b7f 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -547,7 +547,7 @@ pub struct GrandpaParams { /// block import worker that has already been instantiated with `block_import`. pub fn run_grandpa_voter( grandpa_params: GrandpaParams, -) -> sp_blockchain::Result + Send + 'static> where +) -> sp_blockchain::Result + Send + 'static> where Block::Hash: Ord, B: Backend + 'static, E: CallExecutor + Send + Sync + 'static, @@ -639,9 +639,9 @@ pub fn run_grandpa_voter( let telemetry_task = telemetry_task .then(|_| futures::future::empty::<(), ()>()); - use futures03::{FutureExt, TryFutureExt, future::select, compat::Future01CompatExt}; + use futures03::{FutureExt, TryFutureExt}; - Ok(select(select(voter_work.compat(), telemetry_task.compat()), on_exit).map(drop)) + Ok(voter_work.select(on_exit.map(Ok).compat()).select2(telemetry_task).then(|_| Ok(()))) } /// Future that powers the voter. @@ -885,7 +885,7 @@ where #[deprecated(since = "1.1.0", note = "Please switch to run_grandpa_voter.")] pub fn run_grandpa( grandpa_params: GrandpaParams, -) -> sp_blockchain::Result + Send + 'static> where +) -> sp_blockchain::Result + Send + 'static> where Block::Hash: Ord, B: Backend + 'static, E: CallExecutor + Send + Sync + 'static, diff --git a/client/finality-grandpa/src/observer.rs b/client/finality-grandpa/src/observer.rs index 615cb72e0775f..3dbb2aff6a9cf 100644 --- a/client/finality-grandpa/src/observer.rs +++ b/client/finality-grandpa/src/observer.rs @@ -156,7 +156,7 @@ pub fn run_grandpa_observer( network: N, on_exit: impl futures03::Future + Clone + Send + Unpin + 'static, executor: Sp, -) -> sp_blockchain::Result + Send + 'static> where +) -> sp_blockchain::Result + Send + 'static> where B: Backend + 'static, E: CallExecutor + Send + Sync + 'static, N: NetworkT + Send + Clone + 'static, @@ -195,9 +195,9 @@ pub fn run_grandpa_observer( warn!("GRANDPA Observer failed: {:?}", e); }); - use futures03::{FutureExt, future::select, compat::Future01CompatExt}; + use futures03::{FutureExt, TryFutureExt}; - Ok(select(observer_work.compat(), on_exit).map(drop)) + Ok(observer_work.select(on_exit.map(Ok).compat()).map(|_| ()).map_err(|_| ())) } /// Future that powers the observer. @@ -359,12 +359,12 @@ where } match self.voter_commands_rx.poll() { - Ok(Async::No{ + Ok(Async::NotReady) => {} + Err(_) => { // the `voter_commands_rx` stream should not fail. return Ok(Async::Ready(())) } - Ok(Async::Ready(None)) => tReady) => {} - Err(_) => { + Ok(Async::Ready(None)) => { // the `voter_commands_rx` stream should never conclude since it's never closed. return Ok(Async::Ready(())) } diff --git a/utils/prometheus/README.pdf b/utils/prometheus/README.pdf deleted file mode 100644 index 8e8adbd1f8e01f1da040653bf9e2b97ba5de72eb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 34842 zcmeFZbyyrtvp0;pdkC_)+u|PF0>K@EySqaO7TldASRlB&Yw#qvL$DyhUEf`j-15kI z&iT&uUhhBOFvE2BR@YSZ^j3HOs(Psu#U+{8m^qNx0IUFeBP%2U0VEbxOBWkc0PXz) z9TJO}lc}MLz00k2DoA*^ zNU6Aho`l4rA_8!6as?;k0j$idKqMApLjW5yD@c5ipLY=%6@Zzcjq@Xop|drBMZwf3epAJ>JE|)X5IOB5vwtX>6)2C93yZXr6zPLGy)?m8r1{=)tZ=E{|%+*n-4I zV$rZPaj^ifaUrotn_8M%xI89BEnS=yO`XK-Z5==lw{rpTfCRL+v3F8&Ff;}=!5>dV zVtHzIZJcJko6eJ}0{B=OXLW2)D7#L_+csO`?@P&YgjEI1Mga8kZgo=cOi~>5~5z)|5 zQP99?FcWZfa4pb@f&h;Irud&74;>Jg2oM+$7|@X95Kx$q(3p@9JrJZ25RkASX~6>j zIv}B-VPN4vA|WAz2x>7v;zL72frN#HfdNtbf)i<^g+PfT1wQc7AzRz+1!T|-k#+t|d^ z%-q7#%Gt%$&E3P(>vd3YNNCub@c4wpq~w&;wDg?Zy!;OZg&&Kms%vWN>KhuHy1ILM z`}#i(41OJ-n4FrPnVnnxwzj^px%GW}=jiz4^z8iN^6DC_7bFDqPqqHg>>u>P1nC6@ zdIvD@V7(xr+(8#KCJZbY8yuF161<@!HaYMW0*+{0c4a3b1-tSgu94FhBs@xvRjMPf zYLA-z_Y@2K|D@R;iv6kA90Uq9B##i*n_BGJ#`=Zozt3~rksO}{ zo|a!)SiU9lw9P+SO2{8^VLELl*k_uNajJec|1BOU3#SZ(mv!$%5A>rxME~)$%wt+3 zqKl9;G=JPjivHPKfv>JwKSoB=e2Fm7nYTByZU>BG+`bMgyzsi){@ih=q}87>+g!|W zvR8ZASYE#3hm)V`>$&_cWv-Zia3Q66e08Jl-J6G5kPZ9w<@;sLz+Y3aRpa4d|7|PS z{@KEb*xA|t)l@vUw6jKHQ3lx$fDXt;0svgxoB#lj2b|*J2IwKNh}t`ufWG%StRViZ zpu7m+(L6sI8WCd`kfjA#9srA)vJ4XVAAr`v#l^vykA=nE-JRLk&e)9E(w^nf?EY!# zxc^gx>(oee!GD~(YpsX{1?N@=ask6PSlQGCLvw>};GDsM(I-o3=At)wHnqui2gYyi;tyYerK z{#ZfAmInZ~`HyV>Y{5s3!HVbr9^bMu=vDpd2#>AxTgP8Eob9J%e;9E|8_<~bPiEXB z^M~HcnDs(T|AQB+TM47a9R#sC(#`DrO5{{utt1D<5<@MRQ^vP9<3|M7cl#ga6%(^9 zzNhV5M(um)ahYB!si}&*I=DYPjoEqGuI7I6;^CwI=JHJebaDFqfw#J&p5>G}OL?gM zWPSH^_w@Zk_d$KPa^8~%KkutE2W~e0=ZOV3?WZ>P8b>=X?)?4t>4Y`>Z@eE)x`)j? zzMlbtxBdN}_$TdO`*ZFdJbTzaoIWUe`NDU(lIQ6|U9an;s~(ls@=Uba!`;?u|4R4s zwD5t?)z6EMw$-HshJ%Sn)#ZD-bJ9pQpNk7DPHVBtX5AF5?Jfutz1+HA{m%CkYcwRV zI(x6&B+h}IM$)STwmJZe^6YN%UptD?uR=h(p zP9_zsxlD(aJkJSr(Wq4q@9m+cIp;SbKaY~?bO*P0A;z6Y+jZ$tSJJ>(j+#;$1)PBz zF)fCHBBox5a5W?+{W!MCWFv^)n{x`&vUhex6rBw)2N_v&QFrL?9b{hDsF%#YH&#-w zgx2K2DaKiE8RYBe%Jx|H%Nss}Hqd+|t<|U1RUXoHVH~uQhQLGXrHAD$pF%cRRcx`Z z|7_{|i^`D&hxrZk?CSfA26W`mE|CL= kgT;>87DYpEIw}yBxcO_1L9DQ#tGb^Z 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%0Ag|mMUMs+#gvI{A8(UA}~ey<~=zk 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 Date: Mon, 13 Jan 2020 16:39:17 +0100 Subject: [PATCH 24/26] Fix utils --- utils/browser/src/lib.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/utils/browser/src/lib.rs b/utils/browser/src/lib.rs index e404c6612906c..0dbde57182766 100644 --- a/utils/browser/src/lib.rs +++ b/utils/browser/src/lib.rs @@ -22,10 +22,7 @@ use service::{ ChainSpec, RuntimeGenesis }; use wasm_bindgen::prelude::*; -use futures::{ - TryFutureExt as _, FutureExt as _, Stream as _, Future as _, TryStreamExt as _, - channel::{oneshot, mpsc}, future::{poll_fn, ok}, compat::*, -}; +use futures::{prelude::*, channel::{oneshot, mpsc}, future::{poll_fn, ok}, compat::*}; use std::task::Poll; use std::pin::Pin; use chain_spec::Extension; @@ -82,8 +79,7 @@ struct RpcMessage { } /// Create a Client object that connects to a service. -pub fn start_client(service: impl AbstractService) -> Client { - let mut service = service.compat(); +pub fn start_client(mut service: impl AbstractService) -> Client { // We dispatch a background task responsible for processing the service. // // The main action performed by the code below consists in polling the service with @@ -94,10 +90,8 @@ pub fn start_client(service: impl AbstractService) -> Client { loop { match Pin::new(&mut rpc_send_rx).poll_next(cx) { Poll::Ready(Some(message)) => { - let fut = service.get_ref() + let fut = service .rpc_query(&message.session, &message.rpc_json) - .compat() - .unwrap_or_else(|_| None) .boxed(); let _ = message.send_back.send(fut); }, From 01e207340a2fd4883767b48d9adc5010114aa8e9 Mon Sep 17 00:00:00 2001 From: Ashley Date: Tue, 14 Jan 2020 11:59:21 +0100 Subject: [PATCH 25/26] Revert substrate service test --- Cargo.lock | 4 +- client/service/test/Cargo.toml | 6 +- client/service/test/src/lib.rs | 109 +++++++++++++++++++-------------- 3 files changed, 69 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4d19541afca28..7fc486ea195cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5767,9 +5767,9 @@ dependencies = [ name = "sc-service-test" version = "2.0.0" dependencies = [ - "async-std 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "sc-client 2.0.0", @@ -5780,7 +5780,7 @@ dependencies = [ "sp-runtime 2.0.0", "sp-transaction-pool 2.0.0", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index 4be4831ba94ae..6fa6e145cfd5e 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -6,12 +6,12 @@ edition = "2018" [dependencies] tempfile = "3.1.0" -tokio = { version = "0.2", features = ["rt-core"] } -futures = "0.3" -async-std = { version = "1", features = ["unstable"] } +tokio = "0.1.22" +futures01 = { package = "futures", version = "0.1.29" } log = "0.4.8" env_logger = "0.7.0" fdlimit = "0.1.1" +futures = { version = "0.3.1", features = ["compat"] } sc-service = { version = "2.0.0", default-features = false, path = "../../service" } sc-network = { version = "0.8", path = "../../network" } sp-consensus = { version = "0.8", path = "../../../primitives/consensus/common" } diff --git a/client/service/test/src/lib.rs b/client/service/test/src/lib.rs index 82b2d7070e597..dd6395e9c6228 100644 --- a/client/service/test/src/lib.rs +++ b/client/service/test/src/lib.rs @@ -20,13 +20,11 @@ use std::iter; use std::sync::{Arc, Mutex, MutexGuard}; use std::net::Ipv4Addr; use std::time::Duration; -use std::pin::Pin; -use std::task::{Poll, Context}; use log::info; -use futures::{Future, FutureExt, StreamExt, future::ready}; +use futures01::{Future, Stream, Poll}; use tempfile::TempDir; -use tokio::runtime::Runtime; -use async_std::stream::interval; +use tokio::{runtime::Runtime, prelude::FutureExt}; +use tokio::timer::Interval; use sc_service::{ AbstractService, ChainSpec, @@ -40,6 +38,9 @@ use sc_network::config::{NetworkConfiguration, TransportConfig, NodeKeyConfig, S use sp_runtime::{generic::BlockId, traits::Block as BlockT}; use sp_transaction_pool::TransactionPool; +/// Maximum duration of single wait call. +const MAX_WAIT_TIME: Duration = Duration::from_secs(60 * 3); + struct TestNet { runtime: Runtime, authority_nodes: Vec<(usize, SyncService, U, Multiaddr)>, @@ -71,11 +72,13 @@ impl From for SyncService { } } -impl> + Unpin> Future for SyncService { - type Output = Result<(), sc_service::Error>; +impl> + Unpin> Future for SyncService { + type Item = (); + type Error = sc_service::Error; - fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { - Pin::new(&mut *Pin::into_inner(self).0.lock().unwrap()).poll(cx) + fn poll(&mut self) -> Poll { + let mut f = self.0.lock().unwrap(); + futures::compat::Compat::new(&mut *f).poll() } } @@ -93,24 +96,34 @@ where F: Send + 'static, L: Send +'static, U: Clone + Send + 'static { let full_nodes = self.full_nodes.clone(); let light_nodes = self.light_nodes.clone(); - let interval = interval(Duration::from_millis(100)) + let interval = Interval::new_interval(Duration::from_millis(100)) + .map_err(|_| ()) .for_each(move |_| { let full_ready = full_nodes.iter().all(|&(ref id, ref service, _, _)| full_predicate(*id, service) ); if !full_ready { - return ready(()); + return Ok(()); } - let _ = light_nodes.iter().all(|&(ref id, ref service, _)| + let light_ready = light_nodes.iter().all(|&(ref id, ref service, _)| light_predicate(*id, service) ); - ready(()) - }); + if !light_ready { + Ok(()) + } else { + Err(()) + } + }) + .timeout(MAX_WAIT_TIME); - self.runtime.block_on(interval); + match self.runtime.block_on(interval) { + Ok(()) => unreachable!("interval always fails; qed"), + Err(ref err) if err.is_inner() => (), + Err(_) => panic!("Waited for too long"), + } } } @@ -235,7 +248,7 @@ impl TestNet where light: impl Iterator) -> Result>, authorities: impl Iterator) -> Result<(F, U), Error>)> ) { - let executor = self.runtime.handle(); + let executor = self.runtime.executor(); for (key, authority) in authorities { let node_config = node_config( @@ -250,7 +263,7 @@ impl TestNet where let (service, user_data) = authority(node_config).expect("Error creating test node service"); let service = SyncService::from(service); - executor.spawn(service.clone().map(drop)); + executor.spawn(service.clone().map_err(|_| ())); let addr = addr.with(multiaddr::Protocol::P2p(service.get().network().local_peer_id().into())); self.authority_nodes.push((self.nodes, service, user_data, addr)); self.nodes += 1; @@ -262,7 +275,7 @@ impl TestNet where let (service, user_data) = full(node_config).expect("Error creating test node service"); let service = SyncService::from(service); - executor.spawn(service.clone().map(drop)); + executor.spawn(service.clone().map_err(|_| ())); let addr = addr.with(multiaddr::Protocol::P2p(service.get().network().local_peer_id().into())); self.full_nodes.push((self.nodes, service, user_data, addr)); self.nodes += 1; @@ -273,7 +286,7 @@ impl TestNet where let addr = node_config.network.listen_addresses.iter().next().unwrap().clone(); let service = SyncService::from(light(node_config).expect("Error creating test node service")); - executor.spawn(service.clone().map(drop)); + executor.spawn(service.clone().map_err(|_| ())); let addr = addr.with(multiaddr::Protocol::P2p(service.get().network().local_peer_id().into())); self.light_nodes.push((self.nodes, service, addr)); self.nodes += 1; @@ -304,33 +317,39 @@ pub fn connectivity( { let temp = tempdir_with_prefix("substrate-connectivity-test"); - let mut network = TestNet::new( - &temp, - spec.clone(), - (0..NUM_FULL_NODES).map(|_| { |cfg| full_builder(cfg).map(|s| (s, ())) }), - (0..NUM_LIGHT_NODES).map(|_| { |cfg| light_builder(cfg) }), - // Note: this iterator is empty but we can't just use `iter::empty()`, otherwise - // the type of the closure cannot be inferred. - (0..0).map(|_| (String::new(), { |cfg| full_builder(cfg).map(|s| (s, ())) })), - 30400, - ); - info!("Checking star topology"); - let first_address = network.full_nodes[0].3.clone(); - for (_, service, _, _) in network.full_nodes.iter().skip(1) { - service.get().network().add_reserved_peer(first_address.to_string()) - .expect("Error adding reserved peer"); - } - for (_, service, _) in network.light_nodes.iter() { - service.get().network().add_reserved_peer(first_address.to_string()) - .expect("Error adding reserved peer"); - } + let runtime = { + let mut network = TestNet::new( + &temp, + spec.clone(), + (0..NUM_FULL_NODES).map(|_| { |cfg| full_builder(cfg).map(|s| (s, ())) }), + (0..NUM_LIGHT_NODES).map(|_| { |cfg| light_builder(cfg) }), + // Note: this iterator is empty but we can't just use `iter::empty()`, otherwise + // the type of the closure cannot be inferred. + (0..0).map(|_| (String::new(), { |cfg| full_builder(cfg).map(|s| (s, ())) })), + 30400, + ); + info!("Checking star topology"); + let first_address = network.full_nodes[0].3.clone(); + for (_, service, _, _) in network.full_nodes.iter().skip(1) { + service.get().network().add_reserved_peer(first_address.to_string()) + .expect("Error adding reserved peer"); + } + for (_, service, _) in network.light_nodes.iter() { + service.get().network().add_reserved_peer(first_address.to_string()) + .expect("Error adding reserved peer"); + } + + network.run_until_all_full( + move |_index, service| service.get().network().num_connected() + == expected_full_connections, + move |_index, service| service.get().network().num_connected() + == expected_light_connections, + ); + + network.runtime + }; - network.run_until_all_full( - move |_index, service| service.get().network().num_connected() - == expected_full_connections, - move |_index, service| service.get().network().num_connected() - == expected_light_connections, - ); + runtime.shutdown_now().wait().expect("Error shutting down runtime"); temp.close().expect("Error removing temp dir"); } From 87c740e63780faedbab5b789144973674a64e72b Mon Sep 17 00:00:00 2001 From: Ashley Date: Tue, 14 Jan 2020 15:14:24 +0100 Subject: [PATCH 26/26] Revert gitlab --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4b32f0a8c1c3d..05834f11d1944 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -203,7 +203,7 @@ test-linux-stable-int: - echo "___Full log will be saved to the job artifacts only in case of failure.___" - WASM_BUILD_NO_COLOR=1 RUST_LOG=sync=trace,consensus=trace,client=trace,state-db=trace,db=trace,forks=trace,state_db=trace,storage_cache=trace time cargo test -p node-cli --release --verbose --locked -- --ignored - 2>&1 | tee ${CI_COMMIT_SHORT_SHA}_int_failure.log + &> ${CI_COMMIT_SHORT_SHA}_int_failure.log - sccache -s after_script: - awk '/FAILED|^error\[/,0' ${CI_COMMIT_SHORT_SHA}_int_failure.log