Skip to content

[E5] Ordering strategy — same-block vs next-block, tip ladder, race detection on path_hash #125

@0xfandom

Description

@0xfandom

Follow-up to #117 / #74. Today the executor hard-codes target_block = current + 1 and uses a fixed tip percentage. With mempool-triggered opps coming online (#117 + sim issue), we need a real ordering policy that distinguishes mempool-fresh from block-driven candidates and reacts to competition.

This is the policy layer between detection and bundle build. No new submission paths — still shadow-only — just smarter decisions recorded on the arbs row.

To do

Strategy enum on arbs

  • migration 0003_add_strategy_to_arbs.sql adding strategy TEXT NOT NULL DEFAULT 'backrun_next_block'
  • Rust + Go enum in lockstep: BackrunNextBlock, BackrunSameBlock, Skipped (with reason)
  • protocol_label-style adapter so renaming the variant ripples to the DB binding

Policy

  • BackrunSameBlock for ultra-fresh mempool-triggered opps (target = current pending block, not next)
  • BackrunNextBlock retained as default for block-driven opps
  • reject (skip) if a competing bundle for the same path_hash was submitted within the last block — record in arbs with strategy='skipped' + reason

Tip ladder

  • base tip = X% of net profit (config knob)
  • race bump: if same path_hash detected ≥2 times within current block, escalate tip by Y bps per repeat (capped)
  • tip decided per-bundle, recorded on bundles.tip_bps (already in schema)
  • config under config/strategy.yaml — hot-reloadable via existing ControlService.ReloadConfig

Builder selection

  • Flashbots-only path for sandwich-resistant routes (mempool-triggered backruns)
  • broadcast all four (Flashbots, Titan, Beaver, Rsync) for plain backruns
  • selection recorded in bundles.builders JSONB (already wired)

Metrics

  • aether_strategy_chosen_total{strategy} counter
  • aether_tip_bps_chosen histogram with bucket boundaries at common bps tiers
  • aether_race_bumps_total{path_hash_bucket} (low-cardinality bucket of path_hash)

Out of scope (separate issue)

Done when

  • 30-min live shadow run shows non-zero counts across at least two strategy values in arbs table
  • repeat-detection test: same simulated path_hash published twice within 1s produces an escalated tip on second bundles row
  • builder-selection test: mempool-triggered candidate produces a bundle row with builders=["flashbots"] only; block-driven candidate produces a row with all four

Files touched

  • crates/grpc-server/src/engine.rs (build_new_arb)
  • crates/grpc-server/src/strategy.rs (new)
  • crates/common/src/types.rs (Strategy enum)
  • cmd/executor/main.go (mirror enum, builder selection)
  • internal/db/ledger.go (NewArb gains Strategy field)
  • migrations/0003_add_strategy_to_arbs.sql
  • config/strategy.yaml

Branch

feat/mempool-tracking-scaffold

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions