@@ -5,7 +5,7 @@
 | 
				
			|||||||
use hash::Hash;
 | 
					use hash::Hash;
 | 
				
			||||||
use entry::Entry;
 | 
					use entry::Entry;
 | 
				
			||||||
use event::Event;
 | 
					use event::Event;
 | 
				
			||||||
use plan::{Action, Plan, PlanEvent};
 | 
					use plan::{Plan, Witness};
 | 
				
			||||||
use transaction::Transaction;
 | 
					use transaction::Transaction;
 | 
				
			||||||
use signature::{KeyPair, PublicKey, Signature};
 | 
					use signature::{KeyPair, PublicKey, Signature};
 | 
				
			||||||
use mint::Mint;
 | 
					use mint::Mint;
 | 
				
			||||||
@@ -13,6 +13,7 @@ use historian::{reserve_signature, Historian};
 | 
				
			|||||||
use recorder::Signal;
 | 
					use recorder::Signal;
 | 
				
			||||||
use std::sync::mpsc::SendError;
 | 
					use std::sync::mpsc::SendError;
 | 
				
			||||||
use std::collections::{HashMap, HashSet};
 | 
					use std::collections::{HashMap, HashSet};
 | 
				
			||||||
 | 
					use std::collections::hash_map::Entry::Occupied;
 | 
				
			||||||
use std::result;
 | 
					use std::result;
 | 
				
			||||||
use chrono::prelude::*;
 | 
					use chrono::prelude::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -26,6 +27,19 @@ pub enum AccountingError {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
pub type Result<T> = result::Result<T, AccountingError>;
 | 
					pub type Result<T> = result::Result<T, AccountingError>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Commit funds to the 'to' party.
 | 
				
			||||||
 | 
					fn complete_transaction(balances: &mut HashMap<PublicKey, i64>, plan: &Plan) {
 | 
				
			||||||
 | 
					    if let Plan::Pay(ref payment) = *plan {
 | 
				
			||||||
 | 
					        if balances.contains_key(&payment.to) {
 | 
				
			||||||
 | 
					            if let Some(x) = balances.get_mut(&payment.to) {
 | 
				
			||||||
 | 
					                *x += payment.tokens;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            balances.insert(payment.to, payment.tokens);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct Accountant {
 | 
					pub struct Accountant {
 | 
				
			||||||
    pub historian: Historian,
 | 
					    pub historian: Historian,
 | 
				
			||||||
    pub balances: HashMap<PublicKey, i64>,
 | 
					    pub balances: HashMap<PublicKey, i64>,
 | 
				
			||||||
@@ -85,7 +99,7 @@ impl Accountant {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    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 {
 | 
					        if let Plan::Pay(ref payment) = *plan {
 | 
				
			||||||
            allow_deposits && *from == payment.to
 | 
					            allow_deposits && *from == payment.to
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            false
 | 
					            false
 | 
				
			||||||
@@ -112,19 +126,6 @@ impl Accountant {
 | 
				
			|||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Commit funds to the 'to' party.
 | 
					 | 
				
			||||||
    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) {
 | 
					 | 
				
			||||||
                    *x += payment.tokens;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                self.balances.insert(payment.to, payment.tokens);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn process_verified_transaction(
 | 
					    fn process_verified_transaction(
 | 
				
			||||||
        self: &mut Self,
 | 
					        self: &mut Self,
 | 
				
			||||||
        tr: &Transaction,
 | 
					        tr: &Transaction,
 | 
				
			||||||
@@ -141,30 +142,26 @@ impl Accountant {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let mut plan = tr.plan.clone();
 | 
					        let mut plan = tr.plan.clone();
 | 
				
			||||||
        let actionable = plan.process_event(PlanEvent::Timestamp(self.last_time));
 | 
					        plan.apply_witness(Witness::Timestamp(self.last_time));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if !actionable {
 | 
					        if plan.is_complete() {
 | 
				
			||||||
 | 
					            complete_transaction(&mut self.balances, &plan);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
            self.pending.insert(tr.sig, plan);
 | 
					            self.pending.insert(tr.sig, plan);
 | 
				
			||||||
            return Ok(());
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.complete_transaction(&plan);
 | 
					 | 
				
			||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn process_verified_sig(&mut self, from: PublicKey, tx_sig: Signature) -> Result<()> {
 | 
					    fn process_verified_sig(&mut self, from: PublicKey, tx_sig: Signature) -> Result<()> {
 | 
				
			||||||
        let actionable = if let Some(plan) = self.pending.get_mut(&tx_sig) {
 | 
					        if let Occupied(mut e) = self.pending.entry(tx_sig) {
 | 
				
			||||||
            plan.process_event(PlanEvent::Signature(from))
 | 
					            e.get_mut().apply_witness(Witness::Signature(from));
 | 
				
			||||||
        } else {
 | 
					            if e.get().is_complete() {
 | 
				
			||||||
            false
 | 
					                complete_transaction(&mut self.balances, e.get());
 | 
				
			||||||
 | 
					                e.remove_entry();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if actionable {
 | 
					 | 
				
			||||||
            if let Some(plan) = self.pending.remove(&tx_sig) {
 | 
					 | 
				
			||||||
                self.complete_transaction(&plan);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -186,15 +183,15 @@ impl Accountant {
 | 
				
			|||||||
        // Check to see if any timelocked transactions can be completed.
 | 
					        // Check to see if any timelocked transactions can be completed.
 | 
				
			||||||
        let mut completed = vec![];
 | 
					        let mut completed = vec![];
 | 
				
			||||||
        for (key, plan) in &mut self.pending {
 | 
					        for (key, plan) in &mut self.pending {
 | 
				
			||||||
            if plan.process_event(PlanEvent::Timestamp(self.last_time)) {
 | 
					            plan.apply_witness(Witness::Timestamp(self.last_time));
 | 
				
			||||||
 | 
					            if plan.is_complete() {
 | 
				
			||||||
 | 
					                complete_transaction(&mut self.balances, &plan);
 | 
				
			||||||
                completed.push(key.clone());
 | 
					                completed.push(key.clone());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for key in completed {
 | 
					        for key in completed {
 | 
				
			||||||
            if let Some(plan) = self.pending.remove(&key) {
 | 
					            self.pending.remove(&key);
 | 
				
			||||||
                self.complete_transaction(&plan);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
@@ -288,7 +285,7 @@ mod tests {
 | 
				
			|||||||
        let mut acc = Accountant::new(&alice, None);
 | 
					        let mut acc = Accountant::new(&alice, None);
 | 
				
			||||||
        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::Pay(ref mut payment) = tr.plan {
 | 
				
			||||||
            payment.tokens = 2; // <-- attack!
 | 
					            payment.tokens = 2; // <-- attack!
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        assert_eq!(
 | 
					        assert_eq!(
 | 
				
			||||||
@@ -297,7 +294,7 @@ mod tests {
 | 
				
			|||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Also, ensure all branchs of the plan spend all tokens
 | 
					        // Also, ensure all branchs of the plan spend all tokens
 | 
				
			||||||
        if let Plan::Action(Action::Pay(ref mut payment)) = tr.plan {
 | 
					        if let Plan::Pay(ref mut payment) = tr.plan {
 | 
				
			||||||
            payment.tokens = 0; // <-- whoops!
 | 
					            payment.tokens = 0; // <-- whoops!
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        assert_eq!(
 | 
					        assert_eq!(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -58,13 +58,13 @@ impl Mint {
 | 
				
			|||||||
mod tests {
 | 
					mod tests {
 | 
				
			||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
    use ledger::verify_slice;
 | 
					    use ledger::verify_slice;
 | 
				
			||||||
    use plan::{Action, Plan};
 | 
					    use plan::Plan;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn test_create_events() {
 | 
					    fn test_create_events() {
 | 
				
			||||||
        let mut events = Mint::new(100).create_events().into_iter();
 | 
					        let mut events = Mint::new(100).create_events().into_iter();
 | 
				
			||||||
        if let Event::Transaction(tr) = events.next().unwrap() {
 | 
					        if let Event::Transaction(tr) = events.next().unwrap() {
 | 
				
			||||||
            if let Plan::Action(Action::Pay(payment)) = tr.plan {
 | 
					            if let Plan::Pay(payment) = tr.plan {
 | 
				
			||||||
                assert_eq!(tr.from, payment.to);
 | 
					                assert_eq!(tr.from, payment.to);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										128
									
								
								src/plan.rs
									
									
									
									
									
								
							
							
						
						
									
										128
									
								
								src/plan.rs
									
									
									
									
									
								
							@@ -1,45 +1,33 @@
 | 
				
			|||||||
//! The `plan` crate provides functionality for creating spending plans.
 | 
					//! A domain-specific language for payment plans. Users create Plan objects that
 | 
				
			||||||
 | 
					//! are given to an interpreter. The interpreter listens for `Witness` events,
 | 
				
			||||||
 | 
					//! which it uses to reduce the payment plan. When the plan is reduced to a
 | 
				
			||||||
 | 
					//! `Payment`, the payment is executed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use signature::PublicKey;
 | 
					use signature::PublicKey;
 | 
				
			||||||
use chrono::prelude::*;
 | 
					use chrono::prelude::*;
 | 
				
			||||||
use std::mem;
 | 
					use std::mem;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub enum Witness {
 | 
				
			||||||
 | 
					    Timestamp(DateTime<Utc>),
 | 
				
			||||||
 | 
					    Signature(PublicKey),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
 | 
					#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
 | 
				
			||||||
pub enum Condition {
 | 
					pub enum Condition {
 | 
				
			||||||
    Timestamp(DateTime<Utc>),
 | 
					    Timestamp(DateTime<Utc>),
 | 
				
			||||||
    Signature(PublicKey),
 | 
					    Signature(PublicKey),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub enum PlanEvent {
 | 
					 | 
				
			||||||
    Timestamp(DateTime<Utc>),
 | 
					 | 
				
			||||||
    Signature(PublicKey),
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Condition {
 | 
					impl Condition {
 | 
				
			||||||
    pub fn is_satisfied(&self, event: &PlanEvent) -> bool {
 | 
					    pub fn is_satisfied(&self, witness: &Witness) -> bool {
 | 
				
			||||||
        match (self, event) {
 | 
					        match (self, witness) {
 | 
				
			||||||
            (&Condition::Signature(ref pubkey), &PlanEvent::Signature(ref from)) => pubkey == from,
 | 
					            (&Condition::Signature(ref pubkey), &Witness::Signature(ref from)) => pubkey == from,
 | 
				
			||||||
            (&Condition::Timestamp(ref dt), &PlanEvent::Timestamp(ref last_time)) => {
 | 
					            (&Condition::Timestamp(ref dt), &Witness::Timestamp(ref last_time)) => dt <= last_time,
 | 
				
			||||||
                dt <= last_time
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            _ => false,
 | 
					            _ => false,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
 | 
					 | 
				
			||||||
pub enum Action {
 | 
					 | 
				
			||||||
    Pay(Payment),
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Action {
 | 
					 | 
				
			||||||
    pub fn spendable(&self) -> i64 {
 | 
					 | 
				
			||||||
        match *self {
 | 
					 | 
				
			||||||
            Action::Pay(ref payment) => payment.tokens,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
 | 
					#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
 | 
				
			||||||
pub struct Payment {
 | 
					pub struct Payment {
 | 
				
			||||||
    pub tokens: i64,
 | 
					    pub tokens: i64,
 | 
				
			||||||
@@ -48,28 +36,22 @@ pub struct Payment {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
 | 
					#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
 | 
				
			||||||
pub enum Plan {
 | 
					pub enum Plan {
 | 
				
			||||||
    Action(Action),
 | 
					    Pay(Payment),
 | 
				
			||||||
    After(Condition, Action),
 | 
					    After(Condition, Payment),
 | 
				
			||||||
    Race((Condition, Action), (Condition, Action)),
 | 
					    Race((Condition, Payment), (Condition, Payment)),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Plan {
 | 
					impl Plan {
 | 
				
			||||||
    pub fn new_payment(tokens: i64, to: PublicKey) -> Self {
 | 
					    pub fn new_payment(tokens: i64, to: PublicKey) -> Self {
 | 
				
			||||||
        Plan::Action(Action::Pay(Payment { tokens, to }))
 | 
					        Plan::Pay(Payment { tokens, to })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn new_authorized_payment(from: PublicKey, tokens: i64, to: PublicKey) -> Self {
 | 
					    pub fn new_authorized_payment(from: PublicKey, tokens: i64, to: PublicKey) -> Self {
 | 
				
			||||||
        Plan::After(
 | 
					        Plan::After(Condition::Signature(from), Payment { tokens, to })
 | 
				
			||||||
            Condition::Signature(from),
 | 
					 | 
				
			||||||
            Action::Pay(Payment { tokens, to }),
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn new_future_payment(dt: DateTime<Utc>, tokens: i64, to: PublicKey) -> Self {
 | 
					    pub fn new_future_payment(dt: DateTime<Utc>, tokens: i64, to: PublicKey) -> Self {
 | 
				
			||||||
        Plan::After(
 | 
					        Plan::After(Condition::Timestamp(dt), Payment { tokens, to })
 | 
				
			||||||
            Condition::Timestamp(dt),
 | 
					 | 
				
			||||||
            Action::Pay(Payment { tokens, to }),
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn new_cancelable_future_payment(
 | 
					    pub fn new_cancelable_future_payment(
 | 
				
			||||||
@@ -79,50 +61,40 @@ impl Plan {
 | 
				
			|||||||
        to: PublicKey,
 | 
					        to: PublicKey,
 | 
				
			||||||
    ) -> Self {
 | 
					    ) -> Self {
 | 
				
			||||||
        Plan::Race(
 | 
					        Plan::Race(
 | 
				
			||||||
            (
 | 
					            (Condition::Timestamp(dt), Payment { tokens, to }),
 | 
				
			||||||
                Condition::Timestamp(dt),
 | 
					            (Condition::Signature(from), Payment { tokens, to: from }),
 | 
				
			||||||
                Action::Pay(Payment { tokens, to }),
 | 
					 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
            (
 | 
					 | 
				
			||||||
                Condition::Signature(from),
 | 
					 | 
				
			||||||
                Action::Pay(Payment { tokens, to: from }),
 | 
					 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn is_complete(&self) -> bool {
 | 
				
			||||||
 | 
					        match *self {
 | 
				
			||||||
 | 
					            Plan::Pay(_) => true,
 | 
				
			||||||
 | 
					            _ => false,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn verify(&self, spendable_tokens: i64) -> bool {
 | 
					    pub fn verify(&self, spendable_tokens: i64) -> bool {
 | 
				
			||||||
        match *self {
 | 
					        match *self {
 | 
				
			||||||
            Plan::Action(ref action) => action.spendable() == spendable_tokens,
 | 
					            Plan::Pay(ref payment) => payment.tokens == spendable_tokens,
 | 
				
			||||||
            Plan::After(_, ref action) => action.spendable() == spendable_tokens,
 | 
					            Plan::After(_, ref payment) => payment.tokens == spendable_tokens,
 | 
				
			||||||
            Plan::Race(ref a, ref b) => {
 | 
					            Plan::Race(ref a, ref b) => {
 | 
				
			||||||
                a.1.spendable() == spendable_tokens && b.1.spendable() == spendable_tokens
 | 
					                a.1.tokens == spendable_tokens && b.1.tokens == spendable_tokens
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn process_event(&mut self, event: PlanEvent) -> bool {
 | 
					    /// Apply a witness to the spending plan to see if the plan can be reduced.
 | 
				
			||||||
        let mut new_action = None;
 | 
					    /// If so, modify the plan in-place.
 | 
				
			||||||
        match *self {
 | 
					    pub fn apply_witness(&mut self, witness: Witness) {
 | 
				
			||||||
            Plan::Action(_) => return true,
 | 
					        let new_payment = match *self {
 | 
				
			||||||
            Plan::After(ref cond, ref action) => {
 | 
					            Plan::After(ref cond, ref payment) if cond.is_satisfied(&witness) => Some(payment),
 | 
				
			||||||
                if cond.is_satisfied(&event) {
 | 
					            Plan::Race((ref cond, ref payment), _) if cond.is_satisfied(&witness) => Some(payment),
 | 
				
			||||||
                    new_action = Some(action.clone());
 | 
					            Plan::Race(_, (ref cond, ref payment)) if cond.is_satisfied(&witness) => Some(payment),
 | 
				
			||||||
                }
 | 
					            _ => None,
 | 
				
			||||||
            }
 | 
					        }.map(|x| x.clone());
 | 
				
			||||||
            Plan::Race(ref a, ref b) => {
 | 
					 | 
				
			||||||
                if a.0.is_satisfied(&event) {
 | 
					 | 
				
			||||||
                    new_action = Some(a.1.clone());
 | 
					 | 
				
			||||||
                } else if b.0.is_satisfied(&event) {
 | 
					 | 
				
			||||||
                    new_action = Some(b.1.clone());
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if let Some(action) = new_action {
 | 
					        if let Some(payment) = new_payment {
 | 
				
			||||||
            mem::replace(self, Plan::Action(action));
 | 
					            mem::replace(self, Plan::Pay(payment));
 | 
				
			||||||
            true
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            false
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -134,16 +106,16 @@ mod tests {
 | 
				
			|||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn test_signature_satisfied() {
 | 
					    fn test_signature_satisfied() {
 | 
				
			||||||
        let sig = PublicKey::default();
 | 
					        let sig = PublicKey::default();
 | 
				
			||||||
        assert!(Condition::Signature(sig).is_satisfied(&PlanEvent::Signature(sig)));
 | 
					        assert!(Condition::Signature(sig).is_satisfied(&Witness::Signature(sig)));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn test_timestamp_satisfied() {
 | 
					    fn test_timestamp_satisfied() {
 | 
				
			||||||
        let dt1 = Utc.ymd(2014, 11, 14).and_hms(8, 9, 10);
 | 
					        let dt1 = Utc.ymd(2014, 11, 14).and_hms(8, 9, 10);
 | 
				
			||||||
        let dt2 = Utc.ymd(2014, 11, 14).and_hms(10, 9, 8);
 | 
					        let dt2 = Utc.ymd(2014, 11, 14).and_hms(10, 9, 8);
 | 
				
			||||||
        assert!(Condition::Timestamp(dt1).is_satisfied(&PlanEvent::Timestamp(dt1)));
 | 
					        assert!(Condition::Timestamp(dt1).is_satisfied(&Witness::Timestamp(dt1)));
 | 
				
			||||||
        assert!(Condition::Timestamp(dt1).is_satisfied(&PlanEvent::Timestamp(dt2)));
 | 
					        assert!(Condition::Timestamp(dt1).is_satisfied(&Witness::Timestamp(dt2)));
 | 
				
			||||||
        assert!(!Condition::Timestamp(dt2).is_satisfied(&PlanEvent::Timestamp(dt1)));
 | 
					        assert!(!Condition::Timestamp(dt2).is_satisfied(&Witness::Timestamp(dt1)));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
@@ -163,7 +135,7 @@ mod tests {
 | 
				
			|||||||
        let to = PublicKey::default();
 | 
					        let to = PublicKey::default();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let mut plan = Plan::new_authorized_payment(from, 42, to);
 | 
					        let mut plan = Plan::new_authorized_payment(from, 42, to);
 | 
				
			||||||
        assert!(plan.process_event(PlanEvent::Signature(from)));
 | 
					        plan.apply_witness(Witness::Signature(from));
 | 
				
			||||||
        assert_eq!(plan, Plan::new_payment(42, to));
 | 
					        assert_eq!(plan, Plan::new_payment(42, to));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -173,7 +145,7 @@ mod tests {
 | 
				
			|||||||
        let to = PublicKey::default();
 | 
					        let to = PublicKey::default();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let mut plan = Plan::new_future_payment(dt, 42, to);
 | 
					        let mut plan = Plan::new_future_payment(dt, 42, to);
 | 
				
			||||||
        assert!(plan.process_event(PlanEvent::Timestamp(dt)));
 | 
					        plan.apply_witness(Witness::Timestamp(dt));
 | 
				
			||||||
        assert_eq!(plan, Plan::new_payment(42, to));
 | 
					        assert_eq!(plan, Plan::new_payment(42, to));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -184,11 +156,11 @@ mod tests {
 | 
				
			|||||||
        let to = PublicKey::default();
 | 
					        let to = PublicKey::default();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let mut plan = Plan::new_cancelable_future_payment(dt, from, 42, to);
 | 
					        let mut plan = Plan::new_cancelable_future_payment(dt, from, 42, to);
 | 
				
			||||||
        assert!(plan.process_event(PlanEvent::Timestamp(dt)));
 | 
					        plan.apply_witness(Witness::Timestamp(dt));
 | 
				
			||||||
        assert_eq!(plan, Plan::new_payment(42, to));
 | 
					        assert_eq!(plan, Plan::new_payment(42, to));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let mut plan = Plan::new_cancelable_future_payment(dt, from, 42, to);
 | 
					        let mut plan = Plan::new_cancelable_future_payment(dt, from, 42, to);
 | 
				
			||||||
        assert!(plan.process_event(PlanEvent::Signature(from)));
 | 
					        plan.apply_witness(Witness::Signature(from));
 | 
				
			||||||
        assert_eq!(plan, Plan::new_payment(42, from));
 | 
					        assert_eq!(plan, Plan::new_payment(42, from));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,7 @@ use signature::{KeyPair, KeyPairUtil, PublicKey, Signature, SignatureUtil};
 | 
				
			|||||||
use bincode::serialize;
 | 
					use bincode::serialize;
 | 
				
			||||||
use hash::Hash;
 | 
					use hash::Hash;
 | 
				
			||||||
use chrono::prelude::*;
 | 
					use chrono::prelude::*;
 | 
				
			||||||
use plan::{Action, Condition, Payment, Plan};
 | 
					use plan::{Condition, Payment, Plan};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
 | 
					#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
 | 
				
			||||||
pub struct Transaction {
 | 
					pub struct Transaction {
 | 
				
			||||||
@@ -18,7 +18,7 @@ pub struct Transaction {
 | 
				
			|||||||
impl Transaction {
 | 
					impl Transaction {
 | 
				
			||||||
    pub fn new(from_keypair: &KeyPair, to: PublicKey, tokens: i64, last_id: Hash) -> Self {
 | 
					    pub fn new(from_keypair: &KeyPair, to: PublicKey, tokens: i64, last_id: Hash) -> Self {
 | 
				
			||||||
        let from = from_keypair.pubkey();
 | 
					        let from = from_keypair.pubkey();
 | 
				
			||||||
        let plan = Plan::Action(Action::Pay(Payment { tokens, to }));
 | 
					        let plan = Plan::Pay(Payment { tokens, to });
 | 
				
			||||||
        let mut tr = Transaction {
 | 
					        let mut tr = Transaction {
 | 
				
			||||||
            from,
 | 
					            from,
 | 
				
			||||||
            plan,
 | 
					            plan,
 | 
				
			||||||
@@ -39,14 +39,8 @@ impl Transaction {
 | 
				
			|||||||
    ) -> Self {
 | 
					    ) -> Self {
 | 
				
			||||||
        let from = from_keypair.pubkey();
 | 
					        let from = from_keypair.pubkey();
 | 
				
			||||||
        let plan = Plan::Race(
 | 
					        let plan = Plan::Race(
 | 
				
			||||||
            (
 | 
					            (Condition::Timestamp(dt), Payment { tokens, to }),
 | 
				
			||||||
                Condition::Timestamp(dt),
 | 
					            (Condition::Signature(from), Payment { tokens, to: from }),
 | 
				
			||||||
                Action::Pay(Payment { tokens, to }),
 | 
					 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
            (
 | 
					 | 
				
			||||||
                Condition::Signature(from),
 | 
					 | 
				
			||||||
                Action::Pay(Payment { tokens, to: from }),
 | 
					 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        let mut tr = Transaction {
 | 
					        let mut tr = Transaction {
 | 
				
			||||||
            from,
 | 
					            from,
 | 
				
			||||||
@@ -98,10 +92,10 @@ mod tests {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn test_serialize_claim() {
 | 
					    fn test_serialize_claim() {
 | 
				
			||||||
        let plan = Plan::Action(Action::Pay(Payment {
 | 
					        let plan = Plan::Pay(Payment {
 | 
				
			||||||
            tokens: 0,
 | 
					            tokens: 0,
 | 
				
			||||||
            to: Default::default(),
 | 
					            to: Default::default(),
 | 
				
			||||||
        }));
 | 
					        });
 | 
				
			||||||
        let claim0 = Transaction {
 | 
					        let claim0 = Transaction {
 | 
				
			||||||
            from: Default::default(),
 | 
					            from: Default::default(),
 | 
				
			||||||
            plan,
 | 
					            plan,
 | 
				
			||||||
@@ -134,7 +128,7 @@ mod tests {
 | 
				
			|||||||
        let zero = Hash::default();
 | 
					        let zero = Hash::default();
 | 
				
			||||||
        let mut tr = Transaction::new(&keypair0, pubkey1, 42, zero);
 | 
					        let mut tr = Transaction::new(&keypair0, pubkey1, 42, zero);
 | 
				
			||||||
        tr.sign(&keypair0);
 | 
					        tr.sign(&keypair0);
 | 
				
			||||||
        if let Plan::Action(Action::Pay(ref mut payment)) = tr.plan {
 | 
					        if let Plan::Pay(ref mut payment) = tr.plan {
 | 
				
			||||||
            payment.to = thief_keypair.pubkey(); // <-- attack!
 | 
					            payment.to = thief_keypair.pubkey(); // <-- attack!
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        assert!(!tr.verify());
 | 
					        assert!(!tr.verify());
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user