diff --git a/src/error.rs b/src/error.rs index 01618c66c..e3d880103 100644 --- a/src/error.rs +++ b/src/error.rs @@ -19,16 +19,19 @@ pub struct OutOfBounds { /// Result of executing the transaction. #[derive(PartialEq, Debug)] pub enum ExecutionError { + /// Returned when there gas paid for transaction execution is + /// lower than base gas required. + NotEnoughBaseGas { required: U256, got: U256 }, /// Returned when block (gas_used + gas) > gas_limit. /// /// If gas =< gas_limit, upstream may try to execute the transaction /// in next block. BlockGasLimitReached { gas_limit: U256, gas_used: U256, gas: U256 }, /// Returned when transaction nonce does not match state nonce. - InvalidNonce { expected: U256, is: U256 }, + InvalidNonce { expected: U256, got: U256 }, /// Returned when cost of transaction (value + gas_price * gas) exceeds /// current sender balance. - NotEnoughCash { required: U512, is: U512 }, + NotEnoughCash { required: U512, got: U512 }, /// Returned when internal evm error occurs. Internal } diff --git a/src/executive.rs b/src/executive.rs index 3fc942afe..3251763f4 100644 --- a/src/executive.rs +++ b/src/executive.rs @@ -109,11 +109,18 @@ impl<'a> Executive<'a> { let sender = try!(t.sender()); let nonce = self.state.nonce(&sender); - // TODO: error on base gas required + let schedule = self.engine.schedule(self.info); + let base_gas_required = U256::from(t.gas_required(&schedule)); + + if t.gas < base_gas_required { + return Err(From::from(ExecutionError::NotEnoughBaseGas { required: base_gas_required, got: t.gas })); + } + + let init_gas = t.gas - base_gas_required; // validate transaction nonce if t.nonce != nonce { - return Err(From::from(ExecutionError::InvalidNonce { expected: nonce, is: t.nonce })); + return Err(From::from(ExecutionError::InvalidNonce { expected: nonce, got: t.nonce })); } // validate if transaction fits into given block @@ -132,7 +139,7 @@ impl<'a> Executive<'a> { // avoid unaffordable transactions if U512::from(balance) < total_cost { - return Err(From::from(ExecutionError::NotEnoughCash { required: total_cost, is: U512::from(balance) })); + return Err(From::from(ExecutionError::NotEnoughCash { required: total_cost, got: U512::from(balance) })); } // NOTE: there can be no invalid transactions from this point. @@ -141,9 +148,6 @@ impl<'a> Executive<'a> { let mut substate = Substate::new(); - let schedule = self.engine.schedule(self.info); - let init_gas = t.gas - U256::from(t.gas_required(&schedule)); - let res = match t.action() { &Action::Create => { let params = ActionParams { @@ -937,8 +941,8 @@ mod tests { }; match res { - Err(Error::Execution(ExecutionError::InvalidNonce { expected, is })) - if expected == U256::zero() && is == U256::one() => (), + Err(Error::Execution(ExecutionError::InvalidNonce { expected, got })) + if expected == U256::zero() && got == U256::one() => (), _ => assert!(false, "Expected invalid nonce error.") } } @@ -988,8 +992,8 @@ mod tests { }; match res { - Err(Error::Execution(ExecutionError::NotEnoughCash { required , is })) - if required == U512::from(100_018) && is == U512::from(100_017) => (), + Err(Error::Execution(ExecutionError::NotEnoughCash { required , got })) + if required == U512::from(100_018) && got == U512::from(100_017) => (), _ => assert!(false, "Expected not enough cash error. {:?}", res) } }