mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 15:41:02 +00:00
Remove the service, replacing it with a struct of individual chain components (#6352)
* WIP * Making progress * Almost ready * Get service tests compiling * Fix node screenshot * Line widths * Fix node cli tests * Fix node cli warning * ChainComponents -> ServiceComponents, fix tests * make spawn_handle public * Remove spawnnamed impl for taskmanager * Move the keep alive stuff to the task manager * Move the telemetry, base path, rpc keep_alive to the service builder * Make the task manager keep alive an internal detail * Rewrite the browser start_client future * Remove run_node etc * Revert my personal changes to browser-demo/build.sh * use |config| * Add a runtime_version function to SubstrateCli * Reexport role and runtime version from sc cli * Update Cargo.lock * runtime_version -> native_runtime_version * Pass chain spec to native_runtime_version for polkadot * Fix line widths * Traitify ServiceComponents Client
This commit is contained in:
@@ -36,22 +36,15 @@ mod client;
|
||||
mod task_manager;
|
||||
|
||||
use std::{io, pin::Pin};
|
||||
use std::marker::PhantomData;
|
||||
use std::net::SocketAddr;
|
||||
use std::collections::HashMap;
|
||||
use std::time::Duration;
|
||||
use wasm_timer::Instant;
|
||||
use std::task::{Poll, Context};
|
||||
use std::task::Poll;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use client::Client;
|
||||
use futures::{
|
||||
Future, FutureExt, Stream, StreamExt,
|
||||
compat::*,
|
||||
sink::SinkExt,
|
||||
task::{Spawn, FutureObj, SpawnError},
|
||||
};
|
||||
use sc_network::{NetworkService, NetworkStatus, network_state::NetworkState, PeerId};
|
||||
use futures::{Future, FutureExt, Stream, StreamExt, compat::*};
|
||||
use sc_network::{NetworkStatus, network_state::NetworkState, PeerId};
|
||||
use log::{log, warn, debug, error, Level};
|
||||
use codec::{Encode, Decode};
|
||||
use sp_runtime::generic::BlockId;
|
||||
@@ -84,14 +77,9 @@ pub use sc_network::config::{
|
||||
TransactionImportFuture,
|
||||
};
|
||||
pub use sc_tracing::TracingReceiver;
|
||||
pub use task_manager::{SpawnEssentialTaskHandle, SpawnTaskHandle};
|
||||
use task_manager::TaskManager;
|
||||
use sp_blockchain::{HeaderBackend, HeaderMetadata};
|
||||
use sp_api::{ApiExt, ConstructRuntimeApi, ApiErrorExt};
|
||||
use sc_client_api::{
|
||||
Backend as BackendT, BlockchainEvents, CallExecutor, UsageProvider,
|
||||
};
|
||||
use sp_block_builder::BlockBuilder;
|
||||
pub use task_manager::SpawnTaskHandle;
|
||||
pub use task_manager::TaskManager;
|
||||
use sc_client_api::{Backend, BlockchainEvents};
|
||||
|
||||
const DEFAULT_PROTOCOL_ID: &str = "sup";
|
||||
|
||||
@@ -105,88 +93,10 @@ impl<T: MallocSizeOf> MallocSizeOfWasm for T {}
|
||||
#[cfg(target_os = "unknown")]
|
||||
impl<T> MallocSizeOfWasm for T {}
|
||||
|
||||
/// Substrate service.
|
||||
pub struct Service<TBl, TCl, TSc, TNetStatus, TNet, TTxPool, TOc> {
|
||||
client: Arc<TCl>,
|
||||
task_manager: TaskManager,
|
||||
select_chain: Option<TSc>,
|
||||
network: Arc<TNet>,
|
||||
// Sinks to propagate network status updates.
|
||||
// For each element, every time the `Interval` fires we push an element on the sender.
|
||||
network_status_sinks: Arc<Mutex<status_sinks::StatusSinks<(TNetStatus, NetworkState)>>>,
|
||||
transaction_pool: Arc<TTxPool>,
|
||||
// Send a signal when a spawned essential task has concluded. The next time
|
||||
// the service future is polled it should complete with an error.
|
||||
essential_failed_tx: TracingUnboundedSender<()>,
|
||||
// A receiver for spawned essential-tasks concluding.
|
||||
essential_failed_rx: TracingUnboundedReceiver<()>,
|
||||
rpc_handlers: sc_rpc_server::RpcHandler<sc_rpc::Metadata>,
|
||||
_rpc: Box<dyn std::any::Any + Send + Sync>,
|
||||
_telemetry: Option<sc_telemetry::Telemetry>,
|
||||
_telemetry_on_connect_sinks: Arc<Mutex<Vec<TracingUnboundedSender<()>>>>,
|
||||
_offchain_workers: Option<Arc<TOc>>,
|
||||
keystore: sc_keystore::KeyStorePtr,
|
||||
marker: PhantomData<TBl>,
|
||||
prometheus_registry: Option<prometheus_endpoint::Registry>,
|
||||
// The base path is kept here because it can be a temporary directory which will be deleted
|
||||
// when dropped
|
||||
_base_path: Option<Arc<BasePath>>,
|
||||
}
|
||||
|
||||
impl<TBl, TCl, TSc, TNetStatus, TNet, TTxPool, TOc> Unpin for Service<TBl, TCl, TSc, TNetStatus, TNet, TTxPool, TOc> {}
|
||||
|
||||
/// Abstraction over a Substrate service.
|
||||
pub trait AbstractService: Future<Output = Result<(), Error>> + Send + Unpin + Spawn + 'static {
|
||||
/// Type of block of this chain.
|
||||
type Block: BlockT;
|
||||
/// Backend storage for the client.
|
||||
type Backend: 'static + BackendT<Self::Block>;
|
||||
/// How to execute calls towards the runtime.
|
||||
type CallExecutor: 'static + CallExecutor<Self::Block> + Send + Sync + Clone;
|
||||
/// API that the runtime provides.
|
||||
type RuntimeApi: Send + Sync;
|
||||
/// Chain selection algorithm.
|
||||
type SelectChain: sp_consensus::SelectChain<Self::Block>;
|
||||
/// Transaction pool.
|
||||
type TransactionPool: TransactionPool<Block = Self::Block> + MallocSizeOfWasm;
|
||||
/// The generic Client type, the bounds here are the ones specifically required by
|
||||
/// internal crates like sc_informant.
|
||||
type Client:
|
||||
HeaderMetadata<Self::Block, Error = sp_blockchain::Error> + UsageProvider<Self::Block>
|
||||
+ BlockchainEvents<Self::Block> + HeaderBackend<Self::Block> + Send + Sync;
|
||||
|
||||
/// Get event stream for telemetry connection established events.
|
||||
fn telemetry_on_connect_stream(&self) -> TracingUnboundedReceiver<()>;
|
||||
|
||||
/// return a shared instance of Telemetry (if enabled)
|
||||
fn telemetry(&self) -> Option<sc_telemetry::Telemetry>;
|
||||
|
||||
/// Spawns a task in the background that runs the future passed as parameter.
|
||||
///
|
||||
/// Information about this task will be reported to Prometheus.
|
||||
///
|
||||
/// The task name is a `&'static str` as opposed to a `String`. The reason for that is that
|
||||
/// in order to avoid memory consumption issues with the Prometheus metrics, the set of
|
||||
/// possible task names has to be bounded.
|
||||
#[deprecated(note = "Use `spawn_task_handle().spawn() instead.")]
|
||||
fn spawn_task(&self, name: &'static str, task: impl Future<Output = ()> + Send + '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.
|
||||
#[deprecated(note = "Use `spawn_essential_task_handle().spawn() instead.")]
|
||||
fn spawn_essential_task(&self, name: &'static str, task: impl Future<Output = ()> + Send + 'static);
|
||||
|
||||
/// Returns a handle for spawning essential tasks. Any task spawned through this handle is
|
||||
/// considered essential, i.e. if it errors we trigger a service exit.
|
||||
fn spawn_essential_task_handle(&self) -> SpawnEssentialTaskHandle;
|
||||
|
||||
/// Returns a handle for spawning tasks.
|
||||
fn spawn_task_handle(&self) -> SpawnTaskHandle;
|
||||
|
||||
/// Returns the keystore that stores keys.
|
||||
fn keystore(&self) -> sc_keystore::KeyStorePtr;
|
||||
/// RPC handlers that can perform RPC queries.
|
||||
pub struct RpcHandlers(sc_rpc_server::RpcHandler<sc_rpc::Metadata>);
|
||||
|
||||
impl RpcHandlers {
|
||||
/// Starts an RPC query.
|
||||
///
|
||||
/// The query is passed as a string and must be a JSON text similar to what an HTTP client
|
||||
@@ -196,178 +106,76 @@ pub trait AbstractService: Future<Output = Result<(), Error>> + Send + Unpin + S
|
||||
///
|
||||
/// 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) -> Pin<Box<dyn Future<Output = Option<String>> + Send>>;
|
||||
pub fn rpc_query(&self, mem: &RpcSession, request: &str)
|
||||
-> Pin<Box<dyn Future<Output = Option<String>> + Send>> {
|
||||
self.0.handle_request(request, mem.metadata.clone())
|
||||
.compat()
|
||||
.map(|res| res.expect("this should never fail"))
|
||||
.boxed()
|
||||
}
|
||||
}
|
||||
|
||||
/// Get shared client instance.
|
||||
fn client(&self) -> Arc<Self::Client>;
|
||||
/// Sinks to propagate network status updates.
|
||||
/// For each element, every time the `Interval` fires we push an element on the sender.
|
||||
pub struct NetworkStatusSinks<Block: BlockT>(
|
||||
Arc<Mutex<status_sinks::StatusSinks<(NetworkStatus<Block>, NetworkState)>>>,
|
||||
);
|
||||
|
||||
/// Get clone of select chain.
|
||||
fn select_chain(&self) -> Option<Self::SelectChain>;
|
||||
|
||||
/// Get shared network instance.
|
||||
fn network(&self)
|
||||
-> Arc<NetworkService<Self::Block, <Self::Block as BlockT>::Hash>>;
|
||||
impl<Block: BlockT> NetworkStatusSinks<Block> {
|
||||
fn new(
|
||||
sinks: Arc<Mutex<status_sinks::StatusSinks<(NetworkStatus<Block>, NetworkState)>>>
|
||||
) -> Self {
|
||||
Self(sinks)
|
||||
}
|
||||
|
||||
/// Returns a receiver that periodically receives a status of the network.
|
||||
fn network_status(&self, interval: Duration) -> TracingUnboundedReceiver<(NetworkStatus<Self::Block>, NetworkState)>;
|
||||
|
||||
/// Get shared transaction pool instance.
|
||||
fn transaction_pool(&self) -> Arc<Self::TransactionPool>;
|
||||
|
||||
/// Get a handle to a future that will resolve on exit.
|
||||
#[deprecated(note = "Use `spawn_task`/`spawn_essential_task` instead, those functions will attach on_exit signal.")]
|
||||
fn on_exit(&self) -> ::exit_future::Exit;
|
||||
|
||||
/// Get the prometheus metrics registry, if available.
|
||||
fn prometheus_registry(&self) -> Option<prometheus_endpoint::Registry>;
|
||||
|
||||
/// Get a clone of the base_path
|
||||
fn base_path(&self) -> Option<Arc<BasePath>>;
|
||||
}
|
||||
|
||||
impl<TBl, TBackend, TExec, TRtApi, TSc, TExPool, TOc> AbstractService for
|
||||
Service<TBl, Client<TBackend, TExec, TBl, TRtApi>, TSc, NetworkStatus<TBl>,
|
||||
NetworkService<TBl, TBl::Hash>, TExPool, TOc>
|
||||
where
|
||||
TBl: BlockT,
|
||||
TBackend: 'static + BackendT<TBl>,
|
||||
TExec: 'static + CallExecutor<TBl, Backend = TBackend> + Send + Sync + Clone,
|
||||
TRtApi: 'static + Send + Sync + ConstructRuntimeApi<TBl, Client<TBackend, TExec, TBl, TRtApi>>,
|
||||
<TRtApi as ConstructRuntimeApi<TBl, Client<TBackend, TExec, TBl, TRtApi>>>::RuntimeApi:
|
||||
sp_api::Core<TBl>
|
||||
+ ApiExt<TBl, StateBackend = TBackend::State>
|
||||
+ ApiErrorExt<Error = sp_blockchain::Error>
|
||||
+ BlockBuilder<TBl>,
|
||||
TSc: sp_consensus::SelectChain<TBl> + 'static + Clone + Send + Unpin,
|
||||
TExPool: 'static + TransactionPool<Block = TBl> + MallocSizeOfWasm,
|
||||
TOc: 'static + Send + Sync,
|
||||
{
|
||||
type Block = TBl;
|
||||
type Backend = TBackend;
|
||||
type CallExecutor = TExec;
|
||||
type RuntimeApi = TRtApi;
|
||||
type SelectChain = TSc;
|
||||
type TransactionPool = TExPool;
|
||||
type Client = Client<Self::Backend, Self::CallExecutor, Self::Block, Self::RuntimeApi>;
|
||||
|
||||
fn telemetry_on_connect_stream(&self) -> TracingUnboundedReceiver<()> {
|
||||
let (sink, stream) = tracing_unbounded("mpsc_telemetry_on_connect");
|
||||
self._telemetry_on_connect_sinks.lock().push(sink);
|
||||
stream
|
||||
}
|
||||
|
||||
fn telemetry(&self) -> Option<sc_telemetry::Telemetry> {
|
||||
self._telemetry.clone()
|
||||
}
|
||||
|
||||
fn keystore(&self) -> sc_keystore::KeyStorePtr {
|
||||
self.keystore.clone()
|
||||
}
|
||||
|
||||
fn spawn_task(&self, name: &'static str, task: impl Future<Output = ()> + Send + 'static) {
|
||||
self.task_manager.spawn(name, task)
|
||||
}
|
||||
|
||||
fn spawn_essential_task(&self, name: &'static str, task: impl Future<Output = ()> + Send + 'static) {
|
||||
let mut essential_failed = self.essential_failed_tx.clone();
|
||||
let essential_task = std::panic::AssertUnwindSafe(task)
|
||||
.catch_unwind()
|
||||
.map(move |_| {
|
||||
error!("Essential task `{}` failed. Shutting down service.", name);
|
||||
let _ = essential_failed.send(());
|
||||
});
|
||||
|
||||
let _ = self.spawn_task_handle().spawn(name, essential_task);
|
||||
}
|
||||
|
||||
fn spawn_task_handle(&self) -> SpawnTaskHandle {
|
||||
self.task_manager.spawn_handle()
|
||||
}
|
||||
|
||||
fn spawn_essential_task_handle(&self) -> SpawnEssentialTaskHandle {
|
||||
SpawnEssentialTaskHandle::new(
|
||||
self.essential_failed_tx.clone(),
|
||||
self.task_manager.spawn_handle(),
|
||||
)
|
||||
}
|
||||
|
||||
fn rpc_query(&self, mem: &RpcSession, request: &str) -> Pin<Box<dyn Future<Output = Option<String>> + Send>> {
|
||||
Box::pin(
|
||||
self.rpc_handlers.handle_request(request, mem.metadata.clone())
|
||||
.compat()
|
||||
.map(|res| res.expect("this should never fail"))
|
||||
)
|
||||
}
|
||||
|
||||
fn client(&self) -> Arc<Self::Client> {
|
||||
self.client.clone()
|
||||
}
|
||||
|
||||
fn select_chain(&self) -> Option<Self::SelectChain> {
|
||||
self.select_chain.clone()
|
||||
}
|
||||
|
||||
fn network(&self)
|
||||
-> Arc<NetworkService<Self::Block, <Self::Block as BlockT>::Hash>>
|
||||
{
|
||||
self.network.clone()
|
||||
}
|
||||
|
||||
fn network_status(&self, interval: Duration) -> TracingUnboundedReceiver<(NetworkStatus<Self::Block>, NetworkState)> {
|
||||
pub fn network_status(&self, interval: Duration)
|
||||
-> TracingUnboundedReceiver<(NetworkStatus<Block>, NetworkState)> {
|
||||
let (sink, stream) = tracing_unbounded("mpsc_network_status");
|
||||
self.network_status_sinks.lock().push(interval, sink);
|
||||
self.0.lock().push(interval, sink);
|
||||
stream
|
||||
}
|
||||
}
|
||||
|
||||
fn transaction_pool(&self) -> Arc<Self::TransactionPool> {
|
||||
self.transaction_pool.clone()
|
||||
}
|
||||
/// Sinks to propagate telemetry connection established events.
|
||||
pub struct TelemetryOnConnectSinks(pub Arc<Mutex<Vec<TracingUnboundedSender<()>>>>);
|
||||
|
||||
fn on_exit(&self) -> exit_future::Exit {
|
||||
self.task_manager.on_exit()
|
||||
}
|
||||
|
||||
fn prometheus_registry(&self) -> Option<prometheus_endpoint::Registry> {
|
||||
self.prometheus_registry.clone()
|
||||
}
|
||||
|
||||
fn base_path(&self) -> Option<Arc<BasePath>> {
|
||||
self._base_path.clone()
|
||||
impl TelemetryOnConnectSinks {
|
||||
/// Get event stream for telemetry connection established events.
|
||||
pub fn on_connect_stream(&self) -> TracingUnboundedReceiver<()> {
|
||||
let (sink, stream) =tracing_unbounded("mpsc_telemetry_on_connect");
|
||||
self.0.lock().push(sink);
|
||||
stream
|
||||
}
|
||||
}
|
||||
|
||||
impl<TBl, TCl, TSc, TNetStatus, TNet, TTxPool, TOc> Future for
|
||||
Service<TBl, TCl, TSc, TNetStatus, TNet, TTxPool, TOc>
|
||||
{
|
||||
type Output = Result<(), Error>;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
||||
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 Poll::Ready(Err(Error::Other("Essential task failed.".into())));
|
||||
}
|
||||
}
|
||||
|
||||
// The service future never ends.
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
|
||||
impl<TBl, TCl, TSc, TNetStatus, TNet, TTxPool, TOc> Spawn for
|
||||
Service<TBl, TCl, TSc, TNetStatus, TNet, TTxPool, TOc>
|
||||
{
|
||||
fn spawn_obj(
|
||||
&self,
|
||||
future: FutureObj<'static, ()>
|
||||
) -> Result<(), SpawnError> {
|
||||
self.task_manager.spawn_handle().spawn("unnamed", future);
|
||||
Ok(())
|
||||
}
|
||||
/// The individual components of the chain, built by the service builder. You are encouraged to
|
||||
/// deconstruct this into its fields.
|
||||
pub struct ServiceComponents<TBl: BlockT, TBackend: Backend<TBl>, TSc, TExPool, TCl> {
|
||||
/// A blockchain client.
|
||||
pub client: Arc<TCl>,
|
||||
/// A shared transaction pool instance.
|
||||
pub transaction_pool: Arc<TExPool>,
|
||||
/// The chain task manager.
|
||||
pub task_manager: TaskManager,
|
||||
/// A keystore that stores keys.
|
||||
pub keystore: sc_keystore::KeyStorePtr,
|
||||
/// A shared network instance.
|
||||
pub network: Arc<sc_network::NetworkService<TBl, <TBl as BlockT>::Hash>>,
|
||||
/// RPC handlers that can perform RPC queries.
|
||||
pub rpc_handlers: Arc<RpcHandlers>,
|
||||
/// A shared instance of the chain selection algorithm.
|
||||
pub select_chain: Option<TSc>,
|
||||
/// Sinks to propagate network status updates.
|
||||
pub network_status_sinks: NetworkStatusSinks<TBl>,
|
||||
/// A prometheus metrics registry, (if enabled).
|
||||
pub prometheus_registry: Option<prometheus_endpoint::Registry>,
|
||||
/// Shared Telemetry connection sinks,
|
||||
pub telemetry_on_connect_sinks: TelemetryOnConnectSinks,
|
||||
/// A shared offchain workers instance.
|
||||
pub offchain_workers: Option<Arc<sc_offchain::OffchainWorkers<
|
||||
TCl, TBackend::OffchainStorage, TBl
|
||||
>>>,
|
||||
}
|
||||
|
||||
/// Builds a never-ending future that continuously polls the network.
|
||||
|
||||
Reference in New Issue
Block a user