More cleanup

Far fewer branches when we process transfers outside the context
of events.
This commit is contained in:
Greg Fitzgerald
2018-03-06 11:43:53 -07:00
parent 1929601425
commit a2811842c8
4 changed files with 66 additions and 54 deletions

View File

@ -3,7 +3,8 @@
//! transfer funds to other users. //! transfer funds to other users.
use log::{Entry, Sha256Hash}; 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 genesis::Genesis;
use historian::{reserve_signature, Historian}; use historian::{reserve_signature, Historian};
use ring::signature::Ed25519KeyPair; use ring::signature::Ed25519KeyPair;
@ -14,7 +15,8 @@ use std::result;
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub enum AccountingError { pub enum AccountingError {
InsufficientFunds, InsufficientFunds,
InvalidEvent, InvalidTransfer,
InvalidTransferSignature,
SendError, SendError,
} }
@ -74,20 +76,44 @@ impl Accountant {
allow_deposits && from == to allow_deposits && from == to
} }
pub fn process_event(self: &mut Self, event: Event<i64>) -> Result<()> { pub fn process_transfer(self: &mut Self, tr: Transfer<i64>) -> Result<()> {
if !verify_event(&event) { if !verify_transfer(&tr) {
return Err(AccountingError::InvalidEvent); return Err(AccountingError::InvalidTransfer);
} }
if let Event::Transaction(Transfer { from, data, .. }) = event { if self.get_balance(&tr.from).unwrap_or(0) < tr.data {
if self.get_balance(&from).unwrap_or(0) < data {
return Err(AccountingError::InsufficientFunds); 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);
} }
self.process_verified_event(&event, false)?; Ok(())
if let Err(SendError(_)) = self.historian.sender.send(event) { }
return Err(AccountingError::SendError);
fn process_verified_transfer(
self: &mut Self,
tr: &Transfer<i64>,
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;
}
}
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(()) Ok(())
@ -98,26 +124,10 @@ impl Accountant {
event: &Event<i64>, event: &Event<i64>,
allow_deposits: bool, allow_deposits: bool,
) -> Result<()> { ) -> Result<()> {
if !reserve_signature(&mut self.historian.signatures, event) { match *event {
return Err(AccountingError::InvalidEvent); 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( pub fn transfer(
@ -129,14 +139,14 @@ impl Accountant {
let from = get_pubkey(keypair); let from = get_pubkey(keypair);
let last_id = self.last_id; let last_id = self.last_id;
let sig = sign_transaction_data(&n, keypair, &to, &last_id); let sig = sign_transaction_data(&n, keypair, &to, &last_id);
let event = Event::Transaction(Transfer { let tr = Transfer {
from, from,
to, to,
data: n, data: n,
last_id, last_id,
sig, sig,
}); };
self.process_event(event).map(|_| sig) self.process_transfer(tr).map(|_| sig)
} }
pub fn get_balance(self: &Self, pubkey: &PublicKey) -> Option<i64> { pub fn get_balance(self: &Self, pubkey: &PublicKey) -> Option<i64> {

View File

@ -31,9 +31,8 @@ impl AccountantSkel {
pub fn process_request(self: &mut Self, msg: Request) -> Option<Response> { pub fn process_request(self: &mut Self, msg: Request) -> Option<Response> {
match msg { match msg {
Request::Transaction(transfer) => { Request::Transaction(tr) => {
let event = Event::Transaction(transfer); if let Err(err) = self.acc.process_transfer(tr) {
if let Err(err) = self.acc.process_event(event) {
eprintln!("Transfer error: {:?}", err); eprintln!("Transfer error: {:?}", err);
} }
None None

View File

@ -34,6 +34,18 @@ pub struct Transfer<T> {
pub sig: Signature, pub sig: Signature,
} }
impl<T> Transfer<T> {
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 /// 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 /// 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 /// be generated in 'num_hashes' hashes and verified in 'num_hashes' hashes. By logging
@ -47,14 +59,7 @@ pub enum Event<T> {
impl<T> Event<T> { impl<T> Event<T> {
pub fn new_claim(to: PublicKey, data: T, last_id: Sha256Hash, sig: Signature) -> Self { pub fn new_claim(to: PublicKey, data: T, last_id: Sha256Hash, sig: Signature) -> Self {
let transfer = Transfer { Event::Transaction(Transfer::new_claim(to, data, last_id, sig))
from: to,
to,
data,
last_id,
sig,
};
Event::Transaction(transfer)
} }
} }

View File

@ -7,7 +7,7 @@ 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::{ExitReason, Logger}; use logger::{ExitReason, Logger};
use event::{get_signature, Event, Signature}; use event::{Event, Signature};
use serde::Serialize; use serde::Serialize;
use std::fmt::Debug; use std::fmt::Debug;
@ -55,13 +55,11 @@ impl<T: 'static + Serialize + Clone + Debug + Send> Historian<T> {
} }
} }
pub fn reserve_signature<T>(sigs: &mut HashSet<Signature>, event: &Event<T>) -> bool { pub fn reserve_signature(sigs: &mut HashSet<Signature>, sig: &Signature) -> bool {
if let Some(sig) = get_signature(&event) { if sigs.contains(sig) {
if sigs.contains(&sig) {
return false; return false;
} }
sigs.insert(sig); sigs.insert(*sig);
}
true true
} }
@ -116,10 +114,10 @@ mod tests {
let data = b"hello, world"; let data = b"hello, world";
let zero = Sha256Hash::default(); let zero = Sha256Hash::default();
let sig = sign_claim_data(&data, &keypair, &zero); 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(); let mut sigs = HashSet::new();
assert!(reserve_signature(&mut sigs, &event0)); assert!(reserve_signature(&mut sigs, &tr0.sig));
assert!(!reserve_signature(&mut sigs, &event0)); assert!(!reserve_signature(&mut sigs, &tr0.sig));
} }
#[test] #[test]