Don't let users accidentally burn their funds either

This commit is contained in:
Greg Fitzgerald
2018-03-11 12:04:44 -06:00
parent aa0a184ebe
commit 45765b625a
2 changed files with 21 additions and 17 deletions

View File

@ -288,10 +288,19 @@ mod tests {
let bob_pubkey = KeyPair::new().pubkey(); let bob_pubkey = KeyPair::new().pubkey();
let mut tr = Transaction::new(&alice.keypair(), bob_pubkey, 1, alice.seed()); let mut tr = Transaction::new(&alice.keypair(), bob_pubkey, 1, alice.seed());
if let Plan::Action(Action::Pay(ref mut payment)) = tr.plan { if let Plan::Action(Action::Pay(ref mut payment)) = tr.plan {
payment.asset = 2; // <-- Attack! payment.asset = 2; // <-- attack!
} }
assert_eq!( assert_eq!(
acc.process_transaction(tr), acc.process_transaction(tr.clone()),
Err(AccountingError::InvalidTransfer)
);
// Also, ensure all branchs of the plan spend all assets
if let Plan::Action(Action::Pay(ref mut payment)) = tr.plan {
payment.asset = 0; // <-- whoops!
}
assert_eq!(
acc.process_transaction(tr.clone()),
Err(AccountingError::InvalidTransfer) Err(AccountingError::InvalidTransfer)
); );
} }

View File

@ -6,7 +6,6 @@ use bincode::serialize;
use hash::Hash; use hash::Hash;
use chrono::prelude::*; use chrono::prelude::*;
use std::mem; use std::mem;
use std::cmp;
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub enum Condition { pub enum Condition {
@ -20,7 +19,7 @@ pub enum Action<T> {
} }
impl<T: Clone> Action<T> { impl<T: Clone> Action<T> {
pub fn max_spendable(&self) -> T { pub fn spendable(&self) -> T {
match *self { match *self {
Action::Pay(ref payment) => payment.asset.clone(), Action::Pay(ref payment) => payment.asset.clone(),
} }
@ -40,19 +39,15 @@ pub enum Plan<T> {
Race(Box<Plan<T>>, Box<Plan<T>>), Race(Box<Plan<T>>, Box<Plan<T>>),
} }
impl<T: Clone + Ord> Plan<T> { impl<T: Clone + Eq> Plan<T> {
pub fn max_spendable(&self) -> T {
match *self {
Plan::Action(ref action) => action.max_spendable(),
Plan::Race(ref plan_a, ref plan_b) => {
cmp::max(plan_a.max_spendable(), plan_b.max_spendable())
}
Plan::After(_, ref action) => action.max_spendable(),
}
}
pub fn verify(&self, spendable_assets: &T) -> bool { pub fn verify(&self, spendable_assets: &T) -> bool {
self.max_spendable() <= *spendable_assets match *self {
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)
}
Plan::After(_, ref action) => action.spendable() == *spendable_assets,
}
} }
pub fn run_race(&mut self) -> bool { pub fn run_race(&mut self) -> bool {
@ -140,7 +135,7 @@ pub struct Transaction<T> {
pub sig: Signature, pub sig: Signature,
} }
impl<T: Serialize + Clone + Ord> Transaction<T> { impl<T: Serialize + Clone + Eq> Transaction<T> {
pub fn new(from_keypair: &KeyPair, to: PublicKey, asset: T, last_id: Hash) -> Self { pub fn new(from_keypair: &KeyPair, to: PublicKey, asset: T, last_id: Hash) -> Self {
let from = from_keypair.pubkey(); let from = from_keypair.pubkey();
let plan = Plan::Action(Action::Pay(Payment { let plan = Plan::Action(Action::Pay(Payment {