diff --git a/src/accountant.rs b/src/accountant.rs index 08864f7c81..755a5510f1 100644 --- a/src/accountant.rs +++ b/src/accountant.rs @@ -3,7 +3,8 @@ //! transfer funds to other users. use log::{Entry, Sha256Hash}; -use event::{get_pubkey, sign_transaction_data, verify_event, Event, PublicKey, Signature, Transfer}; +use event::{get_pubkey, sign_transaction_data, verify_transfer, Event, PublicKey, Signature, + Transfer}; use genesis::Genesis; use historian::{reserve_signature, Historian}; use ring::signature::Ed25519KeyPair; @@ -14,7 +15,8 @@ use std::result; #[derive(Debug, PartialEq, Eq)] pub enum AccountingError { InsufficientFunds, - InvalidEvent, + InvalidTransfer, + InvalidTransferSignature, SendError, } @@ -74,20 +76,44 @@ impl Accountant { allow_deposits && from == to } - pub fn process_event(self: &mut Self, event: Event) -> Result<()> { - if !verify_event(&event) { - return Err(AccountingError::InvalidEvent); + pub fn process_transfer(self: &mut Self, tr: Transfer) -> Result<()> { + if !verify_transfer(&tr) { + return Err(AccountingError::InvalidTransfer); } - if let Event::Transaction(Transfer { from, data, .. }) = event { - if self.get_balance(&from).unwrap_or(0) < data { - return Err(AccountingError::InsufficientFunds); + if self.get_balance(&tr.from).unwrap_or(0) < tr.data { + return Err(AccountingError::InsufficientFunds); + } + + self.process_verified_transfer(&tr, false)?; + if let Err(SendError(_)) = self.historian.sender.send(Event::Transaction(tr)) { + return Err(AccountingError::SendError); + } + + Ok(()) + } + + fn process_verified_transfer( + self: &mut Self, + tr: &Transfer, + allow_deposits: bool, + ) -> Result<()> { + if !reserve_signature(&mut self.historian.signatures, &tr.sig) { + return Err(AccountingError::InvalidTransferSignature); + } + + if !Self::is_deposit(allow_deposits, &tr.from, &tr.to) { + if let Some(x) = self.balances.get_mut(&tr.from) { + *x -= tr.data; } } - self.process_verified_event(&event, false)?; - if let Err(SendError(_)) = self.historian.sender.send(event) { - return Err(AccountingError::SendError); + if self.balances.contains_key(&tr.to) { + if let Some(x) = self.balances.get_mut(&tr.to) { + *x += tr.data; + } + } else { + self.balances.insert(tr.to, tr.data); } Ok(()) @@ -98,26 +124,10 @@ impl Accountant { event: &Event, allow_deposits: bool, ) -> Result<()> { - if !reserve_signature(&mut self.historian.signatures, event) { - return Err(AccountingError::InvalidEvent); + match *event { + Event::Tick => Ok(()), + Event::Transaction(ref tr) => self.process_verified_transfer(tr, allow_deposits), } - - if let Event::Transaction(Transfer { 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.balances.contains_key(&to) { - if let Some(x) = self.balances.get_mut(&to) { - *x += data; - } - } else { - self.balances.insert(to, data); - } - } - Ok(()) } pub fn transfer( @@ -129,14 +139,14 @@ impl Accountant { let from = get_pubkey(keypair); let last_id = self.last_id; let sig = sign_transaction_data(&n, keypair, &to, &last_id); - let event = Event::Transaction(Transfer { + let tr = Transfer { from, to, data: n, last_id, sig, - }); - self.process_event(event).map(|_| sig) + }; + self.process_transfer(tr).map(|_| sig) } pub fn get_balance(self: &Self, pubkey: &PublicKey) -> Option { diff --git a/src/accountant_skel.rs b/src/accountant_skel.rs index 228b840200..ae82024644 100644 --- a/src/accountant_skel.rs +++ b/src/accountant_skel.rs @@ -31,9 +31,8 @@ impl AccountantSkel { pub fn process_request(self: &mut Self, msg: Request) -> Option { match msg { - Request::Transaction(transfer) => { - let event = Event::Transaction(transfer); - if let Err(err) = self.acc.process_event(event) { + Request::Transaction(tr) => { + if let Err(err) = self.acc.process_transfer(tr) { eprintln!("Transfer error: {:?}", err); } None diff --git a/src/event.rs b/src/event.rs index 463b82bbaa..94f5fc47f9 100644 --- a/src/event.rs +++ b/src/event.rs @@ -34,6 +34,18 @@ pub struct Transfer { pub sig: Signature, } +impl Transfer { + pub fn new_claim(to: PublicKey, data: T, last_id: Sha256Hash, sig: Signature) -> Self { + Transfer { + from: to, + to, + data, + last_id, + sig, + } + } +} + /// When 'event' is Tick, the event represents a simple clock tick, and exists for the /// sole purpose of improving the performance of event log verification. A tick can /// be generated in 'num_hashes' hashes and verified in 'num_hashes' hashes. By logging @@ -47,14 +59,7 @@ pub enum Event { impl Event { pub fn new_claim(to: PublicKey, data: T, last_id: Sha256Hash, sig: Signature) -> Self { - let transfer = Transfer { - from: to, - to, - data, - last_id, - sig, - }; - Event::Transaction(transfer) + Event::Transaction(Transfer::new_claim(to, data, last_id, sig)) } } diff --git a/src/historian.rs b/src/historian.rs index 6db553b476..bdb019ed9a 100644 --- a/src/historian.rs +++ b/src/historian.rs @@ -7,7 +7,7 @@ use std::sync::mpsc::{sync_channel, Receiver, SyncSender}; use std::time::Instant; use log::{hash, Entry, Sha256Hash}; use logger::{ExitReason, Logger}; -use event::{get_signature, Event, Signature}; +use event::{Event, Signature}; use serde::Serialize; use std::fmt::Debug; @@ -55,13 +55,11 @@ 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); +pub fn reserve_signature(sigs: &mut HashSet, sig: &Signature) -> bool { + if sigs.contains(sig) { + return false; } + sigs.insert(*sig); true } @@ -116,10 +114,10 @@ mod tests { let data = b"hello, world"; let zero = Sha256Hash::default(); let sig = sign_claim_data(&data, &keypair, &zero); - let event0 = Event::new_claim(to, &data, zero, sig); + let tr0 = Transfer::new_claim(to, &data, zero, sig); let mut sigs = HashSet::new(); - assert!(reserve_signature(&mut sigs, &event0)); - assert!(!reserve_signature(&mut sigs, &event0)); + assert!(reserve_signature(&mut sigs, &tr0.sig)); + assert!(!reserve_signature(&mut sigs, &tr0.sig)); } #[test]