Files
solana/src/recorder.rs

90 lines
2.6 KiB
Rust
Raw Normal View History

//! The `recorder` crate provides an object for generating a Proof-of-History.
//! 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
//! tags each Event with an Entry and sends it back. The Entry includes the
//! Event, the latest hash, and the number of hashes since the last event.
//! The resulting stream of entries represents ordered events in time.
use entry::{create_entry_mut, Entry};
use event::Event;
use hash::{hash, Hash};
use std::mem;
use std::sync::mpsc::{Receiver, SyncSender, TryRecvError};
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))]
pub enum Signal {
Tick,
Event(Event),
}
2018-03-03 14:24:32 -07:00
#[derive(Debug, PartialEq, Eq)]
pub enum ExitReason {
RecvDisconnected,
SendDisconnected,
}
pub struct Recorder {
2018-03-20 23:15:44 -06:00
sender: SyncSender<Entry>,
receiver: Receiver<Signal>,
last_hash: Hash,
events: Vec<Event>,
num_hashes: u64,
num_ticks: u64,
2018-03-03 14:24:32 -07:00
}
impl Recorder {
pub fn new(receiver: Receiver<Signal>, sender: SyncSender<Entry>, start_hash: Hash) -> Self {
Recorder {
2018-03-03 14:24:32 -07:00
receiver,
sender,
2018-03-20 23:15:44 -06:00
last_hash: start_hash,
events: vec![],
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;
}
pub fn record_entry(&mut self) -> Result<(), ExitReason> {
let events = mem::replace(&mut self.events, vec![]);
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
}
pub fn process_events(
2018-03-03 14:24:32 -07:00
&mut self,
epoch: Instant,
ms_per_tick: Option<u64>,
) -> 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) {
self.record_entry()?;
2018-03-03 14:24:32 -07:00
self.num_ticks += 1;
}
}
2018-03-03 14:24:32 -07:00
match self.receiver.try_recv() {
Ok(signal) => match signal {
Signal::Tick => {
2018-03-20 23:15:44 -06:00
self.record_entry()?;
}
Signal::Event(event) => {
self.events.push(event);
}
},
Err(TryRecvError::Empty) => return Ok(()),
Err(TryRecvError::Disconnected) => return Err(ExitReason::RecvDisconnected),
};
2018-03-03 14:24:32 -07:00
}
}
}