More cleanup
Far fewer branches when we process transfers outside the context of events.
This commit is contained in:
@ -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> {
|
||||||
|
@ -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
|
||||||
|
21
src/event.rs
21
src/event.rs
@ -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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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]
|
||||||
|
Reference in New Issue
Block a user