Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Binding to the Flashbots lattice

audience: ai

The searcher has a CoalitionConfig for searcher-α (setup) and a reference to testnet-1a’s stable id. This chapter completes the handshake: a concrete TicketValidator composition that admits testnet-1a’s read-side surfaces, pins the Flashbots-declared TDX Measurements on every write-side surface the searcher intends to use, and — once bonded — observes the first event each surface produces as a smoke test.

This chapter is where the convergence mechanism named in ai/emergent-coordination.md shows up for the first time in the example. The searcher’s TicketValidator admits the shared policy fingerprints of the organisms mediating its interaction with every other agent on testnet-1a: zipnet’s submission contract, unseal’s decryption protocol, offer’s clearing rule, tally’s refund accounting. Two TDX-attested searchers whose TicketValidators admit the same Flashbots-published Measurements are, by the TDX arm of that mechanism, agreeing on a shared runtime policy on the submission path.

The network handle

One Arc<Network> per searcher process:

use std::sync::Arc;
use mosaik::Network;
use builder::UNIVERSE;

let network = Arc::new(Network::new(UNIVERSE).await?);

UNIVERSE is the shared mosaik NetworkId every builder lattice lives on (builder book). searcher-α lives on the same universe — coalitions do not fork the universe.

The searcher’s TicketValidator

The TicketValidator is the searcher’s declaration of what it will accept a bond from, and what it requires the counterpart to bond to in return. It is the compositional answer to “which shared policies does this searcher agree to”.

use coalition::{TicketValidator, Tdx};
use coalition::acl::{ReputationFloor, MarketSettlement};
use builder::testnet_1a::{
    // Flashbots publishes these constants on the
    // testnet-1a release page; they are re-exported
    // from the builder crate once pinned.
    ZIPNET_SEAL_MEASUREMENTS,
    UNSEAL_COMMITTEE_MEASUREMENTS,
    OFFER_READER_MEASUREMENTS,
    TALLY_READER_MEASUREMENTS,
};

fn searcher_ticket_validator()
    -> TicketValidator<'static>
{
    TicketValidator::new()
        // ── read-side bonds ──────────────────────
        // tally::Refunds is attested-read-only:
        // Flashbots requires readers present an
        // attested identity so refund attribution
        // cannot be scraped anonymously.
        .require_ticket(
            Tdx::new().require_mrtd(
                TALLY_READER_MEASUREMENTS
            )
        )
        // offer's order flow read-side is similarly
        // attested-read-only.
        .require_ticket(
            Tdx::new().require_mrtd(
                OFFER_READER_MEASUREMENTS
            )
        )

        // ── write-side bonds ─────────────────────
        // zipnet::seal accepts a searcher's sealed
        // submission only from a TDX-attested binary
        // whose Measurements match the set Flashbots
        // published for permitted searchers.
        .require_ticket(
            Tdx::new().require_mrtd(
                ZIPNET_SEAL_MEASUREMENTS
            )
        )
        // The unseal committee is downstream of the
        // searcher; the searcher verifies its
        // Measurements but does not itself bond as a
        // ticket holder against unseal.
        .verify_peer(
            Tdx::new().require_mrtd(
                UNSEAL_COMMITTEE_MEASUREMENTS
            )
        )

        // ── self-admission ───────────────────────
        // Once the searcher has a reputation
        // history (chapter 7), its own admission
        // policy folds a reputation floor. Omitted
        // in the first-run handshake.
        // .require_ticket(
        //     ReputationFloor::from(
        //         ACCURACY_REPUTATION_ORG, 0.55
        //     ),
        // )
}

Each require_ticket(Tdx::new().require_mrtd(...)) clause is the searcher declaring: “the counterpart I bond to must run this exact TDX-attested binary, and I will re-verify its Measurements on every session establishment”. Inverted, as in ai/sustainability.md: the searcher agrees to the runtime policy those Measurements bind.

Constructing the searcher organism

With the validator in hand, the searcher constructs its organism handle via the typed free-function constructor reused across the book:

use coalition::Organism;
use searcher_alpha::Searcher;

// Narrow Config.content — every field here is part
// of the searcher's identity. Using a plain struct
// named after the organism; no wrapper.
const SEARCHER_CONTENT: SearcherContent<'static> = SearcherContent {
    model_family:            "orca-3.1",
    decoding_temperature_q16: 0,
    mission_statement_hash:
        const_blake3!(include_bytes!(
            "../policy/mission.txt"
        )),
    scope_boundaries: &[
        ScopeRule::Chain("testnet-1a"),
        ScopeRule::SubmissionOnly,
    ],
    successor_policy: SuccessorPolicy::
        HandOffToReputationLeader,
};

const SEARCHER_CFG: OrganismConfig<'static, SearcherContent<'static>> =
    OrganismConfig {
        coalition:     SEARCHER_ALPHA.stable_id(),
        content:       &SEARCHER_CONTENT,
        validator:     &searcher_ticket_validator(),
        image_posthash: Some(SEARCHER_IMAGE_MRTD),
    };

let searcher: Searcher<Submission> =
    Organism::searcher(&network, &SEARCHER_CFG).await?;

Two notes:

  • Organism::searcher is the typed free function every mosaik organism in the book exposes (Organism::<D>::verb(&network, &Config)), reused from zipnet onward.
  • image_posthash folds the searcher’s TDX Measurements into the organism’s Config fingerprint. Other searchers’ validators that require the fingerprint are agreeing to run, or bond against, the same runtime policy.

Smoke test — first events from each surface

With the handle constructed, the searcher runs a minimal observation loop to confirm the handshake succeeded:

use futures::StreamExt;
use tokio::{pin, select, time::{timeout, Duration}};
use testnet_1a::{Tally, Offer};

let mut tally = network
    .subscribe::<Tally::Refunds>(TESTNET_1A.stable_id())
    .await?;
let mut offer = network
    .subscribe::<Offer::Orders>(TESTNET_1A.stable_id())
    .await?;

pin!(tally, offer);

let smoke = async {
    let (first_refund, first_order) = tokio::join!(
        tally.next(),
        offer.next(),
    );
    (first_refund, first_order)
};

match timeout(Duration::from_secs(30), smoke).await {
    Ok((Some(r), Some(o))) => {
        tracing::info!(
            refund = %r.refund_id,
            order  = %o.order_id,
            "smoke handshake succeeded"
        );
    }
    Ok(_)    => anyhow::bail!("empty surfaces"),
    Err(_)   => anyhow::bail!("surface timeout"),
}

If the smoke test fails, the handshake is broken at the TicketValidator. The common failure modes:

  • UnattestedPeer — the searcher is running a non-TDX binary, but a TALLY_READER_MEASUREMENTS bond requires attested readers. Fix: rebuild in TDX, or remove that clause from the validator and accept the reduced access.
  • UnknownMeasurements — Flashbots rotated the testnet-1a Measurements set and the searcher has not pulled the new release notes. Fix: pin the new constants.
  • ConnectTimeout — the Flashbots operator’s endpoint for the intended surface is not yet advertised in Atlas, or the searcher’s coalition does not have the right discovery bond. Fix: consult binding to an organism and the testnet-1a Atlas card.

What this chapter’s handshake does not cover

  • Write-side submissions. The zipnet::seal bond is declared in the validator above but not yet exercised. Chapter 6 (sealed submission and settlement) walks the first bundle.
  • Reputation bonds. The reputation-floor clause above is commented out. Chapter 7 (sustainability) brings it in once the searcher has a scoring history.
  • Compute bonds. If the searcher’s policy runs under the Compute basic service, Compute has its own TicketValidator composition. Chapter 5 (inference) adds those.

Market-maker variant — differences at handshake

  • No ZIPNET_SEAL_MEASUREMENTS bond in the require_ticket slot. Market-makers submit to offer’s write-side quote surface directly, not through the shuffle sealed path; Flashbots may therefore publish a different Measurements set (OFFER_QUOTE_MEASUREMENTS) for that endpoint. The market-maker’s validator swaps the two clauses.
  • Heavier read-side bonds. Market-makers read offer::OrderBook state in addition to the order- flow stream, which may require an additional attested-read-only Measurements clause.
  • Same verify_peer on unseal. The market-maker also verifies the UNSEAL_COMMITTEE_MEASUREMENTS, even though it does not depend on the unseal path directly, because its quotes can be cross-filled by searcher bundles whose settlement the unseal committee touches.

Cross-references