diff --git a/ethcore/src/client/chain_notify.rs b/ethcore/src/client/chain_notify.rs index 737cd0153..0c34382a0 100644 --- a/ethcore/src/client/chain_notify.rs +++ b/ethcore/src/client/chain_notify.rs @@ -20,8 +20,7 @@ use util::H256; /// Represents what has to be handled by actor listening to chain events #[derive(Ipc)] pub trait ChainNotify : Send + Sync { - /// fires when chain has new blocks, not including those encountered during - /// a major sync. + /// fires when chain has new blocks. fn new_blocks(&self, _imported: Vec, _invalid: Vec, diff --git a/ethcore/src/snapshot/watcher.rs b/ethcore/src/snapshot/watcher.rs index d2dd1d7dc..5bf157312 100644 --- a/ethcore/src/snapshot/watcher.rs +++ b/ethcore/src/snapshot/watcher.rs @@ -37,11 +37,29 @@ impl HashToNumber for Client { } } +// helper trait for broadcasting a block to take a snapshot at. +trait Broadcast: Send + Sync { + fn take_at(&self, num: Option); +} + +impl Broadcast for IoChannel { + fn take_at(&self, num: Option) { + let num = match num { + Some(n) => n, + None => return, + }; + + if let Err(e) = self.send(ClientIoMessage::TakeSnapshot(num)) { + warn!("Snapshot watcher disconnected from IoService: {}", e); + } + } +} + /// A `ChainNotify` implementation which will trigger a snapshot event /// at certain block numbers. pub struct Watcher { oracle: Arc, - channel: IoChannel, + broadcast: Box, period: u64, history: u64, } @@ -53,7 +71,7 @@ impl Watcher { pub fn new(client: Arc, channel: IoChannel, period: u64, history: u64) -> Self { Watcher { oracle: client, - channel: channel, + broadcast: Box::new(channel), period: period, history: history, } @@ -70,7 +88,6 @@ impl ChainNotify for Watcher { _: Vec, _duration: u64) { - let highest = imported.into_iter() .filter_map(|h| self.oracle.to_number(h)) .filter(|&num| num >= self.period + self.history) @@ -78,23 +95,20 @@ impl ChainNotify for Watcher { .filter(|num| num % self.period == 0) .fold(0, ::std::cmp::max); - if highest != 0 { - if let Err(e) = self.channel.send(ClientIoMessage::TakeSnapshot(highest)) { - warn!("Snapshot watcher disconnected from IoService: {}", e); - } + match highest { + 0 => self.broadcast.take_at(None), + _ => self.broadcast.take_at(Some(highest)), } } } #[cfg(test)] mod tests { - use super::{HashToNumber, Watcher}; + use super::{Broadcast, HashToNumber, Watcher}; use client::ChainNotify; - use service::ClientIoMessage; - use util::{H256, U256, Mutex}; - use io::{IoContext, IoHandler, IoService}; + use util::{H256, U256}; use std::collections::HashMap; use std::sync::Arc; @@ -107,30 +121,23 @@ mod tests { } } - struct Handler(Arc>>); - - impl IoHandler for Handler { - fn message(&self, _context: &IoContext, message: &ClientIoMessage) { - match *message { - ClientIoMessage::TakeSnapshot(num) => self.0.lock().push(num), - _ => {} + struct TestBroadcast(Option); + impl Broadcast for TestBroadcast { + fn take_at(&self, num: Option) { + if num != self.0 { + panic!("Watcher broadcast wrong number. Expected {:?}, found {:?}", self.0, num); } } } - // helper harness for tests. - fn harness(numbers: Vec, period: u64, history: u64) -> Vec { - let events = Arc::new(Mutex::new(Vec::new())); - - let service = IoService::start().unwrap(); - service.register_handler(Arc::new(Handler(events.clone()))).unwrap(); - + // helper harness for tests which expect a notification. + fn harness(numbers: Vec, period: u64, history: u64, expected: Option) { let hashes: Vec<_> = numbers.clone().into_iter().map(|x| H256::from(U256::from(x))).collect(); - let mut map = hashes.clone().into_iter().zip(numbers).collect(); + let map = hashes.clone().into_iter().zip(numbers).collect(); let watcher = Watcher { oracle: Arc::new(TestOracle(map)), - channel: service.channel(), + broadcast: Box::new(TestBroadcast(expected)), period: period, history: history, }; @@ -143,35 +150,27 @@ mod tests { vec![], 0, ); - - drop(service); - - // binding necessary for compilation. - let v = events.lock().clone(); - v } + // helper + #[test] fn should_not_fire() { - let events = harness(vec![0], 5, 0); - assert_eq!(events, vec![]); + harness(vec![0], 5, 0, None); } #[test] fn fires_once_for_two() { - let events = harness(vec![14, 15], 10, 5); - assert_eq!(events, vec![10]); + harness(vec![14, 15], 10, 5, Some(10)); } #[test] fn finds_highest() { - let events = harness(vec![15, 25], 10, 5); - assert_eq!(events, vec![20]); + harness(vec![15, 25], 10, 5, Some(20)); } #[test] fn doesnt_fire_before_history() { - let events = harness(vec![10, 11], 10, 5); - assert_eq!(events, vec![]); + harness(vec![10, 11], 10, 5, None); } } \ No newline at end of file