diff --git a/src/bank.rs b/src/bank.rs index 35aa30aacb..8fee843eb6 100644 --- a/src/bank.rs +++ b/src/bank.rs @@ -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"); @@ -170,7 +170,7 @@ 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); } @@ -178,14 +178,14 @@ impl Bank { 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, ); @@ -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"))); diff --git a/src/bin/testnode.rs b/src/bin/testnode.rs index 864d668fe3..1907589cbd 100644 --- a/src/bin/testnode.rs +++ b/src/bin/testnode.rs @@ -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 }; diff --git a/src/mint.rs b/src/mint.rs index 53c7e3cca4..8b1cb2ed9c 100644 --- a/src/mint.rs +++ b/src/mint.rs @@ -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); } } diff --git a/src/thin_client.rs b/src/thin_client.rs index 63899ed6fa..b5632c9ae3 100644 --- a/src/thin_client.rs +++ b/src/thin_client.rs @@ -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); diff --git a/src/transaction.rs b/src/transaction.rs index ef2acccae4..0c08d032b0 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -12,9 +12,8 @@ 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, } @@ -22,7 +21,8 @@ pub struct TransactionData { pub struct Transaction { pub sig: Signature, pub from: PublicKey, - pub data: TransactionData, + pub contract: Contract, + pub last_id: Hash, } impl Transaction { @@ -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 @@ -57,12 +54,9 @@ 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); @@ -70,7 +64,10 @@ impl Transaction { } fn get_sign_data(&self) -> Vec { - 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. @@ -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) } } @@ -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(); @@ -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()); @@ -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()); @@ -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());