Maintaining a list of transactions propagated from other peers

This commit is contained in:
Tomasz Drwięga
2016-12-10 14:56:41 +01:00
parent 6eb63a7316
commit e1ade5b375
12 changed files with 137 additions and 29 deletions

View File

@@ -99,6 +99,8 @@ pub struct TransactionStats {
pub first_seen: u64,
/// Peers it was propagated to.
pub propagated_to: BTreeMap<H512, usize>,
/// Peers that propagated the transaction back.
pub received_from: BTreeMap<H512, usize>,
}
/// Peer connection information
@@ -144,7 +146,7 @@ pub struct EthSync {
network: NetworkService,
/// Main (eth/par) protocol handler
sync_handler: Arc<SyncProtocolHandler>,
/// Light (les) protocol handler
/// Light (les) protocol handler
light_proto: Option<Arc<LightProtocol>>,
/// The main subprotocol name
subprotocol_name: [u8; 3],
@@ -155,7 +157,7 @@ pub struct EthSync {
impl EthSync {
/// Creates and register protocol with the network service
pub fn new(params: Params) -> Result<Arc<EthSync>, NetworkError> {
let pruning_info = params.chain.pruning_info();
let pruning_info = params.chain.pruning_info();
let light_proto = match params.config.serve_light {
false => None,
true => Some({
@@ -297,7 +299,7 @@ impl ChainNotify for EthSync {
Some(lp) => lp,
None => return,
};
let chain_info = self.sync_handler.chain.chain_info();
light_proto.make_announcement(context, Announcement {
head_hash: chain_info.best_block_hash,
@@ -323,7 +325,7 @@ impl ChainNotify for EthSync {
// register the warp sync subprotocol
self.network.register_protocol(self.sync_handler.clone(), WARP_SYNC_PROTOCOL_ID, SNAPSHOT_SYNC_PACKET_COUNT, &[1u8])
.unwrap_or_else(|e| warn!("Error registering snapshot sync protocol: {:?}", e));
// register the light protocol.
if let Some(light_proto) = self.light_proto.as_ref().map(|x| x.clone()) {
self.network.register_protocol(light_proto, self.light_subprotocol_name, ::light::net::PACKET_COUNT, ::light::net::PROTOCOL_VERSIONS)
@@ -335,6 +337,11 @@ impl ChainNotify for EthSync {
self.sync_handler.snapshot_service.abort_restore();
self.network.stop().unwrap_or_else(|e| warn!("Error stopping network: {:?}", e));
}
fn transactions_imported(&self, hashes: Vec<H256>, peer_id: Option<H512>, block_number: u64) {
let mut sync = self.sync_handler.sync.write();
sync.transactions_imported(hashes, peer_id, block_number);
}
}
/// LES event handler.
@@ -344,7 +351,8 @@ struct TxRelay(Arc<BlockChainClient>);
impl LightHandler for TxRelay {
fn on_transactions(&self, ctx: &EventContext, relay: &[::ethcore::transaction::SignedTransaction]) {
trace!(target: "les", "Relaying {} transactions from peer {}", relay.len(), ctx.peer());
self.0.queue_transactions(relay.iter().map(|tx| ::rlp::encode(tx).to_vec()).collect())
// TODO [ToDr] Can we get a peer enode somehow?
self.0.queue_transactions(relay.iter().map(|tx| ::rlp::encode(tx).to_vec()).collect(), None)
}
}
@@ -547,4 +555,4 @@ pub struct ServiceConfiguration {
pub net: NetworkConfiguration,
/// IPC path.
pub io_path: String,
}
}

View File

@@ -432,6 +432,13 @@ impl ChainSync {
self.transactions_stats.stats()
}
/// Updates statistics for imported transactions.
pub fn transactions_imported(&mut self, hashes: Vec<H256>, peer_id: Option<H512>, block_number: u64) {
for hash in hashes {
self.transactions_stats.received(hash, peer_id, block_number);
}
}
/// Abort all sync activity
pub fn abort(&mut self, io: &mut SyncIo) {
self.reset_and_continue(io);
@@ -1409,7 +1416,8 @@ impl ChainSync {
let tx = rlp.as_raw().to_vec();
transactions.push(tx);
}
io.chain().queue_transactions(transactions);
let id = io.peer_session_info(peer_id).and_then(|info| info.id);
io.chain().queue_transactions(transactions, id);
Ok(())
}

View File

@@ -26,6 +26,7 @@ type BlockNumber = u64;
pub struct Stats {
first_seen: BlockNumber,
propagated_to: HashMap<NodeId, usize>,
received_from: HashMap<NodeId, usize>,
}
impl Stats {
@@ -33,6 +34,7 @@ impl Stats {
Stats {
first_seen: number,
propagated_to: Default::default(),
received_from: Default::default(),
}
}
}
@@ -45,6 +47,10 @@ impl<'a> From<&'a Stats> for TransactionStats {
.iter()
.map(|(hash, size)| (*hash, *size))
.collect(),
received_from: other.received_from
.iter()
.map(|(hash, size)| (*hash, *size))
.collect(),
}
}
}
@@ -63,6 +69,14 @@ impl TransactionsStats {
*count = count.saturating_add(1);
}
/// Increase number of back-propagations from given `enodeid`.
pub fn received(&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::new(current_block_num));
let mut count = stats.received_from.entry(enode_id).or_insert(0);
*count = count.saturating_add(1);
}
/// Returns propagation stats for given hash or `None` if hash is not known.
#[cfg(test)]
pub fn get(&self, hash: &H256) -> Option<&Stats> {
@@ -112,6 +126,32 @@ mod tests {
propagated_to: hash_map![
enodeid1 => 2,
enodeid2 => 1
],
received_from: Default::default(),
}));
}
#[test]
fn should_keep_track_of_back_propagations() {
// given
let mut stats = TransactionsStats::default();
let hash = 5.into();
let enodeid1 = 2.into();
let enodeid2 = 5.into();
// when
stats.received(hash, Some(enodeid1), 5);
stats.received(hash, Some(enodeid1), 10);
stats.received(hash, Some(enodeid2), 15);
// then
let stats = stats.get(&hash);
assert_eq!(stats, Some(&Stats {
first_seen: 5,
propagated_to: Default::default(),
received_from: hash_map![
enodeid1 => 2,
enodeid2 => 1
]
}));
}