Skip to content

Commit 32ba732

Browse files
committed
feat: updates the bundle prep to track the rollup tx hash
1 parent 14a7e35 commit 32ba732

File tree

1 file changed

+92
-36
lines changed

1 file changed

+92
-36
lines changed

src/tasks/submit/flashbots.rs

Lines changed: 92 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ use init4_bin_base::{deps::metrics::counter, utils::signer::LocalOrAws};
1616
use tokio::{sync::mpsc, task::JoinHandle};
1717
use tracing::{Instrument, debug, debug_span};
1818

19-
/// Handles construction, simulation, and submission of rollup blocks to the
20-
/// Flashbots network.
19+
/// Handles preparation and submission of simulated rollup blocks to the
20+
/// Flashbots relay as MEV bundles.
2121
#[derive(Debug)]
2222
pub struct FlashbotsTask {
2323
/// Builder configuration for the task.
@@ -31,12 +31,14 @@ pub struct FlashbotsTask {
3131
/// The key used to sign requests to the Flashbots relay.
3232
signer: LocalOrAws,
3333
/// Channel for sending hashes of outbound transactions.
34-
_outbound: mpsc::UnboundedSender<TxHash>,
34+
outbound: mpsc::UnboundedSender<TxHash>,
3535
}
3636

3737
impl FlashbotsTask {
38-
/// Returns a new `FlashbotsTask` instance that receives `SimResult` types from the given
39-
/// channel and handles their preparation, submission to the Flashbots network.
38+
/// Creates a new `FlashbotsTask` instance with initialized providers and connections.
39+
///
40+
/// Sets up Quincey for block signing, host provider for transaction submission,
41+
/// Flashbots provider for bundle submission, and Zenith instance for contract interactions.
4042
pub async fn new(
4143
config: BuilderConfig,
4244
outbound: mpsc::UnboundedSender<TxHash>,
@@ -50,28 +52,56 @@ impl FlashbotsTask {
5052

5153
let zenith = config.connect_zenith(host_provider);
5254

53-
Ok(Self { config, quincey, zenith, flashbots, signer: builder_key, _outbound: outbound })
55+
Ok(Self { config, quincey, zenith, flashbots, signer: builder_key, outbound })
5456
}
5557

56-
/// Returns a reference to the inner `HostProvider`
57-
pub fn host_provider(&self) -> HostProvider {
58-
self.zenith.provider().clone()
59-
}
60-
61-
/// Returns a reference to the inner `FlashbotsProvider`
62-
pub const fn flashbots(&self) -> &FlashbotsProvider {
63-
&self.flashbots
64-
}
65-
66-
/// Prepares a MEV bundle with the configured submit call
58+
/// Prepares a MEV bundle from a simulation result.
59+
///
60+
/// This function serves as an entry point for bundle preparation and is left
61+
/// for forward compatibility when adding different bundle preparation methods.
6762
pub async fn prepare(&self, sim_result: &SimResult) -> eyre::Result<MevSendBundle> {
6863
// This function is left for forwards compatibility when we want to add
6964
// different bundle preparation methods in the future.
7065
self.prepare_bundle_helper(sim_result).await
7166
}
7267

73-
/// Prepares a BundleHelper call containing the rollup block and corresponding fills into a MEV bundle.
68+
/// Prepares a MEV bundle containing the host transactions and the rollup block.
69+
///
70+
/// This method orchestrates the bundle preparation by:
71+
/// 1. Preparing and signing the submission transaction
72+
/// 2. Tracking the transaction hash for monitoring
73+
/// 3. Encoding the transaction for bundle inclusion
74+
/// 4. Constructing the complete bundle body
7475
async fn prepare_bundle_helper(&self, sim_result: &SimResult) -> eyre::Result<MevSendBundle> {
76+
// Prepare and sign the transaction
77+
let block_tx = self.prepare_signed_transaction(sim_result).await?;
78+
79+
// Track the outbound transaction
80+
self.track_outbound_tx(&block_tx);
81+
82+
// Encode the transaction
83+
let tx_bytes = block_tx.encoded_2718().into();
84+
85+
// Build the bundle body with the block_tx bytes as the last transaction in the bundle.
86+
let bundle_body = self.build_bundle_body(sim_result, tx_bytes);
87+
88+
// Create the MEV bundle (valid only in the specific host block)
89+
Ok(MevSendBundle::new(
90+
sim_result.host_block_number(),
91+
Some(sim_result.host_block_number()),
92+
ProtocolVersion::V0_1,
93+
bundle_body,
94+
))
95+
}
96+
97+
/// Prepares and signs the submission transaction for the rollup block.
98+
///
99+
/// Creates a `SubmitPrep` instance to build the transaction, then fills
100+
/// and signs it using the host provider.
101+
async fn prepare_signed_transaction(
102+
&self,
103+
sim_result: &SimResult,
104+
) -> eyre::Result<alloy::consensus::TxEnvelope> {
75105
let prep = SubmitPrep::new(
76106
&sim_result.block,
77107
self.host_provider(),
@@ -80,34 +110,48 @@ impl FlashbotsTask {
80110
);
81111

82112
let tx = prep.prep_transaction(sim_result.prev_host()).await?;
83-
84113
let sendable = self.host_provider().fill(tx.into_request()).await?;
85114

86-
let tx_bytes = sendable
87-
.as_envelope()
88-
.ok_or_eyre("failed to get envelope from filled tx")?
89-
.encoded_2718()
90-
.into();
115+
sendable.as_envelope().ok_or_eyre("failed to get envelope from filled tx").cloned()
116+
}
117+
118+
/// Tracks the outbound transaction hash and increments submission metrics.
119+
///
120+
/// Sends the transaction hash to the outbound channel for monitoring.
121+
/// Logs a debug message if the channel is closed.
122+
fn track_outbound_tx(&self, envelope: &alloy::consensus::TxEnvelope) {
123+
counter!("signet.builder.flashbots.").increment(1);
124+
let hash = *envelope.tx_hash();
125+
if self.outbound.send(hash).is_err() {
126+
debug!("outbound channel closed, could not track tx hash");
127+
}
128+
}
91129

92-
let bundle_body = sim_result
130+
/// Constructs the MEV bundle body from host transactions and the submission transaction.
131+
///
132+
/// Combines all host transactions from the rollup block with the prepared rollup block
133+
/// submission transaction, wrapping each as a non-revertible bundle item.
134+
///
135+
/// The rollup block transaction is placed last in the bundle.
136+
fn build_bundle_body(
137+
&self,
138+
sim_result: &SimResult,
139+
tx_bytes: alloy::primitives::Bytes,
140+
) -> Vec<BundleItem> {
141+
sim_result
93142
.block
94143
.host_transactions()
95144
.iter()
96145
.cloned()
97146
.chain(std::iter::once(tx_bytes))
98147
.map(|tx| BundleItem::Tx { tx, can_revert: false })
99-
.collect::<Vec<_>>();
100-
101-
// Only valid in the specific host block
102-
Ok(MevSendBundle::new(
103-
sim_result.host_block_number(),
104-
Some(sim_result.host_block_number()),
105-
ProtocolVersion::V0_1,
106-
bundle_body,
107-
))
148+
.collect()
108149
}
109150

110-
/// Task future that runs the Flashbots submission loop.
151+
/// Main task loop that processes simulation results and submits bundles to Flashbots.
152+
///
153+
/// Receives `SimResult`s from the inbound channel, prepares MEV bundles, and submits
154+
/// them to the Flashbots relay. Skips empty blocks and continues processing on errors.
111155
async fn task_future(self, mut inbound: mpsc::UnboundedReceiver<SimResult>) {
112156
debug!("starting flashbots task");
113157

@@ -172,7 +216,19 @@ impl FlashbotsTask {
172216
}
173217
}
174218

175-
/// Spawns the Flashbots task that handles incoming `SimResult`s.
219+
/// Returns a clone of the host provider for transaction operations.
220+
fn host_provider(&self) -> HostProvider {
221+
self.zenith.provider().clone()
222+
}
223+
224+
/// Returns a reference to the Flashbots provider.
225+
const fn flashbots(&self) -> &FlashbotsProvider {
226+
&self.flashbots
227+
}
228+
229+
/// Spawns the Flashbots task in a new Tokio task.
230+
///
231+
/// Returns a channel sender for submitting `SimResult`s and a join handle for the task.
176232
pub fn spawn(self) -> (mpsc::UnboundedSender<SimResult>, JoinHandle<()>) {
177233
let (sender, inbound) = mpsc::unbounded_channel::<SimResult>();
178234
let handle = tokio::spawn(self.task_future(inbound));

0 commit comments

Comments
 (0)