Stats RPC
This commit is contained in:
@@ -15,13 +15,13 @@
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, BTreeMap};
|
||||
use std::io;
|
||||
use util::Bytes;
|
||||
use network::{NetworkProtocolHandler, NetworkService, NetworkContext, PeerId, ProtocolId,
|
||||
NetworkConfiguration as BasicNetworkConfiguration, NonReservedPeerMode, NetworkError,
|
||||
AllowIP as NetworkAllowIP};
|
||||
use util::{U256, H256};
|
||||
use util::{U256, H256, H512};
|
||||
use io::{TimerToken};
|
||||
use ethcore::client::{BlockChainClient, ChainNotify};
|
||||
use ethcore::snapshot::SnapshotService;
|
||||
@@ -76,6 +76,16 @@ pub trait SyncProvider: Send + Sync {
|
||||
|
||||
/// Get the enode if available.
|
||||
fn enode(&self) -> Option<String>;
|
||||
|
||||
/// Returns propagation count for pending transactions.
|
||||
fn transactions_stats(&self) -> BTreeMap<H256, TransactionStats>;
|
||||
}
|
||||
|
||||
/// Transaction stats
|
||||
#[derive(Debug, Binary)]
|
||||
pub struct TransactionStats {
|
||||
pub first_seen: u64,
|
||||
pub propagated_to: BTreeMap<H512, usize>,
|
||||
}
|
||||
|
||||
/// Peer connection information
|
||||
@@ -150,6 +160,14 @@ impl SyncProvider for EthSync {
|
||||
fn enode(&self) -> Option<String> {
|
||||
self.network.external_url()
|
||||
}
|
||||
|
||||
fn transactions_stats(&self) -> BTreeMap<H256, TransactionStats> {
|
||||
let sync = self.handler.sync.read();
|
||||
sync.transactions_stats()
|
||||
.iter()
|
||||
.map(|(hash, stats)| (*hash, stats.into()))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
struct SyncProtocolHandler {
|
||||
|
||||
@@ -102,7 +102,7 @@ use block_sync::{BlockDownloader, BlockRequest, BlockDownloaderImportError as Do
|
||||
use snapshot::{Snapshot, ChunkType};
|
||||
use rand::{thread_rng, Rng};
|
||||
use api::{PeerInfo as PeerInfoDigest, WARP_SYNC_PROTOCOL_ID};
|
||||
use transactions_stats::TransactionsStats;
|
||||
use transactions_stats::{TransactionsStats, Stats as TransactionStats};
|
||||
|
||||
known_heap_size!(0, PeerInfo);
|
||||
|
||||
@@ -412,6 +412,11 @@ impl ChainSync {
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Returns transactions propagation statistics
|
||||
pub fn transactions_stats(&self) -> &H256FastMap<TransactionStats> {
|
||||
self.transactions_stats.stats()
|
||||
}
|
||||
|
||||
/// Abort all sync activity
|
||||
pub fn abort(&mut self, io: &mut SyncIo) {
|
||||
self.reset_and_continue(io);
|
||||
@@ -1877,6 +1882,7 @@ impl ChainSync {
|
||||
// sqrt(x)/x scaled to max u32
|
||||
let fraction = (self.peers.len() as f64).powf(-0.5).mul(u32::max_value() as f64).round() as u32;
|
||||
let small = self.peers.len() < MIN_PEERS_PROPAGATION;
|
||||
let block_number = io.chain().chain_info().best_block_number;
|
||||
|
||||
let lucky_peers = {
|
||||
let stats = &mut self.transactions_stats;
|
||||
@@ -1889,7 +1895,7 @@ impl ChainSync {
|
||||
// update stats
|
||||
for hash in &all_transactions_hashes {
|
||||
let id = io.peer_session_info(*peer_id).and_then(|info| info.id);
|
||||
stats.propagated(*hash, id);
|
||||
stats.propagated(*hash, id, block_number);
|
||||
}
|
||||
peer_info.last_sent_transactions = all_transactions_hashes.clone();
|
||||
return Some((*peer_id, all_transactions_rlp.clone()));
|
||||
@@ -1907,8 +1913,8 @@ impl ChainSync {
|
||||
if to_send.contains(&tx.hash()) {
|
||||
packet.append(tx);
|
||||
// update stats
|
||||
let peer_id = io.peer_session_info(*peer_id).and_then(|info| info.id);
|
||||
stats.propagated(tx.hash(), peer_id);
|
||||
let id = io.peer_session_info(*peer_id).and_then(|info| info.id);
|
||||
stats.propagated(tx.hash(), id, block_number);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2362,6 +2368,21 @@ mod tests {
|
||||
assert_eq!(0x02, io.queue[1].packet_id);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_maintain_transations_propagation_stats() {
|
||||
let mut client = TestBlockChainClient::new();
|
||||
client.add_blocks(100, EachBlockWith::Uncle);
|
||||
client.insert_transaction_to_queue();
|
||||
let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(1), &client);
|
||||
let mut queue = VecDeque::new();
|
||||
let ss = TestSnapshotService::new();
|
||||
let mut io = TestIo::new(&mut client, &ss, &mut queue, None);
|
||||
sync.propagate_new_transactions(&mut io);
|
||||
|
||||
let stats = sync.transactions_stats();
|
||||
assert_eq!(stats.len(), 1, "Should maintain stats for single transaction.")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn handles_peer_new_block_malformed() {
|
||||
let mut client = TestBlockChainClient::new();
|
||||
|
||||
@@ -62,7 +62,7 @@ mod api {
|
||||
}
|
||||
|
||||
pub use api::{EthSync, SyncProvider, SyncClient, NetworkManagerClient, ManageNetwork, SyncConfig,
|
||||
ServiceConfiguration, NetworkConfiguration, PeerInfo, AllowIP};
|
||||
ServiceConfiguration, NetworkConfiguration, PeerInfo, AllowIP, TransactionStats};
|
||||
pub use chain::{SyncStatus, SyncState};
|
||||
pub use network::{is_valid_node_url, NonReservedPeerMode, NetworkError};
|
||||
|
||||
|
||||
@@ -14,8 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Transaction Stats
|
||||
|
||||
use api::TransactionStats;
|
||||
use std::collections::{HashSet, HashMap};
|
||||
use util::{H256, H512};
|
||||
use util::hash::H256FastMap;
|
||||
@@ -23,12 +22,33 @@ use util::hash::H256FastMap;
|
||||
type NodeId = H512;
|
||||
type BlockNumber = u64;
|
||||
|
||||
#[derive(Debug, Default, PartialEq)]
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct Stats {
|
||||
first_seen: BlockNumber,
|
||||
propagated_to: HashMap<NodeId, usize>,
|
||||
}
|
||||
|
||||
impl Stats {
|
||||
pub fn new(number: BlockNumber) -> Self {
|
||||
Stats {
|
||||
first_seen: number,
|
||||
propagated_to: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Stats> for TransactionStats {
|
||||
fn from(other: &'a Stats) -> Self {
|
||||
TransactionStats {
|
||||
first_seen: other.first_seen,
|
||||
propagated_to: other.propagated_to
|
||||
.iter()
|
||||
.map(|(hash, size)| (*hash, *size))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct TransactionsStats {
|
||||
pending_transactions: H256FastMap<Stats>,
|
||||
@@ -36,18 +56,23 @@ pub struct TransactionsStats {
|
||||
|
||||
impl TransactionsStats {
|
||||
/// Increases number of propagations to given `enodeid`.
|
||||
pub fn propagated(&mut self, hash: H256, enode_id: Option<NodeId>) {
|
||||
pub fn propagated(&mut self, hash: H256, enode_id: Option<NodeId>, current_block_num: BlockNumber) {
|
||||
let enode_id = enode_id.unwrap_or_default();
|
||||
let mut stats = self.pending_transactions.entry(hash).or_insert_with(|| Stats::default());
|
||||
let mut stats = self.pending_transactions.entry(hash).or_insert_with(|| Stats::new(current_block_num));
|
||||
let mut count = stats.propagated_to.entry(enode_id).or_insert(0);
|
||||
*count = count.saturating_add(1);
|
||||
}
|
||||
|
||||
/// Returns propagation stats for given hash or `None` if hash is not known.
|
||||
pub fn stats(&self, hash: &H256) -> Option<&Stats> {
|
||||
#[cfg(test)]
|
||||
pub fn get(&self, hash: &H256) -> Option<&Stats> {
|
||||
self.pending_transactions.get(hash)
|
||||
}
|
||||
|
||||
pub fn stats(&self) -> &H256FastMap<Stats> {
|
||||
&self.pending_transactions
|
||||
}
|
||||
|
||||
/// Retains only transactions present in given `HashSet`.
|
||||
pub fn retain(&mut self, hashes: &HashSet<H256>) {
|
||||
let to_remove = self.pending_transactions.keys()
|
||||
@@ -76,14 +101,14 @@ mod tests {
|
||||
let enodeid2 = 5.into();
|
||||
|
||||
// when
|
||||
stats.propagated(hash, Some(enodeid1));
|
||||
stats.propagated(hash, Some(enodeid1));
|
||||
stats.propagated(hash, Some(enodeid2));
|
||||
stats.propagated(hash, Some(enodeid1), 5);
|
||||
stats.propagated(hash, Some(enodeid1), 10);
|
||||
stats.propagated(hash, Some(enodeid2), 15);
|
||||
|
||||
// then
|
||||
let stats = stats.stats(&hash);
|
||||
let stats = stats.get(&hash);
|
||||
assert_eq!(stats, Some(&Stats {
|
||||
first_seen: 0,
|
||||
first_seen: 5,
|
||||
propagated_to: hash_map![
|
||||
enodeid1 => 2,
|
||||
enodeid2 => 1
|
||||
@@ -97,13 +122,13 @@ mod tests {
|
||||
let mut stats = TransactionsStats::default();
|
||||
let hash = 5.into();
|
||||
let enodeid1 = 5.into();
|
||||
stats.propagated(hash, Some(enodeid1));
|
||||
stats.propagated(hash, Some(enodeid1), 10);
|
||||
|
||||
// when
|
||||
stats.retain(&HashSet::new());
|
||||
|
||||
// then
|
||||
let stats = stats.stats(&hash);
|
||||
let stats = stats.get(&hash);
|
||||
assert_eq!(stats, None);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user