Skip to content

Commit

Permalink
feat: estimate user operation gas RPC endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
Vid201 committed Feb 16, 2023
1 parent 98ca24a commit e534d92
Show file tree
Hide file tree
Showing 9 changed files with 242 additions and 50 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ build:
cargo build

run-bundler:
cargo run -- --eth-client-address http://127.0.0.1:8545 --mnemonic-file ${HOME}/.aa-bundler/0x129D197b2a989C6798601A49D89a4AEC822A17a3 --beneficiary 0x690B9A9E9aa1C9dB991C7721a92d351Db4FaC990 --gas-factor 600 --min-balance 1 --entry-points 0x1306b01bc3e4ad202612d3843387e94737673f53 --helper 0x0000000000000000000000000000000000000000 --min-stake 1 --min-unstake-delay 0 --min-priority-fee-per-gas 0 --max-verification-gas 1500000
cargo run -- --eth-client-address http://127.0.0.1:8545 --mnemonic-file ${HOME}/.aa-bundler/0x129D197b2a989C6798601A49D89a4AEC822A17a3 --beneficiary 0x690B9A9E9aa1C9dB991C7721a92d351Db4FaC990 --gas-factor 600 --min-balance 1 --entry-points 0x1306b01bC3e4AD202612D3843387e94737673F53 --helper 0x0000000000000000000000000000000000000000 --min-stake 1 --min-unstake-delay 0 --min-priority-fee-per-gas 0 --max-verification-gas 1500000

run-bundler-uopool:
cargo run --bin bundler-uopool -- --eth-client-address http://127.0.0.1:8545 --entry-points 0x1306b01bc3e4ad202612d3843387e94737673f53 --min-stake 1 --min-unstake-delay 0 --min-priority-fee-per-gas 0 --max-verification-gas 1500000
cargo run --bin bundler-uopool -- --eth-client-address http://127.0.0.1:8545 --entry-points 0x1306b01bC3e4AD202612D3843387e94737673F53 --min-stake 1 --min-unstake-delay 0 --min-priority-fee-per-gas 0 --max-verification-gas 1500000

run-bundler-rpc:
cargo run --bin bundler-rpc
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ cargo run --bin create-wallet -- --output-path ${HOME}/.aa-bundler --chain-id 5
Run bundler (with user operation pool and JSON-RPC API):

```bash
cargo run -- --mnemonic-file ${HOME}/.aa-bundler/0x129D197b2a989C6798601A49D89a4AEC822A17a3 --beneficiary 0x690B9A9E9aa1C9dB991C7721a92d351Db4FaC990 --gas-factor 600 --min-balance 1 --eth-client-address http://127.0.0.1:8545 --entry-points 0x1306b01bc3e4ad202612d3843387e94737673f53 --helper 0x0000000000000000000000000000000000000000 --min-stake 1 --min-unstake-delay 0 --min-priority-fee-per-gas 0 --max-verification-gas 1500000
cargo run -- --mnemonic-file ${HOME}/.aa-bundler/0x129D197b2a989C6798601A49D89a4AEC822A17a3 --beneficiary 0x690B9A9E9aa1C9dB991C7721a92d351Db4FaC990 --gas-factor 600 --min-balance 1 --eth-client-address http://127.0.0.1:8545 --entry-points 0x1306b01bC3e4AD202612D3843387e94737673F53 --helper 0x0000000000000000000000000000000000000000 --min-stake 1 --min-unstake-delay 0 --min-priority-fee-per-gas 0 --max-verification-gas 1500000
```

Run only user operation pool:

```bash
cargo run --bin bundler-uopool -- --eth-client-address http://127.0.0.1:8545 --entry-points 0x1306b01bc3e4ad202612d3843387e94737673f53 --min-stake 1 --min-unstake-delay 0 --min-priority-fee-per-gas 0 --max-verification-gas 1500000
cargo run --bin bundler-uopool -- --eth-client-address http://127.0.0.1:8545 --entry-points 0x1306b01bC3e4AD202612D3843387e94737673F53 --min-stake 1 --min-unstake-delay 0 --min-priority-fee-per-gas 0 --max-verification-gas 1500000
```

Run only JSON-RPC API:
Expand Down
8 changes: 7 additions & 1 deletion bin/bundler-uopool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ use aa_bundler::utils::{parse_address, parse_u256};
use anyhow::Result;
use clap::Parser;
use ethers::{
providers::{Http, Provider},
providers::{Http, Middleware, Provider},
types::{Address, U256},
};
use jsonrpsee::tracing::info;
use std::{future::pending, sync::Arc};

#[derive(Parser)]
Expand Down Expand Up @@ -34,6 +35,11 @@ async fn main() -> Result<()> {
tracing_subscriber::fmt::init();

let eth_provider = Arc::new(Provider::<Http>::try_from(opt.eth_client_address.clone())?);
info!(
"Connected to Ethereum execution client at {}: {}",
opt.eth_client_address,
eth_provider.client_version().await?
);

aa_bundler::uopool::run(
opt.uopool_opts,
Expand Down
2 changes: 1 addition & 1 deletion bundler-spec-test/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ services:
bundler:
build:
context: ../ # https://github.com/Vid201/aa-bundler.git
command: --rpc-listen-address 0.0.0.0:3000 --eth-client-address http://geth-dev:8545 --mnemonic-file /root/${BUNDLER_ACCOUNT} --beneficiary 0x690B9A9E9aa1C9dB991C7721a92d351Db4FaC990 --gas-factor 600 --min-balance 1 --entry-points 0x1306b01bc3e4ad202612d3843387e94737673f53 --helper 0x0000000000000000000000000000000000000000 --min-stake 1 --min-unstake-delay 0 --min-priority-fee-per-gas 0 --max-verification-gas 1500000
command: --rpc-listen-address 0.0.0.0:3000 --eth-client-address http://geth-dev:8545 --mnemonic-file /root/${BUNDLER_ACCOUNT} --beneficiary 0x690B9A9E9aa1C9dB991C7721a92d351Db4FaC990 --gas-factor 600 --min-balance 1 --entry-points 0x1306b01bC3e4AD202612D3843387e94737673F53 --helper 0x0000000000000000000000000000000000000000 --min-stake 1 --min-unstake-delay 0 --min-priority-fee-per-gas 0 --max-verification-gas 1500000
ports: [ '3000:3000' ]
volumes:
- ./keys:/root
Expand Down
8 changes: 7 additions & 1 deletion src/contracts/entrypoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ impl<M: Middleware + 'static> EntryPoint<M> {
let request_result = self
.entry_point_api
.simulate_validation(user_operation.into())
.call()
.await;
match request_result {
Ok(_) => Err(EntryPointErr::UnknownErr(
Expand Down Expand Up @@ -118,6 +119,7 @@ impl<M: Middleware + 'static> EntryPoint<M> {
) -> Result<(), EntryPointErr> {
self.entry_point_api
.handle_ops(ops.into_iter().map(|u| u.into()).collect(), beneficiary)
.call()
.await
.or_else(|e| {
let err_msg = e.to_string();
Expand Down Expand Up @@ -151,7 +153,11 @@ impl<M: Middleware + 'static> EntryPoint<M> {
&self,
initcode: Bytes,
) -> Result<SenderAddressResult, EntryPointErr> {
let result = self.entry_point_api.get_sender_address(initcode).await;
let result = self
.entry_point_api
.get_sender_address(initcode)
.call()
.await;

match result {
Ok(_) => Err(EntryPointErr::UnknownErr(
Expand Down
56 changes: 40 additions & 16 deletions src/rpc/eth.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
use crate::{
rpc::eth_api::{EstimateUserOperationGasResponse, EthApiServer},
types::user_operation::{UserOperation, UserOperationHash, UserOperationReceipt},
rpc::eth_api::EthApiServer,
types::user_operation::{
UserOperation, UserOperationGasEstimation, UserOperationHash, UserOperationPartial,
UserOperationReceipt,
},
uopool::server::uopool::{

uo_pool_client::UoPoolClient, AddRequest, AddResult, GetChainIdRequest, GetChainIdResult, GetSupportedEntryPointsRequest, GetSupportedEntryPointsResult,
uo_pool_client::UoPoolClient, AddRequest, AddResult, EstimateUserOperationGasRequest,
EstimateUserOperationGasResult, GetChainIdRequest, GetChainIdResult,
GetSupportedEntryPointsRequest, GetSupportedEntryPointsResult,
},
};
use anyhow::format_err;
use async_trait::async_trait;
use ethers::types::{Address, U256, U64};
use ethers::{
types::{Address, U64},
utils::to_checksum,
};
use jsonrpsee::{
core::RpcResult,
tracing::info,
Expand Down Expand Up @@ -43,7 +50,7 @@ impl EthApiServer for EthApiServerImpl {
)))
}

async fn supported_entry_points(&self) -> RpcResult<Vec<Address>> {
async fn supported_entry_points(&self) -> RpcResult<Vec<String>> {
let mut uopool_grpc_client = self.uopool_grpc_client.clone();

let request = tonic::Request::new(GetSupportedEntryPointsRequest {});
Expand All @@ -58,7 +65,7 @@ impl EthApiServer for EthApiServerImpl {
return Ok(response
.eps
.into_iter()
.map(|entry_point| entry_point.into())
.map(|entry_point| to_checksum(&entry_point.into(), None))
.collect());
}

Expand Down Expand Up @@ -102,16 +109,33 @@ impl EthApiServer for EthApiServerImpl {

async fn estimate_user_operation_gas(
&self,
user_operation: UserOperation,
user_operation: UserOperationPartial,
entry_point: Address,
) -> RpcResult<EstimateUserOperationGasResponse> {
info!("{:?}", user_operation);
info!("{:?}", entry_point);
Ok(EstimateUserOperationGasResponse {
pre_verification_gas: U256::from(0),
verification_gas_limit: U256::from(0),
call_gas_limit: U256::from(self.call_gas_limit),
})
) -> RpcResult<UserOperationGasEstimation> {
let mut uopool_grpc_client = self.uopool_grpc_client.clone();

let request = tonic::Request::new(EstimateUserOperationGasRequest {
uo: Some(UserOperation::from(user_operation).into()),
ep: Some(entry_point.into()),
});

let response = uopool_grpc_client
.estimate_user_operation_gas(request)
.await
.map_err(|status| format_err!("GRPC error (uopool): {}", status.message()))?
.into_inner();

if response.result == EstimateUserOperationGasResult::Estimated as i32 {
let user_operation_gas_estimation = serde_json::from_str::<UserOperationGasEstimation>(
&response.data,
)
.map_err(|err| format_err!("error parsing user operation gas estimation: {}", err))?;
return Ok(user_operation_gas_estimation);
}

Err(jsonrpsee::core::Error::Call(CallError::Failed(
anyhow::format_err!("failed to gas estimation for user operation"),
)))
}

async fn get_user_operation_receipt(
Expand Down
21 changes: 8 additions & 13 deletions src/rpc/eth_api.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,18 @@
use ethers::types::{Address, U256, U64};
use ethers::types::{Address, U64};
use jsonrpsee::{core::RpcResult, proc_macros::rpc};
use serde::{Deserialize, Serialize};

use crate::types::user_operation::{UserOperation, UserOperationHash, UserOperationReceipt};

#[derive(Serialize, Deserialize)]
pub struct EstimateUserOperationGasResponse {
pub pre_verification_gas: U256,
pub verification_gas_limit: U256,
pub call_gas_limit: U256,
}
use crate::types::user_operation::{
UserOperation, UserOperationGasEstimation, UserOperationHash, UserOperationPartial,
UserOperationReceipt,
};

#[rpc(server, namespace = "eth")]
pub trait EthApi {
#[method(name = "chainId")]
async fn chain_id(&self) -> RpcResult<U64>;

#[method(name = "supportedEntryPoints")]
async fn supported_entry_points(&self) -> RpcResult<Vec<Address>>;
async fn supported_entry_points(&self) -> RpcResult<Vec<String>>;

#[method(name = "sendUserOperation")]
async fn send_user_operation(
Expand All @@ -29,9 +24,9 @@ pub trait EthApi {
#[method(name = "estimateUserOperationGas")]
async fn estimate_user_operation_gas(
&self,
user_operation: UserOperation,
user_operation: UserOperationPartial,
entry_point: Address,
) -> RpcResult<EstimateUserOperationGasResponse>;
) -> RpcResult<UserOperationGasEstimation>;

#[method(name = "getUserOperationReceipt")]
async fn get_user_operation_receipt(
Expand Down
95 changes: 95 additions & 0 deletions src/types/user_operation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use rustc_hex::FromHexError;
use serde::{Deserialize, Serialize};
use std::ops::Deref;
use std::str::FromStr;
use std::vec;

#[derive(
Eq, Hash, PartialEq, Debug, Serialize, Deserialize, Clone, Copy, Default, PartialOrd, Ord,
Expand Down Expand Up @@ -155,6 +156,100 @@ pub struct UserOperationReceipt {
pub receipt: TransactionReceipt,
}

#[derive(Serialize, Deserialize)]
pub struct UserOperationPartial {
pub sender: Address,
pub nonce: U256,
pub init_code: Option<Bytes>,
pub call_data: Option<Bytes>,
pub call_gas_limit: Option<U256>,
pub verification_gas_limit: Option<U256>,
pub pre_verification_gas: Option<U256>,
pub max_fee_per_gas: Option<U256>,
pub max_priority_fee_per_gas: Option<U256>,
pub paymaster_and_data: Option<Bytes>,
pub signature: Option<Bytes>,
}

impl From<UserOperationPartial> for UserOperation {
fn from(user_operation: UserOperationPartial) -> Self {
Self {
sender: user_operation.sender,
nonce: user_operation.nonce,
init_code: {
if let Some(init_code) = user_operation.init_code {
init_code
} else {
Bytes::default()
}
},
call_data: {
if let Some(call_data) = user_operation.call_data {
call_data
} else {
Bytes::default()
}
},
call_gas_limit: {
if let Some(call_gas_limit) = user_operation.call_gas_limit {
call_gas_limit
} else {
U256::zero()
}
},
verification_gas_limit: {
if let Some(verification_gas_limit) = user_operation.verification_gas_limit {
verification_gas_limit
} else {
U256::from(10000000)
}
},
pre_verification_gas: {
if let Some(pre_verification_gas) = user_operation.pre_verification_gas {
pre_verification_gas
} else {
U256::zero()
}
},
max_fee_per_gas: {
if let Some(max_fee_per_gas) = user_operation.max_fee_per_gas {
max_fee_per_gas
} else {
U256::zero()
}
},
max_priority_fee_per_gas: {
if let Some(max_priority_fee_per_gas) = user_operation.max_priority_fee_per_gas {
max_priority_fee_per_gas
} else {
U256::zero()
}
},
paymaster_and_data: {
if let Some(paymaster_and_data) = user_operation.paymaster_and_data {
paymaster_and_data
} else {
Bytes::default()
}
},
signature: {
if let Some(signature) = user_operation.signature {
signature
} else {
Bytes::from(vec![1; 65])
}
},
}
}
}

#[derive(Serialize, Deserialize)]
pub struct UserOperationGasEstimation {
pub pre_verification_gas: U256,
pub verification_gas_limit: U256,
pub call_gas_limit: U256,
}

#[cfg(test)]
mod tests {
use std::str::FromStr;
Expand Down
Loading

0 comments on commit e534d92

Please sign in to comment.