2018-03-29 12:20:54 -06:00
|
|
|
//! The `recorder` module provides an object for generating a Proof of History.
|
2018-03-19 10:16:16 -06:00
|
|
|
//! It records Event items on behalf of its users. It continuously generates
|
2018-03-03 14:24:32 -07:00
|
|
|
//! new hashes, only stopping to check if it has been sent an Event item. It
|
2018-03-30 10:43:38 -07:00
|
|
|
//! tags each Event with an Entry, and sends it back. The Entry includes the
|
2018-03-03 14:24:32 -07:00
|
|
|
//! Event, the latest hash, and the number of hashes since the last event.
|
|
|
|
|
//! The resulting stream of entries represents ordered events in time.
|
|
|
|
|
|
2018-03-06 17:31:17 -07:00
|
|
|
use entry::{create_entry_mut, Entry};
|
2018-03-04 22:26:46 -07:00
|
|
|
use event::Event;
|
2018-03-26 22:03:26 -06:00
|
|
|
use hash::{hash, Hash};
|
2018-05-09 11:15:14 -06:00
|
|
|
use std::sync::mpsc::{Receiver, Sender, TryRecvError};
|
2018-03-26 22:03:26 -06:00
|
|
|
use std::time::{Duration, Instant};
|
2018-03-03 14:24:32 -07:00
|
|
|
|
2018-03-22 14:59:25 -06:00
|
|
|
#[cfg_attr(feature = "cargo-clippy", allow(large_enum_variant))]
|
2018-03-09 17:22:14 -07:00
|
|
|
pub enum Signal {
|
|
|
|
|
Tick,
|
2018-05-09 08:05:40 -06:00
|
|
|
Events(Vec<Event>),
|
2018-03-09 17:22:14 -07:00
|
|
|
}
|
|
|
|
|
|
2018-03-03 14:24:32 -07:00
|
|
|
#[derive(Debug, PartialEq, Eq)]
|
|
|
|
|
pub enum ExitReason {
|
|
|
|
|
RecvDisconnected,
|
|
|
|
|
SendDisconnected,
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-19 10:16:16 -06:00
|
|
|
pub struct Recorder {
|
2018-05-09 11:15:14 -06:00
|
|
|
sender: Sender<Entry>,
|
2018-03-20 23:15:44 -06:00
|
|
|
receiver: Receiver<Signal>,
|
|
|
|
|
last_hash: Hash,
|
|
|
|
|
num_hashes: u64,
|
|
|
|
|
num_ticks: u64,
|
2018-03-03 14:24:32 -07:00
|
|
|
}
|
|
|
|
|
|
2018-03-19 10:16:16 -06:00
|
|
|
impl Recorder {
|
2018-05-09 11:15:14 -06:00
|
|
|
pub fn new(receiver: Receiver<Signal>, sender: Sender<Entry>, last_hash: Hash) -> Self {
|
2018-03-19 10:16:16 -06:00
|
|
|
Recorder {
|
2018-03-03 14:24:32 -07:00
|
|
|
receiver,
|
|
|
|
|
sender,
|
2018-04-02 09:30:10 -06:00
|
|
|
last_hash,
|
2018-03-03 14:24:32 -07:00
|
|
|
num_hashes: 0,
|
|
|
|
|
num_ticks: 0,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-20 23:15:44 -06:00
|
|
|
pub fn hash(&mut self) {
|
|
|
|
|
self.last_hash = hash(&self.last_hash);
|
|
|
|
|
self.num_hashes += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-09 08:15:49 -06:00
|
|
|
pub fn record_entry(&mut self, events: Vec<Event>) -> Result<(), ExitReason> {
|
2018-03-20 23:15:44 -06:00
|
|
|
let entry = create_entry_mut(&mut self.last_hash, &mut self.num_hashes, events);
|
|
|
|
|
self.sender
|
|
|
|
|
.send(entry)
|
|
|
|
|
.or(Err(ExitReason::SendDisconnected))?;
|
|
|
|
|
Ok(())
|
2018-03-03 14:24:32 -07:00
|
|
|
}
|
|
|
|
|
|
2018-03-05 10:30:05 -07:00
|
|
|
pub fn process_events(
|
2018-03-03 14:24:32 -07:00
|
|
|
&mut self,
|
|
|
|
|
epoch: Instant,
|
|
|
|
|
ms_per_tick: Option<u64>,
|
2018-03-05 10:30:05 -07:00
|
|
|
) -> Result<(), ExitReason> {
|
2018-03-03 14:24:32 -07:00
|
|
|
loop {
|
|
|
|
|
if let Some(ms) = ms_per_tick {
|
|
|
|
|
if epoch.elapsed() > Duration::from_millis((self.num_ticks + 1) * ms) {
|
2018-05-09 08:15:49 -06:00
|
|
|
self.record_entry(vec![])?;
|
2018-03-03 14:24:32 -07:00
|
|
|
self.num_ticks += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-03-05 10:30:05 -07:00
|
|
|
|
2018-03-03 14:24:32 -07:00
|
|
|
match self.receiver.try_recv() {
|
2018-03-09 17:22:14 -07:00
|
|
|
Ok(signal) => match signal {
|
|
|
|
|
Signal::Tick => {
|
2018-05-09 08:15:49 -06:00
|
|
|
self.record_entry(vec![])?;
|
2018-03-09 17:22:14 -07:00
|
|
|
}
|
2018-05-09 08:05:40 -06:00
|
|
|
Signal::Events(events) => {
|
2018-05-09 08:15:49 -06:00
|
|
|
self.record_entry(events)?;
|
2018-05-09 08:05:40 -06:00
|
|
|
}
|
2018-03-09 17:22:14 -07:00
|
|
|
},
|
2018-03-05 10:30:05 -07:00
|
|
|
Err(TryRecvError::Empty) => return Ok(()),
|
|
|
|
|
Err(TryRecvError::Disconnected) => return Err(ExitReason::RecvDisconnected),
|
|
|
|
|
};
|
2018-03-03 14:24:32 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-05-04 11:50:13 -06:00
|
|
|
|
2018-05-09 08:05:40 -06:00
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::*;
|
|
|
|
|
use signature::{KeyPair, KeyPairUtil};
|
2018-05-09 11:15:14 -06:00
|
|
|
use std::sync::mpsc::channel;
|
2018-05-09 08:05:40 -06:00
|
|
|
use transaction::Transaction;
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_events() {
|
2018-05-09 11:15:14 -06:00
|
|
|
let (signal_sender, signal_receiver) = channel();
|
|
|
|
|
let (entry_sender, entry_receiver) = channel();
|
2018-05-09 08:05:40 -06:00
|
|
|
let zero = Hash::default();
|
|
|
|
|
let mut recorder = Recorder::new(signal_receiver, entry_sender, zero);
|
|
|
|
|
let alice_keypair = KeyPair::new();
|
|
|
|
|
let bob_pubkey = KeyPair::new().pubkey();
|
|
|
|
|
let event0 = Event::Transaction(Transaction::new(&alice_keypair, bob_pubkey, 1, zero));
|
|
|
|
|
let event1 = Event::Transaction(Transaction::new(&alice_keypair, bob_pubkey, 2, zero));
|
|
|
|
|
signal_sender
|
|
|
|
|
.send(Signal::Events(vec![event0, event1]))
|
|
|
|
|
.unwrap();
|
|
|
|
|
recorder.process_events(Instant::now(), None).unwrap();
|
|
|
|
|
|
|
|
|
|
drop(recorder.sender);
|
|
|
|
|
let entries: Vec<_> = entry_receiver.iter().collect();
|
|
|
|
|
assert_eq!(entries.len(), 1);
|
|
|
|
|
}
|
|
|
|
|
}
|