From aa5f1699a71741db146b2f1133bf3c093f8d57cc Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Sun, 4 Mar 2018 22:26:46 -0700 Subject: [PATCH] Update the set of unique signatures when loading an existing log. --- src/accountant.rs | 62 +++++++++++++++++++++++++---------------------- src/historian.rs | 35 +++++++++++++++++++------- src/logger.rs | 35 ++------------------------ 3 files changed, 61 insertions(+), 71 deletions(-) diff --git a/src/accountant.rs b/src/accountant.rs index 74c4922c6..770494e6c 100644 --- a/src/accountant.rs +++ b/src/accountant.rs @@ -3,9 +3,9 @@ //! transfer funds to other users. 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 historian::Historian; +use historian::{reserve_signature, Historian}; use ring::signature::Ed25519KeyPair; use std::sync::mpsc::SendError; use std::collections::HashMap; @@ -37,7 +37,7 @@ impl Accountant { balances: HashMap::new(), 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 @@ -61,46 +61,50 @@ impl Accountant { } pub fn process_event(self: &mut Self, event: Event) -> Result<()> { - if !self.historian.verify_event(&event) { + if !verify_event(&event) { return Err(AccountingError::InvalidEvent); } - self.process_verified_event(event, false) + + if let Event::Transaction { from, data, .. } = event { + if self.get_balance(&from).unwrap_or(0) < data { + return Err(AccountingError::InsufficientFunds); + } + } + + self.process_verified_event(&event, false)?; + + if let Err(SendError(_)) = self.historian.sender.send(event) { + return Err(AccountingError::SendError); + } + + Ok(()) } fn process_verified_event( self: &mut Self, - event: Event, + event: &Event, 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 { - return Err(AccountingError::InsufficientFunds); - } - } + if !reserve_signature(&mut self.historian.signatures, event) { + return Err(AccountingError::InvalidEvent); + } - if let Err(SendError(_)) = self.historian.sender.send(event) { - return Err(AccountingError::SendError); + if let Event::Transaction { from, to, data, .. } = *event { + if !Self::is_deposit(allow_deposits, &from, &to) { + if let Some(x) = self.balances.get_mut(&from) { + *x -= data; } + } - if !Self::is_deposit(allow_deposits, &from, &to) { - if let Some(x) = self.balances.get_mut(&from) { - *x -= data; - } + if self.balances.contains_key(&to) { + if let Some(x) = self.balances.get_mut(&to) { + *x += data; } - - if self.balances.contains_key(&to) { - if let Some(x) = self.balances.get_mut(&to) { - *x += data; - } - } else { - self.balances.insert(to, data); - } - Ok(()) + } else { + self.balances.insert(to, data); } } + Ok(()) } pub fn transfer( diff --git a/src/historian.rs b/src/historian.rs index 745416c0a..8e88f2acd 100644 --- a/src/historian.rs +++ b/src/historian.rs @@ -1,16 +1,15 @@ //! The `historian` crate provides a microservice for generating a Proof-of-History. //! 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::sync::mpsc::{sync_channel, Receiver, SyncSender}; use std::time::Instant; use log::{hash, Entry, Sha256Hash}; -use logger::{verify_event_and_reserve_signature, ExitReason, Logger}; -use event::{Event, Signature}; +use logger::{ExitReason, Logger}; +use event::{get_signature, Event, Signature}; use serde::Serialize; use std::fmt::Debug; -use std::thread; pub struct Historian { pub sender: SyncSender>, @@ -34,10 +33,6 @@ impl Historian { } } - pub fn verify_event(self: &mut Self, event: &Event) -> bool { - return verify_event_and_reserve_signature(&mut self.signatures, event); - } - /// A background thread that will continue tagging received Event messages and /// sending back Entry messages until either the receiver or sender channel is closed. fn create_logger( @@ -46,7 +41,7 @@ impl Historian { receiver: Receiver>, sender: SyncSender>, ) -> JoinHandle<(Entry, ExitReason)> { - thread::spawn(move || { + spawn(move || { let mut logger = Logger::new(receiver, sender, start_hash); let now = Instant::now(); loop { @@ -60,6 +55,16 @@ impl Historian { } } +pub fn reserve_signature(sigs: &mut HashSet, event: &Event) -> bool { + if let Some(sig) = get_signature(&event) { + if sigs.contains(&sig) { + return false; + } + sigs.insert(sig); + } + true +} + #[cfg(test)] mod tests { 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] fn test_ticking_historian() { let zero = Sha256Hash::default(); diff --git a/src/logger.rs b/src/logger.rs index c06300e23..67c812419 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -5,11 +5,10 @@ //! Event, the latest hash, and the number of hashes since the last event. //! The resulting stream of entries represents ordered events in time. -use std::collections::HashSet; use std::sync::mpsc::{Receiver, SyncSender, TryRecvError}; use std::time::{Duration, Instant}; use log::{create_entry_mut, Entry, Sha256Hash}; -use event::{get_signature, verify_event, Event, Signature}; +use event::Event; use serde::Serialize; use std::fmt::Debug; @@ -27,22 +26,6 @@ pub struct Logger { pub num_ticks: u64, } -pub fn verify_event_and_reserve_signature( - signatures: &mut HashSet, - event: &Event, -) -> 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 Logger { pub fn new( receiver: Receiver>, @@ -111,21 +94,7 @@ mod tests { let keypair = generate_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 mut sigs = HashSet::new(); - 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)); + assert!(!verify_event(&event0)); } fn run_genesis(gen: Genesis) -> Vec> {