feat: allow bundles to target storage slots for blind backrunning#933
Open
MavenRain wants to merge 1 commit into
Open
feat: allow bundles to target storage slots for blind backrunning#933MavenRain wants to merge 1 commit into
MavenRain wants to merge 1 commit into
Conversation
Implements flashbots#27. A bundle can declare the storage slots it targets via the optional `targetStorageSlots` field on eth_sendBundle (v2+). The builder only attempts to include such a bundle after an order that writes one of those slots has been added to the block, enabling blind backrunning and reducing wasted inclusion attempts. - rbuilder-primitives: add target_storage_slots to Bundle, the targetStorageSlots wire field + round-trip, v2 gating, and Order::target_storage_slots(). - PrioritizedOrderStore: park target-slot bundles until one of their slots is written (mirrors the nonce pending/release machinery) via notify_slots_written(). - ordering_builder: after each committed order, feed the slots it wrote (from the order's simulation trace) to the store so waiting bundles are released. Adds unit tests for parsing/round-trip, v1 rejection, and store parking/release. Signed-off-by: Onyeka Obi <softwareengineerasaservant@isurvivable.cv>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
📝 Summary
Closes #27. Lets a bundle declare the storage slots it targets via a new optional
targetStorageSlotsfield oneth_sendBundle(bundle v2+). The builder only attempts toinclude such a bundle after an order that writes one of those slots has been added to the
block. This enables blind backrunning (backrun any transaction that touches, e.g., a pool
reserve slot, without knowing its hash) and reduces the wasted inclusion attempts / spam that
searchers otherwise generate by submitting a bundle for every candidate position.
An empty
targetStorageSlots(the default) leaves a bundle unconditional, so existing bundlesare completely unaffected.
Example request:
{ "version": "v2", "txs": ["0x..."], "targetStorageSlots": [ { "address": "0x1f98431c8ad98523631ae4a59f267346ea31f984", "slot": "0x0000...0008" } ] }💡 Motivation and Context
Blind backrunning is a common searcher pattern: a bundle wants to land immediately after any
transaction that mutates some piece of state (a DEX pool reserve, an oracle slot, ...), but the
searcher does not know the triggering transaction's hash ahead of time. Today the only way to
express this is to spam many speculative bundles, most of which the builder simulates and
discards. Letting the bundle name the storage slots it depends on lets the builder attempt it
exactly once, and only when the precondition is actually met.
How it works
The change deliberately reuses machinery that already exists, so it adds no cost to the hot path:
(
simulate_orderruns anAccumulatorSimulationTracer, so everySimulatedOrdercarries apopulated
used_state_trace).PrioritizedOrderStorealready gates "attempt-after" dependencies for nonces: an order whoserequired nonce is not yet reached is parked in
pending_orders(keyed byAccountNonce) andreleased by
update_onchain_nonceswhen a committed order satisfies it.Target storage slots mirror that exact pattern, keyed by
SlotKeyinstead ofAccountNonce:pending_on_slotmap instead of entering the ready queue.fill_ordersloop feeds the slots that order wrote(taken from its already-computed simulation trace) to a new
notify_slots_written, whichreleases any bundle waiting on one of those slots back into the normal priority queue.
Because the slot writes come from the existing simulation trace, no change is made to the
block-building commit tracer and there is no added EVM instrumentation. Bundles that do not
use the feature see identical behavior.
Notes / scope
targetStorageSlotsis only accepted on bundle version >= v2; a v1 bundlethat sets it is rejected with
FieldNotSupportedByVersion, consistent with the other v2 fields.of them is written.
does not currently gate on target slots (documented on the field).
slot 0 for nonce tracking, so a bundle that explicitly targets
{eoa, 0x0}may be released byany transaction from that account. This is a benign over-report (it can only release a bundle
early, never miss a release) and is noted in a code comment.
🗂️ Changes
rbuilder-primitivesBundle::target_storage_slots: Vec<SlotKey>and anOrder::target_storage_slots()accessor.targetStorageSlotswire field (RawTargetStorageSlot { address, slot }) onRawBundleMetadata, with decode/encode round-trip and the v2 version gate.compatibility (same as
signer/external_hash).rbuilderPrioritizedOrderStore:pending_on_slot+written_slots, slot gating ininsert_order,and
notify_slots_written.ordering_builder::fill_orders: releases waiting bundles using each committed order'swritten slots.
🧪 Testing
rbuilder-primitives:targetStorageSlotsv2 parse + wire round-trip, and v1 rejection.rbuilder:test_block_orders_target_storage_slots— a slot-targeting bundle stays pending,is not released by an unrelated slot write, and becomes includable once its target slot is
written.
✅ I have completed the following steps:
make lintmake test