Lumen

Reacting to Solana transactions before the chain has confirmed them — a private SVM bank fed straight from the shred stream

Rust · solana-svm internals · LMDB · custom thread pipeline · 2026 — the third major version of the arb system, private repo

What it is

Lumen is a Solana state machine that does not wait for the chain. It consumes the raw shred stream — the pre-confirmation transaction data validators gossip to each other — decodes every transaction, simulates it in an embedded SVM against a speculative copy of chain state, and reacts to the result. By the time a swap is confirmed on chain, Lumen has already priced what it did to the pool and, if that opened an opportunity, sent its own transaction.

The first two versions of this system read prices from an indexer and simulated through an API. Lumen replaces all of that with a bank: an LMDB-backed accounts database with a real solana-svm execution engine on top, so the whole loop — ingest, simulate, price, gate, sign, send — happens in one process with nothing in the hot path that talks to a network.

The whole system on one page

One loop and one lag. The hot lane takes a transaction off the shred stream and, inside the same slot, simulates it, finds a route, gates it and sends its own transaction back to the network — everything in one process, nothing on that path talks to a server. The confirmed lane trails the chain by a slot or two: complete blocks are replayed through the same SVM, verified against the network's bank hash, and only then promoted to disk. The bank in the middle is what joins them — the hot lane reads and writes its speculative head, the confirmed lane writes its root and evicts the guesses each block supersedes.

Not drawn: boot (an agave snapshot ingested straight into LMDB, DEX pools discovered into a registry, the token-pair graph built once) and observability (a histogram per stage into Prometheus, a liveness watchdog per worker).

Two lanes around one bank: the hot lane goes shred stream → router → workers → executor → dispatcher → senders → network within the slot; the confirmed lane goes complete blocks → replay and verify → pending fork → commit to the LMDB root, evicting superseded guesses from the speculative head

How a shred becomes a transaction

The hot path is hand-built threads and channels, not an async runtime: a router thread, a set of workers pinned to their own cores, an executor and a dispatcher. Every stage is measured; every stage has a histogram.

Shred stream → router (decode, ALT resolve, account-lock scheduler) → pinned workers (SVM execute against the bank, route finder over the pool registry) → executor gate → tx router by leader schedule → dispatcher with the tick-derived blockhash → senders

Two forks over one root

This is the part that took the longest to get right. The bank keeps confirmed state in LMDB and two layers on top of it, in the same shape as agave's bank forks:

Root LMDB state with a speculative head written by shred workers and a pending fork written by the confirmer, promoted atomically by commit_slot

Replay is verified against the chain the way a validator verifies itself: an accounts lt-hash folded per block, sealed into the agave bank hash, compared with the quorum-attested hash for that slot. Same-block program upgrades and lookup-table extensions stay invisible for one slot because the chain delays them — that came out of reading agave's loader rather than guessing.

How fast the SVM actually is

On the production Xeon with the x86-64 JIT a real Raydium V4 swap simulates in about 0.2 ms p50. The rest of the table is the same benchmark, cargo bench --bench svm_sim, on the real mainnet SOL/USDC pool and program bytes captured as fixtures, run on a 10-core Apple M-series laptop — which means the sBPF interpreter (the JIT only exists for x86-64), so those rows are roughly a 5× pessimistic floor, not the real-world cost.

PathWhat runsp50p90p99
Raydium V4 swap — productionXeon, x86-64 JIT, same swap, measured on the live box0.2 ms——
Raydium V4 swap — laptopsanitize → load → execute, 16 384 CU, sBPF interpreter1.01 ms1.11 ms1.22 ms
Hot path, 200 tx / slotspeculative execute: snapshot head, simulate, append, then confirm0.98 ms1.06 ms1.14 ms
System transferthe floor: SVM overhead with almost no BPF59 µs62 µs110 µs
Scheduleradmit + dispatch + release, 30 accounts, 8 in flight3.5 µs per transaction

The hot-path row is the one that matters: a full speculative execute with the bookkeeping around it costs no more than the bare simulation, so the scheduler and the bank add nothing measurable on top of the SVM. Throughput on the laptop scales from 960 to 2 770 swaps/s across eight threads — sub-linear, which points at a shared program-cache lock inside the SVM as the next thing to profile.

Landing

Simulation is only half of it; the transaction still has to reach the leader first. Lumen keeps a router over every landing service I could get access to and measures each endpoint continuously, so a transaction goes to whichever path is closest to the current leader's region. This is the live probe table from the sender router — same transaction, every provider, every region.

Latency table across landing providers and regions: Jito, Astralane, Helius, NextBlock, 0slot, Falcon, FlashBlock — Amsterdam under 1 ms, Frankfurt and London around 7 ms, US 70–130 ms
Per-endpoint round-trip from the bot's box: Amsterdam providers answer in under a millisecond, Frankfurt and London in about seven, the US east coast in seventy. The router uses this to pick the sender per leader slot.

What I learned building it

The repository is private. The on-chain program that recomputes every arbitrage before it settles is open: Solscan.