Lux Proposals
← All proposals
LP-0301Final

Status

Final. This is a status / audit document, not a Standards Track LP.

No wire change, no precompile slot, no consensus rule. The activation

marker is the same Quasar Edition genesis used by every wire-and-state

LP in the new final Lux network. The numbers in this document reflect

the state of the canonical main branches at the date in the

created field; the methodology stays valid forward — re-running the

audit at any later commit is a one-shot grep.

This LP is one of the contexts allowed by TAXONOMY.md §"Historical

references — preserved" to mention upstream names directly. It compares

luxd against avalanchego; the upstream name is qualified everywhere it

appears.

TL;DR

luxd main at v1.30.3 (2026-06-06) carries zero files with an

"Ava Labs" copyright header, zero avalanche or ava-labs literal

references in source, zero imports of google.golang.org/grpc,

and zero packages from the github.com/ava-labs/* namespace. The

last bridge — luxfi/codec, a transitional shim derived from

avalanchego's codec.Manager — was ripped from go.mod on v1.30.0

(commit 1e284093a0). The luxfi/p2p package, the final upstream

shape that survived into Quasar Edition, is in active removal in

favour of QUIC + ZAP under LP-201 (13 remaining imports, all leaf

sites). Once those are flipped, the audit returns zero on every

dimension.

luxd's binary is 35 MB at bin/luxd. avalanchego's release build

is 61 MB at build/avalanchego-release. luxd's source tree is

274,124 Go LOC across 1,444 files; avalanchego is **623,940 Go LOC

across 2,785 files**. Both numbers are measured by `find . -name

'*.go' -not -path './.git/*' | wc -l and wc -l` against the same

file set, on the canonical main of each repo at the date of this LP.

The structural reasons for the win — no codec marshal hops, no grpc,

no reflection registry, LE-end-to-end wire, ZapDB instead of LevelDB,

QUIC + ZAP instead of TCP + Protobuf, Quasar finality instead of

Snowball confidence accumulation — are catalogued in §3. The

classical-only consensus profile that lets benchmarks compare

apples-to-apples (BLS-only validator identity, classical TLS, BLS

threshold sigs, no PQ overhead) is documented in §4. Real-workload

throughput / latency / memory numbers are TBD; §5 gives the methodology

and the location at which numbers will live (benchmarks.lux.network).

We do not invent numbers we have not measured.

1. What's left of avalanchego in luxd

1.1 Method

Four orthogonal greps against the working tree of ~/work/lux/node at

commit d58699bbd8 (v1.30.3, 2026-06-06):


# Literal upstream references in source
grep -rln 'ava-labs' --include='*.go' .                  # → 0 files
grep -rln -i 'avalanche' --include='*.go' .              # → 0 files

# Upstream copyright headers
grep -rln 'Copyright.*Ava Labs\|(c) Ava Labs' \
  --include='*.go' .                                     # → 0 files

# gRPC imports
grep -rln '"google.golang.org/grpc"' --include='*.go' .  # → 0 files

# Upstream package paths
grep -rln '"github.com/ava-labs/' --include='*.go' .     # → 0 files

# Last upstream-shape bridge: luxfi/p2p (in flight)
grep -rln '"github.com/luxfi/p2p"' --include='*.go' .    # → 13 files

Same script run against ~/work/ava/avalanchego at commit

9f8b9461cf (2026-05-14):


grep -rln 'Copyright.*Ava Labs\|(c) Ava Labs' \
  --include='*.go' .                                     # → 2,665 files
grep -rln '"google.golang.org/grpc"' --include='*.go' .  # → 26 files

1.2 Findings

| Surface | luxd v1.30.3 | avalanchego (main at 2026-05-14) |
|---|---:|---:|
| Total .go files | 1,444 | 2,785 |
| Total Go LOC | 274,124 | 623,940 |
| Files with Copyright … Ava Labs header | 0 | 2,665 (95.7 %) |
| Files with "ava-labs" literal | 0 | n/a |
| Files with "avalanche" literal | 0 | n/a |
| Files importing google.golang.org/grpc | 0 | 26 |
| Files importing github.com/ava-labs/* | 0 | n/a |
| Files importing github.com/luxfi/p2p | 13 | 0 |
| snow/ directory | absent | present (consensus engines, choices, engine, networking) |
| consensus/quasar/ directory | present | absent |
| consensus/zap/ directory | present | absent |
| vms/pcodecs/ directory | present | absent |
| Direct deps in go.mod | 206 | 184 |
| go.sum size | 63,588 B | 213,447 B (3.4×) |

The Go LOC ratio (274 k luxd vs 624 k avalanchego) understates the

divergence: avalanchego's 624 k LOC includes ~120 k LOC of generated

gRPC stubs (*.pb.go, *_grpc.pb.go) that have no analog in luxd.

Stripping generated code, avalanchego is closer to 500 k LOC of

human-written source. Even at that ratio, luxd is roughly **55 % of

upstream's source mass** for the canonical equivalent feature set

(P-Chain, C-Chain equivalent, X-Chain equivalent, plus seven Lux-only

VMs that avalanchego doesn't have).

1.3 Per-subsystem audit

What replaced what, layer by layer:

| Subsystem | Avalanchego shape | luxd shape | Replacement LP |
|---|---|---|---|
| Wire format | codec.Manager + reflection linearcodec (big-endian, runtime-registered versioned codecs) | luxfi/zapcodec LE, per-VM hand-rolled offset readers in vms/pcodecs/ | LP-022, LP-023, LP-200 |
| Consensus engine | Snowball / Snowflake / Snowman / Avalanche-DAG (snow/) | Quasar (Photon committee selection + Wave threshold voting + Focus β-finality + Nova / Nebula modes + Ray / Field drivers) | LP-017 (historical), LP-020, LP-027, LP-028 |
| Validator identity | TLS cert hash → 20-byte NodeID, ECDSA pubkey | ML-DSA-65 (FIPS 204) hybrid + secp256k1, BIP-44 path m/44'/9000'/<idx>'/0'/0', NodeID = SHAKE256-384("NODE_ID_V1" \|\| chainID \|\| 0x42 \|\| pubkey)[:20] | LP-015, LP-070, LP-073 |
| Network transport | TCP + TLS 1.3, Protobuf over gRPC | QUIC + ZAP with X-Wing handshake (X25519 ⊕ ML-KEM-768 hybrid) — ~/work/lux/zap/handshake/ constant SuiteX25519MLKEM | LP-201 |
| VM plugin IPC | gRPC over Unix socket, rpcchainvm Protobuf service | ZAP-native transport, rpcchainvm flipped to ZAP (vms/rpcchainvm/zap/) | LP-022, LP-200 |
| State storage | LevelDB / BadgerDB with versiondb wrappers | ZapDB (Badger fork) under !grpc build tag; native pb_zap.go encoders; same byte stream wire → mempool → state → snapshot | LP-200 layer 1 |
| Snapshot / backup | Custom encoded snapshot stream | age-encrypted streaming snapshot of ZapDB byte stream (no re-encode) | LP-200 layer 1 |
| Identity-on-wire | ids.NodeID = [20]byte | ids.NodeID = [20]byte byte-identical; derivation function is the difference (Bitcoin-style RIPEMD160(SHA256(pubkey)) is replaced by SHAKE256-384 of a domain-separated transcript) | LP-015 |
| EVM | coreth (a libevm fork) | luxfi/evm + luxfi/evmgpu (GPU-parallel EVM, 622-file Go tree, no coreth ancestry — separate libevm fork at luxfi/geth) | LP-009 |
| FHE precompile | absent | luxfi/fhe-coprocessor + F-Chain (FHEVM) | LP-013, LP-167 |
| Bridge | subnet-evm + awm-relayer + ICM | luxfi/bridge + Warp 2.0 (Beam + ML-DSA + Pulse), B-Chain (BridgeVM) | LP-177, LP-204 |
| Cross-shard atomicity | UTXO-based shared memory between P/C/X | Cross-shard 2PC + atomic-L1-spawn primitive (CreateSovereignL1Tx) | LP-018, LP-211 |
| Threshold | absent | M-Chain (MPCVM, FROST, CGGMP21), Q-Chain (Quasar/Pulsar DKG), Magnetar threshold SLH-DSA | LP-141, LP-154, LP-155, LP-171, LP-181 |
| TEE attestation | absent | A-Chain (AIVM) TEE attestation + AI provenance | LP-020 |
| Zero-knowledge | absent | Z-Chain (ZKVM) Groth16 + P3Q rollups | LP-169, LP-218, LP-220 |
| Block-STM parallel exec | absent | luxd EVM execution engine | LP-010 |

The audit's headline: no Avalanche surface has survived in shape.

Every named upstream subsystem has either been replaced wholesale or

shipped only in luxd. The single transitional residue documented in

LP-200's "What's NOT yet decomplected" section — luxfi/p2p and its

12 codec-bridged Tx.Sign call sites — is in active removal under

LP-201. All 12 of those sites speak ZAP on either side of the bridge;

the bridge itself is the last upstream-derived control-flow shape, and

it is leaf, not load-bearing.

1.4 The genesis cut

The Quasar Edition genesis (2025-12-25 16:20 PST, unix 1766708400) is

the line under which the legacy Lux network — itself a 2020-vintage

fork of avalanchego — is out of scope. There is no migration path

because the new network starts from genesis with the ZAP stack. The

pre-Quasar Lux network's chain bytes are not readable by a v1.30.x

luxd binary (LE-only build; the legacy BE-encoded P-chain state is

explicitly out of scope per LP-200).

Operationally this means: the only upstream code that ever ran in

production Lux Network is the 2020-vintage pre-Quasar mainnet. That

network's last block was committed before genesis-2025. The post-

genesis network is byte-isolated from it. There is no shared state, no

shared block hash, no shared validator set.

2. Three layers of architectural separation

2.1 Network layer

Avalanchego: TCP + TLS 1.3, Protobuf messages framed by length-

prefixed envelopes, gRPC for VM-plugin IPC (rpcchainvm), gRPC-

gateway for the public API. Classical-only key exchange (X25519 or

ECDHE-P-256), classical-only authentication (ECDSA-secp256k1 cert

chain). Harvest-now-decrypt-later viable against any captured stream.

luxd: QUIC streams carrying ZAP frames. Handshake is X-Wing:

X25519 classical ECDH ⊕ ML-KEM-768 (FIPS 203) post-quantum KEM, with

a single shared secret derived via SHAKE256-based KDF over a typed

transcript. Constant: SuiteX25519MLKEM = 0x01 in

~/work/lux/zap/handshake/labels.go; suite-byte negotiation, single

admitted suite in v1. Authentication uses ML-DSA-65 over a transcript

hash that the responder cannot precompute (deterministic-sign mode

disabled outside KAT tests; rejection of malformed transcripts is one

KAT row).

This is harvest-resistant: even given a recorded session and a

quantum break of X25519, the attacker still needs to break ML-KEM-768

to recover the shared secret. NIST level 1 + level 3 hedged in one

suite.

Source: ~/work/lux/zap/handshake/ (initiator.go, transcript.go,

labels.go, identity.go). The frames_test.go, kat_test.go, and

protocol_test.go files lock the wire format byte-for-byte.

2.2 Wire format layer

Avalanchego: codec.Manager is a runtime registry of versioned

type-codec pairs. Each (struct, codec-version) pair is registered at

init() time. Marshal reflects over the struct, walks the field

list, dispatches to the per-field marshaller, and produces a byte

stream prefixed with the codec version (big-endian uint16). Unmarshal

does the inverse — reflect, dispatch, allocate the struct, populate

fields. Every Sign and Verify call goes through this path. Every block

parse goes through this path. Every state read goes through this path.

The marshaller is ~3 μs per allocation on a typical tx; the

unmarshaller is ~1 μs; both allocate one Go object per encoded type

and the GC pays for it.

luxd: there is no Marshal. There is no Unmarshal. There is no

runtime codec registry. There is no reflection. Per-VM hand-rolled

serializers live in vms/pcodecs/ and consume the ZAP buffer directly.

The wire layout for each tx kind is declared once in a per-fx

wire.go (e.g. ~/work/lux/utxo/wire/secp256k1fx/wire.go). Sign and

Verify read offsets into the ZAP buffer; no struct allocation

intermediates a verify call. The byte order is little-endian — native

on every modern CPU; no byte-swap on load.

Performance characteristic from LP-200's microbenchmarks:

| Op | Legacy (linearcodec) | ZAP Stack | Win |
|---|---|---|---|
| Parse small tx | 129 ns/op, 2 allocs | 36 ns/op, 1 alloc | 3.6× |
| Parse complex tx | 1008 ns/op, 6 allocs | 75 ns/op, 1 alloc | 13.4× |
| Mempool insert | parse → struct → re-marshal | parse → buffer ref | ~5× |
| State write | unmarshal → mutate → marshal | wrap → mutate → write buffer | ~3× |
| Snapshot stream | re-encode for backup | direct buffer stream | ~10× (write-amp gone) |

Compose this across a validator running consensus, admitting txs, and

writing state, and the wins multiply rather than add. See §5 for the

full-node benchmark methodology.

2.3 State layer

Avalanchego: LevelDB or BadgerDB underneath a versiondb wrapper.

The wrapper serializes each value via the legacy codec, prefixes the

key with the database version, and persists. State reads go

key → bytes → codec.Unmarshal → struct. State writes go

struct → codec.Marshal → bytes → key. Both pay the codec roundtrip.

luxd: ZapDB. A Badger fork built under the !grpc build tag with

native pb_zap.go encoders that consume ZAP buffers directly. The

ZAP buffer that arrives over the wire goes into the mempool by

reference, lands in a block by reference, persists to ZapDB by

reference, and streams out to the age-encrypted snapshot by reference.

The buffer is the value, transitively, at every layer.

Source: ~/work/lux/zapdb/. See LP-200 §1 layer 1 for the architectural

contract.

3. New components with no Avalanche analog

These are luxd's net-new surfaces — no upstream ancestor, no port from

avalanchego, no LP corresponds to "we kept their thing":

| Component | LP | Path |
|---|---|---|
| GPU-native EVM execution | LP-009 | ~/work/lux/evmgpu/ (622 .go files) |
| Block-STM parallel execution | LP-010, LP-210 | luxfi/evm STM scheduler |
| GPU crypto acceleration | LP-011 | luxfi/crypto/bls, luxfi/crypto/mldsa GPU paths |
| PQ crypto on GPU | LP-012 | luxfi/crypto ML-DSA / SLH-DSA GPU bench harness |
| FHE-GPU precompile + F-Chain | LP-013, LP-167 | luxfi/fhe-coprocessor, ~/work/lux/fhe/ |
| Multi-EVM (C / Z / A / B / M / F / D) | LP-014, LP-134 | ~/work/lux/node/vms/ and ~/work/lux/chains/* |
| Threshold VM substrate | LP-141 | ~/work/lux/chains/thresholdvm (library; M-Chain and F-Chain depend on it) |
| Atomic L1 spawn (CreateSovereignL1Tx) | LP-018 | P-Chain executor |
| Lux DEX precompile + D-Chain (DEXVM) | LP-013-based, LP-032 | ~/work/lux/dex/, ~/work/lux/node/vms/dexvm/ |
| ZapDB age-encrypted streaming snapshot | LP-200 layer 1 | ~/work/lux/zapdb/backup.go |
| Quasar consensus family (Photon, Wave, Focus, Nova, Nebula, Prism, Horizon, Flare, Ray, Field) | LP-017 (historical), LP-020, LP-027 | ~/work/lux/consensus/quasar/, ~/work/lux/node/consensus/quasar/ |
| X-Wing handshake (X25519 ⊕ ML-KEM-768) | LP-201 | ~/work/lux/zap/handshake/ |
| Magnetar threshold SLH-DSA | LP-181 | ~/work/lux/magnetar/ |
| Hash-of-hash BIP-44 NodeID derivation | LP-015 | ~/work/lux/keys/service_identity.go |
| P3Q (Plonky3 PQ-only fork) precompile family | LP-218, LP-220 | ~/work/lux/p3q-evm/ |
| Pulsar / Corona / Magnetar cert-leg composition (QuasarCert) | LP-017, LP-073, LP-181, LP-217 | ~/work/lux/consensus/quasar/cert.go |
| Network-of-Blockchains topology | LP-204 | (architecture; cross-chain shared validators for Hanzo/Zoo/SPC L2s) |
| Cross-shard atomic 2PC | LP-211 | (schemas 0xE2..0xE7 in LP-300) |

None of these have an upstream equivalent. avalanchego has no GPU

path, no FHE, no PQ wire, no atomic L1 spawn, no threshold VM, no Wave

finality driver, no ZapDB snapshot streaming, no STARK-FRI verifier

precompile, no ZK rollup as a first-class chain class.

4. Optional classical-only profile

4.1 What it is

The default Lux Network is post-quantum throughout (LP-217 cert

mode PQ-strict or PQ-heavy). The validator identity is ML-DSA-65

hybrid. The handshake is X-Wing. The threshold legs in the

QuasarCert include Pulsar (Module-LWE) and optionally Corona (Ring-

LWE) and Magnetar (SLH-DSA hash-family). This is the production wire

on mainnet.

A classical-only profile is supported for two operational

purposes:

1. Apples-to-apples benchmarking against avalanchego, on equal

cryptographic footing. avalanchego has no PQ stack — benchmarking

luxd in PQ-strict against avalanchego measures both the

architectural difference *and* the PQ overhead. The classical-only

profile removes the PQ overhead so the architectural difference is

isolated.

2. Educational / research deploys where operators want a "what

does ZAP + Quasar give us, independent of post-quantum cost?"

answer.

The classical-only profile does not revert any other architectural

choice. ZapDB stays. ZAP wire stays. Quasar consensus stays. GPU-EVM

stays. The only thing that flips is the cryptographic suite: BLS-only

validator identity (no ML-DSA leg), classical TLS 1.3 X25519 handshake

(no ML-KEM-768 leg), BLS-only threshold signatures in the QuasarCert

(no Pulsar / Corona / Magnetar legs). Think of it as "post-Avalanche-

snow-consensus but pre-PQ": the architecture wins are intact, the PQ

overhead is gone.

4.2 LP-217 cert-profile mapping

The classical-only profile maps to LP-217's PQ-off cert mode:

| Profile | QuasarCert legs | Use |
|---|---|---|
| PQ-off (classical) | BLS only | Benchmarks, research, localnet/devnet |
| PQ-fast | BLS ‖ Pulsar | Testnet, conservative production |
| PQ-strict | BLS ‖ Pulsar ‖ Corona | Mainnet default |
| PQ-heavy | BLS ‖ Pulsar ‖ Corona ‖ Magnetar | Maximum-assurance, cross-family redundancy |

Activation: per-network setting baked into the spawn tx

(CreateSovereignL1Tx's pq_profile field, LP-018). Mainnet is

strict-PQ at genesis. Localnet and devnet may be classical (or any

intermediate) for testing. The profile is observable on-chain via the

network's spawn record.

4.3 Engaging the classical-only profile

For benchmarking against avalanchego, the operator-side knob is a

Network CR field (LP-018):


apiVersion: lux.cloud/v1
kind: Network
metadata:
  name: lux-classical-bench
spec:
  networkID: 1337            # localnet
  consensus:
    profile: PQ-off          # LP-217 cert mode
  validators: [...]

The luxd binary is the same. The genesis-time PQ-profile selector

configures: validator-identity verifier (BLS-only), handshake suite

(classical TLS), QuasarCert verifier (BLS-leg only). No build-time

flag, no separate binary.

4.4 What this is NOT

The classical-only profile is not "avalanchego in luxd shape". It

is luxd in classical crypto shape. ZAP wire stays, ZapDB stays,

QUIC transport stays, Quasar consensus family stays, GPU-EVM stays,

multi-VM topology stays. The benchmark measures: at equal crypto cost,

what does ZAP + ZapDB + QUIC + Quasar give us over Protobuf + LevelDB

+ TCP + Snowman?

A "true classical baseline" — i.e., disabling ZAP and falling back to

the legacy codec — is not supported. The legacy codec is gone from

go.mod; there is no compile path back. This is intentional. ZAP is

not a feature flag; it's the architecture.

5. Performance — claimed wins + benchmark methodology

5.1 What we have measured

| Dimension | Method | Result |
|---|---|---|
| Binary size | ls -la build/luxd ~/work/ava/avalanchego/avalanchego-release | luxd 35 MB vs avalanchego 61 MB → 43 % smaller |
| Source tree LOC | find . -name '*.go' -not -path './.git/*' \| xargs wc -l | luxd 274 k vs avalanchego 624 k → 56 % smaller (~120 k of upstream's surplus is generated gRPC stubs) |
| go.sum size | ls -la go.sum | luxd 64 kB vs avalanchego 213 kB → 3.4× smaller dependency closure |
| Direct deps | grep -c '^\t' go.mod | luxd 206 vs avalanchego 184 (avalanchego counts deps including grpc-toolchain; luxd's slightly higher count includes the per-VM luxfi/* family) |
| google.golang.org/grpc imports | grep -rln '"google.golang.org/grpc"' --include='*.go' . | luxd 0 vs avalanchego 26 |
| Parse small tx (LP-200 microbench) | go test -bench against linearcodec vs ZAP | 129 ns → 36 ns, 3.6× |
| Parse complex tx (LP-200 microbench) | same | 1008 ns → 75 ns, 13.4× |
| Snapshot streaming (LP-200 microbench) | qualitative; re-encode vs direct buffer | ~10× write-amplification reduction |
| Corona consensus round n=64 (LP-200) | parallel-aggregate correctness fix | 14 s serial (incorrect) → 356–440 ms parallel (correct); the serial baseline was a bug, the parallel number is the honest comparison point |

These are the numbers we will defend. The 35 MB / 61 MB binary

measurement, the 274 k / 624 k LOC measurement, and the 0 / 26 grpc-

import measurement are reproducible from ~/work/lux/node and

~/work/ava/avalanchego main branches at the date of this LP and

will not move materially. The LP-200 microbenchmarks are reproducible

via go test -bench against the named packages.

5.2 What we have NOT measured — methodology for closing the gap

The marketing-flavor claim "luxd is light-years faster than

avalanchego, with much less memory" is unsubstantiated until full-node

benchmark numbers exist. This section lays out exactly what to measure,

how, and where the numbers will live. No fabricated numbers.

5.2.1 Throughput (tx/s, sustained)

Hypothesis: at the classical-only profile (LP-217 PQ-off,

matching avalanchego's classical crypto footing), luxd sustains

≥ 3× the tx throughput of avalanchego at the same hardware budget. The

3× lower bound is the per-tx parse win compounded by the elimination

of mempool re-marshal and state re-encode hops.

Method:

Where the numbers live: `~/work/lux/benchmarks/avalanchego-vs-

luxd/throughput/` (to be created); CI job posts the run on every

tagged release; results page at benchmarks.lux.network/throughput.

5.2.2 Block-to-finality latency

Hypothesis: Quasar's Wave + Focus + Sink composition reaches

local finality in fewer rounds than Snowman's confidence-counter

β-accumulation. Wave gives a per-round threshold vote (single round

trip among the committee); Focus accumulates β consecutive Wave

successes for finality. Snowman accumulates β confidence over per-

preference repeated polls. At committee size 64, β=20, network RTT

50 ms intra-AZ: luxd's Wave round-trip is two committee passes

(~5 ms + handshake-amortized 50 ms); Focus over 20 rounds is ~1 s.

Snowman at same parameters polls ~25–50 rounds at ~50 ms each

(1.25–2.5 s) before reaching β confidence.

Method:

Where the numbers live: same as above, `benchmarks.lux.network/

latency`.

5.2.3 Memory (runtime steady-state RSS)

Hypothesis: luxd's runtime heap is smaller than avalanchego's at

the same workload, because (a) no reflection-tagged codec registry,

(b) no Protobuf descriptor table, (c) no gRPC service registry, (d)

ZAP buffer pool (sync.Pool over fixed-size slices) bounds the

allocation profile.

Method:

Expected concrete savings on binary, before RSS measurement:

That's ~21 MB of grpc-toolchain dead weight that luxd does not link.

That accounts for ~80 % of the binary-size gap (35 vs 61 MB → 26 MB

delta; 21 MB is grpc-toolchain).

Where the numbers live: benchmarks.lux.network/memory.

5.2.4 CPU profile / hot path

Hypothesis: avalanchego's CPU profile under sustained load is

dominated by codec.linearcodec.Unmarshal and proto.Unmarshal

called from gossip, consensus, and state. luxd's CPU profile has no

such hot frame because the offset-read accessors are inlined arithmetic

into the buffer.

Method: 30 s CPU profile at steady-state 1000 tx/s; publish flame

graphs for both binaries side-by-side; report top-10 self-time frames

for each. Expected top frames for luxd: BLS verify, secp256k1 verify,

ZAP frame parse (~50 ns/call), Pebble I/O. Expected top frames for

avalanchego: linearcodec reflect dispatch, proto.Unmarshal, GC

mark, TLS handshake.

Where the numbers live: benchmarks.lux.network/cpu-profile.

5.3 What we explicitly do not claim

5.4 Bench harness location

The bench harness will live at `~/work/lux/benchmarks/avalanchego-vs-

luxd/` once authored. It is not yet in tree at the date of this LP.

The taxonomy convention: scripts under that root, results posted by

CI on tag push to benchmarks.lux.network (a static site under

hanzoai PaaS). LP-301 will not update with numbers; instead a sibling

LP-302 will publish the bench results once they exist and cross-

reference back here.

6. Migration status as of 2026-06-06

6.1 go.mod rip lineage

| Tag | Commit | What landed |
|---|---|---|
| v1.30.0 | 1e284093a0 | Rip grpc + grpc-gateway + luxfi/codec from go.mod; the last upstream-derived dep graph node removed |
| v1.30.1 | 779e9b6e43 | Bump luxfi/proto v1.3.1 → v1.3.2 |
| v1.30.2 | 3d5b8d1c12 + f691faa4b9 | Rip BE-fallback, forward-only ZAP; test fixture + default version bump |
| v1.30.3 | d58699bbd8 | luxfi/proto v1.3.3 → v1.3.4 + luxfi/utils → v1.2.0 — LE end-to-end |

The pre-v1.30 series (v1.28.x, v1.29.x) carried the codec / grpc

bridge as transitional shims. The Wave 2D codec rip (commits

d5bbfb23f8, 71d6fd9d7d, 868ce085c0, beeaf621a9, d867ae46ed,

60f7266e73) migrated 73 files across xvm, evm, example,

proposervm, platformvm, and rpcchainvm to vms/pcodecs. Wave 2G-

Cascade (833b9b2a3d, 987633893c) was the last upstream-symbol

sweep. By v1.30.0 the luxfi/codec package was unreferenced and

deletable.

6.2 Production deployment

Mainnet at the date of this LP is running **5 validators on luxd

v1.28.29, C-Chain head 1,082,780**, P-Chain healthy. v1.30.x has

been tagged but not deployed: the LE-only build cannot read the

pre-LP-023 BE-encoded P-chain state, so the rollout plan is **fresh

bootstrap** (a Quasar Edition mainnet relaunch from genesis-2025).

Genesis cutover ran 2025-12-25 16:20 PST; the post-cutover network

is fresh from block 0. Pre-cutover state is preserved at archive

mainnet for historical query only.

6.3 Residual upstream-shape work

Per LP-200 §"What's NOT yet decomplected":

These four items are the entire residual upstream-shape inventory.

None mutates the architecture. Once LP-201 lands, the residual list

collapses to zero and the audit returns clean on every dimension.

7. Why luxd is faster — the structural reasons

This section translates the marketing claim ("light-years faster")

into specific mechanical reasons. Each row is testable; the test

either confirms or refutes.

7.1 No codec.Marshal() on the hot path

The single biggest hot-path cost in avalanchego is `codec.Manager.

Marshal() / Unmarshal()` called per-block per-tx per-validator.

luxd does not have this call. The ZAP buffer that arrives over the

wire goes directly into the mempool (one buffer-pool pointer). It

goes into the block (a list of buffer-pool pointers). It persists to

ZapDB (one Badger write of the same buffer). The block ID is

sha256(block.Bytes()) where block.Bytes() is the concatenation

of the already-existing buffers; no re-marshal.

Measurable: profile a luxd validator under load; look for

Marshal in the top-100 self-time frames. Result: not present. (See

LP-200 §"Performance Characteristics" — 3.6×–13.4× per-op win is the

direct measurement of this absence.)

7.2 No reflection in the wire format

Avalanchego's linearcodec reflects over every Go struct it

encodes. Reflection in Go is ~10× slower than direct field access

and forces interface-typed allocations. luxd's accessors are

arithmetic — buf[8:12] for a 4-byte field at offset 8. Inlined,

no allocation, no GC pressure.

Measurable: heap allocs per tx-parse. LP-200 reports luxd at

1 alloc/op (the buffer itself); avalanchego at 2–6 allocs/op (one

per reflected field group). Inspect with `go test -bench -

benchmem`.

7.3 LE-end-to-end

Avalanchego is big-endian on wire. luxd is little-endian. On x86-64

and ARM64, native byte order is LE; BE-on-wire requires a byte-swap

on every load. The swap is fast (bswap instruction, one cycle), but

the cumulative cost over millions of field reads per block is real.

Measurable: not easily; the win is small per-op (~1 ns) but

compounds. We report this as a contributing factor, not a headline

number.

7.4 ZapDB instead of LevelDB

ZapDB is a Badger fork with a !grpc build tag and native

pb_zap.go encoders. It stores ZAP buffers as-is — no key-value

serialization layer, no versiondb wrapper, no codec roundtrip on

read or write. Snapshot streaming is one age-encrypted streaming

write of the buffer pool; no re-encode.

Measurable: snapshot write-amplification. LP-200 reports ~10×

reduction (qualitative). State write throughput at the validator

level: TBD per §5.2.1.

7.5 QUIC instead of TCP + TLS

QUIC's 0-RTT handshake is faster than TCP + TLS 1.3's 1-RTT (or

2-RTT cold start), and QUIC's stream multiplexing eliminates the

head-of-line blocking that TCP suffers under packet loss. For a

mempool gossip workload where every validator is concurrently

gossipping to every other validator over many small messages, QUIC

wins on tail latency.

Measurable: tx-gossip latency under 1 % packet loss. TBD per

§5.2.2.

7.6 Wave / Focus finality vs Snowman confidence

Snowman's confidence counter is monotonic — every successful poll

increments confidence on the preferred block by 1, every poll

preferring a different block resets it to 0. Reaching β confidence

takes β consecutive successes from the same preferred block.

Wave's threshold vote in one round gives a 2f+1 commitment; Focus

accumulates β consecutive Wave successes. The committee structure

in Wave (k-of-N Fisher-Yates sample under Photon) means each

round's vote is a fresh sample, not a repeated poll on the same

validator subset.

The end-of-round result: luxd reaches local finality in O(β) round

trips, where the constant is small (~5 ms per round trip intra-AZ,

under PQ-strict; ~2 ms classical-only). Snowman reaches β confidence

in O(β·k) round trips because each round trip is a single-peer poll,

not a committee vote.

Measurable: block-to-decision latency per §5.2.2. TBD; the

hypothesis is luxd ~3× faster at committee size 64, β=20, 50 ms RTT.

7.7 No grpc

google.golang.org/grpc is ~12 MB of compiled code and ~5 MB of

import-side-effect heap at boot. Avalanchego links it; luxd does

not. The 26 grpc-importing files in avalanchego are the gRPC service

definitions, the gRPC-gateway adapters, the otlp gRPC trace

exporter, and the rpcchainvm gRPC plugin host. luxd's rpcchainvm

speaks ZAP transport directly (vms/rpcchainvm/zap/), no gRPC.

Measurable: binary size. Done — luxd 35 MB vs avalanchego 61 MB,

26 MB delta, ~21 MB of which is grpc-toolchain dead weight.

8. References

8.1 Source paths (luxd at v1.30.3, commit d58699bbd8)

8.2 Comparison paths (avalanchego at commit 9f8b9461cf, 2026-05-14)

8.3 Git lineage

8.4 LP cross-references

8.5 Methodology references

9. Activation marker


activates: 2025-12-25T16:20:00-08:00
activates-unix: 1766708400

Same marker as every Quasar Edition wire-and-state LP. Set once; does

not move. The audit numbers in this LP are dated 2026-06-06 against

the post-genesis main branch; the numbers move as the residual

migrations (§6.3) land. The architectural claim — no Avalanche shape

survives — was true at genesis and remains true forward.