From e5bae0604bd6e811caf416642385748905facdb4 Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Sat, 17 Mar 2018 14:42:50 -0600 Subject: [PATCH] Specialize transaction assets to i64 Proof-of-history is generic, but now that we're using it entirely for tokens, we can specialize the type and start doing more interesting things than just Eq and Serialize operations. --- src/accountant.rs | 10 +++++----- src/accountant_skel.rs | 2 +- src/accountant_stub.rs | 2 +- src/event.rs | 2 +- src/plan.rs | 26 +++++++++++++------------- src/transaction.rs | 33 ++++++++++++++------------------- 6 files changed, 35 insertions(+), 40 deletions(-) diff --git a/src/accountant.rs b/src/accountant.rs index 2464f57dd..a2dc69bfb 100644 --- a/src/accountant.rs +++ b/src/accountant.rs @@ -31,7 +31,7 @@ pub struct Accountant { pub balances: HashMap, pub first_id: Hash, pub last_id: Hash, - pending: HashMap>, + pending: HashMap, time_sources: HashSet, last_time: DateTime, } @@ -84,7 +84,7 @@ impl Accountant { self.last_id } - fn is_deposit(allow_deposits: bool, from: &PublicKey, plan: &Plan) -> bool { + fn is_deposit(allow_deposits: bool, from: &PublicKey, plan: &Plan) -> bool { if let Plan::Action(Action::Pay(ref payment)) = *plan { allow_deposits && *from == payment.to } else { @@ -92,7 +92,7 @@ impl Accountant { } } - pub fn process_transaction(self: &mut Self, tr: Transaction) -> Result<()> { + pub fn process_transaction(self: &mut Self, tr: Transaction) -> Result<()> { if !tr.verify() { return Err(AccountingError::InvalidTransfer); } @@ -113,7 +113,7 @@ impl Accountant { } /// Commit funds to the 'to' party. - fn complete_transaction(self: &mut Self, plan: &Plan) { + fn complete_transaction(self: &mut Self, plan: &Plan) { if let Plan::Action(Action::Pay(ref payment)) = *plan { if self.balances.contains_key(&payment.to) { if let Some(x) = self.balances.get_mut(&payment.to) { @@ -127,7 +127,7 @@ impl Accountant { fn process_verified_transaction( self: &mut Self, - tr: &Transaction, + tr: &Transaction, allow_deposits: bool, ) -> Result<()> { if !reserve_signature(&mut self.historian.signatures, &tr.sig) { diff --git a/src/accountant_skel.rs b/src/accountant_skel.rs index d1b4b3a77..58729e612 100644 --- a/src/accountant_skel.rs +++ b/src/accountant_skel.rs @@ -19,7 +19,7 @@ pub struct AccountantSkel { #[derive(Serialize, Deserialize, Debug)] pub enum Request { - Transaction(Transaction), + Transaction(Transaction), GetBalance { key: PublicKey }, GetEntries { last_id: Hash }, GetId { is_last: bool }, diff --git a/src/accountant_stub.rs b/src/accountant_stub.rs index 73177b045..d02371677 100644 --- a/src/accountant_stub.rs +++ b/src/accountant_stub.rs @@ -26,7 +26,7 @@ impl AccountantStub { } } - pub fn transfer_signed(&self, tr: Transaction) -> io::Result { + pub fn transfer_signed(&self, tr: Transaction) -> io::Result { let req = Request::Transaction(tr); let data = serialize(&req).unwrap(); self.socket.send_to(&data, &self.addr) diff --git a/src/event.rs b/src/event.rs index 51a71fba9..bfaa58c87 100644 --- a/src/event.rs +++ b/src/event.rs @@ -7,7 +7,7 @@ use bincode::serialize; #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] pub enum Event { - Transaction(Transaction), + Transaction(Transaction), Signature { from: PublicKey, tx_sig: Signature, diff --git a/src/plan.rs b/src/plan.rs index 86ade7591..797483079 100644 --- a/src/plan.rs +++ b/src/plan.rs @@ -11,12 +11,12 @@ pub enum Condition { } #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] -pub enum Action { - Pay(Payment), +pub enum Action { + Pay(Payment), } -impl Action { - pub fn spendable(&self) -> T { +impl Action { + pub fn spendable(&self) -> i64 { match *self { Action::Pay(ref payment) => payment.asset.clone(), } @@ -24,22 +24,22 @@ impl Action { } #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] -pub struct Payment { - pub asset: T, +pub struct Payment { + pub asset: i64, pub to: PublicKey, } #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] -pub enum Plan { - Action(Action), - After(Condition, Box>), - Race(Box>, Box>), +pub enum Plan { + Action(Action), + After(Condition, Box), + Race(Box, Box), } -impl Plan { - pub fn verify(&self, spendable_assets: &T) -> bool { +impl Plan { + pub fn verify(&self, spendable_assets: i64) -> bool { match *self { - Plan::Action(ref action) => action.spendable() == *spendable_assets, + Plan::Action(ref action) => action.spendable() == spendable_assets, Plan::Race(ref plan_a, ref plan_b) => { plan_a.verify(spendable_assets) && plan_b.verify(spendable_assets) } diff --git a/src/transaction.rs b/src/transaction.rs index b7e42b943..a6af7532a 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -1,23 +1,22 @@ //! The `transaction` crate provides functionality for creating log transactions. use signature::{KeyPair, KeyPairUtil, PublicKey, Signature, SignatureUtil}; -use serde::Serialize; use bincode::serialize; use hash::Hash; use chrono::prelude::*; use plan::{Action, Condition, Payment, Plan}; #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] -pub struct Transaction { +pub struct Transaction { pub from: PublicKey, - pub plan: Plan, - pub asset: T, + pub plan: Plan, + pub asset: i64, pub last_id: Hash, pub sig: Signature, } -impl Transaction { - pub fn new(from_keypair: &KeyPair, to: PublicKey, asset: T, last_id: Hash) -> Self { +impl Transaction { + pub fn new(from_keypair: &KeyPair, to: PublicKey, asset: i64, last_id: Hash) -> Self { let from = from_keypair.pubkey(); let plan = Plan::Action(Action::Pay(Payment { asset: asset.clone(), @@ -38,7 +37,7 @@ impl Transaction { from_keypair: &KeyPair, to: PublicKey, dt: DateTime, - asset: T, + asset: i64, last_id: Hash, ) -> Self { let from = from_keypair.pubkey(); @@ -79,7 +78,7 @@ impl Transaction { } pub fn verify(&self) -> bool { - self.sig.verify(&self.from, &self.get_sign_data()) && self.plan.verify(&self.asset) + self.sig.verify(&self.from, &self.get_sign_data()) && self.plan.verify(self.asset) } } @@ -87,14 +86,12 @@ impl Transaction { mod tests { use super::*; use bincode::{deserialize, serialize}; - use hash::hash; #[test] fn test_claim() { let keypair = KeyPair::new(); - let asset = hash(b"hello, world"); let zero = Hash::default(); - let tr0 = Transaction::new(&keypair, keypair.pubkey(), asset, zero); + let tr0 = Transaction::new(&keypair, keypair.pubkey(), 42, zero); assert!(tr0.verify()); } @@ -104,8 +101,7 @@ mod tests { let keypair0 = KeyPair::new(); let keypair1 = KeyPair::new(); let pubkey1 = keypair1.pubkey(); - let asset = hash(b"hello, world"); - let tr0 = Transaction::new(&keypair0, pubkey1, asset, zero); + let tr0 = Transaction::new(&keypair0, pubkey1, 42, zero); assert!(tr0.verify()); } @@ -118,12 +114,12 @@ mod tests { let claim0 = Transaction { from: Default::default(), plan, - asset: 0u8, + asset: 0, last_id: Default::default(), sig: Default::default(), }; let buf = serialize(&claim0).unwrap(); - let claim1: Transaction = deserialize(&buf).unwrap(); + let claim1: Transaction = deserialize(&buf).unwrap(); assert_eq!(claim1, claim0); } @@ -132,9 +128,9 @@ mod tests { let zero = Hash::default(); let keypair = KeyPair::new(); let pubkey = keypair.pubkey(); - let mut tr = Transaction::new(&keypair, pubkey, hash(b"hello, world"), zero); + let mut tr = Transaction::new(&keypair, pubkey, 42, zero); tr.sign(&keypair); - tr.asset = hash(b"goodbye cruel world"); // <-- attack! + tr.asset = 1_000_000; // <-- attack! assert!(!tr.verify()); } @@ -145,8 +141,7 @@ mod tests { let thief_keypair = KeyPair::new(); let pubkey1 = keypair1.pubkey(); let zero = Hash::default(); - let asset = hash(b"hello, world"); - let mut tr = Transaction::new(&keypair0, pubkey1, asset, zero); + let mut tr = Transaction::new(&keypair0, pubkey1, 42, zero); tr.sign(&keypair0); if let Plan::Action(Action::Pay(ref mut payment)) = tr.plan { payment.to = thief_keypair.pubkey(); // <-- attack!