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:
parent
e7da083c31
commit
e5bae0604b
|
@ -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) {
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
26
src/plan.rs
26
src/plan.rs
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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!
|
||||
|
|
Loading…
Reference in New Issue