Skip to content

Commit 9d59ce9

Browse files
authored
fix(sim): use a higher limit for the gas estimation execution gas limit call (#1159)
1 parent 67c55dc commit 9d59ce9

File tree

3 files changed

+103
-50
lines changed

3 files changed

+103
-50
lines changed

bin/rundler/src/cli/mod.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,15 @@ pub struct CommonArgs {
409409
)]
410410
pub call_gas_allowed_error_pct: u128,
411411

412+
#[arg(
413+
long = "max_gas_estimation_gas",
414+
name = "max_gas_estimation_gas",
415+
env = "MAX_GAS_ESTIMATION_GAS",
416+
default_value = "550000000",
417+
global = true
418+
)]
419+
pub max_gas_estimation_gas: u64,
420+
412421
#[arg(
413422
long = "max_gas_estimation_rounds",
414423
name = "max_gas_estimation_rounds",
@@ -555,7 +564,7 @@ impl TryFromWithSpec<&CommonArgs> for EstimationSettings {
555564
> max_bundle_execution_gas.saturating_sub(SIMULATION_GAS_OVERHEAD) as u64
556565
{
557566
anyhow::bail!(
558-
"max_verification_gas ({}) must be less than max_simulate_handle_ops_gas ({}) by at least {}",
567+
"max_verification_gas ({}) must be less than max_bundle_execution_gas ({}) by at least {}",
559568
value.max_verification_gas,
560569
max_bundle_execution_gas,
561570
SIMULATION_GAS_OVERHEAD
@@ -822,6 +831,7 @@ pub fn construct_providers(
822831
chain_spec.clone(),
823832
args.max_verification_gas,
824833
max_bundle_execution_gas,
834+
args.max_gas_estimation_gas,
825835
max_bundle_execution_gas,
826836
provider.clone(),
827837
da_gas_oracle.clone(),
@@ -835,6 +845,7 @@ pub fn construct_providers(
835845
chain_spec.clone(),
836846
args.max_verification_gas,
837847
max_bundle_execution_gas,
848+
args.max_gas_estimation_gas,
838849
max_bundle_execution_gas,
839850
provider.clone(),
840851
da_gas_oracle.clone(),

crates/provider/src/alloy/entry_point/v0_6.rs

Lines changed: 70 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ pub struct EntryPointProvider<AP, D> {
5353
da_gas_oracle: D,
5454
max_verification_gas: u64,
5555
max_simulate_handle_op_gas: u64,
56+
max_gas_estimation_gas: u64,
5657
max_aggregation_gas: u64,
5758
chain_spec: ChainSpec,
5859
}
@@ -67,6 +68,7 @@ where
6768
chain_spec: ChainSpec,
6869
max_verification_gas: u64,
6970
max_simulate_handle_op_gas: u64,
71+
max_gas_estimation_gas: u64,
7072
max_aggregation_gas: u64,
7173
provider: AP,
7274
da_gas_oracle: D,
@@ -79,6 +81,7 @@ where
7981
da_gas_oracle,
8082
max_verification_gas,
8183
max_simulate_handle_op_gas,
84+
max_gas_estimation_gas,
8285
max_aggregation_gas,
8386
chain_spec,
8487
}
@@ -455,40 +458,19 @@ where
455458
target: Address,
456459
target_call_data: Bytes,
457460
block_id: BlockId,
458-
mut state_override: StateOverride,
461+
state_override: StateOverride,
459462
) -> ProviderResult<Result<ExecutionResult, ValidationRevert>> {
460-
let da_gas: u64 = op
461-
.pre_verification_da_gas_limit(&self.chain_spec, Some(1))
462-
.try_into()
463-
.unwrap_or(u64::MAX);
464-
465-
if let Some(authorization) = op.authorization_tuple() {
466-
authorization_utils::apply_7702_overrides(
467-
&mut state_override,
468-
op.sender(),
469-
authorization.address,
470-
);
471-
}
472-
473-
let contract_error = self
474-
.i_entry_point
475-
.simulateHandleOp(op.into(), target, target_call_data)
476-
.block(block_id)
477-
.gas(self.max_simulate_handle_op_gas.saturating_add(da_gas))
478-
.state(state_override)
479-
.call()
480-
.await
481-
.err()
482-
.context("simulateHandleOp succeeded, but should always revert")?;
483-
match contract_error {
484-
ContractError::TransportError(TransportError::ErrorResp(resp)) => {
485-
match resp.as_revert_data() {
486-
Some(err_bytes) => Ok(Self::decode_simulate_handle_ops_revert(&err_bytes)?),
487-
None => Ok(Err(ValidationRevert::Unknown(Bytes::default()))),
488-
}
489-
}
490-
_ => Err(contract_error.into()),
491-
}
463+
simulate_handle_op_inner::<Self, AP>(
464+
&self.chain_spec,
465+
self.max_simulate_handle_op_gas,
466+
&self.i_entry_point,
467+
op,
468+
target,
469+
target_call_data,
470+
block_id,
471+
state_override,
472+
)
473+
.await
492474
}
493475

494476
#[instrument(skip_all)]
@@ -500,8 +482,17 @@ where
500482
block_id: BlockId,
501483
state_override: StateOverride,
502484
) -> ProviderResult<Result<ExecutionResult, ValidationRevert>> {
503-
self.simulate_handle_op(op, target, target_call_data, block_id, state_override)
504-
.await
485+
simulate_handle_op_inner::<Self, AP>(
486+
&self.chain_spec,
487+
self.max_gas_estimation_gas,
488+
&self.i_entry_point,
489+
op,
490+
target,
491+
target_call_data,
492+
block_id,
493+
state_override,
494+
)
495+
.await
505496
}
506497

507498
fn decode_simulate_handle_ops_revert(
@@ -660,6 +651,50 @@ pub fn decode_ops_from_calldata(
660651
}
661652
}
662653

654+
#[allow(clippy::too_many_arguments)]
655+
async fn simulate_handle_op_inner<S: SimulationProvider, AP: AlloyProvider>(
656+
chain_spec: &ChainSpec,
657+
execution_gas_limit: u64,
658+
entry_point: &IEntryPointInstance<AP, AnyNetwork>,
659+
op: UserOperation,
660+
target: Address,
661+
target_call_data: Bytes,
662+
block_id: BlockId,
663+
mut state_override: StateOverride,
664+
) -> ProviderResult<Result<ExecutionResult, ValidationRevert>> {
665+
let da_gas: u64 = op
666+
.pre_verification_da_gas_limit(chain_spec, Some(1))
667+
.try_into()
668+
.unwrap_or(u64::MAX);
669+
670+
if let Some(authorization) = op.authorization_tuple() {
671+
authorization_utils::apply_7702_overrides(
672+
&mut state_override,
673+
op.sender(),
674+
authorization.address,
675+
);
676+
}
677+
678+
let contract_error = entry_point
679+
.simulateHandleOp(op.into(), target, target_call_data)
680+
.block(block_id)
681+
.gas(execution_gas_limit.saturating_add(da_gas))
682+
.state(state_override)
683+
.call()
684+
.await
685+
.err()
686+
.context("simulateHandleOp succeeded, but should always revert")?;
687+
match contract_error {
688+
ContractError::TransportError(TransportError::ErrorResp(resp)) => {
689+
match resp.as_revert_data() {
690+
Some(err_bytes) => Ok(S::decode_simulate_handle_ops_revert(&err_bytes)?),
691+
None => Err(TransportError::ErrorResp(resp).into()),
692+
}
693+
}
694+
_ => Err(contract_error.into()),
695+
}
696+
}
697+
663698
impl TryFrom<ExecutionResultV0_6> for ExecutionResult {
664699
type Error = anyhow::Error;
665700

crates/provider/src/alloy/entry_point/v0_7.rs

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313

1414
use alloy_contract::Error as ContractError;
1515
use alloy_eips::eip7702::SignedAuthorization;
16-
use alloy_json_rpc::ErrorPayload;
1716
use alloy_primitives::{Address, Bytes, U256};
1817
use alloy_provider::network::{AnyNetwork, TransactionBuilder7702};
1918
use alloy_rpc_types_eth::{
@@ -61,6 +60,7 @@ pub struct EntryPointProvider<AP, D> {
6160
da_gas_oracle: D,
6261
max_verification_gas: u64,
6362
max_simulate_handle_ops_gas: u64,
63+
max_gas_estimation_gas: u64,
6464
max_aggregation_gas: u64,
6565
chain_spec: ChainSpec,
6666
}
@@ -74,6 +74,7 @@ where
7474
chain_spec: ChainSpec,
7575
max_verification_gas: u64,
7676
max_simulate_handle_ops_gas: u64,
77+
max_gas_estimation_gas: u64,
7778
max_aggregation_gas: u64,
7879
provider: AP,
7980
da_gas_oracle: D,
@@ -86,6 +87,7 @@ where
8687
da_gas_oracle,
8788
max_verification_gas,
8889
max_simulate_handle_ops_gas,
90+
max_gas_estimation_gas,
8991
max_aggregation_gas,
9092
chain_spec,
9193
}
@@ -500,7 +502,13 @@ where
500502
.context("failed to decode validation result")?;
501503
Ok(Ok(out.try_into().map_err(anyhow::Error::msg)?))
502504
}
503-
Err(TransportError::ErrorResp(resp)) => Ok(Err(decode_validation_revert_payload(resp))),
505+
Err(TransportError::ErrorResp(resp)) => {
506+
if let Some(revert) = resp.as_revert_data() {
507+
Ok(Err(decode_validation_revert(&revert)))
508+
} else {
509+
Err(TransportError::ErrorResp(resp).into())
510+
}
511+
}
504512
Err(error) => Err(error.into()),
505513
}
506514
}
@@ -539,7 +547,7 @@ where
539547
) -> ProviderResult<Result<ExecutionResult, ValidationRevert>> {
540548
simulate_handle_op_inner(
541549
&self.chain_spec,
542-
self.max_simulate_handle_ops_gas,
550+
self.max_gas_estimation_gas,
543551
&self.i_entry_point,
544552
op,
545553
target,
@@ -643,13 +651,6 @@ fn get_handle_ops_call<AP: AlloyProvider>(
643651
txn_request
644652
}
645653

646-
fn decode_validation_revert_payload(err: ErrorPayload) -> ValidationRevert {
647-
match err.as_revert_data() {
648-
Some(err_bytes) => decode_validation_revert(&err_bytes),
649-
None => ValidationRevert::Unknown(Bytes::default()),
650-
}
651-
}
652-
653654
/// Decodes raw validation revert bytes from a v0.7 entry point
654655
pub fn decode_validation_revert(err_bytes: &Bytes) -> ValidationRevert {
655656
if let Ok(rev) = SolContractError::<IEntryPointErrors>::abi_decode(err_bytes) {
@@ -724,7 +725,7 @@ pub fn decode_ops_from_calldata(
724725
#[allow(clippy::too_many_arguments)]
725726
async fn simulate_handle_op_inner<AP: AlloyProvider>(
726727
chain_spec: &ChainSpec,
727-
max_simulate_handle_ops_gas: u64,
728+
execution_gas_limit: u64,
728729
entry_point: &IEntryPointInstance<AP, AnyNetwork>,
729730
op: UserOperation,
730731
target: Address,
@@ -749,24 +750,30 @@ async fn simulate_handle_op_inner<AP: AlloyProvider>(
749750
ep_simulations
750751
.simulateHandleOpNoPostOp(op.pack(), target, target_call_data)
751752
.block(block_id)
752-
.gas(max_simulate_handle_ops_gas.saturating_add(da_gas))
753+
.gas(execution_gas_limit.saturating_add(da_gas))
753754
.state(state_override)
754755
.call()
755756
.await
756757
} else {
757758
ep_simulations
758759
.simulateHandleOp(op.pack(), target, target_call_data)
759760
.block(block_id)
760-
.gas(max_simulate_handle_ops_gas.saturating_add(da_gas))
761+
.gas(execution_gas_limit.saturating_add(da_gas))
761762
.state(state_override)
762763
.call()
763764
.await
764765
};
765766

767+
tracing::info!("simulate_handle_op_inner: {:?}", res);
768+
766769
match res {
767770
Ok(output) => Ok(Ok(output.try_into()?)),
768771
Err(ContractError::TransportError(TransportError::ErrorResp(resp))) => {
769-
Ok(Err(decode_validation_revert_payload(resp)))
772+
if let Some(revert) = resp.as_revert_data() {
773+
Ok(Err(decode_validation_revert(&revert)))
774+
} else {
775+
Err(TransportError::ErrorResp(resp).into())
776+
}
770777
}
771778
Err(error) => Err(error.into()),
772779
}

0 commit comments

Comments
 (0)