Don't process transaction if channel.send() fails.
Do all input validation first, then log (which can fail). If all goes swimmingly, process the transaction.
This commit is contained in:
parent
36bb1f989d
commit
dfd1c4eab3
|
@ -8,6 +8,16 @@ use historian::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;
|
||||||
|
use std::result;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub enum AccountingError {
|
||||||
|
InsufficientFunds,
|
||||||
|
InvalidEvent,
|
||||||
|
SendError,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Result<T> = result::Result<T, AccountingError>;
|
||||||
|
|
||||||
pub struct Accountant {
|
pub struct Accountant {
|
||||||
pub historian: Historian<u64>,
|
pub historian: Historian<u64>,
|
||||||
|
@ -43,12 +53,13 @@ impl Accountant {
|
||||||
key: PublicKey,
|
key: PublicKey,
|
||||||
data: u64,
|
data: u64,
|
||||||
sig: Signature,
|
sig: Signature,
|
||||||
) -> Result<(), SendError<Event<u64>>> {
|
) -> Result<()> {
|
||||||
let event = Event::Claim { key, data, sig };
|
let event = Event::Claim { key, data, sig };
|
||||||
if !self.historian.verify_event(&event) {
|
if !self.historian.verify_event(&event) {
|
||||||
// TODO: Replace the SendError result with a custom one.
|
return Err(AccountingError::InvalidEvent);
|
||||||
println!("Rejecting transaction: Invalid event");
|
}
|
||||||
return Ok(());
|
if let Err(SendError(_)) = self.historian.sender.send(event) {
|
||||||
|
return Err(AccountingError::SendError);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.balances.contains_key(&key) {
|
if self.balances.contains_key(&key) {
|
||||||
|
@ -59,14 +70,10 @@ impl Accountant {
|
||||||
self.balances.insert(key, data);
|
self.balances.insert(key, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.historian.sender.send(event)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deposit(
|
pub fn deposit(self: &mut Self, n: u64, keypair: &Ed25519KeyPair) -> Result<Signature> {
|
||||||
self: &mut Self,
|
|
||||||
n: u64,
|
|
||||||
keypair: &Ed25519KeyPair,
|
|
||||||
) -> Result<Signature, SendError<Event<u64>>> {
|
|
||||||
use event::{get_pubkey, sign_serialized};
|
use event::{get_pubkey, sign_serialized};
|
||||||
let key = get_pubkey(keypair);
|
let key = get_pubkey(keypair);
|
||||||
let sig = sign_serialized(&n, keypair);
|
let sig = sign_serialized(&n, keypair);
|
||||||
|
@ -79,7 +86,11 @@ impl Accountant {
|
||||||
to: PublicKey,
|
to: PublicKey,
|
||||||
data: u64,
|
data: u64,
|
||||||
sig: Signature,
|
sig: Signature,
|
||||||
) -> Result<(), SendError<Event<u64>>> {
|
) -> Result<()> {
|
||||||
|
if self.get_balance(&from).unwrap_or(0) < data {
|
||||||
|
return Err(AccountingError::InsufficientFunds);
|
||||||
|
}
|
||||||
|
|
||||||
let event = Event::Transaction {
|
let event = Event::Transaction {
|
||||||
from,
|
from,
|
||||||
to,
|
to,
|
||||||
|
@ -87,15 +98,10 @@ impl Accountant {
|
||||||
sig,
|
sig,
|
||||||
};
|
};
|
||||||
if !self.historian.verify_event(&event) {
|
if !self.historian.verify_event(&event) {
|
||||||
// TODO: Replace the SendError result with a custom one.
|
return Err(AccountingError::InvalidEvent);
|
||||||
println!("Rejecting transaction: Invalid event");
|
|
||||||
return Ok(());
|
|
||||||
}
|
}
|
||||||
|
if let Err(SendError(_)) = self.historian.sender.send(event) {
|
||||||
if self.get_balance(&from).unwrap_or(0) < data {
|
return Err(AccountingError::SendError);
|
||||||
// TODO: Replace the SendError result with a custom one.
|
|
||||||
println!("Rejecting transaction: Insufficient funds");
|
|
||||||
return Ok(());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(x) = self.balances.get_mut(&from) {
|
if let Some(x) = self.balances.get_mut(&from) {
|
||||||
|
@ -110,7 +116,7 @@ impl Accountant {
|
||||||
self.balances.insert(to, data);
|
self.balances.insert(to, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.historian.sender.send(event)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn transfer(
|
pub fn transfer(
|
||||||
|
@ -118,7 +124,7 @@ impl Accountant {
|
||||||
n: u64,
|
n: u64,
|
||||||
keypair: &Ed25519KeyPair,
|
keypair: &Ed25519KeyPair,
|
||||||
to: PublicKey,
|
to: PublicKey,
|
||||||
) -> Result<Signature, SendError<Event<u64>>> {
|
) -> Result<Signature> {
|
||||||
use event::{get_pubkey, sign_transaction_data};
|
use event::{get_pubkey, sign_transaction_data};
|
||||||
let from = get_pubkey(keypair);
|
let from = get_pubkey(keypair);
|
||||||
let sig = sign_transaction_data(&n, keypair, &to);
|
let sig = sign_transaction_data(&n, keypair, &to);
|
||||||
|
@ -190,7 +196,10 @@ mod tests {
|
||||||
acc.wait_on_signature(&sig);
|
acc.wait_on_signature(&sig);
|
||||||
|
|
||||||
let bob_pubkey = get_pubkey(&bob_keypair);
|
let bob_pubkey = get_pubkey(&bob_keypair);
|
||||||
acc.transfer(10_001, &alice_keypair, bob_pubkey).unwrap();
|
assert_eq!(
|
||||||
|
acc.transfer(10_001, &alice_keypair, bob_pubkey),
|
||||||
|
Err(AccountingError::InsufficientFunds)
|
||||||
|
);
|
||||||
sleep(Duration::from_millis(30));
|
sleep(Duration::from_millis(30));
|
||||||
|
|
||||||
let alice_pubkey = get_pubkey(&alice_keypair);
|
let alice_pubkey = get_pubkey(&alice_keypair);
|
||||||
|
|
Loading…
Reference in New Issue