cevm

package
v1.7.34 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 21, 2026 License: BSD-3-Clause Imports: 5 Imported by: 0

README

cevm — C++ EVM execution backend

The CGO bridge to the C++ EVM in ~/work/luxcpp/cevm. Selected at link time via build tags from chains/evm/backend_{cgo,nocgo}.go.

This is not a standalone VM. It is the GPU-accelerated execution backend for C-Chain when built with LUX_CGO=1. The pure-Go fallback (luxfi/geth) is used when LUX_CGO=0.

Layout

chains/evm/
├── main.go                 # luxd plugin entry
├── backend_cgo.go          # cgo backend selector (LUX_CGO=1)
├── backend_nocgo.go        # pure-Go selector (LUX_CGO=0)
└── cevm/                   # this package — C++ FFI shim
    ├── cevm.go             # Go API
    ├── cevm_cgo.go         # cgo bindings (linked against luxcpp libs)
    ├── cevm_nocgo.go       # no-op stubs for !cgo builds
    └── plugin.go           # plugin registration glue

Linking

cevm_cgo.go references ${SRCDIR}/../../../../luxcpp/... for headers and libs. From ~/work/lux/chains/evm/cevm/ that resolves to ~/work/luxcpp/. For module-cache builds, see accel's fetch-luxcpp.sh pattern (TODO: port the same approach here).

Performance

When CGO is enabled and luxcpp libs are available:

  • ~3–5× the throughput of pure-Go EVM
  • SIMD opcode dispatch (AVX2/NEON)
  • GPU batch operations via Block-STM (CUDA/Metal)

Provenance

Folded into chains/evm from the previously-standalone luxfi/cevm repo on 2026-04-30. cevm is internal-only — no operator daemon. C-Chain runs in luxd. See ~/work/lux/chains/PLUGGABLE.md for the canonicalization pattern that governs the rest of the chain VMs.

Documentation

Overview

Package cevm provides Go bindings to the C++ EVM (cevm) with GPU acceleration. Import this package to use the C++ EVM as a drop-in replacement for go-ethereum's EVM.

The C++ EVM supports:

  • Block-STM parallel execution
  • GPU Keccak-256 state hashing (Metal/CUDA)
  • GPU batch ecrecover (Metal/CUDA)
  • GPU EVM opcode interpreter (Metal/CUDA)
  • ZAP VM plugin protocol (native)

Build against the native library: CGO_ENABLED=1 go build -tags lux_cevm_native Build without it: go build (types only, no execution) — the default, and the only thing that works on a host lacking the lux-cevm bundle. Binary: the `cevm` binary in luxcpp/evm/build/bin/ is the Lux VM plugin.

Concurrency model

ExecuteBlock and ExecuteBlock are safe to call concurrently from multiple goroutines. The implementation guarantees:

  1. No shared mutable state on the Go side. Every call allocates a fresh []C.CGpuTx for its inputs and a fresh runtime.Pinner for its lifetime. The pinner pins the base address of every Go-owned []byte (tx.Data, tx.Code) that the C side dereferences, and is unpinned via defer after the C call returns — including on the error path.

  2. The C result is freed via defer (gpu_free_result / gpu_free_result_v2) on every code path including failure. Gas/status arrays are copied into Go-owned slices before the result is freed.

  3. The C++ engine uses a thread_local engine cache (one per OS thread reached by goroutines via cgo) for the Keccak hasher; per-instance MTLBuffer / CUDA context caches are mutex-protected on the C++ side. Two goroutines on different OS threads use independent kernel state.

  4. The CPU path is fully reentrant: each call constructs a fresh cevm state and tears it down before returning.

What is NOT safe:

  • Mutating the Transaction.Data or Transaction.Code slices while a concurrent ExecuteBlock call is reading them. The pinner only prevents GC moves; it does not provide read/write synchronization.
  • Sharing a *BlockResult between goroutines without external sync.

ABI version

The Go module's ABIVersion constant is checked against the loaded library's gpu_abi_version() in init(). A mismatch panics at process start — that is intentional. A silent ABI mismatch produces wrong gas/state results and would corrupt consensus, so fail-fast is the only safe behaviour.

Use Health() at startup to additionally verify each backend executes the canonical health-check battery (arithmetic, storage, hashing, memory, and the call bridge) without error.

Index

Constants

View Source
const ABIVersion uint32 = 0

No library linked, so there is no ABI to report.

Variables

This section is empty.

Functions

func BackendName

func BackendName(b Backend) string

BackendName uses the local Go-side string when CGo is off.

func BatchRecoverSenders

func BatchRecoverSenders(txs types.Transactions, signer types.Signer) ([]common.Address, error)

BatchRecoverSenders returns an error under !cgo: the GPU sig-batch primitive lives in the C++ luxcpp/crypto library and there is no Go equivalent in this package. Callers should fall back to per-tx types.Sender when this returns an error.

func LibraryABIVersion

func LibraryABIVersion() uint32

LibraryABIVersion returns the Go-side constant when there's no library.

func PluginExists

func PluginExists() bool

PluginExists reports whether the cevm plugin binary is present on disk.

func PluginPath

func PluginPath() string

PluginPath returns the absolute path to the cevm VM plugin binary. Used by lux CLI and universe Makefiles to locate the built plugin.

func VMID

func VMID() string

VMID returns the VM ID for the cevm plugin. This is the identifier used by Lux subnet configuration to reference this VM in the plugin directory.

Types

type Backend

type Backend int
const (
	// CPUSequential runs transactions one at a time on a single core.
	CPUSequential Backend = 0
	// CPUParallel uses Block-STM to run transactions across all cores.
	CPUParallel Backend = 1
	// GPUMetal offloads Keccak, ecrecover, and the EVM interpreter to Metal.
	GPUMetal Backend = 2
	// GPUCUDA offloads Keccak, ecrecover, and the EVM interpreter to CUDA.
	GPUCUDA Backend = 3
)

func AutoDetect

func AutoDetect() Backend

AutoDetect returns CPUSequential when built without CGo.

func AvailableBackends

func AvailableBackends() []Backend

AvailableBackends returns CPUSequential only when built without CGo.

func (Backend) String

func (b Backend) String() string

String returns the human-readable name of the backend.

type BlockContext

type BlockContext struct {
	Origin        [20]byte
	GasPrice      uint64
	Timestamp     uint64
	Number        uint64
	Prevrandao    [32]byte
	GasLimit      uint64
	ChainID       uint64
	BaseFee       uint64
	BlobBaseFee   uint64
	Coinbase      [20]byte
	BlobHashes    [8][32]byte
	NumBlobHashes uint32
}

BlockContext is the block-level execution context shared by every transaction in a block. It feeds the EVM opcodes that report block-level state: TIMESTAMP, NUMBER, CHAINID, BASEFEE, COINBASE, GASLIMIT, PREVRANDAO, BLOBHASH, BLOBBASEFEE.

Pass a non-nil *BlockContext to ExecuteBlock when the call must mirror real chain semantics (consensus, replay, fork-aware execution). The zero-value is the documented "no context" default — chain id resolves to 0, timestamp to 0, etc., which matches the dispatcher's pre-v0.26 behaviour.

Field layout matches the C-side CBlockContext byte-for-byte: this struct is passed to the C ABI via direct memcpy, no field-by-field translation. Field order MUST match go_bridge.h CBlockContext exactly. Adding new fields requires bumping ABIVersion and the C-side EVM_GPU_ABI_VERSION in lockstep.

type BlockResult

type BlockResult struct {
	StateRoot    [32]byte
	GasUsed      []uint64
	Status       []TxStatus
	TotalGas     uint64
	ExecTimeMs   float64
	Conflicts    uint32
	ReExecutions uint32
	ABIVersion   uint32
}

Backend selects the C++ EVM execution mode. BlockResult extends BlockResult with the V2 ABI fields: per-tx status and the post-execution state root.

func ExecuteBlock

func ExecuteBlock(backend Backend, numThreads uint32, txs []Transaction, ctx *BlockContext, state []StateAccount) (*BlockResult, error)

ExecuteBlock returns an error when built without CGo. Mirrors the V4 cgo signature so consumers can call it unconditionally.

type HealthProbeResult

type HealthProbeResult struct {
	Name    string
	OK      bool
	GasUsed uint64
	Status  TxStatus
	Err     error
}

HealthProbeResult mirrors the cgo build's struct so consumers see the same API surface either way. Under nocgo the slice is always empty.

type HealthReport

type HealthReport struct {
	Backend      Backend
	Name         string
	OK           bool
	Err          error
	Probe        string
	ProbesRun    int
	ProbeResults []HealthProbeResult
	GasUsed      uint64
	Status       TxStatus
	ExecTime     float64
}

HealthReport is the per-backend result of Health(). The nocgo build only reports CPUSequential and never executes — it returns OK=false with an explanatory error and an empty ProbeResults slice.

func Health

func Health() []HealthReport

Health returns a single non-OK report indicating CGo is disabled.

type StateAccount

type StateAccount struct {
	Address  [20]byte
	Nonce    uint64
	Balance  [4]uint64
	Code     []byte
	CodeHash [32]byte
}

StateAccount is one entry in the snapshot of touched accounts handed to ExecuteBlock. Fields mirror the C-side CGpuStateAccount byte-for-byte (modulo the inline `Code` slice which the binding flattens into a single blob before crossing the cgo boundary).

Address is canonical 20-byte big-endian. Balance is little-endian limbs (Balance[0] = low 64 bits). Code may be nil for EOAs — empty code is the EOA marker. CodeHash should be keccak256(code); the dispatcher does not recompute it because callers usually have it cached on the StateDB side.

type Transaction

type Transaction struct {
	From     [20]byte
	To       [20]byte
	HasTo    bool
	Data     []byte // Calldata
	Code     []byte // EVM bytecode (optional — required for real GPU execution)
	GasLimit uint64
	Value    uint64
	Nonce    uint64
	GasPrice uint64
}

Transaction is a single EVM transaction to execute.

When Code is non-empty AND a GPU backend is selected, the C++ EVM dispatches each tx through the parallel opcode interpreter (Metal: kernel::EvmKernelHost, CUDA: cuda::EvmKernel). When Code is empty, GPU backends use the scheduler-only Block-STM kernel.

type TxStatus

type TxStatus uint8

TxStatus is a per-transaction execution outcome from the V2 ABI.

const (
	TxOK               TxStatus = 0 // STOP / clean exit
	TxReturn           TxStatus = 1
	TxRevert           TxStatus = 2
	TxOOG              TxStatus = 3
	TxError            TxStatus = 4
	TxCallNotSupported TxStatus = 5
)

func (TxStatus) String

func (s TxStatus) String() string

String returns a short label for the tx status.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL