parent
8579795c40
commit
f5f71a19b8
|
@ -83,8 +83,12 @@ impl Accountant {
|
|||
self.last_id
|
||||
}
|
||||
|
||||
fn is_deposit(allow_deposits: bool, from: &PublicKey, to: &PublicKey) -> bool {
|
||||
allow_deposits && from == to
|
||||
fn is_deposit(allow_deposits: bool, from: &PublicKey, plan: &Plan<i64>) -> bool {
|
||||
if let Plan::Action(Action::Pay(ref payment)) = *plan {
|
||||
allow_deposits && *from == payment.to
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_transaction(self: &mut Self, tr: Transaction<i64>) -> Result<()> {
|
||||
|
@ -109,38 +113,49 @@ impl Accountant {
|
|||
|
||||
/// Commit funds to the 'to' party.
|
||||
fn complete_transaction(self: &mut Self, plan: &Plan<i64>) {
|
||||
let Action::Pay(ref payment) = plan.if_all.1;
|
||||
let to = payment.to;
|
||||
if self.balances.contains_key(&to) {
|
||||
if let Some(x) = self.balances.get_mut(&to) {
|
||||
let payment = match *plan {
|
||||
Plan::Action(Action::Pay(ref payment)) => Some(payment),
|
||||
Plan::After(_, Action::Pay(ref payment)) => Some(payment),
|
||||
Plan::Race(ref plan_a, _) => {
|
||||
if let Plan::After(_, Action::Pay(ref payment)) = **plan_a {
|
||||
Some(payment)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
if let Some(payment) = payment {
|
||||
if self.balances.contains_key(&payment.to) {
|
||||
if let Some(x) = self.balances.get_mut(&payment.to) {
|
||||
*x += payment.asset;
|
||||
}
|
||||
} else {
|
||||
self.balances.insert(to, payment.asset);
|
||||
self.balances.insert(payment.to, payment.asset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return funds to the 'from' party.
|
||||
fn cancel_transaction(self: &mut Self, plan: &Plan<i64>) {
|
||||
let Action::Pay(ref payment) = plan.unless_any.1;
|
||||
if let Plan::Race(_, ref cancel_plan) = *plan {
|
||||
if let Plan::After(_, Action::Pay(ref payment)) = **cancel_plan {
|
||||
if let Some(x) = self.balances.get_mut(&payment.to) {
|
||||
*x += payment.asset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Move this to transaction.rs
|
||||
fn all_satisfied(&self, conds: &[Condition]) -> bool {
|
||||
let mut satisfied = true;
|
||||
for cond in conds {
|
||||
if let &Condition::Timestamp(dt) = cond {
|
||||
if dt > self.last_time {
|
||||
satisfied = false;
|
||||
}
|
||||
} else {
|
||||
satisfied = false;
|
||||
fn all_satisfied(&self, plan: &Plan<i64>) -> bool {
|
||||
match *plan {
|
||||
Plan::Action(_) => true,
|
||||
Plan::After(Condition::Timestamp(dt), _) => dt <= self.last_time,
|
||||
Plan::After(Condition::Signature(_), _) => false,
|
||||
Plan::Race(ref plan_a, ref plan_b) => {
|
||||
self.all_satisfied(plan_a) || self.all_satisfied(plan_b)
|
||||
}
|
||||
}
|
||||
satisfied
|
||||
}
|
||||
|
||||
fn process_verified_transaction(
|
||||
|
@ -152,17 +167,13 @@ impl Accountant {
|
|||
return Err(AccountingError::InvalidTransferSignature);
|
||||
}
|
||||
|
||||
if !tr.plan.unless_any.0.is_empty() {
|
||||
// TODO: Check to see if the transaction is expired.
|
||||
}
|
||||
|
||||
if !Self::is_deposit(allow_deposits, &tr.from, &tr.plan.to()) {
|
||||
if !Self::is_deposit(allow_deposits, &tr.from, &tr.plan) {
|
||||
if let Some(x) = self.balances.get_mut(&tr.from) {
|
||||
*x -= tr.asset;
|
||||
}
|
||||
}
|
||||
|
||||
if !self.all_satisfied(&tr.plan.if_all.0) {
|
||||
if !self.all_satisfied(&tr.plan) {
|
||||
self.pending.insert(tr.sig, tr.plan.clone());
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -178,11 +189,10 @@ impl Accountant {
|
|||
// if Signature(from) is in unless_any, return funds to tx.from, and remove the tx from this map.
|
||||
|
||||
// TODO: Use find().
|
||||
for cond in &plan.unless_any.0 {
|
||||
if let Condition::Signature(pubkey) = *cond {
|
||||
if let Plan::Race(_, ref plan_b) = *plan {
|
||||
if let Plan::After(Condition::Signature(pubkey), _) = **plan_b {
|
||||
if from == pubkey {
|
||||
cancel = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -223,12 +233,14 @@ impl Accountant {
|
|||
// Check to see if any timelocked transactions can be completed.
|
||||
let mut completed = vec![];
|
||||
for (key, plan) in &self.pending {
|
||||
for cond in &plan.if_all.0 {
|
||||
if let Condition::Timestamp(dt) = *cond {
|
||||
if let Plan::After(Condition::Timestamp(dt), _) = *plan {
|
||||
if self.last_time >= dt {
|
||||
if plan.if_all.0.len() == 1 {
|
||||
completed.push(*key);
|
||||
}
|
||||
} else if let Plan::Race(ref plan_a, _) = *plan {
|
||||
if let Plan::After(Condition::Timestamp(dt), _) = **plan_a {
|
||||
if self.last_time >= dt {
|
||||
completed.push(*key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,12 +58,15 @@ impl Mint {
|
|||
mod tests {
|
||||
use super::*;
|
||||
use log::verify_slice;
|
||||
use transaction::{Action, Plan};
|
||||
|
||||
#[test]
|
||||
fn test_create_events() {
|
||||
let mut events = Mint::new(100).create_events().into_iter();
|
||||
if let Event::Transaction(tr) = events.next().unwrap() {
|
||||
assert_eq!(tr.from, tr.plan.to());
|
||||
if let Plan::Action(Action::Pay(payment)) = tr.plan {
|
||||
assert_eq!(tr.from, payment.to);
|
||||
}
|
||||
}
|
||||
assert_eq!(events.next(), None);
|
||||
}
|
||||
|
|
|
@ -24,16 +24,10 @@ pub struct Payment<T> {
|
|||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||
pub struct Plan<T> {
|
||||
pub if_all: (Vec<Condition>, Action<T>),
|
||||
pub unless_any: (Vec<Condition>, Action<T>),
|
||||
}
|
||||
|
||||
impl<T> Plan<T> {
|
||||
pub fn to(&self) -> PublicKey {
|
||||
let Action::Pay(ref payment) = self.if_all.1;
|
||||
payment.to
|
||||
}
|
||||
pub enum Plan<T> {
|
||||
Action(Action<T>),
|
||||
After(Condition, Action<T>),
|
||||
Race(Box<Plan<T>>, Box<Plan<T>>),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||
|
@ -48,22 +42,10 @@ pub struct Transaction<T> {
|
|||
impl<T: Serialize + Clone> Transaction<T> {
|
||||
pub fn new(from_keypair: &KeyPair, to: PublicKey, asset: T, last_id: Hash) -> Self {
|
||||
let from = from_keypair.pubkey();
|
||||
let plan = Plan {
|
||||
if_all: (
|
||||
vec![],
|
||||
Action::Pay(Payment {
|
||||
let plan = Plan::Action(Action::Pay(Payment {
|
||||
asset: asset.clone(),
|
||||
to,
|
||||
}),
|
||||
),
|
||||
unless_any: (
|
||||
vec![Condition::Signature(from)],
|
||||
Action::Pay(Payment {
|
||||
asset: asset.clone(),
|
||||
to: from,
|
||||
}),
|
||||
),
|
||||
};
|
||||
}));
|
||||
let mut tr = Transaction {
|
||||
from,
|
||||
plan,
|
||||
|
@ -83,22 +65,22 @@ impl<T: Serialize + Clone> Transaction<T> {
|
|||
last_id: Hash,
|
||||
) -> Self {
|
||||
let from = from_keypair.pubkey();
|
||||
let plan = Plan {
|
||||
if_all: (
|
||||
vec![Condition::Timestamp(dt)],
|
||||
let plan = Plan::Race(
|
||||
Box::new(Plan::After(
|
||||
Condition::Timestamp(dt),
|
||||
Action::Pay(Payment {
|
||||
asset: asset.clone(),
|
||||
to,
|
||||
}),
|
||||
),
|
||||
unless_any: (
|
||||
vec![Condition::Signature(from)],
|
||||
)),
|
||||
Box::new(Plan::After(
|
||||
Condition::Signature(from),
|
||||
Action::Pay(Payment {
|
||||
asset: asset.clone(),
|
||||
to: from,
|
||||
}),
|
||||
),
|
||||
};
|
||||
)),
|
||||
);
|
||||
let mut tr = Transaction {
|
||||
from,
|
||||
plan,
|
||||
|
@ -111,14 +93,7 @@ impl<T: Serialize + Clone> Transaction<T> {
|
|||
}
|
||||
|
||||
fn get_sign_data(&self) -> Vec<u8> {
|
||||
let plan = &self.plan;
|
||||
serialize(&(
|
||||
&self.from,
|
||||
&plan.if_all,
|
||||
&plan.unless_any,
|
||||
&self.asset,
|
||||
&self.last_id,
|
||||
)).unwrap()
|
||||
serialize(&(&self.from, &self.plan, &self.asset, &self.last_id)).unwrap()
|
||||
}
|
||||
|
||||
pub fn sign(&mut self, keypair: &KeyPair) {
|
||||
|
@ -159,22 +134,10 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_serialize_claim() {
|
||||
let plan = Plan {
|
||||
if_all: (
|
||||
Default::default(),
|
||||
Action::Pay(Payment {
|
||||
let plan = Plan::Action(Action::Pay(Payment {
|
||||
asset: 0,
|
||||
to: Default::default(),
|
||||
}),
|
||||
),
|
||||
unless_any: (
|
||||
Default::default(),
|
||||
Action::Pay(Payment {
|
||||
asset: 0,
|
||||
to: Default::default(),
|
||||
}),
|
||||
),
|
||||
};
|
||||
}));
|
||||
let claim0 = Transaction {
|
||||
from: Default::default(),
|
||||
plan,
|
||||
|
@ -208,10 +171,9 @@ mod tests {
|
|||
let asset = hash(b"hello, world");
|
||||
let mut tr = Transaction::new(&keypair0, pubkey1, asset, zero);
|
||||
tr.sign(&keypair0);
|
||||
tr.plan.if_all.1 = Action::Pay(Payment {
|
||||
asset,
|
||||
to: thief_keypair.pubkey(),
|
||||
}); // <-- attack!
|
||||
if let Plan::Action(Action::Pay(ref mut payment)) = tr.plan {
|
||||
payment.to = thief_keypair.pubkey(); // <-- attack!
|
||||
};
|
||||
assert!(!tr.verify());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue