ethcore: handle vm exception when estimating gas (#9615)

This commit is contained in:
André Silva 2018-09-25 12:35:07 +01:00 committed by Marek Kotewicz
parent 8875dccd11
commit 375ecd4ada

View File

@ -1492,7 +1492,7 @@ impl Call for Client {
let sender = t.sender(); let sender = t.sender();
let options = || TransactOptions::with_tracing().dont_check_nonce(); let options = || TransactOptions::with_tracing().dont_check_nonce();
let cond = |gas| { let exec = |gas| {
let mut tx = t.as_unsigned().clone(); let mut tx = t.as_unsigned().clone();
tx.gas = gas; tx.gas = gas;
let tx = tx.fake_sign(sender); let tx = tx.fake_sign(sender);
@ -1500,22 +1500,28 @@ impl Call for Client {
let mut clone = state.clone(); let mut clone = state.clone();
let machine = self.engine.machine(); let machine = self.engine.machine();
let schedule = machine.schedule(env_info.number); let schedule = machine.schedule(env_info.number);
Ok(Executive::new(&mut clone, &env_info, &machine, &schedule) Executive::new(&mut clone, &env_info, &machine, &schedule)
.transact_virtual(&tx, options()) .transact_virtual(&tx, options())
.ok()
.map(|r| r.exception.is_none()) .map(|r| r.exception.is_none())
.unwrap_or(false))
}; };
if !cond(upper)? { let cond = |gas| exec(gas).unwrap_or(false);
if !cond(upper) {
upper = max_upper; upper = max_upper;
if !cond(upper)? { match exec(upper) {
trace!(target: "estimate_gas", "estimate_gas failed with {}", upper); Some(false) => return Err(CallError::Exceptional),
let err = ExecutionError::Internal(format!("Requires higher than upper limit of {}", upper)); None => {
return Err(err.into()) trace!(target: "estimate_gas", "estimate_gas failed with {}", upper);
let err = ExecutionError::Internal(format!("Requires higher than upper limit of {}", upper));
return Err(err.into())
},
_ => {},
} }
} }
let lower = t.gas_required(&self.engine.schedule(env_info.number)).into(); let lower = t.gas_required(&self.engine.schedule(env_info.number)).into();
if cond(lower)? { if cond(lower) {
trace!(target: "estimate_gas", "estimate_gas succeeded with {}", lower); trace!(target: "estimate_gas", "estimate_gas succeeded with {}", lower);
return Ok(lower) return Ok(lower)
} }
@ -1524,12 +1530,12 @@ impl Call for Client {
/// Returns the lowest value between `lower` and `upper` for which `cond` returns true. /// Returns the lowest value between `lower` and `upper` for which `cond` returns true.
/// We assert: `cond(lower) = false`, `cond(upper) = true` /// We assert: `cond(lower) = false`, `cond(upper) = true`
fn binary_chop<F, E>(mut lower: U256, mut upper: U256, mut cond: F) -> Result<U256, E> fn binary_chop<F, E>(mut lower: U256, mut upper: U256, mut cond: F) -> Result<U256, E>
where F: FnMut(U256) -> Result<bool, E> where F: FnMut(U256) -> bool
{ {
while upper - lower > 1.into() { while upper - lower > 1.into() {
let mid = (lower + upper) / 2; let mid = (lower + upper) / 2;
trace!(target: "estimate_gas", "{} .. {} .. {}", lower, mid, upper); trace!(target: "estimate_gas", "{} .. {} .. {}", lower, mid, upper);
let c = cond(mid)?; let c = cond(mid);
match c { match c {
true => upper = mid, true => upper = mid,
false => lower = mid, false => lower = mid,