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 {
/// Returns the relevant's peer persistent Id (aka 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
/// which a peer would be able to serve. Returns zero if the
/// peer is unknown or has no buffer flow parameters.

View File

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

View File

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

View File

@ -15,7 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
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 v1::types::{U256, H512};
@ -82,12 +82,14 @@ pub struct PeerNetworkInfo {
#[derive(Default, Debug, Serialize)]
pub struct PeerProtocolsInfo {
/// Ethereum protocol information
pub eth: Option<PeerEthereumProtocolInfo>,
pub eth: Option<EthProtocolInfo>,
/// LES protocol information.
pub les: Option<LesProtocolInfo>,
}
/// Peer Ethereum protocol information
#[derive(Default, Debug, Serialize)]
pub struct PeerEthereumProtocolInfo {
pub struct EthProtocolInfo {
/// Negotiated ethereum protocol version
pub version: u32,
/// Peer total difficulty if known
@ -96,6 +98,37 @@ pub struct PeerEthereumProtocolInfo {
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
#[derive(Debug, PartialEq)]
pub enum SyncStatus {
@ -137,11 +170,8 @@ impl From<SyncPeerInfo> for PeerInfo {
local_address: p.local_address,
},
protocols: PeerProtocolsInfo {
eth: Some(PeerEthereumProtocolInfo {
version: p.eth_version,
difficulty: p.eth_difficulty.map(|d| d.into()),
head: p.eth_head.hex(),
})
eth: p.eth_info.map(Into::into),
les: p.les_info.map(Into::into),
},
}
}

View File

@ -36,7 +36,7 @@ use parking_lot::RwLock;
use chain::{ETH_PACKET_COUNT, SNAPSHOT_SYNC_PACKET_COUNT};
use light::client::LightChainClient;
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
pub const WARP_SYNC_PROTOCOL_ID: ProtocolId = *b"par";
@ -123,12 +123,44 @@ pub struct PeerInfo {
pub remote_address: String,
/// Local endpoint address
pub local_address: String,
/// Ethereum protocol version
pub eth_version: u32,
/// Eth protocol info.
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
pub eth_head: H256,
pub head: H256,
/// 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.
@ -214,11 +246,28 @@ impl SyncProvider for EthSync {
/// Get sync peers
fn peers(&self) -> Vec<PeerInfo> {
// TODO: [rob] LES peers/peer info
self.network.with_context_eval(self.subprotocol_name, |context| {
let sync_io = NetSyncIo::new(context, &*self.eth_handler.chain, &*self.eth_handler.snapshot_service, &self.eth_handler.overlay);
self.eth_handler.sync.write().peers(&sync_io)
}).unwrap_or(Vec::new())
self.network.with_context_eval(self.subprotocol_name, |ctx| {
let peer_ids = self.network.connected_peers();
let eth_sync = self.eth_handler.sync.read();
let light_proto = self.light_proto.as_ref();
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> {

View File

@ -102,7 +102,7 @@ use super::SyncConfig;
use block_sync::{BlockDownloader, BlockRequest, BlockDownloaderImportError as DownloaderImportError, DownloadAction};
use rand::Rng;
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};
known_heap_size!(0, PeerInfo);
@ -431,22 +431,14 @@ impl ChainSync {
}
/// Returns information on peers connections
pub fn peers(&self, io: &SyncIo) -> Vec<PeerInfoDigest> {
self.peers.iter()
.filter_map(|(&peer_id, peer_data)|
io.peer_session_info(peer_id).map(|session_info|
PeerInfoDigest {
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_version: peer_data.protocol_version as u32,
eth_difficulty: peer_data.difficulty,
eth_head: peer_data.latest_hash,
})
)
.collect()
pub fn peer_info(&self, peer_id: &PeerId) -> Option<PeerInfoDigest> {
self.peers.get(peer_id).map(|peer_data| {
PeerInfoDigest {
version: peer_data.protocol_version as u32,
difficulty: peer_data.difficulty,
head: peer_data.latest_hash,
}
})
}
/// Returns transactions propagation statistics

View File

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

View File

@ -542,6 +542,20 @@ impl Host {
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> {
if self.info.read().public_endpoint.is_some() {
return Ok(());

View File

@ -16,7 +16,7 @@
use {NetworkProtocolHandler, NetworkConfiguration, NonReservedPeerMode};
use error::NetworkError;
use host::{Host, NetworkContext, NetworkIoMessage, ProtocolId};
use host::{Host, NetworkContext, NetworkIoMessage, PeerId, ProtocolId};
use stats::NetworkStats;
use io::*;
use parking_lot::RwLock;
@ -142,6 +142,11 @@ impl NetworkService {
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.
pub fn add_reserved_peer(&self, peer: &str) -> Result<(), NetworkError> {
let host = self.host.read();