mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-18 00:11:01 +00:00
Move the network status reporting to the service (#2916)
* Move the network status reporting to the service * Fix tests * Fix build
This commit is contained in:
committed by
Gavin Wood
parent
01fcdc2b1a
commit
437a6bc6b1
Generated
+1
@@ -4484,6 +4484,7 @@ dependencies = [
|
|||||||
"sysinfo 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"sysinfo 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"target_info 0.1.0 (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.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tokio 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -40,39 +40,36 @@ pub fn start<C>(service: &Service<C>, exit: ::exit_future::Exit, handle: TaskExe
|
|||||||
/// Creates an informant in the form of a `Future` that must be polled regularly.
|
/// Creates an informant in the form of a `Future` that must be polled regularly.
|
||||||
pub fn build<C>(service: &Service<C>) -> impl Future<Item = (), Error = ()>
|
pub fn build<C>(service: &Service<C>) -> impl Future<Item = (), Error = ()>
|
||||||
where C: Components {
|
where C: Components {
|
||||||
let network = service.network();
|
|
||||||
let client = service.client();
|
let client = service.client();
|
||||||
let mut last_number = None;
|
let mut last_number = None;
|
||||||
let mut last_update = time::Instant::now();
|
let mut last_update = time::Instant::now();
|
||||||
|
|
||||||
let display_notifications = network.status().for_each(move |sync_status| {
|
let display_notifications = service.network_status().for_each(move |net_status| {
|
||||||
|
|
||||||
let info = client.info();
|
let info = client.info();
|
||||||
let best_number = info.chain.best_number.saturated_into::<u64>();
|
let best_number = info.chain.best_number.saturated_into::<u64>();
|
||||||
let best_hash = info.chain.best_hash;
|
let best_hash = info.chain.best_hash;
|
||||||
let speed = move || speed(best_number, last_number, last_update);
|
let speed = move || speed(best_number, last_number, last_update);
|
||||||
last_update = time::Instant::now();
|
last_update = time::Instant::now();
|
||||||
let (status, target) = match (sync_status.sync.state, sync_status.sync.best_seen_block) {
|
let (status, target) = match (net_status.sync_state, net_status.best_seen_block) {
|
||||||
(SyncState::Idle, _) => ("Idle".into(), "".into()),
|
(SyncState::Idle, _) => ("Idle".into(), "".into()),
|
||||||
(SyncState::Downloading, None) => (format!("Syncing{}", speed()), "".into()),
|
(SyncState::Downloading, None) => (format!("Syncing{}", speed()), "".into()),
|
||||||
(SyncState::Downloading, Some(n)) => (format!("Syncing{}", speed()), format!(", target=#{}", n)),
|
(SyncState::Downloading, Some(n)) => (format!("Syncing{}", speed()), format!(", target=#{}", n)),
|
||||||
};
|
};
|
||||||
last_number = Some(best_number);
|
last_number = Some(best_number);
|
||||||
let finalized_number: u64 = info.chain.finalized_number.saturated_into::<u64>();
|
let finalized_number: u64 = info.chain.finalized_number.saturated_into::<u64>();
|
||||||
let bandwidth_download = network.average_download_per_sec();
|
|
||||||
let bandwidth_upload = network.average_upload_per_sec();
|
|
||||||
info!(
|
info!(
|
||||||
target: "substrate",
|
target: "substrate",
|
||||||
"{}{} ({} peers), best: #{} ({}), finalized #{} ({}), ⬇ {} ⬆ {}",
|
"{}{} ({} peers), best: #{} ({}), finalized #{} ({}), ⬇ {} ⬆ {}",
|
||||||
Colour::White.bold().paint(&status),
|
Colour::White.bold().paint(&status),
|
||||||
target,
|
target,
|
||||||
Colour::White.bold().paint(format!("{}", sync_status.num_peers)),
|
Colour::White.bold().paint(format!("{}", net_status.num_connected_peers)),
|
||||||
Colour::White.paint(format!("{}", best_number)),
|
Colour::White.paint(format!("{}", best_number)),
|
||||||
best_hash,
|
best_hash,
|
||||||
Colour::White.paint(format!("{}", finalized_number)),
|
Colour::White.paint(format!("{}", finalized_number)),
|
||||||
info.chain.finalized_hash,
|
info.chain.finalized_hash,
|
||||||
TransferRateFormat(bandwidth_download),
|
TransferRateFormat(net_status.average_download_per_sec),
|
||||||
TransferRateFormat(bandwidth_upload),
|
TransferRateFormat(net_status.average_upload_per_sec),
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -184,8 +184,8 @@ pub use service::{
|
|||||||
NetworkMsg, ExHashT, ReportHandle,
|
NetworkMsg, ExHashT, ReportHandle,
|
||||||
};
|
};
|
||||||
pub use config::{NodeKeyConfig, Secret, Secp256k1Secret, Ed25519Secret};
|
pub use config::{NodeKeyConfig, Secret, Secp256k1Secret, Ed25519Secret};
|
||||||
pub use protocol::{ProtocolStatus, PeerInfo, Context, consensus_gossip, message, specialization};
|
pub use protocol::{PeerInfo, Context, consensus_gossip, message, specialization};
|
||||||
pub use protocol::sync::{Status as SyncStatus, SyncState};
|
pub use protocol::sync::SyncState;
|
||||||
pub use libp2p::{Multiaddr, multiaddr, build_multiaddr};
|
pub use libp2p::{Multiaddr, multiaddr, build_multiaddr};
|
||||||
pub use libp2p::{identity, PeerId, core::PublicKey};
|
pub use libp2p::{identity, PeerId, core::PublicKey};
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ use message::generic::{Message as GenericMessage, ConsensusMessage};
|
|||||||
use consensus_gossip::{ConsensusGossip, MessageRecipient as GossipMessageRecipient};
|
use consensus_gossip::{ConsensusGossip, MessageRecipient as GossipMessageRecipient};
|
||||||
use on_demand::{OnDemandCore, OnDemandNetwork, RequestData};
|
use on_demand::{OnDemandCore, OnDemandNetwork, RequestData};
|
||||||
use specialization::NetworkSpecialization;
|
use specialization::NetworkSpecialization;
|
||||||
use sync::{ChainSync, Context as SyncContext, Status as SyncStatus, SyncState};
|
use sync::{ChainSync, Context as SyncContext, SyncState};
|
||||||
use crate::service::{TransactionPool, ExHashT};
|
use crate::service::{TransactionPool, ExHashT};
|
||||||
use crate::config::Roles;
|
use crate::config::Roles;
|
||||||
use rustc_hex::ToHex;
|
use rustc_hex::ToHex;
|
||||||
@@ -115,17 +115,6 @@ struct HandshakingPeer {
|
|||||||
timestamp: time::Instant,
|
timestamp: time::Instant,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Syncing status and statistics
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct ProtocolStatus<B: BlockT> {
|
|
||||||
/// Sync status.
|
|
||||||
pub sync: SyncStatus<B>,
|
|
||||||
/// Total number of connected peers
|
|
||||||
pub num_peers: usize,
|
|
||||||
/// Total number of active peers.
|
|
||||||
pub num_active_peers: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Peer information
|
/// Peer information
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct Peer<B: BlockT, H: ExHashT> {
|
struct Peer<B: BlockT, H: ExHashT> {
|
||||||
@@ -415,26 +404,33 @@ impl<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an object representing the status of the protocol.
|
/// Returns the number of peers we're connected to.
|
||||||
pub fn status(&self) -> ProtocolStatus<B> {
|
pub fn num_connected_peers(&self) -> usize {
|
||||||
ProtocolStatus {
|
self.context_data.peers.values().count()
|
||||||
sync: self.sync.status(),
|
|
||||||
num_peers: self.context_data.peers.values().count(),
|
|
||||||
num_active_peers: self
|
|
||||||
.context_data
|
|
||||||
.peers
|
|
||||||
.values()
|
|
||||||
.filter(|p| p.block_request.is_some())
|
|
||||||
.count(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_major_syncing(&self) -> bool {
|
/// Returns the number of peers we're connected to and that are being queried.
|
||||||
self.sync.status().is_major_syncing()
|
pub fn num_active_peers(&self) -> usize {
|
||||||
|
self.context_data
|
||||||
|
.peers
|
||||||
|
.values()
|
||||||
|
.filter(|p| p.block_request.is_some())
|
||||||
|
.count()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_offline(&self) -> bool {
|
/// Current global sync state.
|
||||||
self.sync.status().is_offline()
|
pub fn sync_state(&self) -> SyncState {
|
||||||
|
self.sync.status().state
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Target sync block number.
|
||||||
|
pub fn best_seen_block(&self) -> Option<NumberFor<B>> {
|
||||||
|
self.sync.status().best_seen_block
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Number of peers participating in syncing.
|
||||||
|
pub fn num_sync_peers(&self) -> u32 {
|
||||||
|
self.sync.status().num_peers
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Starts a new data demand request.
|
/// Starts a new data demand request.
|
||||||
|
|||||||
@@ -194,22 +194,6 @@ pub struct Status<B: BlockT> {
|
|||||||
pub num_peers: u32,
|
pub num_peers: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: BlockT> Status<B> {
|
|
||||||
/// Whether the synchronization status is doing major downloading work or
|
|
||||||
/// is near the head of the chain.
|
|
||||||
pub fn is_major_syncing(&self) -> bool {
|
|
||||||
match self.state {
|
|
||||||
SyncState::Idle => false,
|
|
||||||
SyncState::Downloading => true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Are we all alone?
|
|
||||||
pub fn is_offline(&self) -> bool {
|
|
||||||
self.num_peers == 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<B: BlockT> ChainSync<B> {
|
impl<B: BlockT> ChainSync<B> {
|
||||||
/// Create a new instance. Pass the initial known state of the chain.
|
/// Create a new instance. Pass the initial known state of the chain.
|
||||||
pub(crate) fn new(role: Roles, info: &ClientInfo<B>) -> Self {
|
pub(crate) fn new(role: Roles, info: &ClientInfo<B>) -> Self {
|
||||||
|
|||||||
@@ -39,13 +39,12 @@ use crate::protocol::consensus_gossip::{ConsensusGossip, MessageRecipient as Gos
|
|||||||
use crate::protocol::message::Message;
|
use crate::protocol::message::Message;
|
||||||
use crate::protocol::on_demand::RequestData;
|
use crate::protocol::on_demand::RequestData;
|
||||||
use crate::protocol::{self, Context, CustomMessageOutcome, Protocol, ConnectedPeer};
|
use crate::protocol::{self, Context, CustomMessageOutcome, Protocol, ConnectedPeer};
|
||||||
use crate::protocol::{ProtocolStatus, PeerInfo, NetworkOut};
|
use crate::protocol::{PeerInfo, NetworkOut};
|
||||||
|
use crate::protocol::sync::SyncState;
|
||||||
use crate::config::Params;
|
use crate::config::Params;
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::protocol::specialization::NetworkSpecialization;
|
use crate::protocol::specialization::NetworkSpecialization;
|
||||||
|
|
||||||
/// Interval at which we send status updates on the status stream.
|
|
||||||
const STATUS_INTERVAL: Duration = Duration::from_millis(5000);
|
|
||||||
/// Interval at which we update the `peers` field on the main thread.
|
/// Interval at which we update the `peers` field on the main thread.
|
||||||
const CONNECTED_PEERS_INTERVAL: Duration = Duration::from_millis(500);
|
const CONNECTED_PEERS_INTERVAL: Duration = Duration::from_millis(500);
|
||||||
|
|
||||||
@@ -90,8 +89,6 @@ impl ReportHandle {
|
|||||||
|
|
||||||
/// Substrate network service. Handles network IO and manages connectivity.
|
/// Substrate network service. Handles network IO and manages connectivity.
|
||||||
pub struct NetworkService<B: BlockT + 'static, S: NetworkSpecialization<B>> {
|
pub struct NetworkService<B: BlockT + 'static, S: NetworkSpecialization<B>> {
|
||||||
/// Sinks to propagate status updates.
|
|
||||||
status_sinks: Arc<Mutex<Vec<mpsc::UnboundedSender<ProtocolStatus<B>>>>>,
|
|
||||||
/// Are we connected to any peer?
|
/// Are we connected to any peer?
|
||||||
is_offline: Arc<AtomicBool>,
|
is_offline: Arc<AtomicBool>,
|
||||||
/// Are we actively catching up with the chain?
|
/// Are we actively catching up with the chain?
|
||||||
@@ -122,7 +119,6 @@ impl<B: BlockT + 'static, S: NetworkSpecialization<B>, H: ExHashT> NetworkWorker
|
|||||||
) -> Result<NetworkWorker<B, S, H>, Error> {
|
) -> Result<NetworkWorker<B, S, H>, Error> {
|
||||||
let (network_chan, network_port) = mpsc::unbounded();
|
let (network_chan, network_port) = mpsc::unbounded();
|
||||||
let (protocol_sender, protocol_rx) = mpsc::unbounded();
|
let (protocol_sender, protocol_rx) = mpsc::unbounded();
|
||||||
let status_sinks = Arc::new(Mutex::new(Vec::new()));
|
|
||||||
|
|
||||||
// Start in off-line mode, since we're not connected to any nodes yet.
|
// Start in off-line mode, since we're not connected to any nodes yet.
|
||||||
let is_offline = Arc::new(AtomicBool::new(true));
|
let is_offline = Arc::new(AtomicBool::new(true));
|
||||||
@@ -148,7 +144,6 @@ impl<B: BlockT + 'static, S: NetworkSpecialization<B>, H: ExHashT> NetworkWorker
|
|||||||
};
|
};
|
||||||
|
|
||||||
let service = Arc::new(NetworkService {
|
let service = Arc::new(NetworkService {
|
||||||
status_sinks: status_sinks.clone(),
|
|
||||||
bandwidth,
|
bandwidth,
|
||||||
is_offline: is_offline.clone(),
|
is_offline: is_offline.clone(),
|
||||||
is_major_syncing: is_major_syncing.clone(),
|
is_major_syncing: is_major_syncing.clone(),
|
||||||
@@ -172,13 +167,46 @@ impl<B: BlockT + 'static, S: NetworkSpecialization<B>, H: ExHashT> NetworkWorker
|
|||||||
finality_proof_provider: params.finality_proof_provider,
|
finality_proof_provider: params.finality_proof_provider,
|
||||||
network_port,
|
network_port,
|
||||||
protocol_rx,
|
protocol_rx,
|
||||||
status_sinks,
|
|
||||||
on_demand_in: params.on_demand.and_then(|od| od.extract_receiver()),
|
on_demand_in: params.on_demand.and_then(|od| od.extract_receiver()),
|
||||||
status_interval: tokio_timer::Interval::new_interval(STATUS_INTERVAL),
|
|
||||||
connected_peers_interval: tokio_timer::Interval::new_interval(CONNECTED_PEERS_INTERVAL),
|
connected_peers_interval: tokio_timer::Interval::new_interval(CONNECTED_PEERS_INTERVAL),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the downloaded bytes per second averaged over the past few seconds.
|
||||||
|
pub fn average_download_per_sec(&self) -> u64 {
|
||||||
|
self.service.bandwidth.average_download_per_sec()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the uploaded bytes per second averaged over the past few seconds.
|
||||||
|
pub fn average_upload_per_sec(&self) -> u64 {
|
||||||
|
self.service.bandwidth.average_upload_per_sec()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the number of peers we're connected to.
|
||||||
|
pub fn num_connected_peers(&self) -> usize {
|
||||||
|
self.protocol.num_connected_peers()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the number of peers we're connected to and that are being queried.
|
||||||
|
pub fn num_active_peers(&self) -> usize {
|
||||||
|
self.protocol.num_active_peers()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Current global sync state.
|
||||||
|
pub fn sync_state(&self) -> SyncState {
|
||||||
|
self.protocol.sync_state()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Target sync block number.
|
||||||
|
pub fn best_seen_block(&self) -> Option<NumberFor<B>> {
|
||||||
|
self.protocol.best_seen_block()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Number of peers participating in syncing.
|
||||||
|
pub fn num_sync_peers(&self) -> u32 {
|
||||||
|
self.protocol.num_sync_peers()
|
||||||
|
}
|
||||||
|
|
||||||
/// Return a `NetworkService` that can be shared through the code base and can be used to
|
/// Return a `NetworkService` that can be shared through the code base and can be used to
|
||||||
/// manipulate the worker.
|
/// manipulate the worker.
|
||||||
pub fn service(&self) -> &Arc<NetworkService<B, S>> {
|
pub fn service(&self) -> &Arc<NetworkService<B, S>> {
|
||||||
@@ -187,16 +215,6 @@ impl<B: BlockT + 'static, S: NetworkSpecialization<B>, H: ExHashT> NetworkWorker
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<B: BlockT + 'static, S: NetworkSpecialization<B>> NetworkService<B, S> {
|
impl<B: BlockT + 'static, S: NetworkSpecialization<B>> NetworkService<B, S> {
|
||||||
/// Returns the downloaded bytes per second averaged over the past few seconds.
|
|
||||||
pub fn average_download_per_sec(&self) -> u64 {
|
|
||||||
self.bandwidth.average_download_per_sec()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the uploaded bytes per second averaged over the past few seconds.
|
|
||||||
pub fn average_upload_per_sec(&self) -> u64 {
|
|
||||||
self.bandwidth.average_upload_per_sec()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the network identity of the node.
|
/// Returns the network identity of the node.
|
||||||
pub fn local_peer_id(&self) -> PeerId {
|
pub fn local_peer_id(&self) -> PeerId {
|
||||||
Swarm::<B>::local_peer_id(&*self.network.lock()).clone()
|
Swarm::<B>::local_peer_id(&*self.network.lock()).clone()
|
||||||
@@ -287,13 +305,6 @@ impl<B: BlockT + 'static, S: NetworkSpecialization<B>> NetworkService<B, S> {
|
|||||||
self.is_major_syncing.load(Ordering::Relaxed)
|
self.is_major_syncing.load(Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get sync status
|
|
||||||
pub fn status(&self) -> mpsc::UnboundedReceiver<ProtocolStatus<B>> {
|
|
||||||
let (sink, stream) = mpsc::unbounded();
|
|
||||||
self.status_sinks.lock().push(sink);
|
|
||||||
stream
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get network state.
|
/// Get network state.
|
||||||
pub fn network_state(&self) -> NetworkState {
|
pub fn network_state(&self) -> NetworkState {
|
||||||
let mut swarm = self.network.lock();
|
let mut swarm = self.network.lock();
|
||||||
@@ -497,12 +508,9 @@ pub struct NetworkWorker<B: BlockT + 'static, S: NetworkSpecialization<B>, H: Ex
|
|||||||
finality_proof_provider: Option<Arc<dyn FinalityProofProvider<B>>>,
|
finality_proof_provider: Option<Arc<dyn FinalityProofProvider<B>>>,
|
||||||
network_port: mpsc::UnboundedReceiver<NetworkMsg<B>>,
|
network_port: mpsc::UnboundedReceiver<NetworkMsg<B>>,
|
||||||
protocol_rx: mpsc::UnboundedReceiver<ProtocolMsg<B, S>>,
|
protocol_rx: mpsc::UnboundedReceiver<ProtocolMsg<B, S>>,
|
||||||
status_sinks: Arc<Mutex<Vec<mpsc::UnboundedSender<ProtocolStatus<B>>>>>,
|
|
||||||
peerset: PeersetHandle,
|
peerset: PeersetHandle,
|
||||||
on_demand_in: Option<mpsc::UnboundedReceiver<RequestData<B>>>,
|
on_demand_in: Option<mpsc::UnboundedReceiver<RequestData<B>>>,
|
||||||
|
|
||||||
/// Interval at which we send status updates on the `status_sinks`.
|
|
||||||
status_interval: tokio_timer::Interval,
|
|
||||||
/// Interval at which we update the `connected_peers` Arc.
|
/// Interval at which we update the `connected_peers` Arc.
|
||||||
connected_peers_interval: tokio_timer::Interval,
|
connected_peers_interval: tokio_timer::Interval,
|
||||||
}
|
}
|
||||||
@@ -580,11 +588,6 @@ impl<B: BlockT + 'static, S: NetworkSpecialization<B>, H: ExHashT> Future for Ne
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while let Ok(Async::Ready(_)) = self.status_interval.poll() {
|
|
||||||
let status = self.protocol.status();
|
|
||||||
self.status_sinks.lock().retain(|sink| sink.unbounded_send(status.clone()).is_ok());
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut network_service = self.network_service.lock();
|
let mut network_service = self.network_service.lock();
|
||||||
let mut link = NetworkLink {
|
let mut link = NetworkLink {
|
||||||
@@ -742,8 +745,11 @@ impl<B: BlockT + 'static, S: NetworkSpecialization<B>, H: ExHashT> Future for Ne
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.is_offline.store(self.protocol.is_offline(), Ordering::Relaxed);
|
self.is_offline.store(self.protocol.num_connected_peers() == 0, Ordering::Relaxed);
|
||||||
self.is_major_syncing.store(self.protocol.is_major_syncing(), Ordering::Relaxed);
|
self.is_major_syncing.store(match self.protocol.sync_state() {
|
||||||
|
SyncState::Idle => false,
|
||||||
|
SyncState::Downloading => true,
|
||||||
|
}, Ordering::Relaxed);
|
||||||
|
|
||||||
Ok(Async::NotReady)
|
Ok(Async::NotReady)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,8 @@ use crate::message::Message;
|
|||||||
use libp2p::PeerId;
|
use libp2p::PeerId;
|
||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::{Mutex, RwLock};
|
||||||
use primitives::{H256, Blake2Hasher};
|
use primitives::{H256, Blake2Hasher};
|
||||||
use crate::protocol::{Context, Protocol, ProtocolConfig, ProtocolStatus, CustomMessageOutcome, NetworkOut};
|
use crate::SyncState;
|
||||||
|
use crate::protocol::{Context, Protocol, ProtocolConfig, CustomMessageOutcome, NetworkOut};
|
||||||
use runtime_primitives::generic::{BlockId, OpaqueDigestItemId};
|
use runtime_primitives::generic::{BlockId, OpaqueDigestItemId};
|
||||||
use runtime_primitives::traits::{Block as BlockT, Header, NumberFor};
|
use runtime_primitives::traits::{Block as BlockT, Header, NumberFor};
|
||||||
use runtime_primitives::{Justification, ConsensusEngineId};
|
use runtime_primitives::{Justification, ConsensusEngineId};
|
||||||
@@ -365,7 +366,8 @@ pub struct Peer<D, S: NetworkSpecialization<Block>> {
|
|||||||
/// instantiation paths or field names is too much hassle, hence
|
/// instantiation paths or field names is too much hassle, hence
|
||||||
/// we allow it to be unused.
|
/// we allow it to be unused.
|
||||||
#[cfg_attr(not(test), allow(unused))]
|
#[cfg_attr(not(test), allow(unused))]
|
||||||
protocol_status: Arc<RwLock<ProtocolStatus<Block>>>,
|
/// `(is_offline, is_major_syncing, num_peers)`
|
||||||
|
protocol_status: Arc<RwLock<(bool, bool, usize)>>,
|
||||||
import_queue: Arc<Mutex<Box<BasicQueue<Block>>>>,
|
import_queue: Arc<Mutex<Box<BasicQueue<Block>>>>,
|
||||||
pub data: D,
|
pub data: D,
|
||||||
best_hash: Mutex<Option<H256>>,
|
best_hash: Mutex<Option<H256>>,
|
||||||
@@ -509,7 +511,7 @@ impl<S: NetworkSpecialization<Block>> ProtocolChannel<S> {
|
|||||||
|
|
||||||
impl<D, S: NetworkSpecialization<Block>> Peer<D, S> {
|
impl<D, S: NetworkSpecialization<Block>> Peer<D, S> {
|
||||||
fn new(
|
fn new(
|
||||||
protocol_status: Arc<RwLock<ProtocolStatus<Block>>>,
|
protocol_status: Arc<RwLock<(bool, bool, usize)>>,
|
||||||
client: PeersClient,
|
client: PeersClient,
|
||||||
import_queue: Arc<Mutex<Box<BasicQueue<Block>>>>,
|
import_queue: Arc<Mutex<Box<BasicQueue<Block>>>>,
|
||||||
use_tokio: bool,
|
use_tokio: bool,
|
||||||
@@ -560,19 +562,19 @@ impl<D, S: NetworkSpecialization<Block>> Peer<D, S> {
|
|||||||
/// SyncOracle: are we connected to any peer?
|
/// SyncOracle: are we connected to any peer?
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn is_offline(&self) -> bool {
|
fn is_offline(&self) -> bool {
|
||||||
self.protocol_status.read().sync.is_offline()
|
self.protocol_status.read().0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SyncOracle: are we in the process of catching-up with the chain?
|
/// SyncOracle: are we in the process of catching-up with the chain?
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn is_major_syncing(&self) -> bool {
|
fn is_major_syncing(&self) -> bool {
|
||||||
self.protocol_status.read().sync.is_major_syncing()
|
self.protocol_status.read().1
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get protocol status.
|
/// Get protocol status.
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn protocol_status(&self) -> ProtocolStatus<Block> {
|
fn num_peers(&self) -> usize {
|
||||||
self.protocol_status.read().clone()
|
self.protocol_status.read().2
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called on connection to other indicated peer.
|
/// Called on connection to other indicated peer.
|
||||||
@@ -873,7 +875,7 @@ pub trait TestNetFactory: Sized {
|
|||||||
/// Add created peer.
|
/// Add created peer.
|
||||||
fn add_peer(
|
fn add_peer(
|
||||||
&mut self,
|
&mut self,
|
||||||
protocol_status: Arc<RwLock<ProtocolStatus<Block>>>,
|
protocol_status: Arc<RwLock<(bool, bool, usize)>>,
|
||||||
import_queue: Arc<Mutex<Box<BasicQueue<Block>>>>,
|
import_queue: Arc<Mutex<Box<BasicQueue<Block>>>>,
|
||||||
tx_pool: EmptyTransactionPool,
|
tx_pool: EmptyTransactionPool,
|
||||||
finality_proof_provider: Option<Arc<dyn FinalityProofProvider<Block>>>,
|
finality_proof_provider: Option<Arc<dyn FinalityProofProvider<Block>>>,
|
||||||
@@ -1009,7 +1011,11 @@ pub trait TestNetFactory: Sized {
|
|||||||
return Ok(Async::Ready(()))
|
return Ok(Async::Ready(()))
|
||||||
}
|
}
|
||||||
|
|
||||||
*protocol_status.write() = protocol.status();
|
*protocol_status.write() = (
|
||||||
|
protocol.num_connected_peers() == 0,
|
||||||
|
protocol.sync_state() == SyncState::Downloading,
|
||||||
|
protocol.num_connected_peers()
|
||||||
|
);
|
||||||
Ok(Async::NotReady)
|
Ok(Async::NotReady)
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
@@ -1054,7 +1060,7 @@ pub trait TestNetFactory: Sized {
|
|||||||
specialization,
|
specialization,
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
let protocol_status = Arc::new(RwLock::new(protocol.status()));
|
let protocol_status = Arc::new(RwLock::new((true, false, 0)));
|
||||||
self.add_peer(
|
self.add_peer(
|
||||||
protocol_status.clone(),
|
protocol_status.clone(),
|
||||||
import_queue.clone(),
|
import_queue.clone(),
|
||||||
@@ -1110,7 +1116,7 @@ pub trait TestNetFactory: Sized {
|
|||||||
specialization,
|
specialization,
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
let protocol_status = Arc::new(RwLock::new(protocol.status()));
|
let protocol_status = Arc::new(RwLock::new((true, false, 0)));
|
||||||
self.add_peer(
|
self.add_peer(
|
||||||
protocol_status.clone(),
|
protocol_status.clone(),
|
||||||
import_queue.clone(),
|
import_queue.clone(),
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ fn sync_peers_works() {
|
|||||||
net.sync();
|
net.sync();
|
||||||
for peer in 0..3 {
|
for peer in 0..3 {
|
||||||
// Assert peers is up to date.
|
// Assert peers is up to date.
|
||||||
assert_eq!(net.peer(peer).protocol_status.read().num_peers, 2);
|
assert_eq!(net.peer(peer).num_peers(), 2);
|
||||||
// And then disconnect.
|
// And then disconnect.
|
||||||
for other in 0..3 {
|
for other in 0..3 {
|
||||||
if other != peer {
|
if other != peer {
|
||||||
@@ -56,8 +56,7 @@ fn sync_peers_works() {
|
|||||||
net.sync();
|
net.sync();
|
||||||
// Now peers are disconnected.
|
// Now peers are disconnected.
|
||||||
for peer in 0..3 {
|
for peer in 0..3 {
|
||||||
let status = net.peer(peer).protocol_status.read();
|
assert_eq!(net.peer(peer).num_peers(), 0);
|
||||||
assert_eq!(status.num_peers, 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -433,7 +432,7 @@ fn can_not_sync_from_light_peer() {
|
|||||||
assert_eq!(net.peer(2).client.info().chain.best_number, 0);
|
assert_eq!(net.peer(2).client.info().chain.best_number, 0);
|
||||||
// and that the #1 is still connected to #2
|
// and that the #1 is still connected to #2
|
||||||
// (because #2 has not tried to fetch block data from the #1 light node)
|
// (because #2 has not tried to fetch block data from the #1 light node)
|
||||||
assert_eq!(net.peer(1).protocol_status().num_peers, 2);
|
assert_eq!(net.peer(1).num_peers(), 2);
|
||||||
|
|
||||||
// and now try to fetch block data from light peer #1
|
// and now try to fetch block data from light peer #1
|
||||||
// (this should result in disconnect)
|
// (this should result in disconnect)
|
||||||
@@ -450,7 +449,7 @@ fn can_not_sync_from_light_peer() {
|
|||||||
);
|
);
|
||||||
net.sync();
|
net.sync();
|
||||||
// check that light #1 has disconnected from #2
|
// check that light #1 has disconnected from #2
|
||||||
assert_eq!(net.peer(1).protocol_status().num_peers, 1);
|
assert_eq!(net.peer(1).num_peers(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ lazy_static = "1.0"
|
|||||||
log = "0.4"
|
log = "0.4"
|
||||||
slog = {version = "^2", features = ["nested-values"]}
|
slog = {version = "^2", features = ["nested-values"]}
|
||||||
tokio = "0.1.7"
|
tokio = "0.1.7"
|
||||||
|
tokio-timer = "0.2"
|
||||||
exit-future = "0.1"
|
exit-future = "0.1"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ pub mod error;
|
|||||||
use std::io;
|
use std::io;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::time::Duration;
|
||||||
use futures::sync::mpsc;
|
use futures::sync::mpsc;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
@@ -39,7 +40,7 @@ use log::{info, warn, debug};
|
|||||||
use parity_codec::{Encode, Decode};
|
use parity_codec::{Encode, Decode};
|
||||||
use primitives::Pair;
|
use primitives::Pair;
|
||||||
use runtime_primitives::generic::BlockId;
|
use runtime_primitives::generic::BlockId;
|
||||||
use runtime_primitives::traits::{Header, SaturatedConversion};
|
use runtime_primitives::traits::{Header, NumberFor, SaturatedConversion};
|
||||||
use substrate_executor::NativeExecutor;
|
use substrate_executor::NativeExecutor;
|
||||||
use sysinfo::{get_current_pid, ProcessExt, System, SystemExt};
|
use sysinfo::{get_current_pid, ProcessExt, System, SystemExt};
|
||||||
use tel::{telemetry, SUBSTRATE_INFO};
|
use tel::{telemetry, SUBSTRATE_INFO};
|
||||||
@@ -75,6 +76,8 @@ pub struct Service<Components: components::Components> {
|
|||||||
client: Arc<ComponentClient<Components>>,
|
client: Arc<ComponentClient<Components>>,
|
||||||
select_chain: Option<<Components as components::Components>::SelectChain>,
|
select_chain: Option<<Components as components::Components>::SelectChain>,
|
||||||
network: Arc<components::NetworkService<Components::Factory>>,
|
network: Arc<components::NetworkService<Components::Factory>>,
|
||||||
|
/// Sinks to propagate network status updates.
|
||||||
|
network_status_sinks: Arc<Mutex<Vec<mpsc::UnboundedSender<NetworkStatus<ComponentBlock<Components>>>>>>,
|
||||||
transaction_pool: Arc<TransactionPool<Components::TransactionPoolApi>>,
|
transaction_pool: Arc<TransactionPool<Components::TransactionPoolApi>>,
|
||||||
keystore: Keystore,
|
keystore: Keystore,
|
||||||
exit: ::exit_future::Exit,
|
exit: ::exit_future::Exit,
|
||||||
@@ -204,8 +207,9 @@ impl<Components: components::Components> Service<Components> {
|
|||||||
let has_bootnodes = !network_params.network_config.boot_nodes.is_empty();
|
let has_bootnodes = !network_params.network_config.boot_nodes.is_empty();
|
||||||
let network_mut = network::NetworkWorker::new(network_params)?;
|
let network_mut = network::NetworkWorker::new(network_params)?;
|
||||||
let network = network_mut.service().clone();
|
let network = network_mut.service().clone();
|
||||||
|
let network_status_sinks = Arc::new(Mutex::new(Vec::new()));
|
||||||
|
|
||||||
task_executor.spawn(network_mut
|
task_executor.spawn(build_network_future(network_mut, network_status_sinks.clone())
|
||||||
.map_err(|_| ())
|
.map_err(|_| ())
|
||||||
.select(exit.clone())
|
.select(exit.clone())
|
||||||
.then(|_| Ok(())));
|
.then(|_| Ok(())));
|
||||||
@@ -331,15 +335,17 @@ impl<Components: components::Components> Service<Components> {
|
|||||||
let network_ = network.clone();
|
let network_ = network.clone();
|
||||||
let mut sys = System::new();
|
let mut sys = System::new();
|
||||||
let self_pid = get_current_pid();
|
let self_pid = get_current_pid();
|
||||||
task_executor.spawn(network.status().for_each(move |sync_status| {
|
let (netstat_tx, netstat_rx) = mpsc::unbounded();
|
||||||
|
network_status_sinks.lock().push(netstat_tx);
|
||||||
|
task_executor.spawn(netstat_rx.for_each(move |net_status| {
|
||||||
let info = client_.info();
|
let info = client_.info();
|
||||||
let best_number = info.chain.best_number.saturated_into::<u64>();
|
let best_number = info.chain.best_number.saturated_into::<u64>();
|
||||||
let best_hash = info.chain.best_hash;
|
let best_hash = info.chain.best_hash;
|
||||||
let num_peers = sync_status.num_peers;
|
let num_peers = net_status.num_connected_peers;
|
||||||
let txpool_status = transaction_pool_.status();
|
let txpool_status = transaction_pool_.status();
|
||||||
let finalized_number: u64 = info.chain.finalized_number.saturated_into::<u64>();
|
let finalized_number: u64 = info.chain.finalized_number.saturated_into::<u64>();
|
||||||
let bandwidth_download = network_.average_download_per_sec();
|
let bandwidth_download = net_status.average_download_per_sec;
|
||||||
let bandwidth_upload = network_.average_upload_per_sec();
|
let bandwidth_upload = net_status.average_upload_per_sec;
|
||||||
|
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
let backend = (*client_).backend();
|
let backend = (*client_).backend();
|
||||||
@@ -447,6 +453,7 @@ impl<Components: components::Components> Service<Components> {
|
|||||||
Ok(Service {
|
Ok(Service {
|
||||||
client,
|
client,
|
||||||
network,
|
network,
|
||||||
|
network_status_sinks,
|
||||||
select_chain,
|
select_chain,
|
||||||
transaction_pool,
|
transaction_pool,
|
||||||
signal: Some(signal),
|
signal: Some(signal),
|
||||||
@@ -495,6 +502,13 @@ impl<Components> Service<Components> where Components: components::Components {
|
|||||||
self.network.clone()
|
self.network.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a receiver that periodically receives a status of the network.
|
||||||
|
pub fn network_status(&self) -> mpsc::UnboundedReceiver<NetworkStatus<ComponentBlock<Components>>> {
|
||||||
|
let (sink, stream) = mpsc::unbounded();
|
||||||
|
self.network_status_sinks.lock().push(sink);
|
||||||
|
stream
|
||||||
|
}
|
||||||
|
|
||||||
/// Get shared transaction pool instance.
|
/// Get shared transaction pool instance.
|
||||||
pub fn transaction_pool(&self) -> Arc<TransactionPool<Components::TransactionPoolApi>> {
|
pub fn transaction_pool(&self) -> Arc<TransactionPool<Components::TransactionPoolApi>> {
|
||||||
self.transaction_pool.clone()
|
self.transaction_pool.clone()
|
||||||
@@ -511,6 +525,57 @@ impl<Components> Service<Components> where Components: components::Components {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds a never-ending future that continuously polls the network.
|
||||||
|
///
|
||||||
|
/// The `status_sink` contain a list of senders to send a periodic network status to.
|
||||||
|
fn build_network_future<B: BlockT, S: network::specialization::NetworkSpecialization<B>, H: network::ExHashT>(
|
||||||
|
mut network: network::NetworkWorker<B, S, H>,
|
||||||
|
status_sinks: Arc<Mutex<Vec<mpsc::UnboundedSender<NetworkStatus<B>>>>>,
|
||||||
|
) -> impl Future<Item = (), Error = ()> {
|
||||||
|
// Interval at which we send status updates on the status stream.
|
||||||
|
const STATUS_INTERVAL: Duration = Duration::from_millis(5000);
|
||||||
|
let mut status_interval = tokio_timer::Interval::new_interval(STATUS_INTERVAL);
|
||||||
|
|
||||||
|
futures::future::poll_fn(move || {
|
||||||
|
while let Ok(Async::Ready(_)) = status_interval.poll() {
|
||||||
|
let status = NetworkStatus {
|
||||||
|
sync_state: network.sync_state(),
|
||||||
|
best_seen_block: network.best_seen_block(),
|
||||||
|
num_sync_peers: network.num_sync_peers(),
|
||||||
|
num_connected_peers: network.num_connected_peers(),
|
||||||
|
num_active_peers: network.num_active_peers(),
|
||||||
|
average_download_per_sec: network.average_download_per_sec(),
|
||||||
|
average_upload_per_sec: network.average_upload_per_sec(),
|
||||||
|
};
|
||||||
|
|
||||||
|
status_sinks.lock().retain(|sink| sink.unbounded_send(status.clone()).is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
network.poll()
|
||||||
|
.map_err(|err| {
|
||||||
|
warn!(target: "service", "Error in network: {:?}", err);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Overview status of the network.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct NetworkStatus<B: BlockT> {
|
||||||
|
/// Current global sync state.
|
||||||
|
pub sync_state: network::SyncState,
|
||||||
|
/// Target sync block number.
|
||||||
|
pub best_seen_block: Option<NumberFor<B>>,
|
||||||
|
/// Number of peers participating in syncing.
|
||||||
|
pub num_sync_peers: u32,
|
||||||
|
/// Total number of connected peers
|
||||||
|
pub num_connected_peers: usize,
|
||||||
|
/// Total number of active peers.
|
||||||
|
pub num_active_peers: usize,
|
||||||
|
/// Downloaded bytes per second averaged over the past few seconds.
|
||||||
|
pub average_download_per_sec: u64,
|
||||||
|
/// Uploaded bytes per second averaged over the past few seconds.
|
||||||
|
pub average_upload_per_sec: u64,
|
||||||
|
}
|
||||||
|
|
||||||
impl<Components> Drop for Service<Components> where Components: components::Components {
|
impl<Components> Drop for Service<Components> where Components: components::Components {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
|
|||||||
Reference in New Issue
Block a user