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]>
README.md per [markdownlint](https://marketplace.visualstudio.com/items?itemName=DavidAnson.vscode-markdownlint) (#116)
Lux EVM
Lux is a network composed of multiple blockchains. Each blockchain is an instance of a Virtual Machine (VM), much like an object in an object-oriented language is an instance of a class. That is, the VM defines the behavior of the blockchain.
Lux EVM is the unified Virtual Machine (VM) that powers both the C-Chain and L1/L2 Subnet EVM chains. This package consolidates the former Coreth (C-Chain) and Subnet EVM codebases into a single implementation.
Note
: The
github.com/luxfi/corethrepository has been deprecated and merged here. See the migration guide below.
This chain implements the Ethereum Virtual Machine and supports Solidity smart contracts as well as most other Ethereum client functionality.
Building
The Subnet EVM runs in a separate process from the main Luxd process and communicates with it over a local ZAP-native connection (LP-186 wire schema, no protobuf, no gRPC).
Luxd Compatibility
[v0.7.0] [email protected] (Protocol Version: 38)
[v0.7.1] [email protected] (Protocol Version: 39)
[v0.7.2] [email protected]/1.13.0-testnet (Protocol Version: 39)
[v0.7.3] [email protected]/1.13.0 (Protocol Version: 39)
[v0.7.4] [email protected] (Protocol Version: 40)
[v0.7.5] [email protected] (Protocol Version: 41)
[v0.7.6] [email protected] (Protocol Version: 42)
[v0.7.7] [email protected] (Protocol Version: 42)
API
The Subnet EVM supports the following API namespaces:
ethpersonaltxpooldebug
Only the eth namespace is enabled by default.
Full documentation for the C-Chain's API can be found here.
Compatibility
The Subnet EVM is compatible with almost all Ethereum tooling, including Remix, Metamask, and Foundry.
C-Chain vs Subnet EVM Mode
This unified EVM package supports both modes:
C-Chain Mode (Primary Network):
- Atomic transactions for cross-chain transfers (X-Chain ↔ C-Chain)
- Shared memory integration
- Primary network consensus
Subnet EVM Mode (L1/L2 Subnets):
- Configurable fees and gas limits in genesis
- Simplified hardfork configuration
- No atomic transactions (cross-chain via Warp messaging)
Migrating from Coreth
If you were using github.com/luxfi/coreth, update your imports:
// Before
import "github.com/luxfi/coreth/core"
// After
import "github.com/luxfi/evm/core"
All coreth functionality is preserved in this package.
Block Format
To support these changes, there have been a number of changes to the EVM block format compared to what exists on the C-Chain and Ethereum. Here we list the changes to the block format as compared to Ethereum.
Block Header
BaseFee: Added by EIP-1559 to represent the base fee of the block (present in Ethereum as of EIP-1559)BlockGasCost: surcharge for producing a block faster than the target rate
Create an EVM Subnet on a Local Network
Clone EVM
First install Go 1.23.9 or later. Follow the instructions here. You can verify by running go version.
Set $GOPATH environment variable properly for Go to look for Go Workspaces. Please read this for details. You can verify by running echo $GOPATH.
As a few software will be installed into $GOPATH/bin, please make sure that $GOPATH/bin is in your $PATH, otherwise, you may get error running the commands below.
Download the evm repository into your $GOPATH:
cd $GOPATH
mkdir -p src/github.com/luxfi
cd src/github.com/luxfi
git clone [email protected]:luxfi/evm.git
cd evm
This will clone and checkout to master branch.
Run Local Network
To run a local network, it is recommended to use the lux-cli to set up an instance of EVM on a local Lux Network.
There are two options when using the Lux-CLI:
- Use an official EVM release: https://docs.lux.network/subnets/build-first-subnet
- Build and deploy a locally built (and optionally modified) version of EVM: https://docs.lux.network/subnets/create-custom-subnet
Releasing
You can refer to the docs/releasing/README.md file for the release process.
Plugin Runtime Env Vars
The EVM plugin reads its rpcchainvm handshake address and transport from the
unprefixed env var names that current luxd (v1.26+) sets: VM_RUNTIME_ENGINE_ADDR
and VM_TRANSPORT. This matches the canonical names defined in
luxfi/vm/rpc/runtime/runtime.go. Earlier builds of this plugin
(via luxfi/vm ≤ v1.1.0) read LUX_VM_RUNTIME_ENGINE_ADDR/LUX_VM_TRANSPORT,
which are no longer recognized.