@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
use budget::Budget;
|
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
use entry::Entry;
|
use entry::Entry;
|
||||||
use hash::Hash;
|
use hash::Hash;
|
||||||
@ -18,7 +17,7 @@ use std::collections::{HashMap, HashSet, VecDeque};
|
|||||||
use std::result;
|
use std::result;
|
||||||
use std::sync::RwLock;
|
use std::sync::RwLock;
|
||||||
use std::sync::atomic::{AtomicIsize, AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicIsize, AtomicUsize, Ordering};
|
||||||
use transaction::{Instruction, Transaction};
|
use transaction::{Instruction, Plan, Transaction};
|
||||||
|
|
||||||
pub const MAX_ENTRY_IDS: usize = 1024 * 4;
|
pub const MAX_ENTRY_IDS: usize = 1024 * 4;
|
||||||
|
|
||||||
@ -33,7 +32,7 @@ pub type Result<T> = result::Result<T, BankError>;
|
|||||||
|
|
||||||
pub struct Bank {
|
pub struct Bank {
|
||||||
balances: RwLock<HashMap<PublicKey, AtomicIsize>>,
|
balances: RwLock<HashMap<PublicKey, AtomicIsize>>,
|
||||||
pending: RwLock<HashMap<Signature, Budget>>,
|
pending: RwLock<HashMap<Signature, Plan>>,
|
||||||
last_ids: RwLock<VecDeque<(Hash, RwLock<HashSet<Signature>>)>>,
|
last_ids: RwLock<VecDeque<(Hash, RwLock<HashSet<Signature>>)>>,
|
||||||
time_sources: RwLock<HashSet<PublicKey>>,
|
time_sources: RwLock<HashSet<PublicKey>>,
|
||||||
last_time: RwLock<DateTime<Utc>>,
|
last_time: RwLock<DateTime<Utc>>,
|
||||||
|
@ -70,14 +70,14 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use budget::Budget;
|
use budget::Budget;
|
||||||
use ledger::Block;
|
use ledger::Block;
|
||||||
use transaction::Instruction;
|
use transaction::{Instruction, Plan};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_create_transactions() {
|
fn test_create_transactions() {
|
||||||
let mut transactions = Mint::new(100).create_transactions().into_iter();
|
let mut transactions = Mint::new(100).create_transactions().into_iter();
|
||||||
let tx = transactions.next().unwrap();
|
let tx = transactions.next().unwrap();
|
||||||
if let Instruction::NewContract(contract) = tx.instruction {
|
if let Instruction::NewContract(contract) = tx.instruction {
|
||||||
if let Budget::Pay(payment) = contract.plan {
|
if let Plan::Budget(Budget::Pay(payment)) = contract.plan {
|
||||||
assert_eq!(tx.from, payment.to);
|
assert_eq!(tx.from, payment.to);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,7 +187,7 @@ mod tests {
|
|||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::thread::sleep;
|
use std::thread::sleep;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use transaction::Instruction;
|
use transaction::{Instruction, Plan};
|
||||||
use tvu::TestNode;
|
use tvu::TestNode;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -282,7 +282,7 @@ mod tests {
|
|||||||
let mut tr2 = Transaction::new(&alice.keypair(), bob_pubkey, 501, last_id);
|
let mut tr2 = Transaction::new(&alice.keypair(), bob_pubkey, 501, last_id);
|
||||||
if let Instruction::NewContract(contract) = &mut tr2.instruction {
|
if let Instruction::NewContract(contract) = &mut tr2.instruction {
|
||||||
contract.tokens = 502;
|
contract.tokens = 502;
|
||||||
contract.plan = Budget::new_payment(502, bob_pubkey);
|
contract.plan = Plan::Budget(Budget::new_payment(502, bob_pubkey));
|
||||||
}
|
}
|
||||||
let _sig = client.transfer_signed(tr2).unwrap();
|
let _sig = client.transfer_signed(tr2).unwrap();
|
||||||
|
|
||||||
|
@ -4,17 +4,43 @@ use bincode::serialize;
|
|||||||
use budget::{Budget, Condition};
|
use budget::{Budget, Condition};
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
use hash::Hash;
|
use hash::Hash;
|
||||||
use plan::{Payment, PaymentPlan};
|
use plan::{Payment, PaymentPlan, Witness};
|
||||||
use signature::{KeyPair, KeyPairUtil, PublicKey, Signature, SignatureUtil};
|
use signature::{KeyPair, KeyPairUtil, PublicKey, Signature, SignatureUtil};
|
||||||
|
|
||||||
pub const SIGNED_DATA_OFFSET: usize = 112;
|
pub const SIGNED_DATA_OFFSET: usize = 112;
|
||||||
pub const SIG_OFFSET: usize = 8;
|
pub const SIG_OFFSET: usize = 8;
|
||||||
pub const PUB_KEY_OFFSET: usize = 80;
|
pub const PUB_KEY_OFFSET: usize = 80;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
|
pub enum Plan {
|
||||||
|
Budget(Budget),
|
||||||
|
}
|
||||||
|
|
||||||
|
// A proxy for the underlying DSL.
|
||||||
|
impl PaymentPlan for Plan {
|
||||||
|
fn final_payment(&self) -> Option<Payment> {
|
||||||
|
match self {
|
||||||
|
Plan::Budget(budget) => budget.final_payment(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn verify(&self, spendable_tokens: i64) -> bool {
|
||||||
|
match self {
|
||||||
|
Plan::Budget(budget) => budget.verify(spendable_tokens),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_witness(&mut self, witness: &Witness) {
|
||||||
|
match self {
|
||||||
|
Plan::Budget(budget) => budget.apply_witness(witness),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
pub struct Contract {
|
pub struct Contract {
|
||||||
pub tokens: i64,
|
pub tokens: i64,
|
||||||
pub plan: Budget,
|
pub plan: Plan,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
@ -51,7 +77,8 @@ impl Transaction {
|
|||||||
|
|
||||||
/// Create and sign a new Transaction. Used for unit-testing.
|
/// Create and sign a new Transaction. Used for unit-testing.
|
||||||
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 plan = Budget::Pay(Payment { tokens, to });
|
let budget = Budget::Pay(Payment { tokens, to });
|
||||||
|
let plan = Plan::Budget(budget);
|
||||||
let instruction = Instruction::NewContract(Contract { plan, tokens });
|
let instruction = Instruction::NewContract(Contract { plan, tokens });
|
||||||
Self::new_from_instruction(from_keypair, instruction, last_id)
|
Self::new_from_instruction(from_keypair, instruction, last_id)
|
||||||
}
|
}
|
||||||
@ -77,10 +104,11 @@ impl Transaction {
|
|||||||
last_id: Hash,
|
last_id: Hash,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let from = from_keypair.pubkey();
|
let from = from_keypair.pubkey();
|
||||||
let plan = Budget::Race(
|
let budget = Budget::Race(
|
||||||
(Condition::Timestamp(dt), Payment { tokens, to }),
|
(Condition::Timestamp(dt), Payment { tokens, to }),
|
||||||
(Condition::Signature(from), Payment { tokens, to: from }),
|
(Condition::Signature(from), Payment { tokens, to: from }),
|
||||||
);
|
);
|
||||||
|
let plan = Plan::Budget(budget);
|
||||||
let instruction = Instruction::NewContract(Contract { plan, tokens });
|
let instruction = Instruction::NewContract(Contract { plan, tokens });
|
||||||
let mut tx = Transaction {
|
let mut tx = Transaction {
|
||||||
instruction,
|
instruction,
|
||||||
@ -163,10 +191,11 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_serialize_claim() {
|
fn test_serialize_claim() {
|
||||||
let plan = Budget::Pay(Payment {
|
let budget = Budget::Pay(Payment {
|
||||||
tokens: 0,
|
tokens: 0,
|
||||||
to: Default::default(),
|
to: Default::default(),
|
||||||
});
|
});
|
||||||
|
let plan = Plan::Budget(budget);
|
||||||
let instruction = Instruction::NewContract(Contract { plan, tokens: 0 });
|
let instruction = Instruction::NewContract(Contract { plan, tokens: 0 });
|
||||||
let claim0 = Transaction {
|
let claim0 = Transaction {
|
||||||
instruction,
|
instruction,
|
||||||
@ -187,7 +216,7 @@ mod tests {
|
|||||||
let mut tx = Transaction::new(&keypair, pubkey, 42, zero);
|
let mut tx = Transaction::new(&keypair, pubkey, 42, zero);
|
||||||
if let Instruction::NewContract(contract) = &mut tx.instruction {
|
if let Instruction::NewContract(contract) = &mut tx.instruction {
|
||||||
contract.tokens = 1_000_000; // <-- attack, part 1!
|
contract.tokens = 1_000_000; // <-- attack, part 1!
|
||||||
if let Budget::Pay(ref mut payment) = contract.plan {
|
if let Plan::Budget(Budget::Pay(ref mut payment)) = contract.plan {
|
||||||
payment.tokens = contract.tokens; // <-- attack, part 2!
|
payment.tokens = contract.tokens; // <-- attack, part 2!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -204,7 +233,7 @@ mod tests {
|
|||||||
let zero = Hash::default();
|
let zero = Hash::default();
|
||||||
let mut tx = Transaction::new(&keypair0, pubkey1, 42, zero);
|
let mut tx = Transaction::new(&keypair0, pubkey1, 42, zero);
|
||||||
if let Instruction::NewContract(contract) = &mut tx.instruction {
|
if let Instruction::NewContract(contract) = &mut tx.instruction {
|
||||||
if let Budget::Pay(ref mut payment) = contract.plan {
|
if let Plan::Budget(Budget::Pay(ref mut payment)) = contract.plan {
|
||||||
payment.to = thief_keypair.pubkey(); // <-- attack!
|
payment.to = thief_keypair.pubkey(); // <-- attack!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -228,7 +257,7 @@ mod tests {
|
|||||||
let zero = Hash::default();
|
let zero = Hash::default();
|
||||||
let mut tx = Transaction::new(&keypair0, keypair1.pubkey(), 1, zero);
|
let mut tx = Transaction::new(&keypair0, keypair1.pubkey(), 1, zero);
|
||||||
if let Instruction::NewContract(contract) = &mut tx.instruction {
|
if let Instruction::NewContract(contract) = &mut tx.instruction {
|
||||||
if let Budget::Pay(ref mut payment) = contract.plan {
|
if let Plan::Budget(Budget::Pay(ref mut payment)) = contract.plan {
|
||||||
payment.tokens = 2; // <-- attack!
|
payment.tokens = 2; // <-- attack!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -236,7 +265,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 Instruction::NewContract(contract) = &mut tx.instruction {
|
if let Instruction::NewContract(contract) = &mut tx.instruction {
|
||||||
if let Budget::Pay(ref mut payment) = contract.plan {
|
if let Plan::Budget(Budget::Pay(ref mut payment)) = contract.plan {
|
||||||
payment.tokens = 0; // <-- whoops!
|
payment.tokens = 0; // <-- whoops!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user