Lesson 3 — Building custom gossip: MEV-Boost-style messaging on Reth
Question
You're running a searcher node. You find a profitable bundle → you want it to reach a small set of trusted builders, not the whole mempool. eth/68 tx gossip assumes a public "everyone relays for everyone" model and has no concept of "send only to this peer set". What custom sub-protocol closes that gap?
Principle (minimum model)
- eth/68 makes three assumptions that custom gossip breaks. Public (anyone connected can see it) + consensus-relevant + every peer cooperates on relay.
- Custom gossip needs three things. Private gossip (specific peer sets only) + application-layer routing (capability-based) + custom signing (chain-specific auth).
- Four production examples. MEV-Boost bundles (private orderflow) + shared-sequencer pre-confirmations + payment-rail merchant attestations + L2-to-L2 sequencer coordination.
bundle/1protocol has four messages. Hello (handshake) + BundleAnnounce (hash + expected profit) + BundleRequest (hash + requester signature) + BundleData (encrypted payload).- Three discovery patterns for private protocols. Allowlist (peer IDs hardcoded) + out-of-band invite (peer IDs swapped on Discord / GitHub — the MEV-Boost pattern) + Tor routing (full network-location hiding).
- MEV-Boost's four roles. Relayer (sells) + Builder (assembles) + Proposer (picks winner) + sealed-bid auction.
- Four DoS-mitigation axes. Announce spam (per-peer rate limit + signature required) + fake bundles (signature checked on request) + bandwidth exhaustion (per-peer caps + eviction) + Sybil (peer-ID allowlist or PoS binding).
- Custom gossip is a strategic surface, not just a tech detail. Whoever sees the orderflow first wins the auction — the gossip topology is the market structure.
Worked example + steps
Building custom gossip — MEV-Boost-style messaging on Reth
You're running a searcher node. You find a profitable bundle. You want to ship it only to a small set of trusted builders — not broadcast it to every peer on the network so the bundle leaks and gets front-run. eth/68 transaction gossip is the wrong tool: it's public, it assumes "everyone relays everything," and it has no concept of "send to these specific peers."
That's the gap custom sub-protocols fill. This lesson builds a minimal one — a peer-to-peer message bus on top of reth's networking — that lets your application broadcast and receive chain-specific messages on its own rules. Same pattern used by MEV-Boost, private mempools, shared sequencer coordination, and payment-routing infra.
1. The motivation — when default gossip fails
eth/68 carries canonical chain data — blocks, transactions, receipts. Its assumptions:
- Messages are public (anyone with a connection sees them)
- Messages are about consensus
- Peers cooperate by relaying everything
Custom traffic breaks all three. To ship it you need:
- Private gossip — only your peer set sees it
- Application-layer routing — route to specific peers based on capabilities
- Custom signatures — chain-specific authentication
Where this shows up in production:
- MEV-Boost bundles (private orderflow)
- Shared sequencer pre-confirmations
- Payment rail merchant attestations
- L2 sequencer-to-sequencer coordination
2. The minimal custom protocol
You're going to build a protocol called bundle/1. Its job: peers announce "I have a profitable bundle" and others can request it.
Four message types:
| Message | Purpose |
|---|---|
Hello | Handshake — share what we support |
BundleAnnounce | "Hash X is a bundle, ~Y gas to extract" |
BundleRequest | "Send me bundle X" |
BundleData | The full bundle (encrypted to sender) |
#[derive(Debug, RlpDecodable, RlpEncodable)]
pub enum BundleMessage {
Hello { protocol_version: u8, peer_capabilities: u64 },
BundleAnnounce { bundle_hash: B256, expected_profit_gwei: u64 },
BundleRequest { bundle_hash: B256, requester_signature: Bytes },
BundleData { bundle_hash: B256, encrypted_payload: Bytes },
}
3. The protocol handler
Implement a Reth-compatible sub-protocol:
use reth_network::SubProtocol;
use std::collections::HashMap;
pub struct BundleProtocol {
known_bundles: HashMap<B256, Bundle>,
peer_set: HashSet<PeerId>,
signer: PrivateKeySigner,
}
impl SubProtocol for BundleProtocol {
const NAME: &'static [u8] = b"bundle";
const VERSION: u8 = 1;
const MESSAGE_COUNT: u8 = 4;
fn on_handshake(&mut self, peer: PeerId) -> eyre::Result<()> {
// Authenticate peer is in our allowlist
if !self.peer_set.contains(&peer) {
return Err(eyre!("not authorized peer"));
}
Ok(())
}
fn on_message(&mut self, peer: PeerId, msg: Bytes) -> eyre::Result<Option<Bytes>> {
let parsed: BundleMessage = decode(&msg)?;
match parsed {
BundleMessage::Hello { protocol_version, .. } => {
tracing::info!(peer = ?peer, version = protocol_version, "peer joined");
Ok(None)
}
BundleMessage::BundleAnnounce { bundle_hash, expected_profit_gwei } => {
// If we don't have the bundle, request it
if !self.known_bundles.contains_key(&bundle_hash) {
let request = BundleMessage::BundleRequest {
bundle_hash,
requester_signature: self.signer.sign(&bundle_hash)?.to_bytes(),
};
Ok(Some(encode(&request)))
} else {
Ok(None)
}
}
BundleMessage::BundleRequest { bundle_hash, requester_signature } => {
// Verify request signature
verify_signature(&bundle_hash, &requester_signature)?;
// Send the bundle
if let Some(bundle) = self.known_bundles.get(&bundle_hash) {
let encrypted = encrypt_for_peer(&peer, bundle.serialize());
let response = BundleMessage::BundleData {
bundle_hash,
encrypted_payload: encrypted,
};
Ok(Some(encode(&response)))
} else {
Ok(None)
}
}
BundleMessage::BundleData { bundle_hash, encrypted_payload } => {
// Decrypt and store
let decrypted = decrypt_from_peer(&peer, encrypted_payload)?;
let bundle = Bundle::deserialize(&decrypted)?;
self.known_bundles.insert(bundle_hash, bundle);
Ok(None)
}
}
}
}
That's the protocol. ~70 lines for a peer-to-peer bundle marketplace.
4. Registering with reth
use reth_node_builder::NodeBuilder;
let bundle_protocol = BundleProtocol::new(allowlisted_peers, signer);
let node = NodeBuilder::new(config)
.with_components(
Components::default()
.add_sub_protocol(bundle_protocol)
)
.launch()
.await?;
That's it. Your custom protocol runs on the same RLPx connections as eth/68. Peers that support bundle/1 send and receive these messages. Peers that don't are unaffected.
5. Peer discovery for private protocols
There's a problem you should be uncomfortable with: default discv5 announces your full capability list. Anyone scanning the network can see "this node supports bundle/1" — which defeats the privacy goal. So private protocols don't use discv5 for peer-finding. Common patterns:
- Allowlist-based: hardcode peer IDs of your protocol participants
- Out-of-band invitation: have peers exchange contact info via separate channel
- Tor-routed: hide network location entirely
MEV-Boost uses the second pattern: bundle relays distribute their peer IDs via Discord, GitHub, etc. The protocol is then point-to-point between known parties.
6. The MEV-Boost pattern
Flashbots' MEV-Boost is the production reference for this whole approach. Its key ideas, mapped to our custom protocol:
| Concept | Implementation |
|---|---|
| Relayer-builder separation | Relayer (publishes "I have a block for sale"), builder (constructs blocks), proposer (picks winning bid) |
| Sealed-bid auctions | Builders submit bids; proposer picks highest |
| Reputation-based | Builders earn reputation, relayers track abusers |
| Network-layer trust | All over private p2p — not on-chain |
For a payment-priority chain like Tempo, an MEV-Boost-equivalent might be:
- Relayers: aggregate merchant payment bundles
- Builders: construct payment-priority blocks (merchant tx + bundle settlement)
- Sequencer: picks the most-profitable + most-merchant-friendly bundle
Could ship in 2026 if Tempo decentralizes its sequencer.
7. The DOS protection problem
Custom protocols expose new attack surfaces. Default eth/68 has battle-tested defenses; yours has none until you write them. The minimum:
| Attack | Mitigation |
|---|---|
| Spam announcements | Rate limit per peer; require signed announcements |
| Fake bundles | Require signature on announce + verify on request |
| Bandwidth exhaustion | Per-peer bandwidth caps; eviction on excess |
| Sybil (many fake peers) | Peer ID allowlist or proof-of-stake binding |
Skip these and your custom protocol is a DOS amplifier — every peer can flood every other peer through your code. Build the protections in alongside the core logic, not as a follow-up.
8. For my projects
Telos (Tempo↔HL intent matching)
Custom gossip would be useful for:
- "I have an intent matching opportunity"
- "Bid X for executing this intent"
- "Proof of intent execution"
These don't fit Ethereum tx semantics. A custom protocol on top of reth's networking is the natural fit.
mppsol (cross-VM settlement)
Settlement attestations from Tempo to Solana go via CCIP (already covered). But for intra-Tempo coordination, custom gossip could:
- Announce pending merchant settlements before they hit the chain
- Coordinate among merchant nodes for HA
Hyperliquid integration
If you build a node that participates in HL's network, you'd need to understand their custom protocols. They are not public, but the pattern is the same: custom sub-protocols on RLPx-like transport.
9. Practice
- Sketch a 2-message protocol for "broadcast my merchant attestation"
- Identify: how does the allowlist prevent Sybil attacks?
- Think: what's the bandwidth cost of broadcasting 1000 messages/sec to 10 peers?
- Read MEV-Boost spec and find the relayer protocol
10. Reading list
- reth network crate
- MEV-Boost docs
- libp2p tutorials — for understanding modular networking
Final check: in one sentence, why is "custom gossip" the natural extension for chain-specific applications like MEV markets and payment routing? If your answer doesn't reference "default gossip is for canonical chain data only," re-read §1.
Pass criteria
- List the three eth/68 assumptions and which ones break for private orderflow.
- Name the three pieces needed for custom gossip and one production system that uses each.
- Walk the four-message
bundle/1handshake and explain why announce/request are separate. - Compare the three discovery patterns (allowlist / out-of-band / Tor) by trade-off.
- Map MEV-Boost's four roles onto the auction structure.
- Sketch the four DoS-mitigation axes with one mitigation each.
- Explain why gossip topology is also market structure.
Summary (3 lines)
- Custom gossip = chain-specific messaging that breaks eth/68's three assumptions (Public / Consensus-relevant / everyone-relays). Three building blocks: private peer set + app-layer routing + custom signing.
bundle/1shows the canonical shape: Hello + Announce + Request + Data; MEV-Boost's four-role auction is the production reference. Discovery uses allowlists, out-of-band invites, or Tor.- DoS is mitigated across four axes (announce spam / fake bundles / bandwidth / Sybil). The gossip topology is itself a market structure — the search surface determines who wins.