Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(7702): use standardized eip7702_auth #973

Merged
merged 7 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Adapted from https://github.com/paradigmxyz/reth/blob/main/Dockerfile
# syntax=docker/dockerfile:1.4

FROM ghcr.io/foundry-rs/foundry:nightly-fe2acca4e379793539db80e032d76ffe0110298b as foundry

FROM --platform=$TARGETPLATFORM rust:1.83.0 AS chef-builder

# Install system dependencies
Expand All @@ -10,10 +12,12 @@ RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg -
RUN echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list
RUN apt-get update && apt-get -y upgrade && apt-get install -y libclang-dev pkg-config protobuf-compiler nodejs yarn rsync

# copy foundry tool
COPY --from=foundry /usr/local/bin/forge /usr/local/bin/forge

SHELL ["/bin/bash", "-c"]
RUN curl -L https://foundry.paradigm.xyz | bash
ENV PATH="/root/.foundry/bin:${PATH}"
RUN foundryup -i nightly-fe2acca4e379793539db80e032d76ffe0110298b

RUN cargo install cargo-chef --locked

Expand Down
11 changes: 11 additions & 0 deletions bin/rundler/src/cli/pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,14 @@ pub struct PoolArgs {
env = "POOL_MAX_TIME_IN_POOL_SECS"
)]
pub max_time_in_pool_secs: Option<u64>,

#[arg(
long = "pool.support_7702",
name = "pool.support_7702",
env = "POOL_SUPPORT_7702",
default_value = "false"
)]
pub support_7702: bool,
}

impl PoolArgs {
Expand Down Expand Up @@ -244,6 +252,7 @@ impl PoolArgs {
gas_limit_efficiency_reject_threshold: self.gas_limit_efficiency_reject_threshold,
max_time_in_pool: self.max_time_in_pool_secs.map(Duration::from_secs),
max_expected_storage_slots: common.max_expected_storage_slots.unwrap_or(usize::MAX),
support_7702: self.support_7702,
};

let mut pool_configs = vec![];
Expand All @@ -255,6 +264,8 @@ impl PoolArgs {
num_shards: common.num_builders_v0_6,
mempool_channel_configs: mempool_channel_configs
.get_for_entry_point(chain_spec.entry_point_address_v0_6),
// always disable 7702 for EP v06.
support_7702: false,
..pool_config_base.clone()
});
}
Expand Down
5 changes: 5 additions & 0 deletions crates/pool/proto/op_pool/op_pool.proto
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,7 @@ message MempoolError {
PreOpGasLimitEfficiencyTooLow pre_op_gas_limit_efficiency_too_low = 17;
ExecutionGasLimitEfficiencyTooLow execution_gas_limit_efficiency_too_low = 18;
TooManyExpectedStorageSlots too_many_expected_storage_slots = 19;
UseUnsupportedEIP use_unsupported_eip= 20;
}
}

Expand Down Expand Up @@ -600,6 +601,10 @@ message TooManyExpectedStorageSlots {
uint64 expected_slots = 2;
}

message UseUnsupportedEIP {
string eip_name = 1;
}

// PRECHECK VIOLATIONS
message PrecheckViolationError {
oneof violation {
Expand Down
2 changes: 2 additions & 0 deletions crates/pool/src/mempool/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ pub struct PoolConfig {
pub max_time_in_pool: Option<Duration>,
/// The maximum number of storage slots that can be expected to be used by a user operation during validation
pub max_expected_storage_slots: usize,
/// Whether to enable UO with 7702 auth
pub support_7702: bool,
}

/// Origin of an operation.
Expand Down
17 changes: 17 additions & 0 deletions crates/pool/src/mempool/pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ pub(crate) struct PoolInnerConfig {
throttled_entity_live_blocks: u64,
da_gas_tracking_enabled: bool,
max_time_in_pool: Option<Duration>,
support_7702: bool,
}

impl From<PoolConfig> for PoolInnerConfig {
Expand All @@ -61,6 +62,7 @@ impl From<PoolConfig> for PoolInnerConfig {
throttled_entity_live_blocks: config.throttled_entity_live_blocks,
da_gas_tracking_enabled: config.da_gas_tracking_enabled,
max_time_in_pool: config.max_time_in_pool,
support_7702: config.support_7702,
}
}
}
Expand Down Expand Up @@ -417,6 +419,20 @@ where
Ok(())
}

pub(crate) fn check_eip7702(&self, uo: &UserOperationVariant) -> MempoolResult<()> {
if uo.authorization_tuple().is_some() {
if self.config.support_7702 {
Ok(())
} else {
Err(MempoolError::EIPNotSupported(
"EIP 7702 is not supported".to_string(),
))
}
} else {
Ok(())
}
}

pub(crate) fn mine_operation(
&mut self,
mined_op: &MinedOp,
Expand Down Expand Up @@ -1521,6 +1537,7 @@ mod tests {
throttled_entity_live_blocks: 10,
da_gas_tracking_enabled: false,
max_time_in_pool: None,
support_7702: false,
}
}

Expand Down
32 changes: 32 additions & 0 deletions crates/pool/src/mempool/uo_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,9 @@ where
// Check if op violates the STO-040 spec rule
state.pool.check_multiple_roles_violation(&op)?;

// Check if op use 7702
state.pool.check_eip7702(&op)?;

// Check if op is already known or replacing another, and if so, ensure its fees are high enough
state
.pool
Expand Down Expand Up @@ -959,6 +962,7 @@ mod tests {
SimulationError, SimulationResult, SimulationSettings, ViolationError,
};
use rundler_types::{
authorization::Eip7702Auth,
chain::ChainSpec,
da::DAGasUOData,
pool::{PrecheckViolation, SimulationViolation},
Expand Down Expand Up @@ -1862,6 +1866,33 @@ mod tests {
.unwrap();
}

#[tokio::test]
async fn test_eip_support() {
let mut config = default_config();
let op = create_op_from_op_v0_6(UserOperation {
call_gas_limit: 50_000,
max_fee_per_gas: 0,
max_priority_fee_per_gas: 0,
authorization_tuple: Some(Eip7702Auth::default()),
..Default::default()
});
{
let pool = create_pool_with_config(config.clone(), vec![op.clone()]);
assert!(pool
.add_operation(OperationOrigin::Local, op.clone().op)
.await
.is_err());
}
{
config.support_7702 = true;
let pool = create_pool_with_config(config.clone(), vec![op.clone()]);
assert!(pool
.add_operation(OperationOrigin::Local, op.clone().op)
.await
.is_ok());
}
}

#[tokio::test]
async fn test_da_gas_ineligible() {
let mut config = default_config();
Expand Down Expand Up @@ -1917,6 +1948,7 @@ mod tests {
gas_limit_efficiency_reject_threshold: 0.0,
max_time_in_pool: None,
max_expected_storage_slots: usize::MAX,
support_7702: false,
}
}

Expand Down
13 changes: 11 additions & 2 deletions crates/pool/src/server/remote/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,9 @@ use super::protos::{
SimulationViolationError as ProtoSimulationViolationError, TooManyExpectedStorageSlots,
TotalGasLimitTooHigh, UnintendedRevert, UnintendedRevertWithMessage, UnknownEntryPointError,
UnknownRevert, UnstakedAggregator, UnstakedPaymasterContext, UnsupportedAggregatorError,
UsedForbiddenOpcode, UsedForbiddenPrecompile, ValidationRevert as ProtoValidationRevert,
VerificationGasLimitBufferTooLow, VerificationGasLimitTooHigh, WrongNumberOfPhases,
UseUnsupportedEip, UsedForbiddenOpcode, UsedForbiddenPrecompile,
ValidationRevert as ProtoValidationRevert, VerificationGasLimitBufferTooLow,
VerificationGasLimitTooHigh, WrongNumberOfPhases,
};

impl TryFrom<ProtoMempoolError> for PoolError {
Expand Down Expand Up @@ -139,6 +140,9 @@ impl TryFrom<ProtoMempoolError> for MempoolError {
e.expected_slots.try_into()?,
)
}
Some(mempool_error::Error::UseUnsupportedEip(e)) => {
MempoolError::EIPNotSupported(e.eip_name)
}
None => bail!("unknown proto mempool error"),
})
}
Expand Down Expand Up @@ -265,6 +269,11 @@ impl From<MempoolError> for ProtoMempoolError {
)),
}
}
MempoolError::EIPNotSupported(msg) => ProtoMempoolError {
error: Some(mempool_error::Error::UseUnsupportedEip(UseUnsupportedEip {
eip_name: msg,
})),
},
}
}
}
Expand Down
10 changes: 5 additions & 5 deletions crates/pool/src/server/remote/protos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use alloy_primitives::{Address, B256};
use anyhow::{anyhow, Context};
use rundler_task::grpc::protos::{from_bytes, ConversionError, ToProtoBytes};
use rundler_types::{
authorization::Authorization,
authorization::Eip7702Auth,
chain::ChainSpec,
da::{
BedrockDAGasUOData as RundlerBedrockDAGasUOData, DAGasUOData as RundlerDAGasUOData,
Expand Down Expand Up @@ -83,9 +83,9 @@ pub trait TryUoFromProto<T>: Sized {
fn try_uo_from_proto(value: T, chain_spec: &ChainSpec) -> Result<Self, ConversionError>;
}

impl From<AuthorizationTuple> for Authorization {
impl From<AuthorizationTuple> for Eip7702Auth {
fn from(value: AuthorizationTuple) -> Self {
Authorization {
Eip7702Auth {
chain_id: value.chain_id,
address: from_bytes(&value.address).unwrap_or_default(),
nonce: value.nonce,
Expand All @@ -103,7 +103,7 @@ impl TryUoFromProto<UserOperationV06> for v0_6::UserOperation {
let authorization_tuple = op
.authorization_tuple
.as_ref()
.map(|authorization| Authorization::from(authorization.clone()));
.map(|authorization| Eip7702Auth::from(authorization.clone()));

Ok(v0_6::UserOperationBuilder::new(
chain_spec,
Expand Down Expand Up @@ -164,7 +164,7 @@ impl TryUoFromProto<UserOperationV07> for v0_7::UserOperation {
let authorization_tuple = op
.authorization_tuple
.as_ref()
.map(|authorization| Authorization::from(authorization.clone()));
.map(|authorization| Eip7702Auth::from(authorization.clone()));

let mut builder = v0_7::UserOperationBuilder::new(
chain_spec,
Expand Down
8 changes: 4 additions & 4 deletions crates/provider/src/alloy/entry_point/v0_6.rs
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,7 @@ fn get_handle_ops_call<AP: AlloyProvider<T>, T: Transport + Clone>(
gas_limit: u64,
gas_fees: GasFees,
) -> TransactionRequest {
let mut authorization_list: Vec<SignedAuthorization> = vec![];
let mut eip7702_auth_list: Vec<SignedAuthorization> = vec![];
let mut ops_per_aggregator: Vec<UserOpsPerAggregatorV0_6> = ops_per_aggregator
.into_iter()
.map(|uoa| UserOpsPerAggregatorV0_6 {
Expand All @@ -541,7 +541,7 @@ fn get_handle_ops_call<AP: AlloyProvider<T>, T: Transport + Clone>(
.into_iter()
.map(|op| {
if let Some(authorization) = &op.authorization_tuple {
authorization_list.push(SignedAuthorization::from(authorization.clone()));
eip7702_auth_list.push(SignedAuthorization::from(authorization.clone()));
}
op.into()
})
Expand All @@ -567,8 +567,8 @@ fn get_handle_ops_call<AP: AlloyProvider<T>, T: Transport + Clone>(
.gas_limit(gas_limit)
.max_fee_per_gas(gas_fees.max_fee_per_gas)
.max_priority_fee_per_gas(gas_fees.max_priority_fee_per_gas);
if !authorization_list.is_empty() {
txn_request = txn_request.with_authorization_list(authorization_list);
if !eip7702_auth_list.is_empty() {
txn_request = txn_request.with_authorization_list(eip7702_auth_list);
}

txn_request
Expand Down
4 changes: 2 additions & 2 deletions crates/provider/src/alloy/entry_point/v0_7.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ use rundler_contracts::v0_7::{
ENTRY_POINT_SIMULATIONS_V0_7_DEPLOYED_BYTECODE,
};
use rundler_types::{
authorization::Authorization,
authorization::Eip7702Auth,
chain::ChainSpec,
da::{DAGasBlockData, DAGasUOData},
v0_7::UserOperation,
Expand Down Expand Up @@ -609,7 +609,7 @@ impl TryFrom<ExecutionResultV0_7> for ExecutionResult {

fn add_authorization_tuple(
sender: Address,
authorization: &Option<Authorization>,
authorization: &Option<Eip7702Auth>,
state_override: &mut StateOverride,
) {
if let Some(authorization) = &authorization {
Expand Down
1 change: 1 addition & 0 deletions crates/rpc/src/eth/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ impl From<MempoolError> for EthRpcError {
MempoolError::TooManyExpectedStorageSlots(_, _) => {
Self::InvalidParams(value.to_string())
}
MempoolError::EIPNotSupported(_) => Self::InvalidParams(value.to_string()),
}
}
}
Expand Down
14 changes: 7 additions & 7 deletions crates/rpc/src/types/rpc_authorization.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use alloy_primitives::{Address, U256, U64, U8};
use rundler_types::authorization::Authorization;
use rundler_types::authorization::Eip7702Auth;
use serde::{Deserialize, Serialize};

/// authorization tuple for 7702 txn support
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub(crate) struct RpcAuthorization {
pub(crate) struct RpcEip7702Auth {
/// The chain ID of the authorization.
pub chain_id: U64,
/// The address of the authorization.
Expand All @@ -20,9 +20,9 @@ pub(crate) struct RpcAuthorization {
pub s: U256,
}

impl From<RpcAuthorization> for Authorization {
fn from(val: RpcAuthorization) -> Self {
Authorization {
impl From<RpcEip7702Auth> for Eip7702Auth {
fn from(val: RpcEip7702Auth) -> Self {
Eip7702Auth {
chain_id: val.chain_id.to(),
address: val.address,
nonce: val.nonce.to(),
Expand All @@ -33,8 +33,8 @@ impl From<RpcAuthorization> for Authorization {
}
}

impl From<Authorization> for RpcAuthorization {
fn from(value: Authorization) -> Self {
impl From<Eip7702Auth> for RpcEip7702Auth {
fn from(value: Eip7702Auth) -> Self {
Self {
chain_id: U64::from(value.chain_id),
address: value.address,
Expand Down
Loading
Loading