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.
This commit is contained in:
Greg Fitzgerald 2018-03-17 14:42:50 -06:00
parent e7da083c31
commit e5bae0604b
6 changed files with 35 additions and 40 deletions

View File

@ -31,7 +31,7 @@ pub struct Accountant {
pub balances: HashMap<PublicKey, i64>,
pub first_id: Hash,
pub last_id: Hash,
pending: HashMap<Signature, Plan<i64>>,
pending: HashMap<Signature, Plan>,
time_sources: HashSet<PublicKey>,
last_time: DateTime<Utc>,
}
@ -84,7 +84,7 @@ impl Accountant {
self.last_id
}
fn is_deposit(allow_deposits: bool, from: &PublicKey, plan: &Plan<i64>) -> 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<i64>) -> 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<i64>) {
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<i64>,
tr: &Transaction,
allow_deposits: bool,
) -> Result<()> {
if !reserve_signature(&mut self.historian.signatures, &tr.sig) {

View File

@ -19,7 +19,7 @@ pub struct AccountantSkel {
#[derive(Serialize, Deserialize, Debug)]
pub enum Request {
Transaction(Transaction<i64>),
Transaction(Transaction),
GetBalance { key: PublicKey },
GetEntries { last_id: Hash },
GetId { is_last: bool },

View File

@ -26,7 +26,7 @@ impl AccountantStub {
}
}
pub fn transfer_signed(&self, tr: Transaction<i64>) -> io::Result<usize> {
pub fn transfer_signed(&self, tr: Transaction) -> io::Result<usize> {
let req = Request::Transaction(tr);
let data = serialize(&req).unwrap();
self.socket.send_to(&data, &self.addr)

View File

@ -7,7 +7,7 @@ use bincode::serialize;
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub enum Event {
Transaction(Transaction<i64>),
Transaction(Transaction),
Signature {
from: PublicKey,
tx_sig: Signature,

View File

@ -11,12 +11,12 @@ pub enum Condition {
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub enum Action<T> {
Pay(Payment<T>),
pub enum Action {
Pay(Payment),
}
impl<T: Clone> Action<T> {
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<T: Clone> Action<T> {
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct Payment<T> {
pub asset: T,
pub struct Payment {
pub asset: i64,
pub to: PublicKey,
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub enum Plan<T> {
Action(Action<T>),
After(Condition, Box<Plan<T>>),
Race(Box<Plan<T>>, Box<Plan<T>>),
pub enum Plan {
Action(Action),
After(Condition, Box<Plan>),
Race(Box<Plan>, Box<Plan>),
}
impl<T: Clone + Eq> Plan<T> {
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)
}

View File

@ -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<T> {
pub struct Transaction {
pub from: PublicKey,
pub plan: Plan<T>,
pub asset: T,
pub plan: Plan,
pub asset: i64,
pub last_id: Hash,
pub sig: Signature,
}
impl<T: Serialize + Clone + Eq> Transaction<T> {
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<T: Serialize + Clone + Eq> Transaction<T> {
from_keypair: &KeyPair,
to: PublicKey,
dt: DateTime<Utc>,
asset: T,
asset: i64,
last_id: Hash,
) -> Self {
let from = from_keypair.pubkey();
@ -79,7 +78,7 @@ impl<T: Serialize + Clone + Eq> Transaction<T> {
}
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<T: Serialize + Clone + Eq> Transaction<T> {
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<u8> = 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!