Files
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

83 lines
1.8 KiB
Go

// Copyright (C) 2025-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package parallel
import (
"sync"
"github.com/luxfi/evm/core/state"
"github.com/luxfi/geth/common"
"github.com/luxfi/geth/core/types"
"github.com/luxfi/geth/core/vm"
ethparams "github.com/luxfi/geth/params"
)
var (
mu sync.RWMutex
executor BlockExecutor
accelerator GPUAccelerator
)
// RegisterExecutor sets the parallel block executor.
func RegisterExecutor(e BlockExecutor) {
mu.Lock()
defer mu.Unlock()
executor = e
}
// RegisterGPU sets the GPU accelerator.
func RegisterGPU(g GPUAccelerator) {
mu.Lock()
defer mu.Unlock()
accelerator = g
}
// DefaultExecutor returns the registered parallel executor,
// or a no-op sequential fallback if none was registered.
func DefaultExecutor() BlockExecutor {
mu.RLock()
defer mu.RUnlock()
if executor != nil {
return executor
}
return fallbackExecutor{}
}
// DefaultGPU returns the registered GPU accelerator,
// or a no-op if none was registered.
func DefaultGPU() GPUAccelerator {
mu.RLock()
defer mu.RUnlock()
if accelerator != nil {
return accelerator
}
return fallbackGPU{}
}
// fallbackExecutor falls through to sequential execution.
type fallbackExecutor struct{}
func (fallbackExecutor) ExecuteBlock(
_ *ethparams.ChainConfig,
_ *types.Header,
_ types.Transactions,
_ *state.StateDB,
_ vm.Config,
) ([]*types.Receipt, error) {
return nil, nil
}
// fallbackGPU is the no-op GPU accelerator.
type fallbackGPU struct{}
func (fallbackGPU) Available() bool { return false }
func (fallbackGPU) BatchEcrecover(_ []*types.Transaction) (map[common.Hash]common.Address, error) {
return nil, nil
}
func (fallbackGPU) BatchKeccak(_ [][]byte) ([]common.Hash, error) {
return nil, nil
}