LES Peer Info (#4195)

* connected peers function for network service

* get LES peer info in sync API

* new peer info in RPC
This commit is contained in:
Robert Habermeier 2017-01-20 12:41:49 +01:00 committed by Arkadiy Paronyan
parent 35666f718b
commit 3ff9324ec0
11 changed files with 150 additions and 48 deletions

View File

@ -77,7 +77,7 @@ impl<'a> IoContext for NetworkContext<'a> {
} }
} }
/// Basic context for a the protocol. /// Basic context for the protocol.
pub trait BasicContext { pub trait BasicContext {
/// Returns the relevant's peer persistent Id (aka NodeId). /// Returns the relevant's peer persistent Id (aka NodeId).
fn persistent_peer_id(&self, peer: PeerId) -> Option<NodeId>; fn persistent_peer_id(&self, peer: PeerId) -> Option<NodeId>;

View File

@ -316,6 +316,12 @@ impl LightProtocol {
} }
} }
/// Attempt to get peer status.
pub fn peer_status(&self, peer: &PeerId) -> Option<Status> {
self.peers.read().get(&peer)
.map(|peer| peer.lock().status.clone())
}
/// Check the maximum amount of requests of a specific type /// Check the maximum amount of requests of a specific type
/// which a peer would be able to serve. Returns zero if the /// which a peer would be able to serve. Returns zero if the
/// peer is unknown or has no buffer flow parameters. /// peer is unknown or has no buffer flow parameters.

View File

@ -18,7 +18,7 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use util::{H256, RwLock}; use util::{H256, RwLock};
use ethsync::{SyncProvider, SyncStatus, SyncState, PeerInfo, TransactionStats}; use ethsync::{SyncProvider, EthProtocolInfo, SyncStatus, SyncState, PeerInfo, TransactionStats};
/// TestSyncProvider config. /// TestSyncProvider config.
pub struct Config { pub struct Config {
@ -78,9 +78,12 @@ impl SyncProvider for TestSyncProvider {
capabilities: vec!["eth/62".to_owned(), "eth/63".to_owned()], capabilities: vec!["eth/62".to_owned(), "eth/63".to_owned()],
remote_address: "127.0.0.1:7777".to_owned(), remote_address: "127.0.0.1:7777".to_owned(),
local_address: "127.0.0.1:8888".to_owned(), local_address: "127.0.0.1:8888".to_owned(),
eth_version: 62, eth_info: Some(EthProtocolInfo {
eth_difficulty: Some(40.into()), version: 62,
eth_head: 50.into() difficulty: Some(40.into()),
head: 50.into(),
}),
les_info: None,
}, },
PeerInfo { PeerInfo {
id: None, id: None,
@ -88,9 +91,12 @@ impl SyncProvider for TestSyncProvider {
capabilities: vec!["eth/63".to_owned(), "eth/64".to_owned()], capabilities: vec!["eth/63".to_owned(), "eth/64".to_owned()],
remote_address: "Handshake".to_owned(), remote_address: "Handshake".to_owned(),
local_address: "127.0.0.1:3333".to_owned(), local_address: "127.0.0.1:3333".to_owned(),
eth_version: 64, eth_info: Some(EthProtocolInfo {
eth_difficulty: None, version: 64,
eth_head: 60.into() difficulty: None,
head: 60.into()
}),
les_info: None,
} }
] ]
} }

View File

@ -265,7 +265,7 @@ fn rpc_parity_net_peers() {
let io = deps.default_client(); let io = deps.default_client();
let request = r#"{"jsonrpc": "2.0", "method": "parity_netPeers", "params":[], "id": 1}"#; let request = r#"{"jsonrpc": "2.0", "method": "parity_netPeers", "params":[], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":{"active":0,"connected":120,"max":50,"peers":[{"caps":["eth/62","eth/63"],"id":"node1","name":"Parity/1","network":{"localAddress":"127.0.0.1:8888","remoteAddress":"127.0.0.1:7777"},"protocols":{"eth":{"difficulty":"0x28","head":"0000000000000000000000000000000000000000000000000000000000000032","version":62}}},{"caps":["eth/63","eth/64"],"id":null,"name":"Parity/2","network":{"localAddress":"127.0.0.1:3333","remoteAddress":"Handshake"},"protocols":{"eth":{"difficulty":null,"head":"000000000000000000000000000000000000000000000000000000000000003c","version":64}}}]},"id":1}"#; let response = r#"{"jsonrpc":"2.0","result":{"active":0,"connected":120,"max":50,"peers":[{"caps":["eth/62","eth/63"],"id":"node1","name":"Parity/1","network":{"localAddress":"127.0.0.1:8888","remoteAddress":"127.0.0.1:7777"},"protocols":{"eth":{"difficulty":"0x28","head":"0000000000000000000000000000000000000000000000000000000000000032","version":62},"les":null}},{"caps":["eth/63","eth/64"],"id":null,"name":"Parity/2","network":{"localAddress":"127.0.0.1:3333","remoteAddress":"Handshake"},"protocols":{"eth":{"difficulty":null,"head":"000000000000000000000000000000000000000000000000000000000000003c","version":64},"les":null}}]},"id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
} }

View File

@ -50,8 +50,8 @@ pub use self::hash::{H64, H160, H256, H512, H520, H2048};
pub use self::index::Index; pub use self::index::Index;
pub use self::log::Log; pub use self::log::Log;
pub use self::sync::{ pub use self::sync::{
SyncStatus, SyncInfo, Peers, PeerInfo, PeerNetworkInfo, PeerProtocolsInfo, PeerEthereumProtocolInfo, SyncStatus, SyncInfo, Peers, PeerInfo, PeerNetworkInfo, PeerProtocolsInfo,
TransactionStats, ChainStatus TransactionStats, ChainStatus, EthProtocolInfo, LesProtocolInfo,
}; };
pub use self::transaction::{Transaction, RichRawTransaction, LocalTransactionStatus}; pub use self::transaction::{Transaction, RichRawTransaction, LocalTransactionStatus};
pub use self::transaction_request::TransactionRequest; pub use self::transaction_request::TransactionRequest;

View File

@ -15,7 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::collections::BTreeMap; use std::collections::BTreeMap;
use ethsync::{PeerInfo as SyncPeerInfo, TransactionStats as SyncTransactionStats}; use ethsync::{self, PeerInfo as SyncPeerInfo, TransactionStats as SyncTransactionStats};
use serde::{Serialize, Serializer}; use serde::{Serialize, Serializer};
use v1::types::{U256, H512}; use v1::types::{U256, H512};
@ -82,12 +82,14 @@ pub struct PeerNetworkInfo {
#[derive(Default, Debug, Serialize)] #[derive(Default, Debug, Serialize)]
pub struct PeerProtocolsInfo { pub struct PeerProtocolsInfo {
/// Ethereum protocol information /// Ethereum protocol information
pub eth: Option<PeerEthereumProtocolInfo>, pub eth: Option<EthProtocolInfo>,
/// LES protocol information.
pub les: Option<LesProtocolInfo>,
} }
/// Peer Ethereum protocol information /// Peer Ethereum protocol information
#[derive(Default, Debug, Serialize)] #[derive(Default, Debug, Serialize)]
pub struct PeerEthereumProtocolInfo { pub struct EthProtocolInfo {
/// Negotiated ethereum protocol version /// Negotiated ethereum protocol version
pub version: u32, pub version: u32,
/// Peer total difficulty if known /// Peer total difficulty if known
@ -96,6 +98,37 @@ pub struct PeerEthereumProtocolInfo {
pub head: String, pub head: String,
} }
impl From<ethsync::EthProtocolInfo> for EthProtocolInfo {
fn from(info: ethsync::EthProtocolInfo) -> Self {
EthProtocolInfo {
version: info.version,
difficulty: info.difficulty.map(Into::into),
head: info.head.hex(),
}
}
}
/// Peer LES protocol information
#[derive(Default, Debug, Serialize)]
pub struct LesProtocolInfo {
/// Negotiated LES protocol version
pub version: u32,
/// Peer total difficulty
pub difficulty: U256,
/// SHA3 of peer best block hash
pub head: String,
}
impl From<ethsync::LesProtocolInfo> for LesProtocolInfo {
fn from(info: ethsync::LesProtocolInfo) -> Self {
LesProtocolInfo {
version: info.version,
difficulty: info.difficulty.into(),
head: info.head.hex(),
}
}
}
/// Sync status /// Sync status
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum SyncStatus { pub enum SyncStatus {
@ -137,11 +170,8 @@ impl From<SyncPeerInfo> for PeerInfo {
local_address: p.local_address, local_address: p.local_address,
}, },
protocols: PeerProtocolsInfo { protocols: PeerProtocolsInfo {
eth: Some(PeerEthereumProtocolInfo { eth: p.eth_info.map(Into::into),
version: p.eth_version, les: p.les_info.map(Into::into),
difficulty: p.eth_difficulty.map(|d| d.into()),
head: p.eth_head.hex(),
})
}, },
} }
} }

View File

@ -36,7 +36,7 @@ use parking_lot::RwLock;
use chain::{ETH_PACKET_COUNT, SNAPSHOT_SYNC_PACKET_COUNT}; use chain::{ETH_PACKET_COUNT, SNAPSHOT_SYNC_PACKET_COUNT};
use light::client::LightChainClient; use light::client::LightChainClient;
use light::Provider; use light::Provider;
use light::net::{LightProtocol, Params as LightParams, Capabilities, Handler as LightHandler, EventContext}; use light::net::{self as light_net, LightProtocol, Params as LightParams, Capabilities, Handler as LightHandler, EventContext};
/// Parity sync protocol /// Parity sync protocol
pub const WARP_SYNC_PROTOCOL_ID: ProtocolId = *b"par"; pub const WARP_SYNC_PROTOCOL_ID: ProtocolId = *b"par";
@ -123,12 +123,44 @@ pub struct PeerInfo {
pub remote_address: String, pub remote_address: String,
/// Local endpoint address /// Local endpoint address
pub local_address: String, pub local_address: String,
/// Ethereum protocol version /// Eth protocol info.
pub eth_version: u32, pub eth_info: Option<EthProtocolInfo>,
/// Light protocol info.
pub les_info: Option<LesProtocolInfo>,
}
/// Ethereum protocol info.
#[derive(Debug)]
#[cfg_attr(feature = "ipc", derive(Binary))]
pub struct EthProtocolInfo {
/// Protocol version
pub version: u32,
/// SHA3 of peer best block hash /// SHA3 of peer best block hash
pub eth_head: H256, pub head: H256,
/// Peer total difficulty if known /// Peer total difficulty if known
pub eth_difficulty: Option<U256>, pub difficulty: Option<U256>,
}
/// LES protocol info.
#[derive(Debug)]
#[cfg_attr(feature = "ipc", derive(Binary))]
pub struct LesProtocolInfo {
/// Protocol version
pub version: u32,
/// SHA3 of peer best block hash
pub head: H256,
/// Peer total difficulty if known
pub difficulty: U256,
}
impl From<light_net::Status> for LesProtocolInfo {
fn from(status: light_net::Status) -> Self {
LesProtocolInfo {
version: status.protocol_version,
head: status.head_hash,
difficulty: status.head_td,
}
}
} }
/// EthSync initialization parameters. /// EthSync initialization parameters.
@ -214,11 +246,28 @@ impl SyncProvider for EthSync {
/// Get sync peers /// Get sync peers
fn peers(&self) -> Vec<PeerInfo> { fn peers(&self) -> Vec<PeerInfo> {
// TODO: [rob] LES peers/peer info self.network.with_context_eval(self.subprotocol_name, |ctx| {
self.network.with_context_eval(self.subprotocol_name, |context| { let peer_ids = self.network.connected_peers();
let sync_io = NetSyncIo::new(context, &*self.eth_handler.chain, &*self.eth_handler.snapshot_service, &self.eth_handler.overlay); let eth_sync = self.eth_handler.sync.read();
self.eth_handler.sync.write().peers(&sync_io) let light_proto = self.light_proto.as_ref();
}).unwrap_or(Vec::new())
peer_ids.into_iter().filter_map(|peer_id| {
let session_info = match ctx.session_info(peer_id) {
None => return None,
Some(info) => info,
};
Some(PeerInfo {
id: session_info.id.map(|id| id.hex()),
client_version: session_info.client_version,
capabilities: session_info.peer_capabilities.into_iter().map(|c| c.to_string()).collect(),
remote_address: session_info.remote_address,
local_address: session_info.local_address,
eth_info: eth_sync.peer_info(&peer_id),
les_info: light_proto.as_ref().and_then(|lp| lp.peer_status(&peer_id)).map(Into::into),
})
}).collect()
}).unwrap_or_else(Vec::new)
} }
fn enode(&self) -> Option<String> { fn enode(&self) -> Option<String> {

View File

@ -102,7 +102,7 @@ use super::SyncConfig;
use block_sync::{BlockDownloader, BlockRequest, BlockDownloaderImportError as DownloaderImportError, DownloadAction}; use block_sync::{BlockDownloader, BlockRequest, BlockDownloaderImportError as DownloaderImportError, DownloadAction};
use rand::Rng; use rand::Rng;
use snapshot::{Snapshot, ChunkType}; use snapshot::{Snapshot, ChunkType};
use api::{PeerInfo as PeerInfoDigest, WARP_SYNC_PROTOCOL_ID}; use api::{EthProtocolInfo as PeerInfoDigest, WARP_SYNC_PROTOCOL_ID};
use transactions_stats::{TransactionsStats, Stats as TransactionStats}; use transactions_stats::{TransactionsStats, Stats as TransactionStats};
known_heap_size!(0, PeerInfo); known_heap_size!(0, PeerInfo);
@ -431,22 +431,14 @@ impl ChainSync {
} }
/// Returns information on peers connections /// Returns information on peers connections
pub fn peers(&self, io: &SyncIo) -> Vec<PeerInfoDigest> { pub fn peer_info(&self, peer_id: &PeerId) -> Option<PeerInfoDigest> {
self.peers.iter() self.peers.get(peer_id).map(|peer_data| {
.filter_map(|(&peer_id, peer_data)| PeerInfoDigest {
io.peer_session_info(peer_id).map(|session_info| version: peer_data.protocol_version as u32,
PeerInfoDigest { difficulty: peer_data.difficulty,
id: session_info.id.map(|id| id.hex()), head: peer_data.latest_hash,
client_version: session_info.client_version, }
capabilities: session_info.peer_capabilities.into_iter().map(|c| c.to_string()).collect(), })
remote_address: session_info.remote_address,
local_address: session_info.local_address,
eth_version: peer_data.protocol_version as u32,
eth_difficulty: peer_data.difficulty,
eth_head: peer_data.latest_hash,
})
)
.collect()
} }
/// Returns transactions propagation statistics /// Returns transactions propagation statistics

View File

@ -75,7 +75,7 @@ mod api;
pub use api::{ pub use api::{
EthSync, Params, SyncProvider, ManageNetwork, SyncConfig, EthSync, Params, SyncProvider, ManageNetwork, SyncConfig,
ServiceConfiguration, NetworkConfiguration, PeerInfo, AllowIP, TransactionStats, ServiceConfiguration, NetworkConfiguration, PeerInfo, AllowIP, TransactionStats,
LightSync, LightSyncParams, LightSync, LightSyncParams, LesProtocolInfo, EthProtocolInfo,
}; };
pub use chain::{SyncStatus, SyncState}; pub use chain::{SyncStatus, SyncState};
pub use network::{is_valid_node_url, NonReservedPeerMode, NetworkError}; pub use network::{is_valid_node_url, NonReservedPeerMode, NetworkError};

View File

@ -542,6 +542,20 @@ impl Host {
Ok(()) Ok(())
} }
/// Get all connected peers.
pub fn connected_peers(&self) -> Vec<PeerId> {
let sessions = self.sessions.read();
let sessions = &*sessions;
let mut peers = Vec::with_capacity(sessions.count());
for i in (0..MAX_SESSIONS).map(|x| x + FIRST_SESSION) {
if sessions.get(i).is_some() {
peers.push(i);
}
}
peers
}
fn init_public_interface(&self, io: &IoContext<NetworkIoMessage>) -> Result<(), NetworkError> { fn init_public_interface(&self, io: &IoContext<NetworkIoMessage>) -> Result<(), NetworkError> {
if self.info.read().public_endpoint.is_some() { if self.info.read().public_endpoint.is_some() {
return Ok(()); return Ok(());

View File

@ -16,7 +16,7 @@
use {NetworkProtocolHandler, NetworkConfiguration, NonReservedPeerMode}; use {NetworkProtocolHandler, NetworkConfiguration, NonReservedPeerMode};
use error::NetworkError; use error::NetworkError;
use host::{Host, NetworkContext, NetworkIoMessage, ProtocolId}; use host::{Host, NetworkContext, NetworkIoMessage, PeerId, ProtocolId};
use stats::NetworkStats; use stats::NetworkStats;
use io::*; use io::*;
use parking_lot::RwLock; use parking_lot::RwLock;
@ -142,6 +142,11 @@ impl NetworkService {
Ok(()) Ok(())
} }
/// Get a list of all connected peers by id.
pub fn connected_peers(&self) -> Vec<PeerId> {
self.host.read().as_ref().map(|h| h.connected_peers()).unwrap_or_else(Vec::new)
}
/// Try to add a reserved peer. /// Try to add a reserved peer.
pub fn add_reserved_peer(&self, peer: &str) -> Result<(), NetworkError> { pub fn add_reserved_peer(&self, peer: &str) -> Result<(), NetworkError> {
let host = self.host.read(); let host = self.host.read();