Files
solana/src/recorder.rs

114 lines
3.5 KiB
Rust
Raw Normal View History

2018-03-29 12:20:54 -06:00
//! The `recorder` module 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
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.
use entry::{create_entry_mut, Entry};
use event::Event;
use hash::{hash, Hash};
use std::sync::mpsc::{Receiver, Sender, 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,
2018-05-09 08:05:40 -06:00
Events(Vec<Event>),
}
2018-03-03 14:24:32 -07:00
#[derive(Debug, PartialEq, Eq)]
pub enum ExitReason {
RecvDisconnected,
SendDisconnected,
}
pub struct Recorder {
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
}
impl Recorder {
pub fn new(receiver: Receiver<Signal>, sender: Sender<Entry>, last_hash: Hash) -> Self {
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;
}
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
}
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(vec![])?;
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 => {
self.record_entry(vec![])?;
}
2018-05-09 08:05:40 -06:00
Signal::Events(events) => {
self.record_entry(events)?;
2018-05-09 08:05:40 -06:00
}
},
Err(TryRecvError::Empty) => return Ok(()),
Err(TryRecvError::Disconnected) => return Err(ExitReason::RecvDisconnected),
};
2018-03-03 14:24:32 -07:00
}
}
}
2018-05-09 08:05:40 -06:00
#[cfg(test)]
mod tests {
use super::*;
use signature::{KeyPair, KeyPairUtil};
use std::sync::mpsc::channel;
2018-05-09 08:05:40 -06:00
use transaction::Transaction;
#[test]
fn test_events() {
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);
}
}