FABRKNT
P2P Networking Internals — From devp2p to Custom Gossip
P2P Networking
Lesson 3 of 4·CONTENT18 min50 XP

Treat this page as a workbench, not a blog post. The goal is to extract a reusable mental model from the source and carry it into the rest of the Fabrknt stack.

Course
P2P Networking Internals — From devp2p to Custom Gossip
Lesson role
CONTENT
Sequence
3 / 4

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/1 protocol 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:

MessagePurpose
HelloHandshake — share what we support
BundleAnnounce"Hash X is a bundle, ~Y gas to extract"
BundleRequest"Send me bundle X"
BundleDataThe 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:

ConceptImplementation
Relayer-builder separationRelayer (publishes "I have a block for sale"), builder (constructs blocks), proposer (picks winning bid)
Sealed-bid auctionsBuilders submit bids; proposer picks highest
Reputation-basedBuilders earn reputation, relayers track abusers
Network-layer trustAll 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:

AttackMitigation
Spam announcementsRate limit per peer; require signed announcements
Fake bundlesRequire signature on announce + verify on request
Bandwidth exhaustionPer-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

  1. Sketch a 2-message protocol for "broadcast my merchant attestation"
  2. Identify: how does the allowlist prevent Sybil attacks?
  3. Think: what's the bandwidth cost of broadcasting 1000 messages/sec to 10 peers?
  4. Read MEV-Boost spec and find the relayer protocol

10. Reading list

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/1 handshake 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/1 shows 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.