Merge pull request #892 from ethcore/eth-call-fix

Fixed eth_call nonce and gas handling
This commit is contained in:
Nikolay Volf 2016-04-06 15:54:58 +04:00
commit b671cbd71f
4 changed files with 35 additions and 14 deletions

View File

@ -38,7 +38,7 @@ use block_queue::{BlockQueue, BlockQueueInfo};
use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute}; use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute};
use client::{BlockId, TransactionId, UncleId, ClientConfig, BlockChainClient}; use client::{BlockId, TransactionId, UncleId, ClientConfig, BlockChainClient};
use env_info::EnvInfo; use env_info::EnvInfo;
use executive::{Executive, Executed, contract_address}; use executive::{Executive, Executed, TransactOptions, contract_address};
use receipt::LocalizedReceipt; use receipt::LocalizedReceipt;
pub use blockchain::CacheSize as BlockChainCacheSize; pub use blockchain::CacheSize as BlockChainCacheSize;
@ -418,7 +418,8 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
// give the sender max balance // give the sender max balance
state.sub_balance(&sender, &balance); state.sub_balance(&sender, &balance);
state.add_balance(&sender, &U256::max_value()); state.add_balance(&sender, &U256::max_value());
Executive::new(&mut state, &env_info, self.engine.deref().deref()).transact(t, false) let options = TransactOptions { tracing: false, check_nonce: false };
Executive::new(&mut state, &env_info, self.engine.deref().deref()).transact(t, options)
} }
// TODO [todr] Should be moved to miner crate eventually. // TODO [todr] Should be moved to miner crate eventually.

View File

@ -36,6 +36,14 @@ pub fn contract_address(address: &Address, nonce: &U256) -> Address {
From::from(stream.out().sha3()) From::from(stream.out().sha3())
} }
/// Transaction execution options.
pub struct TransactOptions {
/// Enable call tracing.
pub tracing: bool,
/// Check transaction nonce before execution.
pub check_nonce: bool,
}
/// Transaction execution receipt. /// Transaction execution receipt.
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub struct Executed { pub struct Executed {
@ -110,7 +118,7 @@ impl<'a> Executive<'a> {
} }
/// This funtion should be used to execute transaction. /// This funtion should be used to execute transaction.
pub fn transact(&'a mut self, t: &SignedTransaction, tracing: bool) -> Result<Executed, Error> { pub fn transact(&'a mut self, t: &SignedTransaction, options: TransactOptions) -> Result<Executed, Error> {
let sender = try!(t.sender()); let sender = try!(t.sender());
let nonce = self.state.nonce(&sender); let nonce = self.state.nonce(&sender);
@ -124,8 +132,10 @@ impl<'a> Executive<'a> {
let init_gas = t.gas - base_gas_required; let init_gas = t.gas - base_gas_required;
// validate transaction nonce // validate transaction nonce
if t.nonce != nonce { if options.check_nonce {
return Err(From::from(ExecutionError::InvalidNonce { expected: nonce, got: t.nonce })); if t.nonce != nonce {
return Err(From::from(ExecutionError::InvalidNonce { expected: nonce, got: t.nonce }));
}
} }
// validate if transaction fits into given block // validate if transaction fits into given block
@ -151,7 +161,7 @@ impl<'a> Executive<'a> {
self.state.inc_nonce(&sender); self.state.inc_nonce(&sender);
self.state.sub_balance(&sender, &U256::from(gas_cost)); self.state.sub_balance(&sender, &U256::from(gas_cost));
let mut substate = Substate::new(tracing); let mut substate = Substate::new(options.tracing);
let (gas_left, output) = match t.action { let (gas_left, output) = match t.action {
Action::Create => { Action::Create => {
@ -881,7 +891,8 @@ mod tests {
let executed = { let executed = {
let mut ex = Executive::new(&mut state, &info, &engine); let mut ex = Executive::new(&mut state, &info, &engine);
ex.transact(&t, false).unwrap() let opts = TransactOptions { check_nonce: true, tracing: false };
ex.transact(&t, opts).unwrap()
}; };
assert_eq!(executed.gas, U256::from(100_000)); assert_eq!(executed.gas, U256::from(100_000));
@ -914,7 +925,8 @@ mod tests {
let res = { let res = {
let mut ex = Executive::new(&mut state, &info, &engine); let mut ex = Executive::new(&mut state, &info, &engine);
ex.transact(&t, false) let opts = TransactOptions { check_nonce: true, tracing: false };
ex.transact(&t, opts)
}; };
match res { match res {
@ -945,7 +957,8 @@ mod tests {
let res = { let res = {
let mut ex = Executive::new(&mut state, &info, &engine); let mut ex = Executive::new(&mut state, &info, &engine);
ex.transact(&t, false) let opts = TransactOptions { check_nonce: true, tracing: false };
ex.transact(&t, opts)
}; };
match res { match res {
@ -978,7 +991,8 @@ mod tests {
let res = { let res = {
let mut ex = Executive::new(&mut state, &info, &engine); let mut ex = Executive::new(&mut state, &info, &engine);
ex.transact(&t, false) let opts = TransactOptions { check_nonce: true, tracing: false };
ex.transact(&t, opts)
}; };
match res { match res {
@ -1011,7 +1025,8 @@ mod tests {
let res = { let res = {
let mut ex = Executive::new(&mut state, &info, &engine); let mut ex = Executive::new(&mut state, &info, &engine);
ex.transact(&t, false) let opts = TransactOptions { check_nonce: true, tracing: false };
ex.transact(&t, opts)
}; };
match res { match res {

View File

@ -16,7 +16,7 @@
use common::*; use common::*;
use engine::Engine; use engine::Engine;
use executive::Executive; use executive::{Executive, TransactOptions};
use account_db::*; use account_db::*;
#[cfg(test)] #[cfg(test)]
#[cfg(feature = "json-tests")] #[cfg(feature = "json-tests")]
@ -220,7 +220,8 @@ impl State {
pub fn apply(&mut self, env_info: &EnvInfo, engine: &Engine, t: &SignedTransaction, tracing: bool) -> ApplyResult { pub fn apply(&mut self, env_info: &EnvInfo, engine: &Engine, t: &SignedTransaction, tracing: bool) -> ApplyResult {
// let old = self.to_pod(); // let old = self.to_pod();
let e = try!(Executive::new(self, env_info, engine).transact(t, tracing)); let options = TransactOptions { tracing: tracing, check_nonce: true };
let e = try!(Executive::new(self, env_info, engine).transact(t, options));
// TODO uncomment once to_pod() works correctly. // TODO uncomment once to_pod() works correctly.
// trace!("Applied transaction. Diff:\n{}\n", StateDiff::diff_pod(&old, &self.to_pod())); // trace!("Applied transaction. Diff:\n{}\n", StateDiff::diff_pod(&old, &self.to_pod()));

View File

@ -43,6 +43,10 @@ fn default_gas() -> U256 {
U256::from(21_000) U256::from(21_000)
} }
fn default_call_gas() -> U256 {
U256::from(50_000_000)
}
/// Eth rpc implementation. /// Eth rpc implementation.
pub struct EthClient<C, S, A, M, EM = ExternalMiner> pub struct EthClient<C, S, A, M, EM = ExternalMiner>
where C: BlockChainClient, where C: BlockChainClient,
@ -175,7 +179,7 @@ impl<C, S, A, M, EM> EthClient<C, S, A, M, EM>
Ok(EthTransaction { Ok(EthTransaction {
nonce: request.nonce.unwrap_or_else(|| client.nonce(&from)), nonce: request.nonce.unwrap_or_else(|| client.nonce(&from)),
action: request.to.map_or(Action::Create, Action::Call), action: request.to.map_or(Action::Create, Action::Call),
gas: request.gas.unwrap_or_else(default_gas), gas: request.gas.unwrap_or_else(default_call_gas),
gas_price: request.gas_price.unwrap_or_else(|| miner.sensible_gas_price()), gas_price: request.gas_price.unwrap_or_else(|| miner.sensible_gas_price()),
value: request.value.unwrap_or_else(U256::zero), value: request.value.unwrap_or_else(U256::zero),
data: request.data.map_or_else(Vec::new, |d| d.to_vec()) data: request.data.map_or_else(Vec::new, |d| d.to_vec())