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

fix(7702): add max_fill, random_fill, and use for gas estimation #991

Merged
merged 4 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from 2 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: 6 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,15 @@ alloy-sol-types = "0.8.15"
# alloy
alloy-consensus = "0.7.3"
alloy-contract = "0.7.3"
alloy-eips = "0.7.3"
alloy-eips = { version = "0.7.3", features = ["k256","serde", "std", ] }
andysim3d marked this conversation as resolved.
Show resolved Hide resolved
alloy-json-rpc = "0.7.3"
alloy-provider = { version = "0.7.3", default-features = false, features = ["reqwest", "reqwest-rustls-tls"] }
alloy-rpc-client = "0.7.3"
alloy-rpc-types-eth = "0.7.3"
alloy-rpc-types-trace = "0.7.3"
alloy-signer = "0.7.3"
alloy-signer-aws = "0.7.3"
alloy-signer-local = "0.7.3"
alloy-signer-local = { version = "0.7.3" }
alloy-transport = "0.7.3"
alloy-transport-http = { version = "0.7.3", default-features = false, features = ["reqwest", "reqwest-rustls-tls"] }
alloy-network = { version = "0.7.3" }
Expand Down
1 change: 1 addition & 0 deletions bin/rundler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ rundler-types.workspace = true
rundler-utils.workspace = true

alloy-primitives.workspace = true
alloy-signer-local.workspace = true
andysim3d marked this conversation as resolved.
Show resolved Hide resolved

anyhow.workspace = true
aws-config.workspace = true
Expand Down
3 changes: 3 additions & 0 deletions crates/pool/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ url.workspace = true
mockall = { workspace = true, optional = true }

[dev-dependencies]
alloy-eips.workspace = true
alloy-signer.workspace = true
alloy-signer-local.workspace = true
mockall.workspace = true
reth-tasks.workspace = true
rundler-provider = { workspace = true, features = ["test-utils"] }
Expand Down
3 changes: 2 additions & 1 deletion crates/pool/src/mempool/pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -420,8 +420,9 @@ where
}

pub(crate) fn check_eip7702(&self, uo: &UserOperationVariant) -> MempoolResult<()> {
if uo.authorization_tuple().is_some() {
if let Some(auth) = uo.authorization_tuple() {
if self.config.support_7702 {
auth.validate()?;
Ok(())
} else {
Err(MempoolError::EIPNotSupported(
Expand Down
39 changes: 37 additions & 2 deletions crates/pool/src/mempool/uo_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -942,9 +942,11 @@ struct UoPoolMetrics {

#[cfg(test)]
mod tests {
use std::{collections::HashMap, vec};
use std::{collections::HashMap, str::FromStr, vec};

use alloy_primitives::{uint, Bytes};
use alloy_signer::SignerSync;
use alloy_signer_local::PrivateKeySigner;
use mockall::Sequence;
use rundler_provider::{
DepositInfo, ExecutionResult, MockDAGasOracleSync, MockEntryPointV0_6, MockEvmProvider,
Expand All @@ -969,7 +971,6 @@ mod tests {
chain::{BalanceUpdate, MinedOp},
mempool::{PaymasterConfig, ReputationParams},
};

const THROTTLE_SLACK: u64 = 5;
const BAN_SLACK: u64 = 10;

Expand Down Expand Up @@ -1882,6 +1883,40 @@ mod tests {
assert!(pool
.add_operation(OperationOrigin::Local, op.clone().op)
.await
.is_err());
}
{
config.support_7702 = true;
let private_key = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80";
let signer: PrivateKeySigner = PrivateKeySigner::from_str(private_key).unwrap();
let authorization = alloy_eips::eip7702::Authorization {
chain_id: 11011,
address: Address::from_str("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266").unwrap(),
nonce: 1,
};
let signature = signer
.sign_hash_sync(&authorization.signature_hash())
.unwrap();
let signed_authorization = authorization.into_signed(signature);
let signed_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 {
address: signed_authorization.address,
chain_id: signed_authorization.chain_id,
nonce: signed_authorization.nonce,
y_parity: signed_authorization.y_parity(),
r: signed_authorization.r(),
s: signed_authorization.s(),
}),
..Default::default()
});

let pool = create_pool_with_config(config.clone(), vec![signed_op.clone()]);
assert!(pool
.add_operation(OperationOrigin::Local, signed_op.clone().op)
.await
.is_ok());
}
}
Expand Down
11 changes: 10 additions & 1 deletion crates/pool/src/server/remote/protos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,16 @@ impl From<&v0_7::UserOperation> for UserOperation {
factory_data: op.factory_data.to_proto_bytes(),
entry_point: op.entry_point.to_proto_bytes(),
chain_id: op.chain_id,
authorization_tuple: None,
authorization_tuple: op.authorization_tuple.as_ref().map(|authorization| {
andysim3d marked this conversation as resolved.
Show resolved Hide resolved
AuthorizationTuple {
chain_id: authorization.chain_id,
address: authorization.address.to_proto_bytes(),
nonce: authorization.nonce,
y_parity: authorization.y_parity.into(),
r: authorization.r.to_proto_bytes(),
s: authorization.s.to_proto_bytes(),
}
}),
};
UserOperation {
uo: Some(user_operation::Uo::V07(op)),
Expand Down
6 changes: 4 additions & 2 deletions crates/provider/src/alloy/entry_point/v0_6.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use rundler_contracts::v0_6::{
UserOperation as ContractUserOperation, UserOpsPerAggregator as UserOpsPerAggregatorV0_6,
};
use rundler_types::{
authorization::Eip7702Auth,
chain::ChainSpec,
da::{DAGasBlockData, DAGasUOData},
v0_6::UserOperation,
Expand Down Expand Up @@ -330,8 +331,9 @@ where
.i_entry_point
.handleOps(vec![user_op.into()], Address::random())
.into_transaction_request();
if let Some(authorization) = au {
txn_request = txn_request.with_authorization_list(vec![authorization.into()]);
if au.is_some() {
txn_request =
txn_request.with_authorization_list(vec![Eip7702Auth::random_fill().into()]);
andysim3d marked this conversation as resolved.
Show resolved Hide resolved
}

let data = txn_request.input.into_input().unwrap();
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 @@ -324,8 +324,8 @@ where
.i_entry_point
.handleOps(vec![user_op.pack()], Address::random())
.into_transaction_request();
if let Some(authorization_tuple) = au {
txn_req = txn_req.with_authorization_list(vec![authorization_tuple.into()]);
if au.is_some() {
txn_req = txn_req.with_authorization_list(vec![Eip7702Auth::random_fill().into()]);
andysim3d marked this conversation as resolved.
Show resolved Hide resolved
}

let data = txn_req.input.into_input().unwrap();
Expand Down
1 change: 1 addition & 0 deletions crates/rpc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ http.workspace = true
jsonrpsee = { workspace = true, features = ["client", "macros", "server"] }
metrics.workspace = true
metrics-derive.workspace = true
rand.workspace = true
andysim3d marked this conversation as resolved.
Show resolved Hide resolved
serde.workspace = true
strum.workspace = true
thiserror.workspace = true
Expand Down
41 changes: 41 additions & 0 deletions crates/types/src/authorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

use alloy_eips::eip7702::SignedAuthorization;
use alloy_primitives::{Address, U256};
use rundler_utils::random::random_bytes_array;
use serde::{Deserialize, Serialize};

/// authorization tuple for 7702 txn support
Expand Down Expand Up @@ -45,3 +46,43 @@ impl From<Eip7702Auth> for alloy_eips::eip7702::SignedAuthorization {
SignedAuthorization::new_unchecked(authorization, value.y_parity, value.r, value.s)
}
}

impl Eip7702Auth {
/// Genreate a random filled Eip7702Auth entity.
pub fn random_fill() -> Eip7702Auth {
Self {
chain_id: u64::from_le_bytes(random_bytes_array::<8, 4>()),
andysim3d marked this conversation as resolved.
Show resolved Hide resolved
address: Address::random(),
nonce: u64::from_le_bytes(random_bytes_array::<8, 4>()),
y_parity: 27,
r: U256::from_le_bytes(random_bytes_array::<64, 32>()),
s: U256::from_le_bytes(random_bytes_array::<64, 32>()),
}
}
/// Generate a maxfilled Eip7702Auth entity.
pub fn max_fill() -> Eip7702Auth {
Self {
chain_id: u64::MAX,
address: Address::repeat_byte(0xf),
andysim3d marked this conversation as resolved.
Show resolved Hide resolved
nonce: u64::MAX,
y_parity: 27,
r: U256::MAX,
s: U256::MAX,
}
}

/// validate a Eip7702Auth's signature.
pub fn validate(&self) -> anyhow::Result<()> {
let signed_auth = SignedAuthorization::from(self.clone());
match signed_auth.recover_authority() {
Ok(address) => {
if address == self.address {
Ok(())
} else {
Err(anyhow::anyhow!("Invalid Signature"))
andysim3d marked this conversation as resolved.
Show resolved Hide resolved
}
}
Err(e) => Err(anyhow::anyhow!(e.to_string())),
}
}
}
16 changes: 0 additions & 16 deletions crates/types/src/user_operation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ use std::{fmt::Debug, time::Duration};

use alloy_primitives::{Address, Bytes, B256, U256};
use alloy_sol_types::SolValue;
use rand::{self, RngCore};

/// User Operation types for Entry Point v0.6
pub mod v0_6;
Expand Down Expand Up @@ -620,21 +619,6 @@ pub(crate) fn default_if_none_or_equal<V: Copy + PartialEq>(
v.filter(|v| v != &equal).unwrap_or(default)
}

/// Fills a bytes array of size ARR_SIZE with FILL_SIZE random bytes starting
/// at the beginning
fn random_bytes_array<const ARR_SIZE: usize, const FILL_SIZE: usize>() -> [u8; ARR_SIZE] {
let mut bytes = [0_u8; ARR_SIZE];
rand::thread_rng().fill_bytes(&mut bytes[..FILL_SIZE]);
bytes
}

/// Fills a bytes object with fill_size random bytes
fn random_bytes(fill_size: usize) -> Bytes {
let mut bytes = vec![0_u8; fill_size];
rand::thread_rng().fill_bytes(&mut bytes);
bytes.into()
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
18 changes: 12 additions & 6 deletions crates/types/src/user_operation/v0_6.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,11 @@
use alloy_primitives::{ruint::FromUintError, Address, Bytes, B256, U256};
use alloy_sol_types::{sol, SolValue};
pub use rundler_contracts::v0_6::UserOperation as ContractUserOperation;
use rundler_utils::random::{random_bytes, random_bytes_array};
use serde::{Deserialize, Serialize};
use strum::IntoEnumIterator;

use super::{
random_bytes, random_bytes_array, UserOperation as UserOperationTrait, UserOperationId,
UserOperationVariant,
};
use super::{UserOperation as UserOperationTrait, UserOperationId, UserOperationVariant};
use crate::{
authorization::Eip7702Auth,
chain::ChainSpec,
Expand Down Expand Up @@ -428,7 +426,11 @@ impl UserOperationOptionalGas {
max_fee_per_gas: max_8,
},
ExtendedUserOperation {
authorization_tuple: None,
authorization_tuple: if self.eip7702_auth_address.is_some() {
Some(Eip7702Auth::max_fill())
} else {
None
},
},
);

Expand Down Expand Up @@ -461,7 +463,11 @@ impl UserOperationOptionalGas {
max_priority_fee_per_gas: u128::from_le_bytes(random_bytes_array::<16, 8>()), // 2^64 max
},
ExtendedUserOperation {
authorization_tuple: None,
authorization_tuple: if self.eip7702_auth_address.is_some() {
Some(Eip7702Auth::random_fill())
} else {
None
},
},
);

Expand Down
18 changes: 7 additions & 11 deletions crates/types/src/user_operation/v0_7.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,9 @@
use alloy_primitives::{ruint::FromUintError, Address, Bytes, FixedBytes, B256, U256};
use alloy_sol_types::{sol, SolValue};
use rundler_contracts::v0_7::PackedUserOperation;
use rundler_utils::random::{random_bytes, random_bytes_array};

use super::{
random_bytes, random_bytes_array, UserOperation as UserOperationTrait, UserOperationId,
UserOperationVariant,
};
use super::{UserOperation as UserOperationTrait, UserOperationId, UserOperationVariant};
use crate::{authorization::Eip7702Auth, chain::ChainSpec, Entity, EntryPointVersion};

/// Gas overhead required by the entry point contract for the inner call
Expand Down Expand Up @@ -373,13 +371,8 @@ impl UserOperationOptionalGas {
vec![255_u8; self.paymaster_data.len()].into(),
);
}
if let Some(eip_7702_auth_address) = self.eip7702_auth_address {
builder = builder.authorization_tuple(Some(Eip7702Auth {
address: eip_7702_auth_address,
chain_id: chain_spec.id,
// fake value for gas estimation.
..Default::default()
}));
if self.eip7702_auth_address.is_some() {
builder = builder.authorization_tuple(Some(Eip7702Auth::max_fill()));
}
if self.factory.is_some() {
builder = builder.factory(
Expand Down Expand Up @@ -427,6 +420,9 @@ impl UserOperationOptionalGas {
if self.factory.is_some() {
builder = builder.factory(self.factory.unwrap(), random_bytes(self.factory_data.len()))
}
if self.eip7702_auth_address.is_some() {
builder = builder.authorization_tuple(Some(Eip7702Auth::random_fill()));
}

builder.build()
}
Expand Down
1 change: 1 addition & 0 deletions crates/utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,6 @@ pub mod eth;
pub mod guard_timer;
pub mod log;
pub mod math;
pub mod random;
pub mod retry;
pub mod strs;
Loading
Loading