Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hoist last_id #237

Merged
merged 2 commits into from
May 22, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ impl Bank {
/// Deduct tokens from the 'from' address the account has sufficient
/// funds and isn't a duplicate.
pub fn process_verified_transaction_debits(&self, tr: &Transaction) -> Result<()> {
info!("Transaction {}", tr.data.tokens);
info!("Transaction {}", tr.contract.tokens);
let bals = self.balances
.read()
.expect("'balances' read lock in process_verified_transaction_debits");
Expand All @@ -170,22 +170,22 @@ impl Bank {
return Err(BankError::AccountNotFound);
}

if !self.reserve_signature_with_last_id(&tr.sig, &tr.data.last_id) {
if !self.reserve_signature_with_last_id(&tr.sig, &tr.last_id) {
return Err(BankError::InvalidTransferSignature);
}

loop {
let bal = option.expect("assignment of option to bal");
let current = bal.load(Ordering::Relaxed) as i64;

if current < tr.data.tokens {
self.forget_signature_with_last_id(&tr.sig, &tr.data.last_id);
if current < tr.contract.tokens {
self.forget_signature_with_last_id(&tr.sig, &tr.last_id);
return Err(BankError::InsufficientFunds);
}

let result = bal.compare_exchange(
current as isize,
(current - tr.data.tokens) as isize,
(current - tr.contract.tokens) as isize,
Ordering::Relaxed,
Ordering::Relaxed,
);
Expand All @@ -201,7 +201,7 @@ impl Bank {
}

pub fn process_verified_transaction_credits(&self, tr: &Transaction) {
let mut plan = tr.data.plan.clone();
let mut plan = tr.contract.plan.clone();
plan.apply_witness(&Witness::Timestamp(*self.last_time
.read()
.expect("timestamp creation in process_verified_transaction_credits")));
Expand Down
2 changes: 1 addition & 1 deletion src/bin/testnode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ fn main() {
// transfer to oneself.
let entry1: Entry = entries.next().unwrap();
let deposit = if let Event::Transaction(ref tr) = entry1.events[0] {
tr.data.plan.final_payment()
tr.contract.plan.final_payment()
} else {
None
};
Expand Down
2 changes: 1 addition & 1 deletion src/mint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ mod tests {
fn test_create_events() {
let mut events = Mint::new(100).create_events().into_iter();
if let Event::Transaction(tr) = events.next().unwrap() {
if let Plan::Pay(payment) = tr.data.plan {
if let Plan::Pay(payment) = tr.contract.plan {
assert_eq!(tr.from, payment.to);
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/thin_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,8 +301,8 @@ mod tests {
let last_id = client.get_last_id().wait().unwrap();

let mut tr2 = Transaction::new(&alice.keypair(), bob_pubkey, 501, last_id);
tr2.data.tokens = 502;
tr2.data.plan = Plan::new_payment(502, bob_pubkey);
tr2.contract.tokens = 502;
tr2.contract.plan = Plan::new_payment(502, bob_pubkey);
let _sig = client.transfer_signed(tr2).unwrap();

let balance = poll_get_balance(&mut client, &bob_pubkey);
Expand Down
50 changes: 22 additions & 28 deletions src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ pub const SIG_OFFSET: usize = 8;
pub const PUB_KEY_OFFSET: usize = 80;

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct TransactionData {
pub struct Contract {
pub tokens: i64,
pub last_id: Hash,
pub plan: Plan,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct Transaction {
pub sig: Signature,
pub from: PublicKey,
pub data: TransactionData,
pub contract: Contract,
pub last_id: Hash,
}

impl Transaction {
Expand All @@ -32,12 +32,9 @@ impl Transaction {
let plan = Plan::Pay(Payment { tokens, to });
let mut tr = Transaction {
sig: Signature::default(),
data: TransactionData {
plan,
tokens,
last_id,
},
from: from,
contract: Contract { plan, tokens },
last_id,
from,
};
tr.sign(from_keypair);
tr
Expand All @@ -57,20 +54,20 @@ impl Transaction {
(Condition::Signature(from), Payment { tokens, to: from }),
);
let mut tr = Transaction {
data: TransactionData {
plan,
tokens,
last_id,
},
from: from,
contract: Contract { plan, tokens },
from,
last_id,
sig: Signature::default(),
};
tr.sign(from_keypair);
tr
}

fn get_sign_data(&self) -> Vec<u8> {
serialize(&(&self.data)).expect("serialize TransactionData in fn get_sign_data")
let mut data = serialize(&(&self.contract)).expect("serialize Contract");
let last_id_data = serialize(&(&self.last_id)).expect("serialize last_id");
data.extend_from_slice(&last_id_data);
data
}

/// Sign this transaction.
Expand All @@ -84,7 +81,7 @@ impl Transaction {
}

pub fn verify_plan(&self) -> bool {
self.data.plan.verify(self.data.tokens)
self.contract.plan.verify(self.contract.tokens)
}
}

Expand Down Expand Up @@ -153,12 +150,9 @@ mod tests {
to: Default::default(),
});
let claim0 = Transaction {
data: TransactionData {
plan,
tokens: 0,
last_id: Default::default(),
},
contract: Contract { plan, tokens: 0 },
from: Default::default(),
last_id: Default::default(),
sig: Default::default(),
};
let buf = serialize(&claim0).unwrap();
Expand All @@ -172,9 +166,9 @@ mod tests {
let keypair = KeyPair::new();
let pubkey = keypair.pubkey();
let mut tr = Transaction::new(&keypair, pubkey, 42, zero);
tr.data.tokens = 1_000_000; // <-- attack, part 1!
if let Plan::Pay(ref mut payment) = tr.data.plan {
payment.tokens = tr.data.tokens; // <-- attack, part 2!
tr.contract.tokens = 1_000_000; // <-- attack, part 1!
if let Plan::Pay(ref mut payment) = tr.contract.plan {
payment.tokens = tr.contract.tokens; // <-- attack, part 2!
};
assert!(tr.verify_plan());
assert!(!tr.verify_sig());
Expand All @@ -188,7 +182,7 @@ mod tests {
let pubkey1 = keypair1.pubkey();
let zero = Hash::default();
let mut tr = Transaction::new(&keypair0, pubkey1, 42, zero);
if let Plan::Pay(ref mut payment) = tr.data.plan {
if let Plan::Pay(ref mut payment) = tr.contract.plan {
payment.to = thief_keypair.pubkey(); // <-- attack!
};
assert!(tr.verify_plan());
Expand All @@ -210,13 +204,13 @@ mod tests {
let keypair1 = KeyPair::new();
let zero = Hash::default();
let mut tr = Transaction::new(&keypair0, keypair1.pubkey(), 1, zero);
if let Plan::Pay(ref mut payment) = tr.data.plan {
if let Plan::Pay(ref mut payment) = tr.contract.plan {
payment.tokens = 2; // <-- attack!
}
assert!(!tr.verify_plan());

// Also, ensure all branchs of the plan spend all tokens
if let Plan::Pay(ref mut payment) = tr.data.plan {
if let Plan::Pay(ref mut payment) = tr.contract.plan {
payment.tokens = 0; // <-- whoops!
}
assert!(!tr.verify_plan());
Expand Down