Skip to content

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 explicit VEX_X=0 always 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.