Skip to content

Commit

Permalink
feat: eth_sendRawTransactionConditional
Browse files Browse the repository at this point in the history
  • Loading branch information
Vid201 committed Apr 13, 2024
1 parent 6f198b7 commit dea3df8
Show file tree
Hide file tree
Showing 27 changed files with 883 additions and 746 deletions.
1,295 changes: 598 additions & 697 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ silius-tests = { version = "0.4.0-alpha", path = "tests", default-features = fal
# eth
alloy-chains = "0.1.14"
discv5 = { version = "0.4.0", features = ["libp2p"] }
ethers = { git = "https://github.com/gakonst/ethers-rs", rev = "fa3017715a298728d9fb341933818a5d0d84c2dc", features = [
ethers = { git = "https://github.com/gakonst/ethers-rs", rev = "5394d899adca736a602e316e6f0c06fdb5aa64b9", features = [
"ws",
] }
ssz_rs = { git = "https://github.com/ralexstokes/ssz-rs.git", rev = "8640128ec83071094d24fb4511147d6b9dd029bb" }
Expand Down Expand Up @@ -82,4 +82,4 @@ tracing = "0.1.40"
[patch.crates-io]
revm-primitives = { git = "https://github.com/bluealloy/revm", rev = "3d8ca6641d2e72448c23f4596f769c8fd1c784d1" }
[patch."https://github.com/gakonst/ethers-rs"]
ethers = { git = "https://github.com/Vid201/ethers-rs", branch = "chore/ws" }
ethers = { git = "https://github.com/Vid201/ethers-rs", branch = "feat/patch" }
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ run-silius-p2p-bootnode:
cargo run --release -- node --eth-client-address http://127.0.0.1:8545 --mnemonic-file ./bundler-spec-tests/keys/0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --beneficiary 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --entry-points 0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789 --http --http.port 4000 --eth-client-proxy-address http://127.0.0.1:8545 --p2p.baddr 127.0.0.1 --enable-p2p

run-silius-p2p-peer:
cargo run --release -- node --eth-client-address http://127.0.0.1:8545 --mnemonic-file ./bundler-spec-tests/keys/0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --beneficiary 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --entry-points 0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789 --http --http.port 4000 --eth-client-proxy-address http://127.0.0.1:8545 --p2p.baddr 127.0.0.1 --bootnodes "enr:-J24QFyIGX9IG6_4WO6F40-BXH0b4gChUm3zTOkYNoYBOWX5LTq7ubqm5oaFjwcg5r1YesmllbqNvKAapeM2JK8fkKoBiGNoYWluX2lkiDkFAAAAAAAAgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQMm_tiGzC78d2_BvxJAUX9hRzBQv9QUmgU4OB4Pv1eVE4N0Y3CCIyiDdWRwgiMo" --enable-p2p --discovery.port 4338 --p2p.port 4338 --datadir ./.local/node1
cargo run --release -- node --eth-client-address http://127.0.0.1:8545 --mnemonic-file ./bundler-spec-tests/keys/0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --beneficiary 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --entry-points 0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789 --http --http.port 4000 --eth-client-proxy-address http://127.0.0.1:8545 --p2p.baddr 127.0.0.1 --bootnodes "enr:-J24QMMKCYqEBAs659G2f4MtvjI8wp3dbAvrvRbTxIEaapZfb9Pi0La0QOs6HoGfVeGk8fsFvZF7WiM_arx43rxSHwQBiGNoYWluX2lkiDkFAAAAAAAAgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQLigwYFOcf1lit2x918h4_6upE1lZ1kK3tD029ZZioW0IN0Y3CCIyiDdWRwgiMo" --enable-p2p --discovery.port 4338 --p2p.port 4338 --datadir ./.local/node1

run-silius-debug:
cargo run --release -- node --eth-client-address ws://127.0.0.1:8546 --mnemonic-file ${HOME}/.silius/0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --beneficiary 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --entry-points 0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789 --http --ws --http.api eth,debug,web3 --ws.api eth,debug,web3
Expand Down
19 changes: 18 additions & 1 deletion bin/silius/src/bundler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
use alloy_chains::{Chain, NamedChain};
use ethers::{providers::Middleware, types::Address};
use parking_lot::RwLock;
use silius_bundler::{EthereumClient, FlashbotsClient};
use silius_bundler::{ConditionalClient, EthereumClient, FlashbotsClient};
use silius_contracts::EntryPoint;
use silius_grpc::{
bundler_client::BundlerClient, bundler_service_run, uo_pool_client::UoPoolClient,
Expand Down Expand Up @@ -154,6 +154,23 @@ where
args.enable_access_list,
);
}
SendStrategy::Conditional => {
let client = Arc::new(ConditionalClient::new(eth_client.clone(), wallet.clone()));
bundler_service_run(
SocketAddr::new(args.bundler_addr, args.bundler_port),
wallet,
entry_points,
chain_conn,
args.beneficiary,
args.min_balance,
args.bundle_interval,
eth_client,
client,
uopool_grpc_client,
metrics_args.enable_metrics,
args.enable_access_list,
);
}
SendStrategy::Flashbots => {
let relay_endpoints: Vec<String> = match chain_conn
.named()
Expand Down
1 change: 0 additions & 1 deletion crates/bundler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ tokio = { workspace = true }
bytes = "1.5.0"
eyre = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
tracing = { workspace = true }
url = "2.5.0"

Expand Down
18 changes: 14 additions & 4 deletions crates/bundler/src/bundler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use ethers::{
},
};
use silius_contracts::entry_point::EntryPointAPI;
use silius_primitives::{UserOperation, UserOperationHash, Wallet};
use silius_primitives::{simulation::StorageMap, UserOperation, UserOperationHash, Wallet};
use std::sync::Arc;
use tracing::{info, trace};

Expand All @@ -18,10 +18,15 @@ pub trait SendBundleOp: Send + Sync + 'static {
///
/// # Arguments
/// * `bundle` - Bundle of [UserOperations](UserOperation)
/// * 'storage_map' - Storage map
///
/// # Returns
/// * `H256` - The hash
async fn send_bundle(&self, bundle: TypedTransaction) -> eyre::Result<H256>;
async fn send_bundle(
&self,
bundle: TypedTransaction,
storage_map: StorageMap,
) -> eyre::Result<H256>;
}

/// The `Bundler` struct is used to represent a bundler with necessary properties
Expand Down Expand Up @@ -140,10 +145,15 @@ where
///
/// # Arguments
/// * `uos` - An array of [UserOperations](UserOperation)
/// * `storage_map` - Storage map
///
/// # Returns
/// * `H256` - The hash
pub async fn send_bundle(&self, uos: &Vec<UserOperation>) -> eyre::Result<Option<H256>> {
pub async fn send_bundle(
&self,
uos: &Vec<UserOperation>,
storage_map: StorageMap,
) -> eyre::Result<Option<H256>> {
if uos.is_empty() {
info!("Skipping creating a new bundle, no user operations");
return Ok(None);
Expand All @@ -157,7 +167,7 @@ where
trace!("Bundle content: {uos:?}");

let bundle = self.create_bundle(uos).await?;
let hash = self.client.send_bundle(bundle).await?;
let hash = self.client.send_bundle(bundle, storage_map).await?;

info!(
"Bundle successfully sent, hash: {:?}, account: {:?}, entry point: {:?}, beneficiary: {:?}",
Expand Down
89 changes: 89 additions & 0 deletions crates/bundler/src/conditional.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
use crate::bundler::SendBundleOp;
use ethers::{
middleware::SignerMiddleware,
providers::Middleware,
signers::LocalWallet,
types::{
transaction::{
conditional::{AccountStorage, ConditionalOptions},
eip2718::TypedTransaction,
},
Address, H256,
},
};
use silius_primitives::{simulation::StorageMap, Wallet};
use std::{collections::HashMap, sync::Arc, time::Duration};
use tracing::trace;

/// A type alias for the Ethereum Conditional Signer client
#[derive(Clone)]
pub struct ConditionalClient<M>(pub SignerMiddleware<Arc<M>, LocalWallet>);

#[async_trait::async_trait]
impl<M> SendBundleOp for ConditionalClient<M>
where
M: Middleware + 'static,
{
/// Send a bundle of [UserOperations](UserOperation) to the Ethereum execution client
/// over conditional RPC method.
///
/// # Arguments
/// * `bundle` - Bundle of [UserOperations](UserOperation)
/// * 'storage_map' - Storage map
///
/// # Returns
/// * `H256` - The transaction hash
async fn send_bundle(
&self,
bundle: TypedTransaction,
storage_map: StorageMap,
) -> eyre::Result<H256> {
trace!("Sending transaction to the conditional endpoint: {bundle:?}");

let mut known_accounts: HashMap<Address, AccountStorage> = HashMap::default();

for (k, v) in storage_map.root_hashes {
known_accounts.insert(k, AccountStorage::RootHash(v));
}

for (k, v) in storage_map.slots {
known_accounts.insert(k, AccountStorage::SlotValues(v));
}

let signed_tx = self.0.sign_transaction(bundle).await?;

let tx = self
.0
.send_raw_transaction_conditional(
signed_tx,
ConditionalOptions { known_accounts, ..Default::default() },
)
.await?
.interval(Duration::from_millis(75));
let tx_hash = tx.tx_hash();

let tx_receipt = tx.await?;

trace!("Transaction receipt: {tx_receipt:?}");

Ok(tx_hash)
}
}

impl<M> ConditionalClient<M>
where
M: Middleware + 'static,
{
/// Create an Conditional client
///
/// # Arguments
/// * `eth_client` - Connection to the Ethereum execution client
/// * `wallet` - A [Wallet](Wallet) instance
///
/// # Returns
/// * `ConditionalClient` - A [Ethereum Signer Middleware](ConditionalClient)
pub fn new(eth_client: Arc<M>, wallet: Wallet) -> Self {
let signer = SignerMiddleware::new(eth_client, wallet.signer);
Self(signer)
}
}
13 changes: 9 additions & 4 deletions crates/bundler/src/ethereum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ use ethers::{
signers::LocalWallet,
types::{transaction::eip2718::TypedTransaction, H256},
};
use silius_primitives::Wallet;
use silius_primitives::{simulation::StorageMap, Wallet};
use std::{sync::Arc, time::Duration};
use tracing::trace;

/// A type alias for the Ethereum Signer client
#[derive(Clone)]
pub struct EthereumClient<M>(pub Arc<SignerMiddleware<Arc<M>, LocalWallet>>);
pub struct EthereumClient<M>(pub SignerMiddleware<Arc<M>, LocalWallet>);

#[async_trait::async_trait]
impl<M> SendBundleOp for EthereumClient<M>
Expand All @@ -22,10 +22,15 @@ where
///
/// # Arguments
/// * `bundle` - Bundle of [UserOperations](UserOperation)
/// * 'storage_map' - Storage map
///
/// # Returns
/// * `H256` - The transaction hash
async fn send_bundle(&self, bundle: TypedTransaction) -> eyre::Result<H256> {
async fn send_bundle(
&self,
bundle: TypedTransaction,
_storage_map: StorageMap,
) -> eyre::Result<H256> {
trace!("Sending transaction to the execution client: {bundle:?}");

let tx = self.0.send_transaction(bundle, None).await?.interval(Duration::from_millis(75));
Expand Down Expand Up @@ -53,6 +58,6 @@ where
/// * `EthereumClient` - A [Ethereum Signer Middleware](EthereumClient)
pub fn new(eth_client: Arc<M>, wallet: Wallet) -> Self {
let signer = SignerMiddleware::new(eth_client, wallet.signer);
Self(Arc::new(signer))
Self(signer)
}
}
9 changes: 7 additions & 2 deletions crates/bundler/src/flashbots.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use ethers::{
types::{transaction::eip2718::TypedTransaction, H256},
};
use ethers_flashbots::{BundleRequest, FlashbotsMiddleware, PendingBundleError, SimulatedBundle};
use silius_primitives::Wallet;
use silius_primitives::{simulation::StorageMap, Wallet};
use std::sync::Arc;
use tracing::{info, trace};
use url::Url;
Expand All @@ -27,10 +27,15 @@ where
///
/// # Arguments
/// * `uos` - Bundler of [UserOperations](UserOperation)
/// * 'storage_map' - Storage map
///
/// # Returns
/// * `H256` - The transaction hash of the bundle
async fn send_bundle(&self, bundle: TypedTransaction) -> eyre::Result<H256> {
async fn send_bundle(
&self,
bundle: TypedTransaction,
_storage_map: StorageMap,
) -> eyre::Result<H256> {
let bundle_req = self.generate_bundle_req(vec![bundle], false).await?;

match self.simulate_flashbots_bundle(&bundle_req).await {
Expand Down
2 changes: 2 additions & 0 deletions crates/bundler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
#![allow(dead_code)]

mod bundler;
mod conditional;
mod ethereum;
mod flashbots;

pub use bundler::{Bundler, SendBundleOp};
pub use conditional::ConditionalClient;
pub use ethereum::EthereumClient;
pub use flashbots::FlashbotsClient;
4 changes: 2 additions & 2 deletions crates/contracts/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ eyre = { workspace = true }
lazy_static = { workspace = true }
regex = "1.10.2"
serde = { workspace = true }
serde_json ={ workspace = true }
serde_json = { workspace = true }
thiserror = { workspace = true }

[dev-dependencies]
Expand All @@ -33,7 +33,7 @@ tokio = { workspace = true }
[build-dependencies]
# eth
ethers = { workspace = true, features = ["solc-full"] }
ethers-solc = "2.0.8"
ethers-solc = "2.0.14"

# misc
eyre = { workspace = true }
2 changes: 2 additions & 0 deletions crates/contracts/src/entry_point.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ impl<M: Middleware + 'static> EntryPoint<M> {
timeout: None,
},
state_overrides: None,
block_overrides: None,
},
)
.await
Expand Down Expand Up @@ -162,6 +163,7 @@ impl<M: Middleware + 'static> EntryPoint<M> {
timeout: None,
},
state_overrides: Some(spoof::balance(Address::zero(), UINT96_MAX.into())),
block_overrides: None,
},
)
.await
Expand Down
23 changes: 15 additions & 8 deletions crates/grpc/src/bundler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use ethers::{
use parking_lot::Mutex;
use silius_bundler::{Bundler, SendBundleOp};
use silius_metrics::grpc::MetricsLayer;
use silius_primitives::{UserOperation, Wallet};
use silius_primitives::{simulation::StorageMap, UserOperation, Wallet};
use std::{net::SocketAddr, sync::Arc, time::Duration};
use tonic::{Request, Response, Status};
use tracing::{error, info};
Expand Down Expand Up @@ -49,22 +49,29 @@ where
async fn get_user_operations(
uopool_grpc_client: &UoPoolClient<tonic::transport::Channel>,
ep: &Address,
) -> eyre::Result<Vec<UserOperation>> {
) -> eyre::Result<(Vec<UserOperation>, StorageMap)> {
let req = Request::new(GetSortedRequest { ep: Some((*ep).into()) });
let res = uopool_grpc_client.clone().get_sorted_user_operations(req).await?;

let uos: Vec<UserOperation> = res.into_inner().uos.into_iter().map(|u| u.into()).collect();
Ok(uos)
let res = res.into_inner();

let uos: Vec<UserOperation> = res.uos.into_iter().map(|u| u.into()).collect();
let map = match res.storage_map {
Some(map) => map.into(),
None => StorageMap::default(),
};

Ok((uos, map))
}

pub async fn send_bundles(&self) -> eyre::Result<(Vec<UserOperation>, Option<H256>)> {
let mut tx_hashes: Vec<Option<H256>> = vec![];
let mut user_operations: Vec<Vec<UserOperation>> = vec![];

for bundler in self.bundlers.iter() {
let uos =
let (uos, map) =
Self::get_user_operations(&self.uopool_grpc_client, &bundler.entry_point).await?;
let tx_hash = bundler.send_bundle(&uos).await?;
let tx_hash = bundler.send_bundle(&uos, map).await?;

tx_hashes.push(tx_hash);
user_operations.push(uos);
Expand Down Expand Up @@ -117,8 +124,8 @@ where
)
.await
{
Ok(bundle) => {
if let Err(e) = bundler_own.send_bundle(&bundle).await {
Ok((bundle, map)) => {
if let Err(e) = bundler_own.send_bundle(&bundle, map).await {
error!("Error while sending bundle: {e:?}");
}
}
Expand Down
Loading

0 comments on commit dea3df8

Please sign in to comment.