Ensure the server isn't passed a Plan that spends more than is bonded
This commit is contained in:
@ -5,7 +5,7 @@
|
|||||||
use hash::Hash;
|
use hash::Hash;
|
||||||
use entry::Entry;
|
use entry::Entry;
|
||||||
use event::Event;
|
use event::Event;
|
||||||
use transaction::{Action, Condition, Plan, Transaction};
|
use transaction::{Action, Plan, Transaction};
|
||||||
use signature::{KeyPair, PublicKey, Signature};
|
use signature::{KeyPair, PublicKey, Signature};
|
||||||
use mint::Mint;
|
use mint::Mint;
|
||||||
use historian::{reserve_signature, Historian};
|
use historian::{reserve_signature, Historian};
|
||||||
@ -281,6 +281,21 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_overspend_attack() {
|
||||||
|
let alice = Mint::new(1);
|
||||||
|
let mut acc = Accountant::new(&alice, None);
|
||||||
|
let bob_pubkey = KeyPair::new().pubkey();
|
||||||
|
let mut tr = Transaction::new(&alice.keypair(), bob_pubkey, 1, alice.seed());
|
||||||
|
if let Plan::Action(Action::Pay(ref mut payment)) = tr.plan {
|
||||||
|
payment.asset = 2; // <-- Attack!
|
||||||
|
}
|
||||||
|
assert_eq!(
|
||||||
|
acc.process_transaction(tr),
|
||||||
|
Err(AccountingError::InvalidTransfer)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_transfer_to_newb() {
|
fn test_transfer_to_newb() {
|
||||||
let alice = Mint::new(10_000);
|
let alice = Mint::new(10_000);
|
||||||
|
@ -6,6 +6,7 @@ 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 {
|
||||||
@ -18,6 +19,14 @@ pub enum Action<T> {
|
|||||||
Pay(Payment<T>),
|
Pay(Payment<T>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Clone> Action<T> {
|
||||||
|
pub fn max_spendable(&self) -> T {
|
||||||
|
match *self {
|
||||||
|
Action::Pay(ref payment) => payment.asset.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
pub struct Payment<T> {
|
pub struct Payment<T> {
|
||||||
pub asset: T,
|
pub asset: T,
|
||||||
@ -31,7 +40,21 @@ pub enum Plan<T> {
|
|||||||
Race(Box<Plan<T>>, Box<Plan<T>>),
|
Race(Box<Plan<T>>, Box<Plan<T>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Clone> Plan<T> {
|
impl<T: Clone + Ord> 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 {
|
||||||
|
self.max_spendable() <= *spendable_assets
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run_race(&mut self) -> bool {
|
pub fn run_race(&mut self) -> bool {
|
||||||
let new_plan = if let Plan::Race(ref a, ref b) = *self {
|
let new_plan = if let Plan::Race(ref a, ref b) = *self {
|
||||||
if let Plan::Action(_) = **a {
|
if let Plan::Action(_) = **a {
|
||||||
@ -117,7 +140,7 @@ pub struct Transaction<T> {
|
|||||||
pub sig: Signature,
|
pub sig: Signature,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Serialize + Clone> Transaction<T> {
|
impl<T: Serialize + Clone + Ord> 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 {
|
||||||
@ -180,7 +203,7 @@ impl<T: Serialize + Clone> Transaction<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn verify(&self) -> bool {
|
pub fn verify(&self) -> bool {
|
||||||
self.sig.verify(&self.from, &self.get_sign_data())
|
self.sig.verify(&self.from, &self.get_sign_data()) && self.plan.verify(&self.asset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user