fix(rpc): cap request gas limit if not set (#1858)

Co-authored-by: Dan Cline <6798349+Rjected@users.noreply.github.com>
This commit is contained in:
Matthias Seitz
2023-03-20 15:44:28 +01:00
committed by GitHub
parent f926ee8af4
commit bd8ff152b7
3 changed files with 36 additions and 2 deletions

View File

@ -28,3 +28,12 @@ pub struct CallRequest {
/// AccessList
pub access_list: Option<AccessList>,
}
impl CallRequest {
/// Returns the configured fee cap, if any.
///
/// The returns `gas_price` (legacy) if set or `max_fee_per_gas` (EIP1559)
pub fn fee_cap(&self) -> Option<U256> {
self.gas_price.or(self.max_fee_per_gas)
}
}

View File

@ -68,7 +68,10 @@ where
// impls and providers <https://github.com/foundry-rs/foundry/issues/4388>
cfg.disable_block_gas_limit = true;
let env = build_call_evm_env(cfg, block, request)?;
let request_gas = request.gas;
let mut env = build_call_evm_env(cfg, block, request)?;
let mut db = SubState::new(State::new(state));
// apply state overrides
@ -76,6 +79,23 @@ where
apply_state_overrides(state_overrides, &mut db)?;
}
if request_gas.is_none() && env.tx.gas_price > U256::ZERO {
// no gas limit was provided in the request, so we need to cap the request's gas limit
let mut allowance = db.basic(env.tx.caller)?.map(|acc| acc.balance).unwrap_or_default();
// subtract transferred value
allowance = allowance
.checked_sub(env.tx.value)
.ok_or_else(|| InvalidTransactionError::InsufficientFunds)?;
// cap the gas limit
if let Ok(gas_limit) =
allowance.checked_div(env.tx.gas_price).unwrap_or_default().try_into()
{
env.tx.gas_limit = gas_limit;
}
}
transact(&mut db, env)
}

View File

@ -57,7 +57,9 @@ where
Ok((res, evm.env))
}
/// Creates a new [Env] to be used for executing the [CallRequest] in `eth_call`
/// Creates a new [Env] to be used for executing the [CallRequest] in `eth_call`.
///
/// Note: this does _not_ access the Database to check the sender.
pub(crate) fn build_call_evm_env(
cfg: CfgEnv,
block: BlockEnv,
@ -68,6 +70,9 @@ pub(crate) fn build_call_evm_env(
}
/// Configures a new [TxEnv] for the [CallRequest]
///
/// All [TxEnv] fields are derived from the given [CallRequest], if fields are `None`, they fall
/// back to the [BlockEnv]'s settings.
pub(crate) fn create_txn_env(block_env: &BlockEnv, request: CallRequest) -> EthResult<TxEnv> {
let CallRequest {
from,