From 08074ef39739ec8f76a37fcbb0a77c7622d2dbb6 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 12 Jan 2016 17:40:34 +0100 Subject: [PATCH] Use U512s for ether cost calculation. --- src/error.rs | 2 +- src/executive.rs | 10 +++++----- src/transaction.rs | 22 +++++++++++++++------- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/error.rs b/src/error.rs index 3e7d3eb6d..01618c66c 100644 --- a/src/error.rs +++ b/src/error.rs @@ -28,7 +28,7 @@ pub enum ExecutionError { InvalidNonce { expected: U256, is: U256 }, /// Returned when cost of transaction (value + gas_price * gas) exceeds /// current sender balance. - NotEnoughCash { required: U256, is: U256 }, + NotEnoughCash { required: U512, is: U512 }, /// Returned when internal evm error occurs. Internal } diff --git a/src/executive.rs b/src/executive.rs index 4e829cdd5..2527209c1 100644 --- a/src/executive.rs +++ b/src/executive.rs @@ -123,17 +123,17 @@ impl<'a> Executive<'a> { // TODO: we might need bigints here, or at least check overflows. let balance = self.state.balance(&sender); - let gas_cost = t.gas * t.gas_price; - let total_cost = t.value + gas_cost; + let gas_cost = U512::from(t.gas) * U512::from(t.gas_price); + let total_cost = U512::from(t.value) + gas_cost; // avoid unaffordable transactions - if balance < total_cost { - return Err(From::from(ExecutionError::NotEnoughCash { required: total_cost, is: balance })); + if U512::from(balance) < total_cost { + return Err(From::from(ExecutionError::NotEnoughCash { required: total_cost, is: U512::from(balance) })); } // NOTE: there can be no invalid transactions from this point. self.state.inc_nonce(&sender); - self.state.sub_balance(&sender, &gas_cost); + self.state.sub_balance(&sender, &U256::from(gas_cost)); let mut substate = Substate::new(); let backup = self.state.clone(); diff --git a/src/transaction.rs b/src/transaction.rs index 661c1355f..e67add169 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -90,25 +90,33 @@ impl Transaction { /// Returns transaction sender. pub fn sender(&self) -> Result { Ok(From::from(try!(ec::recover(&self.signature(), &self.message_hash())).sha3())) } + /// Signs the transaction as coming from `sender`. + pub fn sign(&mut self, secret: &Secret) { + let sig = ec::sign(secret, &self.message_hash()); + let (r, s, v) = sig.unwrap().to_rsv(); + self.r = r; + self.s = s; + self.v = v; + } + /// Get the transaction cost in gas for the given params. - pub fn gas_required_for(is_create: bool, data: &[u8], schedule: &Schedule) -> U256 { - // CRITICAL TODO XXX FIX NEED BIGINT!!!!! + pub fn gas_required_for(is_create: bool, data: &[u8], schedule: &Schedule) -> u64 { data.iter().fold( - U256::from(if is_create {schedule.tx_create_gas} else {schedule.tx_gas}), - |g, b| g + U256::from(match *b { 0 => schedule.tx_data_zero_gas, _ => schedule.tx_data_non_zero_gas}) + (if is_create {schedule.tx_create_gas} else {schedule.tx_gas}) as u64, + |g, b| g + (match *b { 0 => schedule.tx_data_zero_gas, _ => schedule.tx_data_non_zero_gas }) as u64 ) } /// Get the transaction cost in gas for this transaction. - pub fn gas_required(&self, schedule: &Schedule) -> U256 { + pub fn gas_required(&self, schedule: &Schedule) -> u64 { Self::gas_required_for(match self.action{Action::Create=>true, Action::Call(_)=>false}, &self.data, schedule) } /// Do basic validation, checking for valid signature and minimum gas, pub fn validate(self, schedule: &Schedule) -> Result { try!(self.sender()); - if self.gas < self.gas_required(&schedule) { - Err(From::from(TransactionError::InvalidGasLimit(OutOfBounds{min: Some(self.gas_required(&schedule)), max: None, found: self.gas}))) + if self.gas < U256::from(self.gas_required(&schedule)) { + Err(From::from(TransactionError::InvalidGasLimit(OutOfBounds{min: Some(U256::from(self.gas_required(&schedule))), max: None, found: self.gas}))) } else { Ok(self) }