Remove Action from spending plans

This commit is contained in:
Greg Fitzgerald 2018-03-20 15:43:04 -06:00
parent 6f509a8a1e
commit 6be3d62d89
4 changed files with 33 additions and 64 deletions

View File

@ -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, Witness}; 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;
@ -85,7 +85,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
@ -114,7 +114,7 @@ impl Accountant {
/// Commit funds to the 'to' party. /// 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 let Plan::Pay(ref payment) = *plan {
if self.balances.contains_key(&payment.to) { if self.balances.contains_key(&payment.to) {
if let Some(x) = self.balances.get_mut(&payment.to) { if let Some(x) = self.balances.get_mut(&payment.to) {
*x += payment.tokens; *x += payment.tokens;
@ -288,7 +288,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 +297,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!(

View File

@ -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);
} }
} }

View File

@ -25,19 +25,6 @@ impl Condition {
} }
} }
#[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,
@ -46,28 +33,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(
@ -77,47 +58,41 @@ 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 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_witness(&mut self, event: Witness) -> bool { pub fn process_witness(&mut self, event: Witness) -> bool {
let mut new_action = None; let mut new_payment = None;
match *self { match *self {
Plan::Action(_) => return true, Plan::Pay(_) => return true,
Plan::After(ref cond, ref action) => { Plan::After(ref cond, ref payment) => {
if cond.is_satisfied(&event) { if cond.is_satisfied(&event) {
new_action = Some(action.clone()); new_payment = Some(payment.clone());
} }
} }
Plan::Race(ref a, ref b) => { Plan::Race(ref a, ref b) => {
if a.0.is_satisfied(&event) { if a.0.is_satisfied(&event) {
new_action = Some(a.1.clone()); new_payment = Some(a.1.clone());
} else if b.0.is_satisfied(&event) { } else if b.0.is_satisfied(&event) {
new_action = Some(b.1.clone()); new_payment = 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 true
} else { } else {
false false

View File

@ -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());