Skip to content

Commit

Permalink
feat(builder): start support for multiple entry points in builder
Browse files Browse the repository at this point in the history
  • Loading branch information
dancoombs committed Mar 22, 2024
1 parent c089166 commit b623c94
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 51 deletions.
20 changes: 13 additions & 7 deletions bin/rundler/src/cli/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@ use anyhow::Context;
use clap::Args;
use ethers::types::H256;
use rundler_builder::{
self, BuilderEvent, BuilderEventKind, BuilderTask, BuilderTaskArgs, LocalBuilderBuilder,
TransactionSenderType,
self, BuilderEvent, BuilderEventKind, BuilderTask, BuilderTaskArgs, EntryPointBuilderSettings,
LocalBuilderBuilder, TransactionSenderType,
};
use rundler_pool::RemotePoolClient;
use rundler_sim::{MempoolConfig, PriorityFeeMode};
use rundler_task::{
server::{connect_with_retries_shutdown, format_socket_addr},
spawn_tasks_with_shutdown,
};
use rundler_types::chain::ChainSpec;
use rundler_types::{chain::ChainSpec, EntryPointVersion};
use rundler_utils::emit::{self, WithEntryPoint, EVENT_CHANNEL_CAPACITY};
use tokio::sync::broadcast;

Expand Down Expand Up @@ -110,7 +110,7 @@ pub struct BuilderArgs {
pub submit_url: Option<String>,

/// Choice of what sender type to to use for transaction submission.
/// Defaults to the value of `raw`. Other options inclue `flashbots`,
/// Defaults to the value of `raw`. Other options include `flashbots`,
/// `conditional` and `polygon_bloxroute`
#[arg(
long = "builder.sender",
Expand Down Expand Up @@ -191,6 +191,7 @@ impl BuilderArgs {
.context("should have a node HTTP URL")?;
let submit_url = self.submit_url.clone().unwrap_or_else(|| rpc_url.clone());

// TODO these should be scoped by entry point
let mempool_configs = match &common.mempool_config_path {
Some(path) => {
get_json_config::<HashMap<H256, MempoolConfig>>(path, &common.aws_region).await?
Expand All @@ -199,6 +200,14 @@ impl BuilderArgs {
};

Ok(BuilderTaskArgs {
// TODO: support multiple entry points
entry_points: vec![EntryPointBuilderSettings {
address: chain_spec.entry_point_address,
version: EntryPointVersion::V0_6,
num_bundle_builders: common.num_builders,
bundle_builder_index_offset: self.builder_index_offset,
mempool_configs,
}],
chain_spec,
rpc_url,
private_key: self.private_key.clone(),
Expand All @@ -217,14 +226,11 @@ impl BuilderArgs {
sender_type: self.sender_type,
eth_poll_interval: Duration::from_millis(common.eth_poll_interval_millis),
sim_settings: common.into(),
mempool_configs,
max_blocks_to_wait_for_mine: self.max_blocks_to_wait_for_mine,
replacement_fee_percent_increase: self.replacement_fee_percent_increase,
max_fee_increases: self.max_fee_increases,
remote_address,
bloxroute_auth_header: self.bloxroute_auth_header.clone(),
num_bundle_builders: common.num_builders,
bundle_builder_index_offset: self.builder_index_offset,
})
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/builder/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,6 @@ pub use server::{LocalBuilderBuilder, LocalBuilderHandle, RemoteBuilderClient};
mod signer;

mod task;
pub use task::{Args as BuilderTaskArgs, BuilderTask};
pub use task::{Args as BuilderTaskArgs, BuilderTask, EntryPointBuilderSettings};

mod transaction_tracker;
123 changes: 86 additions & 37 deletions crates/builder/src/task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,24 @@ use std::{collections::HashMap, net::SocketAddr, sync::Arc, time::Duration};
use anyhow::{bail, Context};
use async_trait::async_trait;
use ethers::{
providers::{JsonRpcClient, Provider},
types::H256,
providers::{JsonRpcClient, Provider as EthersProvider},
types::{Address, H256},
};
use ethers_signers::Signer;
use futures::future;
use futures_util::TryFutureExt;
use rundler_provider::EthersEntryPointV0_6;
use rundler_provider::{EntryPointProvider, EthersEntryPointV0_6, Provider};
use rundler_sim::{
simulation::v0_6::{
SimulateValidationTracerImpl as SimulateValidationTracerImplV0_6,
Simulator as SimulatorV0_6,
},
MempoolConfig, PriorityFeeMode, SimulationSettings,
MempoolConfig, PriorityFeeMode, SimulationSettings, Simulator,
};
use rundler_task::Task;
use rundler_types::{chain::ChainSpec, pool::Pool};
use rundler_types::{
chain::ChainSpec, pool::Pool, v0_6, EntryPointVersion, UserOperation, UserOperationVariant,
};
use rundler_utils::{emit::WithEntryPoint, handle};
use rusoto_core::Region;
use tokio::{
Expand Down Expand Up @@ -87,8 +89,6 @@ pub struct Args {
pub eth_poll_interval: Duration,
/// Operation simulation settings
pub sim_settings: SimulationSettings,
/// Alt-mempool configs
pub mempool_configs: HashMap<H256, MempoolConfig>,
/// Maximum number of blocks to wait for a transaction to be mined
pub max_blocks_to_wait_for_mine: u64,
/// Percentage to increase the fees by when replacing a bundle transaction
Expand All @@ -103,10 +103,23 @@ pub struct Args {
///
/// Checked ~after~ checking for conditional sender or Flashbots sender.
pub bloxroute_auth_header: Option<String>,
/// Entry points to start builders for
pub entry_points: Vec<EntryPointBuilderSettings>,
}

/// Builder settings for an entrypoint
#[derive(Debug)]
pub struct EntryPointBuilderSettings {
/// Entry point address
pub address: Address,
/// Entry point version
pub version: EntryPointVersion,
/// Number of bundle builders to start
pub num_bundle_builders: u64,
/// Index offset for bundle builders
pub bundle_builder_index_offset: u64,
/// Mempool configs
pub mempool_configs: HashMap<H256, MempoolConfig>,
}

/// Builder task
Expand All @@ -124,23 +137,43 @@ where
P: Pool + Clone,
{
async fn run(mut self: Box<Self>, shutdown_token: CancellationToken) -> anyhow::Result<()> {
info!("Mempool config: {:?}", self.args.mempool_configs);

let provider =
rundler_provider::new_provider(&self.args.rpc_url, Some(self.args.eth_poll_interval))?;

let ep_v0_6 = EthersEntryPointV0_6::new(
self.args.chain_spec.entry_point_address,
Arc::clone(&provider),
);

let mut sender_handles = vec![];
let mut bundle_sender_actions = vec![];
for i in 0..self.args.num_bundle_builders {
let (spawn_guard, bundle_sender_action) = self
.create_bundle_builder(
i + self.args.bundle_builder_index_offset,
Arc::clone(&provider),
)
.await?;
sender_handles.push(spawn_guard);
bundle_sender_actions.push(bundle_sender_action);

for ep in &self.args.entry_points {
// TODO entry point v0.7: needs 0.7 EP and simulator
if ep.version != EntryPointVersion::V0_6 {
bail!("Unsupported entry point version: {:?}", ep.version);
}

info!("Mempool config for ep v0.6: {:?}", ep.mempool_configs);

for i in 0..ep.num_bundle_builders {
let (spawn_guard, bundle_sender_action) = self
.create_bundle_builder(
i + ep.bundle_builder_index_offset,
Arc::clone(&provider),
ep_v0_6.clone(),
self.create_simulator_v0_6(
Arc::clone(&provider),
ep_v0_6.clone(),
ep.mempool_configs.clone(),
),
)
.await?;
sender_handles.push(spawn_guard);
bundle_sender_actions.push(bundle_sender_action);
}
}

// flatten the senders handles to one handle, short-circuit on errors
let sender_handle = tokio::spawn(
future::try_join_all(sender_handles)
Expand Down Expand Up @@ -211,14 +244,23 @@ where
Box::new(self)
}

async fn create_bundle_builder<C: JsonRpcClient + 'static>(
async fn create_bundle_builder<UO, E, S, C>(
&self,
index: u64,
provider: Arc<Provider<C>>,
provider: Arc<EthersProvider<C>>,
entry_point: E,
simulator: S,
) -> anyhow::Result<(
JoinHandle<anyhow::Result<()>>,
mpsc::Sender<BundleSenderAction>,
)> {
)>
where
UO: UserOperation + From<UserOperationVariant>,
UserOperationVariant: AsRef<UO>,
E: EntryPointProvider<UO> + Clone,
S: Simulator<UO = UO>,
C: JsonRpcClient + 'static,
{
let (send_bundle_tx, send_bundle_rx) = mpsc::channel(1);

let signer = if let Some(pk) = &self.args.private_key {
Expand Down Expand Up @@ -265,20 +307,6 @@ where
bundle_priority_fee_overhead_percent: self.args.bundle_priority_fee_overhead_percent,
};

let ep = EthersEntryPointV0_6::new(
self.args.chain_spec.entry_point_address,
Arc::clone(&provider),
);
let simulate_validation_tracer =
SimulateValidationTracerImplV0_6::new(Arc::clone(&provider), ep.clone());
let simulator = SimulatorV0_6::new(
Arc::clone(&provider),
ep.clone(),
simulate_validation_tracer,
self.args.sim_settings,
self.args.mempool_configs.clone(),
);

let submit_provider = rundler_provider::new_provider(
&self.args.submit_url,
Some(self.args.eth_poll_interval),
Expand Down Expand Up @@ -314,7 +342,7 @@ where
index,
self.pool.clone(),
simulator,
ep.clone(),
entry_point.clone(),
Arc::clone(&provider),
proposer_settings,
self.event_sender.clone(),
Expand All @@ -325,7 +353,7 @@ where
self.args.chain_spec.clone(),
beneficiary,
proposer,
ep,
entry_point,
transaction_tracker,
self.pool.clone(),
builder_settings,
Expand All @@ -335,4 +363,25 @@ where
// Spawn each sender as its own independent task
Ok((tokio::spawn(builder.send_bundles_in_loop()), send_bundle_tx))
}

fn create_simulator_v0_6<C, E>(
&self,
provider: Arc<C>,
ep: E,
mempool_configs: HashMap<H256, MempoolConfig>,
) -> SimulatorV0_6<C, E, SimulateValidationTracerImplV0_6<C, E>>
where
C: Provider,
E: EntryPointProvider<v0_6::UserOperation> + Clone,
{
let simulate_validation_tracer =
SimulateValidationTracerImplV0_6::new(Arc::clone(&provider), ep.clone());
SimulatorV0_6::new(
Arc::clone(&provider),
ep,
simulate_validation_tracer,
self.args.sim_settings,
mempool_configs,
)
}
}
9 changes: 7 additions & 2 deletions crates/provider/src/ethers/entry_point/v0_6.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ use rundler_types::{
use rundler_utils::eth::{self, ContractRevertError};

use crate::{
traits::HandleOpsOut, AggregatorOut, AggregatorSimOut, BundleHandler, L1GasProvider, Provider,
SignatureAggregator, SimulationProvider,
traits::HandleOpsOut, AggregatorOut, AggregatorSimOut, BundleHandler, EntryPointProvider,
L1GasProvider, Provider, SignatureAggregator, SimulationProvider,
};

const ARBITRUM_NITRO_NODE_INTERFACE_ADDRESS: Address = H160([
Expand Down Expand Up @@ -384,6 +384,11 @@ where
}
}

impl<P> EntryPointProvider<UserOperation> for EntryPoint<P> where
P: Provider + Middleware + Send + Sync + 'static
{
}

fn get_handle_ops_call<M: Middleware>(
entry_point: &IEntryPoint<M>,
ops_per_aggregator: Vec<UserOpsPerAggregator<UserOperation>>,
Expand Down
5 changes: 3 additions & 2 deletions crates/provider/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub use traits::test_utils::*;
#[cfg(any(test, feature = "test-utils"))]
pub use traits::MockProvider;
pub use traits::{
AggregatorOut, AggregatorSimOut, BundleHandler, EntryPoint, HandleOpsOut, L1GasProvider,
Provider, ProviderError, ProviderResult, SignatureAggregator, SimulationProvider,
AggregatorOut, AggregatorSimOut, BundleHandler, EntryPoint, EntryPointProvider, HandleOpsOut,
L1GasProvider, Provider, ProviderError, ProviderResult, SignatureAggregator,
SimulationProvider,
};
10 changes: 10 additions & 0 deletions crates/provider/src/traits/entry_point.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,13 @@ pub trait SimulationProvider: Send + Sync + 'static {
revert_data: Bytes,
) -> Result<ExecutionResult, String>;
}

/// Trait for a provider that provides all entry point functionality
pub trait EntryPointProvider<UO>:
EntryPoint
+ SignatureAggregator<UO = UO>
+ BundleHandler<UO = UO>
+ SimulationProvider<UO = UO>
+ L1GasProvider<UO = UO>
{
}
4 changes: 2 additions & 2 deletions crates/provider/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ pub use error::ProviderError;

mod entry_point;
pub use entry_point::{
AggregatorOut, AggregatorSimOut, BundleHandler, EntryPoint, HandleOpsOut, L1GasProvider,
SignatureAggregator, SimulationProvider,
AggregatorOut, AggregatorSimOut, BundleHandler, EntryPoint, EntryPointProvider, HandleOpsOut,
L1GasProvider, SignatureAggregator, SimulationProvider,
};

mod provider;
Expand Down

0 comments on commit b623c94

Please sign in to comment.