mirror of
https://github.com/luxfi/evm.git
synced 2026-09-24 00:27:44 +00:00
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.
157 lines
3.8 KiB
Go
157 lines
3.8 KiB
Go
// Copyright (C) 2025-2026, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
// Package parallel defines interfaces for optional parallel block execution
|
|
// and GPU acceleration in the Lux EVM.
|
|
//
|
|
// No build tags required. GPU acceleration is auto-detected at init time:
|
|
// - darwin + CGo: Metal GPU via gpu_bridge.go
|
|
// - linux + CGo + CUDA: NVIDIA GPU (future)
|
|
// - otherwise: CPU sequential (zero overhead)
|
|
//
|
|
// The registration pattern allows platform-specific init() functions
|
|
// to register GPU backends without import cycles.
|
|
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
|
|
txExecutors map[EVMBackend]TransactionExecutor
|
|
activeBack EVMBackend = GoEVM
|
|
)
|
|
|
|
func init() {
|
|
txExecutors = make(map[EVMBackend]TransactionExecutor)
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// RegisterTransactionExecutor registers a per-tx executor for a given backend.
|
|
// Call from init() in backend packages (e.g., revmbackend, cevmbackend).
|
|
func RegisterTransactionExecutor(backend EVMBackend, e TransactionExecutor) {
|
|
mu.Lock()
|
|
defer mu.Unlock()
|
|
txExecutors[backend] = e
|
|
}
|
|
|
|
// SetBackend selects the active EVM backend.
|
|
// Use AutoEVM to select the best available.
|
|
func SetBackend(backend EVMBackend) {
|
|
mu.Lock()
|
|
defer mu.Unlock()
|
|
if backend == AutoEVM {
|
|
// Priority: CppEVM > RustEVM > GoEVM
|
|
for _, b := range []EVMBackend{CppEVM, RustEVM, GoEVM} {
|
|
if _, ok := txExecutors[b]; ok {
|
|
activeBack = b
|
|
return
|
|
}
|
|
}
|
|
activeBack = GoEVM
|
|
} else {
|
|
activeBack = backend
|
|
}
|
|
}
|
|
|
|
// ActiveBackend returns the currently selected EVM backend.
|
|
func ActiveBackend() EVMBackend {
|
|
mu.RLock()
|
|
defer mu.RUnlock()
|
|
return activeBack
|
|
}
|
|
|
|
// AvailableBackends returns all registered backend names.
|
|
func AvailableBackends() []EVMBackend {
|
|
mu.RLock()
|
|
defer mu.RUnlock()
|
|
backends := make([]EVMBackend, 0, len(txExecutors)+1)
|
|
backends = append(backends, GoEVM) // always available
|
|
for b := range txExecutors {
|
|
if b != GoEVM {
|
|
backends = append(backends, b)
|
|
}
|
|
}
|
|
return backends
|
|
}
|
|
|
|
// DefaultTransactionExecutor returns the tx executor for the active backend.
|
|
func DefaultTransactionExecutor() TransactionExecutor {
|
|
mu.RLock()
|
|
defer mu.RUnlock()
|
|
if e, ok := txExecutors[activeBack]; ok {
|
|
return e
|
|
}
|
|
return nil // GoEVM uses native geth path, no TransactionExecutor needed
|
|
}
|
|
|
|
// 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
|
|
}
|