diff --git a/ethcore/light/src/net/mod.rs b/ethcore/light/src/net/mod.rs index fd64f4a4b..7c186aa94 100644 --- a/ethcore/light/src/net/mod.rs +++ b/ethcore/light/src/net/mod.rs @@ -27,7 +27,7 @@ use network::{NetworkProtocolHandler, NetworkContext, NetworkError, PeerId}; use rlp::{RlpStream, Stream, UntrustedRlp, View}; use util::hash::H256; use util::{Bytes, Mutex, RwLock, U256}; -use time::SteadyTime; +use time::{Duration, SteadyTime}; use std::collections::HashMap; use std::sync::Arc; @@ -54,6 +54,9 @@ pub use self::status::{Status, Capabilities, Announcement}; const TIMEOUT: TimerToken = 0; const TIMEOUT_INTERVAL_MS: u64 = 1000; +// minimum interval between updates. +const UPDATE_INTERVAL_MS: i64 = 5000; + // Supported protocol versions. pub const PROTOCOL_VERSIONS: &'static [u8] = &[1]; @@ -107,6 +110,7 @@ pub struct ReqId(usize); // may not have received one for. struct PendingPeer { sent_head: H256, + last_update: SteadyTime, } // data about each peer. @@ -117,6 +121,7 @@ struct Peer { capabilities: Capabilities, remote_flow: FlowParams, sent_head: H256, // last head we've given them. + last_update: SteadyTime, } impl Peer { @@ -293,6 +298,7 @@ impl LightProtocol { /// The announcement is expected to be valid. pub fn make_announcement(&self, io: &IoContext, mut announcement: Announcement) { let mut reorgs_map = HashMap::new(); + let now = SteadyTime::now(); // update stored capabilities self.capabilities.write().update_from(&announcement); @@ -300,6 +306,17 @@ impl LightProtocol { // calculate reorg info and send packets for (peer_id, peer_info) in self.peers.read().iter() { let mut peer_info = peer_info.lock(); + + // TODO: "urgent" announcements like new blocks? + // the timer approach will skip 1 (possibly 2) in rare occasions. + if peer_info.sent_head == announcement.head_hash || + peer_info.status.head_num >= announcement.head_num || + now - peer_info.last_update < Duration::milliseconds(UPDATE_INTERVAL_MS) { + continue + } + + peer_info.last_update = now; + let reorg_depth = reorgs_map.entry(peer_info.sent_head) .or_insert_with(|| { match self.provider.reorg_depth(&announcement.head_hash, &peer_info.sent_head) { @@ -496,6 +513,7 @@ impl LightProtocol { Ok(PendingPeer { sent_head: chain_info.best_block_hash, + last_update: SteadyTime::now(), }) } @@ -523,6 +541,7 @@ impl LightProtocol { capabilities: capabilities.clone(), remote_flow: flow_params, sent_head: pending.sent_head, + last_update: pending.last_update, })); for handler in &self.handlers { diff --git a/sync/src/api.rs b/sync/src/api.rs index acc593fb1..7c531bf7c 100644 --- a/sync/src/api.rs +++ b/sync/src/api.rs @@ -279,6 +279,8 @@ impl ChainNotify for EthSync { sealed: Vec, _duration: u64) { + use light::net::Announcement; + self.network.with_context(self.subprotocol_name, |context| { let mut sync_io = NetSyncIo::new(context, &*self.sync_handler.chain, &*self.sync_handler.snapshot_service, &self.sync_handler.overlay); self.sync_handler.sync.write().chain_new_blocks( @@ -289,6 +291,25 @@ impl ChainNotify for EthSync { &retracted, &sealed); }); + + self.network.with_context(self.light_subprotocol_name, |context| { + let light_proto = match self.light_proto.as_ref() { + 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, + head_num: chain_info.best_block_number, + head_td: chain_info.total_difficulty, + reorg_depth: 0, // recalculated on a per-peer basis. + serve_headers: false, // these fields consist of _changes_ in capability. + serve_state_since: None, + serve_chain_since: None, + tx_relay: false, + }) + }) } fn start(&self) {