Performance Enhancements¶
Docs-site note (2026-06-25, refreshed 2026-07-11): Part of the planned Vexor documentation site (Anza-style). Vexor is testnet-only, version 0.9.x pre-production. This page is an itemized tour of the shipped performance work in the Vexor validator. For each item: what it does, why it helps, and its current status — live or gated/dormant. Status claims are grounded in the source tree and the blessed production build; gated features are stated as gated, not as live.
How to read the status column¶
Vexor's production build is a two-flag command: zig build -Dprod -Dpure_zig -Dcpu=znver4 --release=safe.
-Dprod bundles 8 canonical feature flags — leader mode, stake-weighted repair, parallel execution, FEC
dedup, the watchdog, status cache, native QUIC votes, and VexLedger — into one build-time switch. -Dpure_zig
is passed alongside it but is a no-op: crypto (ed25519/BLAKE3/BN254/Poseidon) runs through Vexor's own
pure-Zig backend unconditionally, and vote execution runs through Vexor's own voteforge program
unconditionally — neither the old Ballet crypto flags nor the old Sig-derived vote flag exist anymore (both
were removed 2026-07-12; see The Vote Program). Each remaining flag is still
individually overridable (-Dprod -Dpure_zig -Dfec_dedup=false) for isolation, but a normal build no longer
hand-assembles a flag list.
At runtime, a boot-time config bake (bakeProdEnvDefaults()) goes one step further: it sets the proven-value
VEX_* env for every one of those runtime-tunable features only if the operator hasn't already set it, so a
bare launch command self-defaults to the fully-armed configuration. This is why most rows below are simply
Live — on by default, no env required — rather than something an operator has to remember to arm:
- Live — on by default in the production deploy (compiled in via
-Dprod, armed by the runtime bake or otherwise unconditional), accelerating the running validator now. An explicitVEX_X=0always disarms it back to the byte-identical baseline path. - Gated / dormant — compiled in but not part of the standard production posture; requires an explicit, separate build flag and is not documented as operator-facing.
| Feature | Activation | Status |
|---|---|---|
| AF_XDP zero-copy datapath | VEX_ENABLE_AFXDP=1 + --xdp-zero-copy |
Live (armed in deploy; host/NIC-specific, never baked) |
| Native QUIC votes | -Dprod (bundles -Duse_native_quic_votes) + poller |
Live, UDP fallback |
| FEC-set ed25519 dedup | -Dprod (bundles -Dfec_dedup) — baked on at boot |
Live by default, bank-hash-neutral |
| Parallel transaction execution | -Dprod (bundles -Dparallel_exec) — baked on at boot |
Live by default, proven bank-exact |
| Zen-4 build target | -Dcpu=znver4 |
Live (build-time) |
| CCX-aware core pinning | src/vex_topo.zig + deploy taskset |
Live |
| VexLedger append-segment | -Dprod (bundles -Dvex_ledger) — baked on at boot |
Live (see ledger) |
| Vote-program rewrite | Vexor-authored vote executor | Live — sole, unconditional executor; Sig-derived test oracle removed (Stage 8, 2026-07-12) |
| Pure-Zig crypto backend | Unconditional (Ballet backend removed 2026-07-12) | Live — sole crypto backend, zero Firedancer symbols linked |
AF_XDP zero-copy datapath¶
What it does. AF_XDP (Address-Family XDP) is a Linux kernel-bypass socket family. Vexor binds an AF_XDP socket to a NIC RX queue with a shared UMEM (a userspace memory pool of fixed-size frames) and the four XDP rings (Fill, Completion, RX, TX). Incoming shred packets are DMA'd by the NIC directly into UMEM frames; the validator's RX path holds frame references and stages shreds without a per-packet copy through the kernel network stack. The TX ring gives a real zero-copy send path as well.
Why it helps. Turbine delivers shreds as a firehose of ~1228-byte UDP packets. The per-packet kernel-stack copy and syscall overhead of a normal socket is exactly the wrong cost model for that workload. Zero-copy RX lets the node keep up at line rate and frees CPU that would otherwise be spent copying bytes.
Status — live. Enabled in the production deploy via VEX_ENABLE_AFXDP=1 (with --enable-af-xdp
--xdp-zero-copy), running on the Mellanox ConnectX-6 Dx (mlx5). The path is gated behind two independent flags
(socket creation and the zero-copy frame-reference path) for conservative driver safety; AF_XDP defaults off
for a real topology reason — enabling XDP on the live-cabled port link-resets it, so it requires a NIC/queue setup
that does not also carry management traffic. See Network setup for enablement and
queue/IRQ tuning.
Native QUIC votes¶
What it does. Vexor has a full Zig-native QUIC TPU client: identity mTLS certificate, ALPN solana-tpu,
RFC-9000 transport-parameter handling, and byte-exact MAX_STREAMS_UNI flow control. When enabled, a dedicated
QuicVotePoller tile (pinned to its own core) owns the QUIC endpoint, drains produced votes, and submits each as
a unidirectional QUIC stream — opening streams only up to the credit the leader has granted.
Why it helps. It removes the dependency on Agave's QUIC stack for vote submission and gives Vexor a native, controllable path to the leader. Most independent validator setups lean on Agave's QUIC; a clean-room Zig client is both a differentiator and one less foreign dependency.
Status — live, with UDP fallback. Compiled in as part of the canonical -Dprod production build (bundles
-Duse_native_quic_votes). Critically, on
StreamLimitReached or any connection failure it falls back to UDP + RPC relay, so a QUIC hiccup can never
cause delinquency. A binary built without the flag votes via UDP, byte-identically. Observability:
[QUIC-VOTE-STATS] is logged roughly every 10 s (QUIC vs UDP counts, pool size, evictions, cache hit/miss).
FEC-set ed25519 signature-verify dedup¶
What it does. Shreds in the same FEC (erasure-coding) set share a Merkle root and a single signature over that
root. Naively, each shred triggers an ed25519 verification. Vexor's dedup keeps a small bounded per-worker cache
keyed on (signature, pubkey, merkle_root); the cache is populated only after a successful verify, so when a
sibling shred from the same FEC set arrives, a cache hit is provably equivalent to having re-verified it — and
the redundant ed25519 verify is skipped.
Why it helps. ed25519 verification is one of the most expensive per-shred operations. Deduplicating it across a FEC set removes a large fraction of redundant signature checks on the ingest hot path, without changing what gets admitted.
Status — live by default, bank-hash-neutral. Compiled in as part of the canonical -Dprod production build
(bundles -Dfec_dedup; individually overridable with -Dfec_dedup=false for isolation) and armed automatically
at boot — the runtime config bake sets VEXOR_ED25519_FEC_DEDUP=1 unless the operator explicitly overrides it
with VEXOR_ED25519_FEC_DEDUP=0. It is proven on live shreds: zero false rejects, bank-exact, with the node
catching up through the deduping path. Because it only ever skips a verify that would have succeeded, it has
no effect on the bank hash.
Parallel transaction execution (wave-barrier)¶
What it does. This is the throughput lever toward true leader-equivalence. A conflict-DAG scheduler (a
port of Firedancer's fd_rdisp model) computes the read/write dependencies among the transactions in a block, so
that non-conflicting transactions can run concurrently. Execution runs as a wave barrier: the main thread
collects a ready set of conflict-free transactions, dispatches them to a persistent core-pinned worker pool
(WavePool, each worker with its own arena), waits on a barrier, then merges the workers' write buffers in wave
order and commits them. This is parallel-execute / serial-commit: execution fans out, but the commit into
the bank is ordered and single-threaded.
Why it is bank-exact. Two structural facts make the merge safe. First, the freeze-time lt-hash fold is
commutative, so merging worker writes in a fixed wave order yields a byte-identical bank hash. Second, the
conflict DAG enforces write→read exclusion, so a worker only ever needs its own buffer plus already-committed
state — never another worker's in-flight writes. The current cut parallelizes only all-native transactions
(System, Vote, ComputeBudget); any BPF/loader transaction runs serially within its wave. This covers the
vote-dominated testnet load.
Why it helps. Serial transaction execution is the throughput ceiling for a would-be leader. Executing independent transactions in parallel on cold-CCX worker cores is the #1 lever toward processing a full block at leader rates.
Status — live by default, proven bank-exact. Compiled in as part of the canonical -Dprod production build
(bundles -Dparallel_exec) and armed automatically at boot by the same runtime config bake, which sets
VEX_PARALLEL_EXEC=1 unless the operator explicitly overrides it with VEX_PARALLEL_EXEC=0. The worker-core
placement (VEX_PARALLEL_EXEC_CORES, default 25,26) stays operator-facing — it is host topology, not baked —
so it's still worth setting explicitly if your CCX layout differs. It graduated to this baked-default status
through a staged campaign: an offline replay proved the parallel path reproduces the cluster's bank hashes exactly
over ~1,600 slots with zero mismatches, then a live flip confirmed the node stays CURRENT and bank-exact with the
WavePool running two worker cores. Setting VEX_PARALLEL_EXEC=0 disarms it back to the serial path,
byte-identically.
Zen-4 build target (-Dcpu=znver4)¶
What it does. The production build compiles with -Dcpu=znver4, so the binary targets the exact Zen-4 ISA the
reference EPYC 9374F advertises: AVX-512 (avx512f/dq/bw/vl), SHA-NI, VAES, and VPCLMULQDQ. This is what lets the
consensus-path crypto and @Vector code lower to the wide SIMD and hardware-accelerated hash/AES/CLMUL
instructions.
Why it helps. A validator does constant hashing (PoH, Merkle, lt-hash) and signature work. Targeting the real
microarchitecture lets the compiler use SHA-NI for SHA-256, AVX-512 for the (pure-Zig, under -Dpure_zig)
BLAKE3 kernel and the lt-hash folds, and the 16-lane vector probe for the accounts index — all output-identical
to scalar, just faster.
Status — live (build-time). It is part of the blessed canonical/production build flags. There is no runtime toggle; it is baked into the deployed binary.
CCX-aware core pinning¶
What it does. The AMD EPYC's 32 cores are organized into Core-Complexes (CCX), each a group of 4 cores sharing
a 32 MiB L3 slice (256 MiB L3 across 8 CCX). Vexor declares a single source-of-truth tile→core map
(src/vex_topo.zig) and pins each tile to a specific core. The map is CCX-aware: latency-critical tiles
(verify, replay, produce, vote/txsend) sit on cache-warm cores and never share a core with background work; cold
work (the VexLedger persist tile, dynamic build relief) is fenced onto a separate CCX (cores 0–4 area) so a
compile or a persist burst cannot evict the hot working set. The deploy wraps the process in a taskset mask and
a cgroup-v2 cpuset wall-off, and auto-carves the parallel-exec wave cores out of the floater mask when
parallel exec is armed, so floating threads can't preempt the workers.
Why it helps. On a single-socket cache-rich part, the dominant variable is whether the hot working set stays resident and whether a latency-critical thread ever gets preempted. Explicit CCX-aware pinning keeps the hot set warm and removes preemption as a source of missed slots.
Status — live, and self-verified. The pinning is applied on every deploy, and deploy.sh reads /proc to
prove the live thread→core map and flag any consensus-core floater — a self-audit no mainstream client
performs. See Hardware for the live table and Tuning for the
VEX_TASKSET_CORES knob.
VexLedger append-segment blockstore¶
What it does. Vexor replaces Agave's RocksDB blockstore with VexLedger, a
100% Zig append-only segment log. Shreds are written once, sequentially, into ~256 MiB segment files; there is
no compaction. Pruning evicts a whole sealed segment with a single unlink(). Reads return a slice straight
out of the mmap'd segment (zero-copy shred-serve).
Why it helps (performance angle). The full design rationale is on the VexLedger page; the performance consequences are: ~1× write amplification (versus an LSM's multi-×), no compaction stalls contending with replay/vote for disk I/O, O(1) instant space reclaim on prune, and a zero-copy read path. On testnet it measures a steady ~1.15 MB/s write rate with no disk blowup, and its persist tile runs on a dedicated cold core entirely off the consensus path.
Status — live. It is the node's blockstore on testnet, voting bank-exact. The richer capabilities (flight recorder, content capture for archival RPC) are gated and dormant by default. See the VexLedger page for the full architecture and Tuning for its knobs.
Pure-Zig crypto backend¶
What it does. Ed25519 signature verification, BLAKE3 hashing, and BN254/alt_bn128 + Poseidon group
operations were originally linked from Firedancer's ballet AVX-512 C libraries. Vexor now runs a from-scratch
Zig implementation (src/vex_crypto/) for all three — no Firedancer code, no FFI, on any of the three
primitives.
Why it helps. It closes the last native-code dependency on the consensus path: this is what makes "100% Zig-native" true without caveat (see How Vexor is different), and it keeps the whole hot signature/hash path in one auditable codebase rather than split across a Zig/C boundary.
Status — live, sole production backend. Verified byte-exact against known-answer test vectors — including
published solana-bn254 / EIP-197 / go-ethereum vectors for BN254 — and against live cluster parity. Crypto is
unconditional pure-Zig: the -Dpure_zig build flag that used to select it is kept on the canonical build
command for compatibility but is now a no-op, and the Firedancer-Ballet-backed alternative it used to override
has been removed from the tree outright (2026-07-12) — there is no build configuration that links
Firedancer crypto code anymore. Deploying still needs VEX_ALLOW_NO_BN254=1 set explicitly, unconditionally
(see the Environment Variable Reference).
Vote-program rewrite¶
What it does. Vote instructions dominate testnet transaction volume (~98% of signatures), so their execution cost sets the floor for per-slot SVM-native execution time. Vexor is rewriting this path from scratch: a zero-heap-allocation front door reads the instruction discriminant with a single stack read, and the full Vote/TowerSync instruction family (Authorize, Withdraw, TowerSync credit and lockout processing, root advancement, and the rest) is reimplemented with a fixed-offset, stack-decoded codec — no generic serialization round-trip, no heap allocation on the hot path — shaped after Firedancer's flat-buffer approach and built directly from the Agave 4.2 specification.
Why it helps. The path it replaces spends measurable time per instruction on generic (de)serialization and heap churn that a purpose-built, fixed-shape codec doesn't need. At testnet's vote volume, shaving microseconds off the dominant instruction type is a meaningful fraction of total per-slot execution time.
How correctness was proven before speed was trusted. Before it went live, the new implementation ran inside an A/B differential oracle: every vote instruction was executed on both the new path and the prior path, and the two were compared byte-for-byte (account bytes, lamports, owner, error codes). Over 990,000 real vote instructions captured from a live epoch-boundary window, the comparison found zero mismatches, and the full 1,992-slot golden replay passed byte-identical with the new path armed or disarmed — the bar it had to clear before taking over as the production executor.
Status — live. The Vexor-authored vote program is the sole, unconditional production vote executor — no build flag selects it, and there is no alternate path to select instead. A Sig-derived component served as the differential-test oracle during development; it has been fully removed from the tree (Stage 8, 2026-07-12, −31,181 lines) now that the new path's own gates (446/446 vote KATs, both carriers canon, 1,992/1,992 golden replay) are sufficient on their own. Measured at ~1,898 ns per vote instruction versus ~8,926 ns for the retired reference transplant — a 4.7× speedup — with the byte-identical output proven above over 990,000+ live instructions. An honest one-line acknowledgment of the transplant's historical provenance persists in NOTICE/PROVENANCE.md. See the Roadmap for what's next.
See also¶
- Tuning — the env knobs for the features above, safe defaults, and what to measure.
- Performance Overview — the philosophy and headline facts.
- Accomplished — the vote-program rewrite's full validation results.
- Roadmap — what's next now that the Sig-derived test oracle has been retired.