Architecture of a lattice
audience: contributors
This chapter is the concrete instantiation of the pattern described in Designing block-building topologies on mosaik. It maps the six organisms onto a single lattice for one EVM chain, identifies the public surface each organism exposes on the shared universe, and traces the data flow from submission through refund attribution.
The reader is assumed to have read the topology intro and the zipnet architecture chapter.
Lattice identity recap
LATTICE = blake3("builder|" || instance_name || "|chain=" || chain_id)
ZIPNET_ROOT = LATTICE.derive("zipnet")
UNSEAL_ROOT = LATTICE.derive("unseal")
OFFER_ROOT = LATTICE.derive("offer")
ATELIER_ROOT = LATTICE.derive("atelier")
RELAY_ROOT = LATTICE.derive("relay")
TALLY_ROOT = LATTICE.derive("tally")
Each *_ROOT is the seed an organism hashes its own Config
against to produce the organism’s committee GroupId, public
StreamIds, and public StoreIds. See
topology-intro — Within-lattice derivation.
Integrators bind via the LatticeConfig they compile in from
operator-published release notes:
const ETH_MAINNET: LatticeConfig = /* operator-published */ ;
let network = Arc::new(Network::new(builder::UNIVERSE).await?);
// Six organism handles, each following the zipnet pattern.
let submit = zipnet::Zipnet::<Tx2718>::submit (&network, Ð_MAINNET.zipnet ).await?;
let read = zipnet::Zipnet::<Tx2718>::read (&network, Ð_MAINNET.zipnet ).await?;
let unseal = unseal::Unseal::<Tx2718>::watch (&network, Ð_MAINNET.unseal ).await?;
let bid = offer::Offer::<Bundle>::bid (&network, Ð_MAINNET.offer ).await?;
let blocks = atelier::Atelier::<Block>::read (&network, Ð_MAINNET.atelier).await?;
let headers = relay::Relay::<Header>::watch (&network, Ð_MAINNET.relay ).await?;
let refunds = tally::Tally::<Attribution>::read (&network, Ð_MAINNET.tally ).await?;
Integrators only open the handles they need. A searcher agent
typically holds bid, blocks, refunds. A wallet typically holds
submit, refunds. A rollup sequencer consuming a lattice
typically holds headers only.
Public surface summary
The lattice’s outward-facing primitives decompose cleanly into the six organisms’ own public surfaces. Full per-organism detail is in The six organisms; this table is the index.
| Organism | Write-side primitives | Read-side primitives |
|---|---|---|
zipnet | Submit<Tx> stream | Broadcasts, LiveRoundCell collections |
unseal | SharesStream (internal) | UnsealedPool collection |
offer | Bid<Bundle> stream | AuctionOutcome collection |
atelier | Hint<Template> stream (internal) | Candidates collection |
relay | Ship<Header> (internal) | AcceptedHeaders collection |
tally | Attribution (internal commit) | Refunds, Attestations collections |
“Internal” here means the primitive is ticket-gated to peers with a
specific role tag (e.g. atelier.member, relay.member) and is
not consumed by generic integrators. It still lives on the shared
universe; the ticket gate does the access control.
Data flow across one proposal slot
This is the canonical happy-path flow for one slot on a lattice. Each step is a commit into one organism’s state machine; transitions between steps are stream/collection subscriptions, not cross-Group commands.
integrator organism commit / effect
---------- -------- --------------------------
wallet / searcher ───► zipnet ──► Broadcasts grows by one
(sealed envelopes for slot S)
unseal ──► UnsealedPool[S] populated
(clear txs + intents for S)
searcher ───► offer ──► AuctionOutcome[S] committed
(winning bundle for S)
atelier ──► Candidates[S] committed
(candidate block for slot S)
relay ──► AcceptedHeaders[S] committed
(header shipped to proposer)
proposer chooses a header; slot S is included on chain
tally ──► Refunds[S] committed
(MEV captured, routed back)
wallet / searcher ◄─── tally ──► refunds + attestations stream
Every [S] index is the chain’s slot number (or block number on L1,
or sequencer slot number on L2). It is the foreign key that glues
the six organisms’ commits together without requiring cross-Group
atomicity. Each organism commits at its own cadence; downstream
organisms react when they see the upstream commit.
Participants
Not every organism is operated by the same entity. The lattice distinguishes three classes of participant.
- Lattice operator — the single team responsible for the
LatticeConfigidentity, the instance name, the chain-id mapping, and theunseal/offer/tallycommittees in the default topology. In Phase 1 this is one org. - Co-builder operator — a team contributing committee members
to
atelierand, optionally,relay. Multiple co-builder operators per lattice is the Phase 2 shape; in Phase 1 the lattice operator runs both roles. - Integrator — external dev, runs no committee members, binds handles against the lattice from their own mosaik agent.
An operator-run process typically hosts committee members for more
than one organism: one binary, several Group memberships. That is
fine and encouraged — the process pays for one Arc<Network> and
carries several organisms’ Raft roles on top.
Where each organism commits
In a non-atomic pipeline the question is not “what commits when” but “what decision is each organism actually making at commit time”. Clarifying this per organism:
zipnetcommits a finalized round’s broadcast vector. That is, the set of sealed envelopes for the round’s slot, in deterministic slot order. Integrator semantics: “one ordered log of sealed envelopes per slot, opaque to anyone without the matching unsealing key material”.unsealcommits the clear-text recovery of a given zipnet round, oncetof the threshold committee members have contributed their decryption shares. Commit is into theUnsealedPoolcollection, keyed by slot. Integrators that bond tounsealare typically downstream organisms (offer,atelier) and a small number of audit-capable integrators with the ACL.offercommits the winning bid per slot. The state machine runs a sealed-bid auction over bundles keyed to a given slot and commits exactly oneAuctionOutcome[S]per slot.ateliercommits a candidate block per slot. The state machine consumes theUnsealedPoolcontent and theAuctionOutcomefor the slot and commits aCandidates[S]block body signed by the TDX committee’s collective attestation.relaycommits that a specificAcceptedHeaders[S]was shipped to the proposer and whose proposer acknowledgement was received (Phase 1) or witnessed on-chain (Phase 2+).tallycommits the slot’s refund attribution: whichClientIdfromzipnetand which searcher fromoffercontributed value to the winning block, and what share they receive. Commit is into theRefunds[S]collection.
Every commit is a normal mosaik group.execute(...). The
orchestration across organisms is built from when() conditions
and collection subscriptions in each organism’s role driver, not
from a global scheduler.
L1 vs L2 specialisation
The six-organism decomposition above targets L1 PBS as the reference. Two specializations are anticipated and accommodated without changing the organism count:
- L2 rollup with centralized sequencer.
relayis replaced by arelayconfiguration that ships headers to a single sequencer endpoint rather than a validator set. The organism identity and public surface are unchanged; only the external endpoint changes. Integrators see the sameRelay::<Header>::watchsurface. - L2 rollup with decentralized sequencer. Same as L1 PBS except
the proposer set is the sequencer set.
relay’s state machine needs to understand the sequencer’s handoff protocol, which is an organism-internal concern.
See Cross-lattice coordination for the cross- chain cases (bundles spanning an L1 and an L2, L2-to-L2 intent routing).
Internal plumbing (optional derived private networks)
Same pattern zipnet established: the public surface lives on UNIVERSE; high-churn internal plumbing may move to a derived private network keyed off the organism’s root.
Candidates for derived private networks in v1:
unseal’s share gossip. Threshold-decryption shares per slot are a high-frequency internal channel; theUnsealedPoolon UNIVERSE is the public result.atelier’s bundle-simulation chatter. Candidate block simulation traffic between committee members.relay’s proposer-side socket pool. Per-slot long-poll connections the relay maintains with proposer endpoints.
Committee Groups themselves stay on UNIVERSE. Bridging a Group’s backing state across networks is worse than the catalog noise; the zipnet design-intro argument applies unchanged.
Identity under operator handover
A lattice’s instance name is an operator-level identity that
outlives specific organism parameter choices. An operator who wants
to retune atelier‘s block-template schema retires the existing
atelier deployment and stands up a new one under the same lattice
name. Integrators compile against the lattice’s new
atelier::Config, not against a new lattice name — provided the
other five organisms’ configs are unchanged.
If the lattice operator wants to hand over to a new operator, the new operator either:
- Keeps the
LatticeConfigbyte-for-byte and rotates secrets in place — an operator-level rotation, not a version bump. - Or stands up a new lattice under a new instance name
(
ethereum.mainnet-v2), and integrators migrate over time.
See operators/rotations-and-upgrades.md.
Concrete sizing for a Phase 1 lattice
Order-of-magnitude targets for a lattice at slot cadence (12s on L1, 2s on an L2):
| Organism | Committee members (v1) | Stream bytes/slot | Bond count per node |
|---|---|---|---|
zipnet | 3–7 servers + 1 agg | ~16 KiB | member-to-member |
unseal | 3–7 members | ~a few KiB | member-to-member |
offer | 3–5 members | O(N_bundles) × bid size | member + searchers |
atelier | 3–7 members (TDX) | O(block body) | member + co-builder |
relay | 3–5 members | O(header + bid) | member + proposer |
tally | 3–5 members | O(num_attributions) | member + consumers |
“v1” here means the Phase 1 shape. Phase 2 adds more committee
members to atelier as co-builders onboard; Phase 3 elasticises
the committee sets via mosaik’s peer discovery without changing the
ACL. See Roadmap.
What this chapter deliberately does not cover
- Per-organism state machines. Each organism owns its own
spec. See organisms.md and the organism’s own
contributors/pages when the crates land. - Wire formats. Same.
- Chain-specific transaction encoding. The lattice is chain- parameterised but organism internals are chain-generic. Chain-specific pieces (EIP-2718 vs OP-stack sequencer envelopes, etc.) are organism Config parameters, not new organisms.
- TDX image builds. Deferred to the operator-side runbook.