mirror of
https://github.com/luxfi/evmgpu.git
synced 2026-10-30 16:57:11 +00:00
Four orthogonal fixes so 'GOWORK=off CGO_ENABLED=1 go build ./...' compiles
the real slot-level Block-STM (core/parallel + state_processor) again:
1. upgrade: re-pin v1.0.1-0.20260603055252-f51810805436 -> v1.0.1. The pinned
pseudo-version commit was force-pushed off origin (orphaned); the published
v1.0.1 tag resolves to the same tree (bd889e9). params, which imports
upgrade, now builds.
2. gpu: re-pin v1.0.2 -> v1.0.1 (matches sibling luxfi/evm). gpu v1.0.2's
e2e_cgo.go calls lux_gpu_{mldsa,slhdsa}_verify_batch with a stale arg list
that no longer matches the C header (cgo 'not enough arguments'); v1.0.1
compiles clean against the installed header.
3. core/vm/runtime: restore the package. An UNANCHORED entry
silently excluded core/vm/runtime/, so cmd/evm/runner.go imported
a package that was never committed. Anchored the ignore to /runtime (root
build artifact) and added the package (ported from luxfi/evm, rewired to
evmgpu's forked core/state.StateDB).
4. gpu_evm.go: add the missing build tag (cgo && darwin && arm64 ->
gpu && cgo && darwin && arm64), aligning the GPU-opcode dispatcher with its
own test (gpu_evm_test.go) and doc comment. Without it the lux-cevm-linked
cgo file was compiled on every darwin build, forcing an absent native dep
on the default build. GPU-opcode dispatch is now opt-in behind -tags gpu;
the pure-Go STM core and the luxfi/gpu ecrecover path stay default.
Verified: ./core/... ./params/... ./cmd/evm build (CGO=1, install pkg-config).
plugin/cmd/abigen link only against absent native archives (accel embeds a
broken relative -L; pqclean/lattice not install-complete) — pre-existing and
identical in luxfi/evm, not introduced here.
171 lines
4.4 KiB
Go
171 lines
4.4 KiB
Go
// Copyright (C) 2026, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
//go:build gpu && cgo && darwin && arm64
|
|
|
|
package parallel
|
|
|
|
// Linkage goes through the lux-cevm pkg-config bundle (libevm + libevm-gpu).
|
|
// The C header "go_bridge.h" ships under
|
|
// $LUXCPP_PREFIX/include/cevm/lib/evm/gpu/, which is in the .pc Cflags.
|
|
//
|
|
// Build + install once with:
|
|
//
|
|
// cmake -S ~/work/luxcpp/cevm -B ~/work/luxcpp/cevm/build \
|
|
// -DCMAKE_INSTALL_PREFIX=$HOME/work/luxcpp/install
|
|
// cmake --build ~/work/luxcpp/cevm/build
|
|
// cmake --install ~/work/luxcpp/cevm/build
|
|
//
|
|
// Then `export PKG_CONFIG_PATH=$HOME/work/luxcpp/install/lib/pkgconfig`.
|
|
|
|
/*
|
|
#cgo pkg-config: lux-cevm
|
|
#cgo darwin LDFLAGS: -framework Metal -framework Foundation -lstdc++
|
|
|
|
#include <stdlib.h>
|
|
#include "go_bridge.h"
|
|
*/
|
|
import "C"
|
|
|
|
import (
|
|
"fmt"
|
|
"unsafe"
|
|
|
|
"github.com/luxfi/geth/common"
|
|
"github.com/luxfi/geth/core/types"
|
|
"github.com/luxfi/geth/log"
|
|
)
|
|
|
|
// GPUEVMDispatcher dispatches GPU-eligible transactions to the C++
|
|
// Metal/CUDA EVM kernel via CGo. Transactions that contain CALL, CREATE,
|
|
// or DELEGATECALL opcodes are not eligible and fall back to Go EVM.
|
|
type GPUEVMDispatcher struct {
|
|
backend C.uint8_t
|
|
}
|
|
|
|
// NewGPUEVMDispatcher creates a dispatcher that routes eligible transactions
|
|
// to the C++ GPU kernel. Auto-detects the best available backend.
|
|
func NewGPUEVMDispatcher() *GPUEVMDispatcher {
|
|
backend := C.gpu_auto_detect_backend()
|
|
log.Info("GPU EVM dispatcher initialized",
|
|
"backend", gpuBackendName(uint8(backend)),
|
|
)
|
|
return &GPUEVMDispatcher{
|
|
backend: backend,
|
|
}
|
|
}
|
|
|
|
// Available returns true if a GPU backend was detected.
|
|
func (d *GPUEVMDispatcher) Available() bool {
|
|
return uint8(d.backend) >= 2 // Metal=2, CUDA=3
|
|
}
|
|
|
|
// Backend returns the name of the active backend.
|
|
func (d *GPUEVMDispatcher) Backend() string {
|
|
return gpuBackendName(uint8(d.backend))
|
|
}
|
|
|
|
// ExecuteBlock dispatches a batch of GPU-eligible transactions to the C++
|
|
// Metal/CUDA kernel. Returns per-transaction gas used.
|
|
//
|
|
// Caller must ensure all txs passed here are GPU-eligible (IsGPUEligible).
|
|
// The signer is needed to recover sender addresses.
|
|
func (d *GPUEVMDispatcher) ExecuteBlock(
|
|
signer types.Signer,
|
|
txs []*types.Transaction,
|
|
senders []common.Address,
|
|
) ([]GPUEVMResult, error) {
|
|
n := len(txs)
|
|
if n == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
// Pack transactions into C structs.
|
|
cTxs := make([]C.CGpuTx, n)
|
|
for i, tx := range txs {
|
|
// From (sender)
|
|
copy(cTxs[i].from[:], senders[i][:])
|
|
|
|
// To
|
|
if tx.To() != nil {
|
|
copy(cTxs[i].to[:], tx.To()[:])
|
|
cTxs[i].has_to = 1
|
|
}
|
|
|
|
// Data -- for GPU-eligible txs this is empty, but handle it.
|
|
if len(tx.Data()) > 0 {
|
|
cTxs[i].data = (*C.uint8_t)(C.CBytes(tx.Data()))
|
|
cTxs[i].data_len = C.uint32_t(len(tx.Data()))
|
|
}
|
|
|
|
cTxs[i].gas_limit = C.uint64_t(tx.Gas())
|
|
cTxs[i].value = C.uint64_t(tx.Value().Uint64())
|
|
cTxs[i].nonce = C.uint64_t(tx.Nonce())
|
|
if tx.GasPrice() != nil {
|
|
cTxs[i].gas_price = C.uint64_t(tx.GasPrice().Uint64())
|
|
}
|
|
}
|
|
|
|
// Call C++ via CGo.
|
|
result := C.gpu_execute_block(
|
|
(*C.CGpuTx)(unsafe.Pointer(&cTxs[0])),
|
|
C.uint32_t(n),
|
|
d.backend,
|
|
)
|
|
|
|
// Free any calldata we allocated.
|
|
for i := range cTxs {
|
|
if cTxs[i].data != nil {
|
|
C.free(unsafe.Pointer(cTxs[i].data))
|
|
}
|
|
}
|
|
|
|
if result.ok == 0 {
|
|
C.gpu_free_result(&result)
|
|
return nil, fmt.Errorf("gpu evm execute_block failed")
|
|
}
|
|
|
|
// Unpack results.
|
|
gasUsedSlice := unsafe.Slice((*C.uint64_t)(result.gas_used), n)
|
|
results := make([]GPUEVMResult, n)
|
|
for i := 0; i < n; i++ {
|
|
results[i] = GPUEVMResult{
|
|
GasUsed: uint64(gasUsedSlice[i]),
|
|
Success: true,
|
|
}
|
|
}
|
|
|
|
C.gpu_free_result(&result)
|
|
return results, nil
|
|
}
|
|
|
|
func gpuBackendName(b uint8) string {
|
|
switch b {
|
|
case 0:
|
|
return "CPU-Sequential"
|
|
case 1:
|
|
return "CPU-Parallel"
|
|
case 2:
|
|
return "Metal"
|
|
case 3:
|
|
return "CUDA"
|
|
default:
|
|
return "Unknown"
|
|
}
|
|
}
|
|
|
|
// WithGPUOpcodes returns an EngineOption that enables GPU EVM opcode dispatch
|
|
// for eligible transactions. Requires the gpu build tag and luxcpp/evm.
|
|
//
|
|
// Trie-node hashing stays on the CPU hasher: GPU keccak dispatch belongs in
|
|
// luxcpp (Metal/CUDA kernels) and is not implemented in Go. Once
|
|
// luxcpp/gpu exposes a batch keccak entry point, the dispatcher can be
|
|
// wired through the existing luxgpu cgo bridge in lux/gpu.
|
|
func WithGPUOpcodes() EngineOption {
|
|
return func(e *Engine) {
|
|
e.gpuEVM = NewGPUEVMDispatcher()
|
|
e.UseGPU = true
|
|
// e.hasher left as the default CPU hasher.
|
|
}
|
|
}
|