Improvements and optimisations to estimate_gas (#4142)
* Return 0 instead of error with out of gas on estimate_gas * Fix stuff up. * Another estimate gas fix. * Alter balance to maximum possible rather than GP=0. * Only increase to amount strictly necessary. * Improvements and optimisations to estimate_gas. - Introduce proper error type - Avoid building costly traces * Fix tests. * Actually fix testsActually fix tests
This commit is contained in:
parent
41da1a0a79
commit
311730ea95
@ -908,7 +908,7 @@ impl BlockChainClient for Client {
|
|||||||
|
|
||||||
Executive::new(&mut state, &env_info, &*self.engine, &self.factories.vm)
|
Executive::new(&mut state, &env_info, &*self.engine, &self.factories.vm)
|
||||||
.transact(&tx, options.clone())
|
.transact(&tx, options.clone())
|
||||||
.map(|r| r.trace[0].result.succeeded())
|
.map(|r| r.exception.is_some())
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ use action_params::ActionParams;
|
|||||||
use evm::Ext;
|
use evm::Ext;
|
||||||
|
|
||||||
/// Evm errors.
|
/// Evm errors.
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// `OutOfGas` is returned when transaction execution runs out of gas.
|
/// `OutOfGas` is returned when transaction execution runs out of gas.
|
||||||
/// The state should be reverted to the state from before the
|
/// The state should be reverted to the state from before the
|
||||||
|
@ -463,8 +463,9 @@ impl<'a> Executive<'a> {
|
|||||||
|
|
||||||
match result {
|
match result {
|
||||||
Err(evm::Error::Internal) => Err(ExecutionError::Internal),
|
Err(evm::Error::Internal) => Err(ExecutionError::Internal),
|
||||||
Err(_) => {
|
Err(exception) => {
|
||||||
Ok(Executed {
|
Ok(Executed {
|
||||||
|
exception: Some(exception),
|
||||||
gas: t.gas,
|
gas: t.gas,
|
||||||
gas_used: t.gas,
|
gas_used: t.gas,
|
||||||
refunded: U256::zero(),
|
refunded: U256::zero(),
|
||||||
@ -479,6 +480,7 @@ impl<'a> Executive<'a> {
|
|||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
Ok(Executed {
|
Ok(Executed {
|
||||||
|
exception: None,
|
||||||
gas: t.gas,
|
gas: t.gas,
|
||||||
gas_used: gas_used,
|
gas_used: gas_used,
|
||||||
refunded: refunded,
|
refunded: refunded,
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
use util::{Bytes, U256, Address, U512};
|
use util::{Bytes, U256, Address, U512};
|
||||||
use rlp::*;
|
use rlp::*;
|
||||||
|
use evm;
|
||||||
use trace::{VMTrace, FlatTrace};
|
use trace::{VMTrace, FlatTrace};
|
||||||
use types::log_entry::LogEntry;
|
use types::log_entry::LogEntry;
|
||||||
use types::state_diff::StateDiff;
|
use types::state_diff::StateDiff;
|
||||||
@ -65,6 +66,9 @@ impl Decodable for CallType {
|
|||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
#[cfg_attr(feature = "ipc", binary)]
|
#[cfg_attr(feature = "ipc", binary)]
|
||||||
pub struct Executed {
|
pub struct Executed {
|
||||||
|
/// True if the outer call/create resulted in an exceptional exit.
|
||||||
|
pub exception: Option<evm::Error>,
|
||||||
|
|
||||||
/// Gas paid up front for execution of transaction.
|
/// Gas paid up front for execution of transaction.
|
||||||
pub gas: U256,
|
pub gas: U256,
|
||||||
|
|
||||||
@ -178,6 +182,8 @@ pub enum CallError {
|
|||||||
TransactionNotFound,
|
TransactionNotFound,
|
||||||
/// Couldn't find requested block's state in the chain.
|
/// Couldn't find requested block's state in the chain.
|
||||||
StatePruned,
|
StatePruned,
|
||||||
|
/// Couldn't find an amount of gas that didn't result in an exception.
|
||||||
|
Exceptional,
|
||||||
/// Error executing.
|
/// Error executing.
|
||||||
Execution(ExecutionError),
|
Execution(ExecutionError),
|
||||||
}
|
}
|
||||||
@ -195,6 +201,7 @@ impl fmt::Display for CallError {
|
|||||||
let msg = match *self {
|
let msg = match *self {
|
||||||
TransactionNotFound => "Transaction couldn't be found in the chain".into(),
|
TransactionNotFound => "Transaction couldn't be found in the chain".into(),
|
||||||
StatePruned => "Couldn't find the transaction block's state in the chain".into(),
|
StatePruned => "Couldn't find the transaction block's state in the chain".into(),
|
||||||
|
Exceptional => "An exception happened in the execution".into(),
|
||||||
Execution(ref e) => format!("{}", e),
|
Execution(ref e) => format!("{}", e),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@ mod codes {
|
|||||||
pub const UNKNOWN_ERROR: i64 = -32009;
|
pub const UNKNOWN_ERROR: i64 = -32009;
|
||||||
pub const TRANSACTION_ERROR: i64 = -32010;
|
pub const TRANSACTION_ERROR: i64 = -32010;
|
||||||
pub const EXECUTION_ERROR: i64 = -32015;
|
pub const EXECUTION_ERROR: i64 = -32015;
|
||||||
|
pub const EXCEPTION_ERROR: i64 = -32016;
|
||||||
pub const ACCOUNT_LOCKED: i64 = -32020;
|
pub const ACCOUNT_LOCKED: i64 = -32020;
|
||||||
pub const PASSWORD_INVALID: i64 = -32021;
|
pub const PASSWORD_INVALID: i64 = -32021;
|
||||||
pub const ACCOUNT_ERROR: i64 = -32023;
|
pub const ACCOUNT_ERROR: i64 = -32023;
|
||||||
@ -130,6 +131,14 @@ pub fn state_pruned() -> Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn exceptional() -> Error {
|
||||||
|
Error {
|
||||||
|
code: ErrorCode::ServerError(codes::EXCEPTION_ERROR),
|
||||||
|
message: "The execution failed due to an exception.".into(),
|
||||||
|
data: None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn no_work() -> Error {
|
pub fn no_work() -> Error {
|
||||||
Error {
|
Error {
|
||||||
code: ErrorCode::ServerError(codes::NO_WORK),
|
code: ErrorCode::ServerError(codes::NO_WORK),
|
||||||
@ -286,6 +295,7 @@ pub fn from_rlp_error(error: DecoderError) -> Error {
|
|||||||
pub fn from_call_error(error: CallError) -> Error {
|
pub fn from_call_error(error: CallError) -> Error {
|
||||||
match error {
|
match error {
|
||||||
CallError::StatePruned => state_pruned(),
|
CallError::StatePruned => state_pruned(),
|
||||||
|
CallError::Exceptional => exceptional(),
|
||||||
CallError::Execution(e) => execution(e),
|
CallError::Execution(e) => execution(e),
|
||||||
CallError::TransactionNotFound => internal("{}, this should not be the case with eth_call, most likely a bug.", CallError::TransactionNotFound),
|
CallError::TransactionNotFound => internal("{}, this should not be the case with eth_call, most likely a bug.", CallError::TransactionNotFound),
|
||||||
}
|
}
|
||||||
|
@ -564,6 +564,7 @@ fn rpc_eth_code() {
|
|||||||
fn rpc_eth_call_latest() {
|
fn rpc_eth_call_latest() {
|
||||||
let tester = EthTester::default();
|
let tester = EthTester::default();
|
||||||
tester.client.set_execution_result(Ok(Executed {
|
tester.client.set_execution_result(Ok(Executed {
|
||||||
|
exception: None,
|
||||||
gas: U256::zero(),
|
gas: U256::zero(),
|
||||||
gas_used: U256::from(0xff30),
|
gas_used: U256::from(0xff30),
|
||||||
refunded: U256::from(0x5),
|
refunded: U256::from(0x5),
|
||||||
@ -599,6 +600,7 @@ fn rpc_eth_call_latest() {
|
|||||||
fn rpc_eth_call() {
|
fn rpc_eth_call() {
|
||||||
let tester = EthTester::default();
|
let tester = EthTester::default();
|
||||||
tester.client.set_execution_result(Ok(Executed {
|
tester.client.set_execution_result(Ok(Executed {
|
||||||
|
exception: None,
|
||||||
gas: U256::zero(),
|
gas: U256::zero(),
|
||||||
gas_used: U256::from(0xff30),
|
gas_used: U256::from(0xff30),
|
||||||
refunded: U256::from(0x5),
|
refunded: U256::from(0x5),
|
||||||
@ -634,6 +636,7 @@ fn rpc_eth_call() {
|
|||||||
fn rpc_eth_call_default_block() {
|
fn rpc_eth_call_default_block() {
|
||||||
let tester = EthTester::default();
|
let tester = EthTester::default();
|
||||||
tester.client.set_execution_result(Ok(Executed {
|
tester.client.set_execution_result(Ok(Executed {
|
||||||
|
exception: None,
|
||||||
gas: U256::zero(),
|
gas: U256::zero(),
|
||||||
gas_used: U256::from(0xff30),
|
gas_used: U256::from(0xff30),
|
||||||
refunded: U256::from(0x5),
|
refunded: U256::from(0x5),
|
||||||
@ -668,6 +671,7 @@ fn rpc_eth_call_default_block() {
|
|||||||
fn rpc_eth_estimate_gas() {
|
fn rpc_eth_estimate_gas() {
|
||||||
let tester = EthTester::default();
|
let tester = EthTester::default();
|
||||||
tester.client.set_execution_result(Ok(Executed {
|
tester.client.set_execution_result(Ok(Executed {
|
||||||
|
exception: None,
|
||||||
gas: U256::zero(),
|
gas: U256::zero(),
|
||||||
gas_used: U256::from(0xff30),
|
gas_used: U256::from(0xff30),
|
||||||
refunded: U256::from(0x5),
|
refunded: U256::from(0x5),
|
||||||
@ -703,6 +707,7 @@ fn rpc_eth_estimate_gas() {
|
|||||||
fn rpc_eth_estimate_gas_default_block() {
|
fn rpc_eth_estimate_gas_default_block() {
|
||||||
let tester = EthTester::default();
|
let tester = EthTester::default();
|
||||||
tester.client.set_execution_result(Ok(Executed {
|
tester.client.set_execution_result(Ok(Executed {
|
||||||
|
exception: None,
|
||||||
gas: U256::zero(),
|
gas: U256::zero(),
|
||||||
gas_used: U256::from(0xff30),
|
gas_used: U256::from(0xff30),
|
||||||
refunded: U256::from(0x5),
|
refunded: U256::from(0x5),
|
||||||
|
@ -51,6 +51,7 @@ fn io() -> Tester {
|
|||||||
block_hash: 10.into(),
|
block_hash: 10.into(),
|
||||||
}]);
|
}]);
|
||||||
*client.execution_result.write() = Some(Ok(Executed {
|
*client.execution_result.write() = Some(Ok(Executed {
|
||||||
|
exception: None,
|
||||||
gas: 20_000.into(),
|
gas: 20_000.into(),
|
||||||
gas_used: 10_000.into(),
|
gas_used: 10_000.into(),
|
||||||
refunded: 0.into(),
|
refunded: 0.into(),
|
||||||
|
Loading…
Reference in New Issue
Block a user