Commit Graph
30 Commits
Author SHA1 Message Date
zeekayandHanzo Dev 2f9a315893 One EVM per process; other EVMs are plugins the host loads
The C++ and Rust EVMs are separate luxd plugins. The host spawns every VM with
VM_TRANSPORT=zap (node/vms/rpcchainvm/factory.go) and the cevm binary is
exercised that way cross-process today. Choosing an EVM is choosing which plugin
binary runs -- not a switch inside the Go EVM.

This tree carried a second mechanism for the same choice: an in-process cgo
bridge that linked C++ into the Go binary behind -tags cevm/revm, with a
per-transaction executor registry, an evm_setBackend RPC to flip between
backends at runtime, a resident-store config knob, and a startup log naming the
chosen backend. Its executor returned nil, nil; its tagged build did not compile
(cevm_resident_store.go referenced symbols cevmbridge never defined); and no
build produced a binary that used it. 3,961 lines, gone.

What stays is what the Go EVM actually has: the BlockExecutor seam and
Block-STM behind it (blockstm.go), and the GPU accelerator seam with its
darwin/cgo bridge into luxfi/gpu (gpu_bridge.go). The state processor consults
both and falls through to sequential execution when neither is registered.

Note for the record: nothing in the shipped binary registers a BlockExecutor,
so blocks run sequentially on the Go interpreter. The removed startup log said
"Block-STM across all cores"; it was not describing this binary. Wiring
Block-STM into the production path changes consensus execution and is a
separate decision, made deliberately, with a parity gate.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-09 12:53:54 -07:00
zeekayandHanzo Dev 6337b219aa style: gofmt the tracked EVM tree
Co-authored-by: Hanzo Dev <[email protected]>
2026-08-21 11:51:32 -07:00
zeekayandHanzo Dev c4979a244c cevmbridge: co-build cevm GPU archives same-tree as build-mpt (close ABI-layout risk)
The cevmgpu overlay linked build-phase5b (Apr/May, cevm project 0.2.0) GPU
archives against Jul build-mpt (0.5.2) state libs — nm-clean but era-skewed
ABI layout. Repoint the four GPU .a from build-phase5b to build-mpt-gpu: a
Metal-ON build (LUX_CEVM_ENABLE_METAL=ON) co-built from the SAME current cevm
source tree AND the SAME conan deps as build-mpt (it references build-mpt's
own generators/conan_toolchain.cmake; the GPU backend luxgpu_core_static is
compiled in-tree at project version 0.5.2 — the version build-mpt reports).

GPU host archives and state libs are now the same era by construction, closing
the cross-build ABI-layout risk. Verified on darwin/arm64: `go build -tags
"cevm cevmgpu"` links all four archives from build-mpt-gpu (confirmed via the
full linker command line + a move-aside falsification that fails citing the
build-mpt-gpu paths, then rebuilds green deterministically); the default
`-tags cevm` build still links the build-mpt state libs unchanged.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-22 09:15:44 -07:00
zeekayandHanzo Dev 00c521b7e8 cevmbridge: add cevmgpu build-tag overlay linking cevm GPU host archives
FRONT 1 of the parallel GPU effort. New file bridge_cevm_gpu.go
(//go:build cgo && cevm && cevmgpu) is a pure LDFLAGS overlay, additive to
bridge_cevm.go: under -tags "cevm cevmgpu" both compile and cgo concatenates
their #cgo LDFLAGS, so the CPU state libs (build-mpt) link alongside the GPU
host archives (build-phase5b Metal-ON build of the same cevm source tree):
libevm-gpu.a + libevm-metal-hosts.a + libevm-kernel-metal.a + libevm-gpu-state.a,
plus -framework Metal -framework Foundation.

Symbol audit (nm): every evm:: core/state/precompile symbol the GPU archives
reference is satisfied by build-mpt's state libs; evm::gpu::* symbols resolve
among the four archives; only Metal/Foundation framework symbols come from
outside (no MetalPerformanceShaders, no luxgpu referenced). Device-free anchors
GPUABIVersion/GPUBackendName pull the GPU dispatch objects into the link.

Verified (darwin/arm64):
  go build -tags "cevm cevmgpu" ./plugin/  -> links, 69,125,858 bytes,
    Metal+Foundation+CoreFoundation linked, 88 evm::gpu symbols in binary
    (EvmKernelHost::create, BlockStmGpuMetal::execute_block, execute_block).
  go build -tags cevm       ./plugin/  -> links, 68,978,754 bytes (CPU-only,
    EvmKernelHost::create count 0 — default cevm stays CPU-only, unchanged).
  go build                  ./plugin/  -> links, 68,701,170 bytes (stub path).

SCOPE: BUILD + LINK only. Metal shaders compile at runtime and
MTLCreateSystemDefaultDevice() returns nil headless, so GPU DISPATCH is
CI-gated on a Metal-capable interactive runner — not claimed here.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-22 01:18:55 -07:00
zeekayandHanzo Dev 4693f7467b cevm: disk-backed resident state — lazy-load a checkpoint at startup, no Go dump
Wires StateLoadFromLazy into the resident applier so the C-Chain, on restart,
resumes cevm from a persisted checkpoint (bounded-RAM lazy load) instead of dumping
the full Go state into cevm — the "own disk-backed state" evolution the seed-cap
comment names. Removes the post-restart declined-too-large seed dump.

- core/parallel/cevm_resident_store.go: SetCevmResidentStore(db) (the VM registers a
  durable KV; nil = off, unchanged behavior). tryLazyLoadCheckpoint pages the account
  trie from disk via cevmbridge.StateLoadFromLazy and sets the resident to the
  checkpoint height; persistCheckpoint writes StatePersist records + the height at a
  bounded cadence (default 4096 blocks).
- cevm_shadow.go: getResident tries the checkpoint before a fresh handle;
  persistCheckpoint runs after a block's cevm root is VERIFIED against the header.
- plugin/evm: CevmResidentStore config flag (default false) → registers a "cevmstate"-
  prefixed sub-DB before chain init.
- cevmbridge/bridge_stub.go: StateLoadFromLazy no-op for the non-cevm build.

Safe by construction + triple-gated: nothing runs unless built -tags cevm, the VM
registered a store, AND a checkpoint exists; and the applier still verifies EVERY
cevm root against the header, so a stale/wrong checkpoint only forces a resync (a
Go-dump seed next block), never a wrong commit. nil store (the default) is the prior
in-memory, seed-from-Go behavior byte-for-byte.

Proof (cevm_resident_store_cevm_test.go, //go:build cevm): seed + apply a block,
persistCheckpoint, simulate restart (free handles, retain store), getResident
LAZY-LOADS the checkpoint (height + root recovered, no Go dump), then the next block
applies to a byte-identical FULL root vs a full-reseed reference. Full parallel cevm
suite green; default (non-cevm) plugin build unchanged.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-21 20:28:02 -07:00
zeekayandHanzo Dev 1bb675f5b1 cevmbridge: StateLoadFromLazy — bounded-RAM block apply from persisted state
Wires cevm's C-ABI lazy load into the Go bridge so a node applies blocks over
persisted state without materializing all of it. StateLoadFromLazy builds a
store-backed cevm StateDB (via C.cevm_state_load_lazy) whose account trie is a
from_store_root ref at the persisted root; reads and writes fault account leaves
and storage sub-tries in from zapdb on demand, so RAM is bounded to the block's
touched working set. StateApplyBlock on the handle produces the FULL state root
paged.

Lifetime: unlike a full reseed (which touches the store only during the load),
a lazy handle faults through the store on every later apply, so its cgo.Handle
AND its cevm_kv_store (C-heap allocated) are retained in lazyResources and freed
by StateFree after cevm_state_free has stopped the C++ side faulting through them.

Proof (store_lazy_cevm_test.go, //go:build cevm): seed + apply 2 blocks, persist
to a REAL on-disk zapdb, restart (free handle + close db), reopen, then load the
SAME state two ways — StateLoadFrom (full reseed) and StateLoadFromLazy — and apply
an identical next block to both. Both recover the committed root; the paged apply
root is byte-identical to the full-reseed apply. The full cevmbridge cevm suite
(incl. the existing restart-survival test) stays green.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-21 16:39:52 -07:00
zeekayandHanzo Dev 449a5f1f79 core/parallel/cevmbridge: durable resident state — StatePersist/StateLoadFrom over zapdb
Wire cevm's new persist/load C-ABI to a geth-style database.Database (in
production luxd's own zapdb), and prove restart-survival.

- store_cevm.go: StatePersist(handle, db) / StateLoadFrom(db) -> handle.
  A cevm_kv_store whose get/put point at Go trampolines is built in C
  (cevmbridge_make_store), so cevm (C++/cgo) calls db.Get/Put back through
  THIS Go runtime — no second Go runtime is embedded (the two-runtime
  constraint). The ctx is an opaque cgo.Handle token cast uintptr->void* in
  C (no uintptr<->unsafe.Pointer in Go).
- store_callbacks_cevm.go: the //export get/put trampolines (kept separate —
  //export forbids C definitions in its file's preamble) resolving the ctx
  back to a *kvStore over a Get/Put backend.
- bridge_stub.go: !cevm no-op StatePersist/StateLoadFrom keep `go build ./...`
  green without the tag.
- store_cevm_test.go (//go:build cevm): RESTART-SURVIVAL PROOF. Seed + apply
  2 blocks against a resident cevm StateDB, StatePersist to a REAL zapdb
  (zapdb.New on t.TempDir()), record the root; then StateFree the handle AND
  Close the zapdb (full restart), reopen the zapdb from disk, StateLoadFrom
  into a NEW handle, and assert StateRoot(new) == pre-restart root
  byte-identical. Then apply the NEXT block on the reloaded handle and assert
  it matches the stateless (geth-golden) reference.
  Result: "persisted 300 accounts to zapdb, reloaded, root
  0x5e9db5d6...794d74f == pre-restart root"; next block after reload matches.

All existing gates stay green: cevmbridge golden + resident-across-blocks,
core/parallel conformance 9/9, resident 256-block, shadow 256-block e2e.

MVP scope (honest): persists account state; the resident MPT is rebuilt on
load (root-identical), NOT yet bounded-RAM load-on-demand.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-21 10:39:23 -07:00
zeekayandHanzo Dev 9faa90f10d core/parallel: cevm applier holds RESIDENT state across blocks (no per-block dump)
The cevm gated applier (cevm_shadow.go) dumped the WHOLE Go pre-state
every block and rebuilt a fresh cevm StateDB for each — capped at
maxShadowAccounts, which WAS the declined-too-large decline at scale.

Wire the persistent cevm StateDB behind a per-chain handle instead:
  - bridge_cevm.go: StateCreate/StateSeed/StateApplyBlock/StateRoot/StateFree
    wrappers over the new cevm_state_* C-ABI; marshalling factored into
    shared marshal*/unmarshal* helpers (DRY with ProcessBlock). Stubs in
    bridge_stub.go keep the default (non-cevm) build a no-op.
  - cevm_shadow.go: a residentState per chain (keyed by chain ID). The FIRST
    block seeds cevm once from the Go pre-state dump; SUBSEQUENT in-sync
    blocks call StateApplyBlock with NO dump and compare cevm's resident root
    to header.Root. On AGREE the four-way apply gate writes cevm's post-state
    delta into the Go statedb (unchanged) and the resident advances to height
    N. On DISAGREE/DECLINE/ERROR the resident is flagged out-of-sync and
    re-seeded from the (correct) Go state on the next block. New counters
    ResidentApplied / ResidentSeeds / ResidentReseeds. A wrong resident root
    can never commit — the root check + four-way gate decline it.

Proof (CGO_ENABLED=1 -tags cevm):
  - TestCevmResidentVerifiesRealBlocks: over the same 256 real InsertChain
    blocks, cevm's RESIDENT root == Go header.Root at ALL 256 heights,
    applied via the resident handle, with ResidentSeeds == 1 (not 256) and
    0 resyncs — the declined-too-large killer: 1 full-state dump vs 256 blocks.
  - TestStateApplyBlockGoldenRoots + TestStateResidentAcrossBlocksMatchesStateless
    (cevmbridge): the resident C-ABI is byte-identical to the geth golden
    roots and to a stateless reseed across blocks.
  - Existing TestProcessBlockGoldenRoots (stateless), the 256-block
    TestCevmShadowVerifiesRealBlocks, and the 9/9 applier conformance all
    stay green.

Caveat: this makes the SHADOW/applier resident (no per-block dump). cevm as
the SOLE mainnet engine additionally needs zero declines + disk-backed state
+ node ownership — not claimed here.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-21 10:15:47 -07:00
zeekayandHanzo Dev 2d93929048 core/parallel: carry EIP-2930 access list into cevm (access-list fee/root parity)
The cevm gated applier declined EIP-2930 access-list txs as DISAGREE: the
access list never crossed the bridge, so cevm charged only the 21000 base
intrinsic where the Go EVM charges 21000 + 2400/addr + 1900/key. On a
fee-bearing block that 4300-gas shortfall under-credits the coinbase and
diverges cevm's keccak-MPT root from header.Root, so the four-way gate
(correctly) routed the block to the Go EVM.

Carry the access list end-to-end:
- cevmbridge.Tx gains AccessList []AccessTuple (nil for legacy txs); new
  AccessTuple{Address, StorageKeys}.
- bridge_cevm.go marshals it across cgo into the appended cevm_pb_tx.access_list
  (tuple array + flattened key buffers allocated in C memory — cTxs is Go
  memory passed to C and cgo forbids nested Go pointers — freed on return).
- cevm_shadow.go populates it from tx.AccessList().

Pairs with luxcpp/cevm's process_block surcharge + EIP-2929 warm-set. The
09-access-list-tx conformance scenario flips DISAGREE -> APPLIED
(Agree:1 Applied:1), lifting the applier to 9/9 diverse tx-types. No
regression: the ABIVersion==2 guard, TestProcessBlockGoldenRoots, and the
256-block TestCevmShadowVerifiesRealBlocks (256/256 applied) stay green, and
the default (non-cevm) build is unchanged (additive shared type + stub path).

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-20 14:11:52 -07:00
zeekayandHanzo Dev 9641ce4a6a core/parallel: add cevm diverse applier-conformance harness (measures 5/9 tx-types)
Adds core/parallel/cevm_applier_conformance_test.go (//go:build cevm) — a
permanent conformance gate that measures cevm's REAL per-tx-type apply/decline
coverage as the gated APPLIER (cevm_shadow.go). For each of 9 diverse scenarios
it builds a fresh preimages-ON chain, generates ONE block exercising exactly one
tx-type (CALL-target contracts pre-deployed in genesis so the measured block is
a single call), resets the shadow counters, runs chain.InsertChain (the applier
path), and records the ShadowStats delta.

Measured today (CGO_ENABLED=1 go test -tags cevm ./core/parallel -run Conformance):
  APPLIED  (5): value-transfer, call-sstore, call-log1, call-oog, multi(transfer+call)
  DECLINED (4): contract-create, call-revert, precompile-identity, access-list-tx
  every decline is DISAGREE (cevm's independent keccak-MPT root != Go header.Root);
  none hit reverted-mismatch / errored / declined-*. InsertChain OK on all 9
  (the Go EVM always applies regardless of cevm's verdict).

Headline: cevm applier covers 5/9 diverse tx-types. New findings vs the doc's
"safe subset" claim: LOG1 and out-of-gas calls DO apply; contract CREATE and
top-level REVERT do not. This table is the punch-list for widening cevm parity.

Measurement only — does NOT modify cevm_shadow.go or the bridge. Tag-gated, so
the default no-tags build is unchanged (build+vet green; -run Conformance finds
no test without -tags cevm).

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-20 13:21:48 -07:00
zeekayandHanzo Dev ba49281f80 core/parallel/cevmbridge: add cevm-vs-Go block/state-layer benchmark
Apples-to-apples benchmark of the cevm (C++ EVM) cgo ProcessBlock path vs
the Go EVM (luxfi/geth core/state) raw state transition, on the golden block
of N value transfers that both engines prove to the same keccak-MPT root
0x57b7250733ad7f7a...020099.

- TestBenchRootParity: validity gate. At N=1000 cevm==go==geth golden; at
  N=10000 cevm==go mutual. If roots diverge the comparison is invalid.
- BenchmarkCevmProcessBlock: whole cgo ProcessBlock (seed C++ state + full
  validated EVM block + real keccak-MPT commit + result marshalling).
- BenchmarkGoStateApply: Go state transition only (Sub/Add/SetNonce +
  IntermediateRoot(true)); seeding excluded. Narrowest Go baseline.
- BenchmarkGoStateSeedApply: Go seed+apply+root, the pure-function analogue
  of ProcessBlock.

Measured (Apple M1 Max, best-of-5, -tags cevm): at N=10k cevm ProcessBlock
~24.5ms / ~8585 Mgas/s vs Go-apply ~71.2ms and Go-seed+apply ~87.6ms — cevm
~2.9x / ~3.6x faster while doing strictly more work (full EVM + validation +
gas + cgo round-trip vs state-mutation-only).

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-19 21:55:35 -07:00
zeekayandHanzo Dev 7eb5c60167 core/parallel/cevmbridge: fix stale ABI-version guard (1 -> 2)
The cevm C-ABI is now v2 (post-state delta export); the golden-roots test
guard still expected v1 and Fatalf'd before the byte-exact root check. Roots
unchanged across v1->v2. TestProcessBlockGoldenRoots now green (N=1/100/1000
byte-match geth).

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-19 21:43:18 -07:00
zeekayandHanzo Dev 3c323394d3 core/parallel: promote cevm from shadow-verifier to GATED APPLIER
cevm now ACTUALLY EXECUTES blocks (applies post-state) in luxfi/evm's block
executor, not just shadow-verifies the root — safely gated so it can never
diverge consensus.

Bridge (cevmbridge): ProcessBlock now surfaces the ABI-v2 post-state DELTA and
logs the C-ABI already exports — PostAccounts (address, absolute nonce/balance/
code, Deleted, CodeChanged), PostStorage (address, key, value), and Logs
(address, topics, data, tx_index) — alongside the root + per-tx results.

Executor (cevm_shadow.go): on the AGREE path (cevm root == header.Root) the
executor PROMOTES to applier under an APPLY-THEN-VERIFY-ELSE-DECLINE gate that
is consensus-safe BY CONSTRUCTION:

  - reconstruct receipts from cevm's per-tx {status, cumulative gas, gasUsed,
    logs} + txs (Type, TxHash, ContractAddress via crypto.CreateAddress for
    CREATE, per-receipt Bloom) mirroring core/state_processor.go applyTransaction;
  - replay cevm's post-state delta onto an ISOLATED statedb.Copy() and compute
    its IntermediateRoot(IsEIP158);
  - keep the writeback ONLY IF all FOUR quantities block_validator.ValidateState
    checks byte-match the header: state root, aggregate bloom, receipt-trie hash
    (DeriveSha), and cumulative gas. Then replay the identical delta onto the
    LIVE statedb and return the receipts — the Go EVM does NOT re-run the block;
  - on ANY mismatch, or an unrepresentable block (blob tx, cevm-rejected tx,
    tx-result count skew, missing preimage, too-large, disagree, finalize-gap),
    return (nil, nil) with the LIVE statedb UNTOUCHED so the Go EVM applies.

The trial runs on a deep Copy() rather than Snapshot()/RevertToSnapshot()
because IntermediateRoot -> Finalise -> clearJournalAndRefund invalidates the
journal, making a post-IntermediateRoot revert unreliable; verifying on a copy
leaves the live statedb pristine on every decline (nothing to revert). A wrong
or incomplete delta can therefore never reach the live state.

New honest counters: Applied (four-way gate passed, cevm EXECUTED the block) and
RevertedMismatch (agreed on root but the gated writeback/gate failed → declined
to Go). Invariant: Applied + RevertedMismatch == Agree.

Proven (-tags cevm, build-mpt CPU): the e2e test drives 256 real InsertChain
blocks (768 transfers) through Process -> ExecuteBlock and reports
Applied:256 RevertedMismatch:0 Disagree:0 — cevm executed every block in the
proven safe subset and InsertChain succeeded (ValidateState's four-way check
passed on the written-back state). Whole ./core suite stays GREEN: 9794 blocks
observed, all safely declining (preimages off => cannot seed cevm) and falling
through to Go, no regression. ./core/parallel suite green.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-19 21:05:12 -07:00
zeekayandHanzo Dev c435ce5aea core: run the ./core block suite through the cevm shadow verifier and report the honest agreement rate
Wires the existing cevm (C++ EVM) byte-exact shadow verifier so it observes
EVERY block of the real ./core suite, and reports the true tally — without
weakening the gate or ever letting cevm apply state.

- core/main_cevm_test.go (//go:build cevm): a cevm-only TestMain that runs the
  whole ./core suite then prints the aggregate parallel.CevmShadowStats(). Because
  state_processor.go:124 routes every block through
  parallel.DefaultExecutor().ExecuteBlock — which under -tags cevm is the
  cevmShadowExecutor — this is the honest whole-suite count. main_test.go's goleak
  TestMain is gated //go:build !cevm so exactly one TestMain exists per build.

- core/parallel/cevm_shadow_registration_test.go (//go:build cevm): asserts
  DefaultExecutor() is the cevmShadowExecutor (not the no-op fallback) — the
  precondition for the whole claim.

- core/parallel/cevm_shadow_e2e_test.go: scaled the real-StateProcessor agreement
  proof from 3 to 256 genuine InsertChain blocks (768 transfers). cevm's
  independent real-MPT process_block root byte-matched the Go EVM header.Root on
  ALL 256/256 blocks (0 disagree, 0 finalize-gap).

- Four precompile test files (genesis_dexsettle_reproduce, precompile_alwayson,
  precompile_statedb_subbalance, precompile_env_call) gated //go:build !cevm: they
  alone pull precompile/registry -> luxfi/precompile/dex -> luxfi/dex/pkg/dex whose
  cgo file #includes the absent dex_gpu.h, breaking the CGO_ENABLED=1 build the
  bridge needs. They are precompile tests, not block-execution tests, and still run
  in every non-cevm build — an orthogonal blocker isolated, not a cevm regression.

HONEST RESULTS (CGO_ENABLED=1 -tags cevm):
- Whole ./core suite: 78 PASS / 0 FAIL / 32 SKIP. cevm observed all 9794 blocks;
  it declined every one as no-preimage (the production default runs preimages OFF,
  and the shadow needs trie-key preimages to recover the 20-byte addresses that
  seed cevm) — 0 disagree, 0 errored, 0 false roots. The Go EVM applied every
  block; cevm never touched state.
- Real-block agreement (preimages ON, the config the shadow requires), driven
  through core.BlockChain.InsertChain -> StateProcessor.Process -> the shadow:
  256/256 blocks byte-exact agreement (768 transfers).

Default (!cevm) build unchanged: ./core and ./core/parallel green in both CGO
modes; the 10 gated precompile tests present in the default build.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-19 18:14:45 -07:00
zeekayandHanzo Dev f70050eed6 core/parallel: wire cevm (C++ EVM) in as a byte-exact block shadow-verifier
Route-gated activation of the Lux C++ EVM (cevm) through the BlockExecutor
seam (SEAM 1): parallel.RegisterExecutor makes core/state_processor.go run
ExecuteBlock on every block. Because the CONSENSUS root is taken from the Go
statedb.IntermediateRoot() (block_validator.go), cevm-as-applier would need
host-callback state write-back (deferred); so this lands cevm as a pure
SHADOW VERIFIER — it recomputes the block's keccak-MPT root independently and
confirms it matches the Go EVM's header.Root, then ALWAYS returns (nil,nil)
so the Go path applies the block. Root-only checking sidesteps both known
cevm gaps (event logs, state write-back).

core/parallel/cevmbridge: cgo seam to cevm's extern "C" cevm_process_block
(luxcpp/cevm build-mpt CPU libs, real MPT commit — NOT the placeholder-root
gpu path). Two variants share one API: bridge_cevm.go (//go:build cevm) links
the verified build-mpt + Conan link line and calls the real process_block;
bridge_stub.go (//go:build !cevm) is pure Go and declines, so `go build ./...`
stays green on any machine and the C++ path is opt-in via -tags cevm (the
existing backend_cevm.go convention). Balance is LE limbs; value/gasPrice/ctx
256-bit fields are BE — matching go_process_block.h exactly.

core/parallel/cevm_shadow.go: the BlockExecutor. Snapshots the pre-block state
read-only via DumpToCollector (address<-trie-key preimage, nonce, balance,
code, storage), builds the cevm tx array (sender via block signer, effective
gas price matching evm/core/state_transition.go's full-fee-to-coinbase model),
runs cevmbridge.ProcessBlock, and cross-checks the root against header.Root.
Atomic counters tally agree / disagree / finalize-gap (withdrawals move
header.Root; cevm runs no engine.Finalize — a state no-op on Lux otherwise) /
declined-too-large / declined-no-preimage / declined-tx / errored, read via
CevmShadowStats. Panics in the snapshot/bridge are swallowed and counted: the
verifier can never destabilise consensus. Registration is gated on
cevmbridge.Enabled so default and -tags parallel builds are byte-unchanged.

parallel.go: initialize txExecutors at declaration instead of in init().
Backend files register from their own init() (backend_cevm.go under -tags
cevm), and Go orders init() funcs alphabetically by filename — backend_cevm.go
precedes parallel.go, so the old init()-time map creation raced too late and
panicked on a nil map under -tags cevm. Var initializers run before all
init() funcs, fixing the order deterministically.

Proven:
  - cevmbridge golden roots through the Go marshalling byte-match luxfi/geth:
    N=1 0xb9d849f9…805e9, N=100 0x2028713f…7cf0f, N=1000 0x57b72507…20099.
  - e2e (TestCevmShadowVerifiesRealBlocks, -tags cevm): 3 real blocks through
    core.BlockChain.InsertChain -> StateProcessor.Process -> shadow ExecuteBlock;
    cevm's real-MPT root byte-matched the Go EVM header.Root on all 3
    (Processed:3 Agree:3 Disagree:0, zero declines/errors).
  - default (stub) core/parallel suite unchanged and green.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-19 18:04:03 -07:00
zeekay 8b3f3cf9bc test(parallel): Block-STM determinism slice on SettleBatch — anti-fork (Phase 1)
The determinism half of the unified executor: parallel-eligible settlement
reproduces the canonical sequential state root. Reuses the REAL kernels
(detectConflicts via ConflictEdges, SettleBatch, geth IntermediateRoot) — no
second engine, no mock conflict detector.

  Test9999_DisjointFillsParallelRootEqualsSequential
    (== TestBlockSTM_DifferentMarketsParallel): fills on different markets ->
    detectConflicts finds 0 edges -> SettleBatch root == sequential root. In-test
    fail-without: collapsing the two onto one market yields an edge (proves the
    detector keys on the market, not vacuously empty).

  Test9999_ConflictingFillsReExecToSequentialRoot
    (== TestHotMarketBatchDeterministicRoot): two fills sharing an account on one
    HOT market -> detectConflicts returns edge (0,1) -> SettleBatch serializes in
    ascending-INDEX order -> root == C-then-D AND != the swapped D-then-C. Uses an
    order-SENSITIVE hot-market slot (keccak(prev||taker)) so the root genuinely
    depends on apply order — a balance-only fill is commutative and would make the
    determinism claim vacuous; the in-test guard rejects a commutative Apply.

Fail-without PROVEN by temporary revert: reversing SettleBatch's apply order
makes the root diverge to the swapped order and the conflicting-fills test FAILS
(restored after). Owner-named tests satisfied by the same bodies. Full
core/parallel suite green; no existing tests weakened.
2026-06-22 19:39:07 -07:00
zooqueen 46a7de4200 test(parallel): live GPU ecrecover dispatch proof (Metal vtable, not CPU fallthrough)
Asserts DefaultGPU().Available()==true and GPU-recovered sender == CPU sender,
proving the block-insert ecrecover path dispatches to the real Metal backend
(libluxgpu_backend_metal.dylib) rather than the CPU fallthrough.
2026-06-22 02:36:21 -07:00
zeekay c0f265e47e evm: wire dex-zap-endpoint -> SetBackend(NewZAPEngine) so 0x9010 routes to the venue D-Chain
config.go: DexZapEndpoint (node-local + version-pinned consensus-safety invariant). vm.go: when
set, SetBackend(NewZAPEngine(endpoint,2s)) BEFORE parseGenesis; INERT when empty (public default
= embedded engine, unchanged). Resolves against published luxfi/[email protected], no replace.
Builds CGO on+off; config decode test added.
2026-06-17 17:26:12 -07:00
zeekay 4eecb66098 evm v0.18.16: fix nil-chainConfig panic at PQ gate + RLP verifier tool
Bug fix (closure-swarm v1.28.15 boot blocker):
PQ gate at plugin/evm/vm.go was setting vm.chainConfig.PQ BEFORE
vm.chainConfig was assigned from g.Config — chainConfig was nil at
that point, panic on dereference. Moved the gate AFTER assignment.

Repro: fresh-PVC bootstrap with chain-config.json pq:true caused
"runtime error: invalid memory address or nil pointer dereference"
in the EVM ZAP plugin → C-Chain never bootstraps. Discovered during
localnet 1337 bring-up against v1.28.15.

Fix: move the gate to AFTER `vm.chainConfig = g.Config`. PQ profile
is now correctly installed on a non-nil chainConfig.

Added:
- cmd/rlp-verify/main.go — decodes C-Chain RLP export, verifies
  genesis hash matches genesis JSON, each block's ParentHash chains
  cleanly. What admin.importChain does sans state execution; sufficient
  proof that an RLP+genesis pair is wireable to a luxd boot.

Indirect dep bumps:
- github.com/ChainSafe/go-schnorrkel v1.1.0 (sr25519Verify precompile)
- github.com/cosmos/go-bip39 v1.0.0 (bridgeRegistrarConfig precompile)
- github.com/luxfi/ai v0.1.0 (aiMiningConfig precompile)

Build tag: drop `gpu` tag on darwin gpu_bridge.go (parallel/gpu is one
concept; the darwin gpu bridge always compiles when cgo+darwin).
2026-06-02 01:04:45 -07:00
zeekay 458178730d evm: derive plugin VM ID from luxfi/constants.EVMID; bump luxfi/gpu v1.0.1
- cmd/vmid prints constants.EVMID — Go source of truth for the C-Chain VM
  ID. Build scripts and Makefile now call this instead of hardcoding the
  base58 string. Drops a stale subnet-evm ID (ag3GReYP…) from the Makefile.
- scripts/build.sh: default output is build/evm; INSTALL=1 installs under
  the derived VMID at \$LUX_PLUGIN_DIR. Codesigns on darwin in-line so a
  fresh binary doesn't get SIGKILLed by gatekeeper post-cp.
- core/parallel/gpu_bridge.go: build tag flipped from \`!nogpu\` (opt-out)
  to \`gpu\` (opt-in) so default builds don't drag in luxfi/gpu cgo.
- go.mod: luxfi/gpu v0.30.0 → v1.0.1. v0.30.0 referenced removed MLX
  symbols (mlx_from_slice_int64 etc.); v1.0.1 migrated to lux/gpu.h and
  builds cleanly with -tags gpu and -tags \"cevm gpu\".
- LLM.md: build commands updated; \"no canonical / no aliases\" reflects
  reality (single VMID, one filename, derived from Go).
2026-05-11 22:36:46 -07:00
zeekay 1775ee8ff1 LP-108 Phase 4: stop pretending parallel/auto-select is GPU-accelerated
backend_auto.go used to auto-select CppEVM when a GPU was detected
("parallel backend: GPU detected, backend=cevm, gpu=Metal"). But
cevmExecutor.ExecuteTransaction returned (nil, nil) — every tx fell
through to Go EVM regardless. The "GPU acceleration" log line was
misleading; the real path was always Go EVM.

Per LP-108 "one and one only": collapsed auto-select to GoEVM. The
GPU presence is still detected and logged honestly:

  parallel backend: Go EVM (Block-STM across all cores)
  cores=10  gpu_status="Metal (detected; cevm dispatch wiring
  pending — runs Go EVM)"

To re-enable CppEVM auto-selection, the per-tx → batched-block
adapter in backend_cevm.go::ExecuteTransaction must be completed
AND a parity test against Go EVM Block-STM must pass.

Documented the gap in backend_cevm.go and backend_revm.go executor
comments. The (nil, nil) return is the documented "this backend
declines; use Go EVM" contract that the parallel framework's
DefaultTransactionExecutor expects (parallel.go:107).

Build verified: CGO_ENABLED=0 go build ./core/parallel/... clean.

Reference cevm bridge that needs wiring:
  github.com/luxfi/chains/evm/cevm/cevm_cgo.go::ExecuteBlock
  takes []Transaction (block-batch), TransactionExecutor is per-tx;
  adapter must accumulate per-tx work and submit at block close.

This is the production-wiring counterpart to LP-108 Phase 4 vapor
deletion. The "GPU EVM is plumbed" claim is now contingent on the
adapter, not on ambient registration.
2026-05-04 17:01:33 -07:00
zeekay 988e4f97ee feat: Lux EVM — GPU auto-detect, anchor precompile, nogpu build tag 2026-03-02 18:00:00 -08:00
zeekay d3d2aa7265 fix: remove last 4 TODOs in backend stubs 2026-03-02 23:59:00 -08:00
zeekay 74364a6e95 fix: cevm is fastest interpreter, revm for parallel Block-STM 2026-04-07 00:43:15 -07:00
zeekay 3ef13e594c feat: Block-STM parallel execution scaffold
Add Block-STM algorithm implementation to core/parallel with:
- TxApplyFunc callback to avoid core<->parallel circular imports
- Goroutine pool with configurable worker count (default NumCPU)
- Address-level read/write set tracking per transaction
- Conflict detection: flag tx[i] when it reads a slot tx[j<i] wrote
- Sequential re-execution of conflicting transactions on merged state
- Cumulative gas accounting in commit phase
- Atomic metrics counters for observability

12 new tests covering executor creation, fallthrough behavior,
RW set construction, conflict detection, cumulative gas ordering,
error propagation, and interface compliance.
2026-04-07 00:28:05 -07:00
zeekay f9e7fb3439 feat: wire modular EVM backend into state processor
In the sequential execution fallback, check for a registered
TransactionExecutor (revm/cevm) and dispatch through it before
falling through to the default geth interpreter. Logs active
backend on first block when a non-default backend is present.

Also fix blockstm.go import cycle by injecting TxApplyFunc instead
of referencing core package symbols directly.
2026-04-07 00:26:47 -07:00
zeekay 3f686f9d65 feat: modular EVM backend switching — gevm, revm, cevm
Three swappable EVM backends via build tags:
  gevm (default) — Go EVM from luxfi/geth (always available)
  revm (-tags revm) — Rust EVM via FFI (2x faster, native Block-STM)
  cevm (-tags cevm) — C++ EVM via CGo (3x faster, GPU kernels)

Architecture:
  parallel.TransactionExecutor interface — per-tx backend dispatch
  parallel.EVMBackend enum — gevm | revm | cevm | auto
  parallel.RegisterTransactionExecutor() — init()-time registration
  parallel.SetBackend(AutoEVM) — runtime selection (cevm > revm > gevm)
  parallel.AvailableBackends() — query what's linked

Block-level: parallel.BlockExecutor (unchanged, already wired)
GPU: parallel.GPUAccelerator (unchanged, Metal ecrecover working)

Backend stubs in backend_revm.go and backend_cevm.go — build-tagged,
register on init(). FFI/CGo bridges TBD in luxfi/revm and luxfi/cevm.

StateDB is the bridge — all backends read/write through the same Go
StateDB interface, ensuring consensus compatibility regardless of
which interpreter runs the bytecode.
2026-04-07 00:19:15 -07:00
zeekay baf5f76f3b evm: add 13 GPU bridge inversion tests
- recoverV: legacy, EIP-155, overflow chain ID/V, invalid V values
- padTo32: normal, exactly-32, oversized, zero
- secp256k1halfN constant check
- Fallback GPU/executor behavior tests
2026-03-02 23:59:00 -08:00
zeekay bc0e3ced20 evm: GPU-accelerated signature recovery via Metal
- GPU ecrecover bridge: 32x speedup (1613ms → ~50ms for 47K sigs)
- Auto-detect Metal on darwin, no build tags required
- Per-tx signer derivation (not per-batch) — fixes mixed-chainID bug
- EIP-2 low-S enforcement before GPU submission
- Zero-address rejection for GPU results
- CacheSender stores pre-recovered senders, CPU fallback for misses
- Merged parallel.go + default.go into single tag-free file
2026-03-02 23:59:00 -08:00
zeekay 41e3cd7961 feat: parallel execution plugin interface (build-tag based) 2026-04-05 15:00:29 -07:00