Skip to content

Commit

Permalink
fix(anvil): properly estimate gas instead of bailing on GasTooHigh (#…
Browse files Browse the repository at this point in the history
…4861)

* fix: use appropiate GasTooHigh error instead of FatalExternalError

* feat: refactor gas estimation bsearch to treat gastoohigh properly

* chore: clippy happy
  • Loading branch information
Evalir authored May 1, 2023
1 parent 91f69dd commit e15e33a
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 27 deletions.
71 changes: 46 additions & 25 deletions anvil/src/eth/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2076,40 +2076,61 @@ impl EthApi {

let mut last_highest_gas_limit = highest_gas_limit;

// Binary search for the ideal gas limit
while (highest_gas_limit - lowest_gas_limit) > U256::one() {
request.gas = Some(mid_gas_limit);
let (exit, _, _gas, _) = self.backend.call_with_state(
match self.backend.call_with_state(
&state,
request.clone(),
fees.clone(),
block_env.clone(),
)?;
match exit {
return_ok!() => {
highest_gas_limit = mid_gas_limit;
// if last two successful estimations only vary by 10%, we consider this to
// sufficiently accurate
const ACCURACY: u64 = 10;
if (last_highest_gas_limit - highest_gas_limit) * ACCURACY /
last_highest_gas_limit <
U256::one()
{
return Ok(highest_gas_limit)
) {
Ok((exit, _, _gas, _)) => {
match exit {
return_ok!() => {
highest_gas_limit = mid_gas_limit;
// if last two successful estimations only vary by 10%, we consider this
// to sufficiently accurate
const ACCURACY: u64 = 10;
if (last_highest_gas_limit - highest_gas_limit) * ACCURACY /
last_highest_gas_limit <
U256::one()
{
return Ok(highest_gas_limit)
}
last_highest_gas_limit = highest_gas_limit;
}
InstructionResult::Revert |
InstructionResult::OutOfGas |
InstructionResult::OutOfFund => {
lowest_gas_limit = mid_gas_limit;
}
reason => {
warn!(target: "node", "estimation failed due to {:?}", reason);
return Err(BlockchainError::EvmError(reason))
}
}
last_highest_gas_limit = highest_gas_limit;
}
InstructionResult::Revert |
InstructionResult::OutOfGas |
InstructionResult::OutOfFund => {
lowest_gas_limit = mid_gas_limit;
// new midpoint
mid_gas_limit = (highest_gas_limit + lowest_gas_limit) / 2;
}
reason => {
warn!(target: "node", "estimation failed due to {:?}", reason);
return Err(BlockchainError::EvmError(reason))
Err(reason) => {
match reason {
// We need to treat REVM reverting due to gas too high just like
// revert/OOG/OOF (see above)
BlockchainError::InvalidTransaction(
InvalidTransactionError::GasTooHigh,
) => {
lowest_gas_limit = mid_gas_limit;
}
_ => {
warn!(target: "node", "estimation failed due to {:?}", reason);
return Err(reason)
}
};
// new midpoint
mid_gas_limit = (highest_gas_limit + lowest_gas_limit) / 2;
}
}
// new midpoint
mid_gas_limit = (highest_gas_limit + lowest_gas_limit) / 2;
};
}

trace!(target : "node", "Estimated Gas for call {:?}", highest_gas_limit);
Expand Down
4 changes: 3 additions & 1 deletion anvil/src/eth/backend/mem/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -999,7 +999,9 @@ impl Backend {
evm.database(state);
let result_and_state = match evm.inspect_ref(&mut inspector) {
Ok(result_and_state) => result_and_state,
Err(_) => return Err(BlockchainError::EvmError(InstructionResult::FatalExternalError)),
Err(_) => {
return Err(BlockchainError::InvalidTransaction(InvalidTransactionError::GasTooHigh))
}
};
let state = result_and_state.state;
let state: hashbrown::HashMap<H160, Account> =
Expand Down
2 changes: 1 addition & 1 deletion forge/src/gas_report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ impl GasReport {
(!self.ignore.contains(&contract_name) && self.report_for.is_empty()) ||
(self.report_for.contains(&contract_name));
if report_contract {
let mut contract_report =
let contract_report =
self.contracts.entry(name.to_string()).or_insert_with(Default::default);

match &trace.data {
Expand Down

0 comments on commit e15e33a

Please sign in to comment.