Final. No backwards compatibility. No flags. No replay.
Activated at the genesis of the new final Lux network: **2025-12-25 16:20
Pacific (unix 1766708400)**. Predates every block. The pre-Quasar
Edition Lux network (2020–2025) is a separate network and is out of
scope. There is no migration path because there is nothing to migrate —
the new network starts from genesis with this stack.
The Lux ZAP Stack is a decomplected blockchain architecture. A
transaction is a ZAP buffer when it crosses the wire; it is the same
ZAP buffer when it sits in the mempool; it is the same ZAP buffer when
it lands in state; it is the same ZAP buffer when ZapDB streams it to
an age-encrypted snapshot. One byte stream. No codec.Manager runtime
registry. No reflection. No Marshal. No Unmarshal. No Encode. No
Decode. No Serialize. The buffer is the value.
Each layer of the stack does one job. ZAP frames the bytes. ZapDB
stores the bytes. Schemas describe the offsets. sha256.Sum256(buf)
yields stable identity. TupleHash256 with SP 800-185 framing yields a
cryptographic transcript. wire.SignSecp256k1 produces a signed-tx
envelope by emitting a credential window over the unsigned bytes.
Per-schema Verify() reads offset-indexed fields. Executor dispatch
keys on the TxKind byte. A block is a ZAP frame containing tx frames.
Consensus composes BLS + Pulsar + Corona + Magnetar legs as opaque
ZAP byte strings inside a QuasarCert. Each of these is a separate
concern, in a separate layer, with no braiding.
The reason this is elegant is not aesthetic. It is operational: the
cost of every braided concern in the legacy Avalanche-derived stack
(re-marshalling between mempool and state, re-encoding for snapshot,
parsing on every consensus-message hop, registering codec versions at
runtime) is paid every block. Removing the braids removes the cost.
Measured wins span 3× to 13× per operation. Composed across a running
luxd validator, the wins compound.
luxfi/zap (LP-022) |luxfi/zapdb (Badger fork, !grpc build tag, pb_zap.go native encoders) |pkg/wire/zap/schemas.go per repo |sha256.Sum256(buf) for stable IDs | callsites, no central impl |consensus/protocol/quasar/round_digest.go, qblock.go::TranscriptHash |wire.SignSecp256k1(unsignedBytes, signers) → ZAP SignedTx{unsignedBytes, creds} | luxfi/utxo/wire/sign.go |Verify() reads offset-indexed fields, no codec dispatch | per-type validators in each VM |sha256(block.Bytes()) | per-chain block schema in consensus/pkg/wire/zap/qblock.go |consensus/protocol/quasar/ |Each row is one job. Each row consumes the layer below and produces
the layer above as a byte slice. No layer reaches across.
Ten things that the legacy Avalanche-derived stack braided together,
unbraided here.
Legacy: three Go structures — wire DTO, runtime struct, storage row —
with marshal/unmarshal hops between them. Every read parsed twice,
every write encoded twice. ZAP Stack: one buffer. The wire is the
struct is the record. Accessors are offset reads. Bytes() returns
the buffer. ZapDB stores the buffer as-is.
Legacy: a signed transaction had a marshal pass for the signature
payload, a separate marshal pass for the consensus transcript, and a
third marshal pass for the gossip envelope. ZAP Stack: one byte
stream feeds three orthogonal operations — sha256 for identity,
TupleHash256 over typed offsets for the consensus transcript, and
ecdsa(sha256(unsigned_bytes)) for the signature. Each operation
reads the same buffer at different offsets. No re-encoding.
Legacy: the Visit pattern — tx.Visit(v UnsignedTxVisitor) —
required every executor to type-switch on Go interface assertions
inside generated code. ZAP Stack: the first byte of the unsigned
envelope is TxKind. The executor is a map[TxKind]Handler lookup.
No interface polymorphism, no generated visitors, no type switch.
Value-based dispatch on a buffer byte.
Legacy: proposervm wrapped every chain-VM block in its own envelope
with its own signature, and the wrapped bytes had to be parsed at
every consensus hop. ZAP Stack: the proposer's signature is a leg of
the QuasarCert (LP-182), not a separate envelope. The block is the
block. Validators verify the cert's BLS leg to authenticate the
proposer.
Legacy: a tx had three representations — gossip wire, mempool
in-memory struct, chain bytes — with marshal hops between them. ZAP
Stack: the same buffer that arrives over the wire goes into the
mempool by reference, lands in a block by reference, and persists to
ZapDB by reference. One buffer, three places.
Legacy: three separate state tables with three separate marshalled
structures and three separate code paths for stake accounting. ZAP
Stack: one ZAP wire format with a StakerKind discriminator (LP-189
platformvm state). One table. One executor path. The kind byte
chooses the fee rules and the reward schedule.
Legacy: each VM had its own copy of UTXO, OutputOwners,
Credential, BaseTx. ZAP Stack: luxfi/utxo/wire/ is the single
source of truth. P-chain (LP-023), X-chain (LP-184), EVM internal
(LP-185), and the 12 chains VMs (LP-186) all consume the same nine
migrated fxs (secp256k1fx, nftfx, propertyfx, ed25519fx,
mldsafx, slhdsafx, secp256r1fx, pqfx, vrffx) through their
per-fx wire.go bridges.
Legacy: the consensus transcript was a separately marshalled
structure that had to be re-derived from the wire envelope at every
hop. ZAP Stack: the transcript function reads typed fields directly
from the ZAP buffer (consensus/pkg/wire/zap/qblock.go::TranscriptHash).
The wire is the input to the transcript. No re-derivation.
Legacy: codec.Manager was a runtime registry of versioned
type-codec pairs; every Sign and Verify call paid a registry lookup
and a reflective marshal. ZAP Stack: compile-time schemas declared in
pkg/wire/zap/schemas.go per repo. Sign and Verify read offsets
directly. No runtime registry. No reflection. No version negotiation
at runtime — versioning lives in the schema kind byte.
Legacy: the genesis file format, the block format, the state-row
format, and the gossip format were four distinct codecs that all had
to be kept in sync. ZAP Stack: one wire codec across all of them. A
genesis is a ZAP buffer with a GenesisKind discriminator. A block
is a ZAP buffer containing a list of tx buffers. A state row is a
ZAP buffer. A gossip message is a ZAP buffer. Same parser, same
writer, same identity function.
Measured on luxd microbenchmarks against the legacy linearcodec
implementation. Numbers are wall-clock per operation and allocation
count from go test -bench.
These compose. A luxd validator running consensus rounds while
admitting transactions and writing state sees the per-op wins
compound at every layer. The Corona row deserves a note: the legacy
serial-aggregate implementation was a bug, not a baseline; the
parallel implementation is the honest comparison point. The win is
real.
Three concerns, three layers, no braiding. The wire is the byte
stream. Identity is sha256.Sum256(buf). The transcript is
TupleHash256 over typed offsets. Each is independently complete.
None reaches into the others. Adding a new transcript function does
not touch the wire. Changing the identity hash does not touch the
transcript. The layers do not know about each other.
A Visit-pattern type switch is a place — the code that names every
concrete type and dispatches on the runtime type tag. A TxKind byte
is a value — the dispatch table is map[TxKind]Handler, the handler
is selected by lookup, and the executor never names a concrete tx
type. Adding a tx kind is one entry in the registry. Removing one is
one deletion. The executor does not change.
Rich Hickey on places versus values: a place is a slot that can hold
different things over time; a value is a thing that does not change.
ZAP-native is values all the way down. The buffer that arrives over
the wire is the same buffer in the mempool, the same buffer in the
block, the same buffer in state, the same buffer in the snapshot.
The identity is a function of the buffer. The transcript is a
function of the buffer. The signature is over a window of the
buffer. Nothing mutates. Nothing re-encodes. The buffer is the
value.
Honest accounting of remaining implementation work. The activation
marker stands; these items are migrations of legacy code paths to the
already-decomplected architecture, not architectural blockers.
codec.Manager imports remain in luxd. The Tx.Sign cascade in platformvm and xvm still routes through codec.Manager for the
signing step. The wire format on either side of Sign is ZAP; the
bridge is a transitional shim.
~/work/lux/codec/ not yet archived. Transitively pulled via luxfi/vm/chains/atomic. Module deletion is gated on the Tx.Sign
migration above.
luxfi/p2p still imported in 11 files. LP-201 replaces it withQUIC + ZAP + mDNS + DHT. The replacement is in flight, not landed.
service/info blocked on luxfi/p2p upstream codec/jsonrpc. Theinfo-service public API still speaks the legacy jsonrpc envelope on
top of luxfi/p2p's codec. Replaced when LP-201 lands.
None of the above mutate the architecture. The architecture is the
10-layer model. These are residual migrations.
What landed across the new final Lux network's pre-genesis sprint:
byte, object discriminator. The bottom layer.
delegator, and L1-staker entries unified under a StakerKind
discriminator.
consensus/pkg/wire/zap/. QuasarCert composes BLS + Pulsar +
Corona + Magnetar legs as opaque ZAP byte strings.
ExportTx, CreateAssetTx, OperationTx all migrated.
representation is ZAP. External Ethereum RLP is preserved at the
RPC boundary — the EVM speaks RLP to clients, ZAP to the rest of
the node.
mpcvm, fhevm, thresholdvm, quantumvm, etc.) all consume the same wire layer.
schemas. Each fx exports a per-fx wire.go bridge.
pb_zap.go encoders under the !grpc build tag. LSM KV consumes ZAP buffers directly.
Module-LWE (Ringtail parameter set). Two Module-LWE parameter regimes, two distinct cert legs (family-disjoint diversity is Magnetar/hash, not Corona).
nova, nebula, prism, quasar. Cert modes per LP-217:
PQ-off → PQ-fast → PQ-strict → PQ-heavy (the v1 Pulsar / Aurora /
Polaris codenames in LP-017 are now internal identifiers).
~/work/lux/zap/transport.go and ~/work/lux/zap/quic/. The wire is the transport's payload.
Transport.Pick() selectorcontract, the QUIC default implementation, mDNS LAN discovery, and
Kademlia DHT for content addressing; replaces luxfi/p2p. Validator
and node discovery becomes mDNS on LAN, DHT on WAN. Tx and block
gossip becomes QUIC streams carrying ZAP frames.
Clients verify a tx is in state without downloading the chain.
The hash function consumes the same buffer the storage layer
stores; no re-encoding for commitment.
reconciliation; the gossip envelope is a ZAP frame containing tx
buffer references.
implementation registered as cxl-pool for same-rack peers. Buffer
pool spans validators in the same rack via CXL 3.0 Type-3 pooled
memory; sub-100ns shared reads. Upgrade to §"Layer 1" UMA buffer
pool when CXL hardware is available; fallback to per-validator UMA
otherwise.
registered as rdma-ib / rdma-rocev2 for cross-rack peers within
a DC. ~3 μs RTT on Mellanox ConnectX-7 NDR; ZAP frames in zero-copy
registered memory buffers. Selected by LP-201's Transport.Pick()
when both peers report CapRDMAIB and CapCXLPool is unavailable.
activates: 2025-12-25T16:20:00-08:00
activates-unix: 1766708400
Same marker as every wire LP in the new final Lux network. Set once,
does not move.
"Polaris cert leg" in LP-017, historical)
/ PQ-heavy; canonical successor to LP-017 codenames)