Update the set of unique signatures when loading an existing log.

This commit is contained in:
Greg Fitzgerald
2018-03-04 22:26:46 -07:00
parent e1e9126d03
commit aa5f1699a7
3 changed files with 61 additions and 71 deletions

View File

@ -3,9 +3,9 @@
//! transfer funds to other users. //! transfer funds to other users.
use log::{hash, Entry, Sha256Hash}; use log::{hash, Entry, Sha256Hash};
use event::{get_pubkey, sign_transaction_data, Event, PublicKey, Signature}; use event::{get_pubkey, sign_transaction_data, verify_event, Event, PublicKey, Signature};
use genesis::Genesis; use genesis::Genesis;
use historian::Historian; use historian::{reserve_signature, Historian};
use ring::signature::Ed25519KeyPair; use ring::signature::Ed25519KeyPair;
use std::sync::mpsc::SendError; use std::sync::mpsc::SendError;
use std::collections::HashMap; use std::collections::HashMap;
@ -37,7 +37,7 @@ impl Accountant {
balances: HashMap::new(), balances: HashMap::new(),
last_id: start_hash, last_id: start_hash,
}; };
for (i, event) in gen.create_events().into_iter().enumerate() { for (i, event) in gen.create_events().iter().enumerate() {
acc.process_verified_event(event, i < 2).unwrap(); acc.process_verified_event(event, i < 2).unwrap();
} }
acc acc
@ -61,30 +61,35 @@ impl Accountant {
} }
pub fn process_event(self: &mut Self, event: Event<u64>) -> Result<()> { pub fn process_event(self: &mut Self, event: Event<u64>) -> Result<()> {
if !self.historian.verify_event(&event) { if !verify_event(&event) {
return Err(AccountingError::InvalidEvent); return Err(AccountingError::InvalidEvent);
} }
self.process_verified_event(event, false)
}
fn process_verified_event( if let Event::Transaction { from, data, .. } = event {
self: &mut Self,
event: Event<u64>,
allow_deposits: bool,
) -> Result<()> {
match event {
Event::Tick => Ok(()),
Event::Transaction { from, to, data, .. } => {
if !Self::is_deposit(allow_deposits, &from, &to) {
if self.get_balance(&from).unwrap_or(0) < data { if self.get_balance(&from).unwrap_or(0) < data {
return Err(AccountingError::InsufficientFunds); return Err(AccountingError::InsufficientFunds);
} }
} }
self.process_verified_event(&event, false)?;
if let Err(SendError(_)) = self.historian.sender.send(event) { if let Err(SendError(_)) = self.historian.sender.send(event) {
return Err(AccountingError::SendError); return Err(AccountingError::SendError);
} }
Ok(())
}
fn process_verified_event(
self: &mut Self,
event: &Event<u64>,
allow_deposits: bool,
) -> Result<()> {
if !reserve_signature(&mut self.historian.signatures, event) {
return Err(AccountingError::InvalidEvent);
}
if let Event::Transaction { from, to, data, .. } = *event {
if !Self::is_deposit(allow_deposits, &from, &to) { if !Self::is_deposit(allow_deposits, &from, &to) {
if let Some(x) = self.balances.get_mut(&from) { if let Some(x) = self.balances.get_mut(&from) {
*x -= data; *x -= data;
@ -98,10 +103,9 @@ impl Accountant {
} else { } else {
self.balances.insert(to, data); self.balances.insert(to, data);
} }
}
Ok(()) Ok(())
} }
}
}
pub fn transfer( pub fn transfer(
self: &mut Self, self: &mut Self,

View File

@ -1,16 +1,15 @@
//! The `historian` crate provides a microservice for generating a Proof-of-History. //! The `historian` crate provides a microservice for generating a Proof-of-History.
//! It manages a thread containing a Proof-of-History Logger. //! It manages a thread containing a Proof-of-History Logger.
use std::thread::JoinHandle; use std::thread::{spawn, JoinHandle};
use std::collections::HashSet; use std::collections::HashSet;
use std::sync::mpsc::{sync_channel, Receiver, SyncSender}; use std::sync::mpsc::{sync_channel, Receiver, SyncSender};
use std::time::Instant; use std::time::Instant;
use log::{hash, Entry, Sha256Hash}; use log::{hash, Entry, Sha256Hash};
use logger::{verify_event_and_reserve_signature, ExitReason, Logger}; use logger::{ExitReason, Logger};
use event::{Event, Signature}; use event::{get_signature, Event, Signature};
use serde::Serialize; use serde::Serialize;
use std::fmt::Debug; use std::fmt::Debug;
use std::thread;
pub struct Historian<T> { pub struct Historian<T> {
pub sender: SyncSender<Event<T>>, pub sender: SyncSender<Event<T>>,
@ -34,10 +33,6 @@ impl<T: 'static + Serialize + Clone + Debug + Send> Historian<T> {
} }
} }
pub fn verify_event(self: &mut Self, event: &Event<T>) -> bool {
return verify_event_and_reserve_signature(&mut self.signatures, event);
}
/// A background thread that will continue tagging received Event messages and /// A background thread that will continue tagging received Event messages and
/// sending back Entry messages until either the receiver or sender channel is closed. /// sending back Entry messages until either the receiver or sender channel is closed.
fn create_logger( fn create_logger(
@ -46,7 +41,7 @@ impl<T: 'static + Serialize + Clone + Debug + Send> Historian<T> {
receiver: Receiver<Event<T>>, receiver: Receiver<Event<T>>,
sender: SyncSender<Entry<T>>, sender: SyncSender<Entry<T>>,
) -> JoinHandle<(Entry<T>, ExitReason)> { ) -> JoinHandle<(Entry<T>, ExitReason)> {
thread::spawn(move || { spawn(move || {
let mut logger = Logger::new(receiver, sender, start_hash); let mut logger = Logger::new(receiver, sender, start_hash);
let now = Instant::now(); let now = Instant::now();
loop { loop {
@ -60,6 +55,16 @@ impl<T: 'static + Serialize + Clone + Debug + Send> Historian<T> {
} }
} }
pub fn reserve_signature<T>(sigs: &mut HashSet<Signature>, event: &Event<T>) -> bool {
if let Some(sig) = get_signature(&event) {
if sigs.contains(&sig) {
return false;
}
sigs.insert(sig);
}
true
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -104,6 +109,18 @@ mod tests {
); );
} }
#[test]
fn test_duplicate_event_signature() {
let keypair = generate_keypair();
let to = get_pubkey(&keypair);
let data = b"hello, world";
let sig = sign_claim_data(&data, &keypair);
let event0 = Event::new_claim(to, &data, sig);
let mut sigs = HashSet::new();
assert!(reserve_signature(&mut sigs, &event0));
assert!(!reserve_signature(&mut sigs, &event0));
}
#[test] #[test]
fn test_ticking_historian() { fn test_ticking_historian() {
let zero = Sha256Hash::default(); let zero = Sha256Hash::default();

View File

@ -5,11 +5,10 @@
//! Event, the latest hash, and the number of hashes since the last event. //! Event, the latest hash, and the number of hashes since the last event.
//! The resulting stream of entries represents ordered events in time. //! The resulting stream of entries represents ordered events in time.
use std::collections::HashSet;
use std::sync::mpsc::{Receiver, SyncSender, TryRecvError}; use std::sync::mpsc::{Receiver, SyncSender, TryRecvError};
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use log::{create_entry_mut, Entry, Sha256Hash}; use log::{create_entry_mut, Entry, Sha256Hash};
use event::{get_signature, verify_event, Event, Signature}; use event::Event;
use serde::Serialize; use serde::Serialize;
use std::fmt::Debug; use std::fmt::Debug;
@ -27,22 +26,6 @@ pub struct Logger<T> {
pub num_ticks: u64, pub num_ticks: u64,
} }
pub fn verify_event_and_reserve_signature<T: Serialize>(
signatures: &mut HashSet<Signature>,
event: &Event<T>,
) -> bool {
if !verify_event(&event) {
return false;
}
if let Some(sig) = get_signature(&event) {
if signatures.contains(&sig) {
return false;
}
signatures.insert(sig);
}
true
}
impl<T: Serialize + Clone + Debug> Logger<T> { impl<T: Serialize + Clone + Debug> Logger<T> {
pub fn new( pub fn new(
receiver: Receiver<Event<T>>, receiver: Receiver<Event<T>>,
@ -111,21 +94,7 @@ mod tests {
let keypair = generate_keypair(); let keypair = generate_keypair();
let sig = sign_claim_data(&hash(b"hello, world"), &keypair); let sig = sign_claim_data(&hash(b"hello, world"), &keypair);
let event0 = Event::new_claim(get_pubkey(&keypair), hash(b"goodbye cruel world"), sig); let event0 = Event::new_claim(get_pubkey(&keypair), hash(b"goodbye cruel world"), sig);
let mut sigs = HashSet::new(); assert!(!verify_event(&event0));
assert!(!verify_event_and_reserve_signature(&mut sigs, &event0));
assert!(!sigs.contains(&sig));
}
#[test]
fn test_duplicate_event_signature() {
let keypair = generate_keypair();
let to = get_pubkey(&keypair);
let data = &hash(b"hello, world");
let sig = sign_claim_data(data, &keypair);
let event0 = Event::new_claim(to, data, sig);
let mut sigs = HashSet::new();
assert!(verify_event_and_reserve_signature(&mut sigs, &event0));
assert!(!verify_event_and_reserve_signature(&mut sigs, &event0));
} }
fn run_genesis(gen: Genesis) -> Vec<Entry<u64>> { fn run_genesis(gen: Genesis) -> Vec<Entry<u64>> {