mirror of
https://github.com/luxfi/cevm.git
synced 2026-10-30 17:00:54 +00:00
C++ bridge: gpu_execute_block_v4 -> gpu_execute_block, CGpuBlockResultV2 -> CGpuBlockResult, gpu_free_result_v2 -> gpu_free_result (unversioned, rebuilt). Go: one ExecuteBlock(backend, txs, opts...) with WithThreads/WithContext functional options + one full BlockResult; deleted ExecuteBlockV2/V3 and BlockResultV2; updated the !cgo mirror + 4 test files. ABIVersion -> 6. Also fixed the cgo include path (../../luxcpp -> ../../../luxcpp; origin couldn't find go_bridge.h) and ordered the lux-crypto archives after -lluxgpu. Package builds CGO=1 and CGO=0. KNOWN PRE-EXISTING GAP (not introduced; origin never linked at all): the TEST binary pulls cevm's full crypto surface where a few bare-C symbols (ed25519_verify, PQCLEAN_randombytes, lux_donna_sr25519_*, evmc_create_cevm) have no provider archive yet — the blake3-class extern-C shim gap, to be closed in luxcpp/cevm + lux-crypto packaging.
178 lines
5.1 KiB
Go
178 lines
5.1 KiB
Go
package cevm
|
|
|
|
import "testing"
|
|
|
|
// Tests in this file run under both `cgo` and `!cgo` builds. They cover the
|
|
// parts of the API that don't depend on the C++ library: enum stringers,
|
|
// constant exports, and the empty-input fast-path that ExecuteBlock promises
|
|
// to return without error.
|
|
|
|
func TestBackendString(t *testing.T) {
|
|
tests := []struct {
|
|
b Backend
|
|
want string
|
|
}{
|
|
{CPUSequential, "cpu-sequential"},
|
|
{CPUParallel, "cpu-parallel"},
|
|
{GPUMetal, "gpu-metal"},
|
|
{GPUCUDA, "gpu-cuda"},
|
|
{Backend(99), "unknown(99)"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
if got := tt.b.String(); got != tt.want {
|
|
t.Errorf("Backend(%d).String() = %q, want %q", int(tt.b), got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTxStatusString(t *testing.T) {
|
|
tests := []struct {
|
|
s TxStatus
|
|
want string
|
|
}{
|
|
{TxOK, "ok"},
|
|
{TxReturn, "return"},
|
|
{TxRevert, "revert"},
|
|
{TxOOG, "oog"},
|
|
{TxError, "error"},
|
|
{TxCallNotSupported, "call-not-supported"},
|
|
{TxStatus(99), "status(99)"},
|
|
}
|
|
for _, tt := range tests {
|
|
if got := tt.s.String(); got != tt.want {
|
|
t.Errorf("TxStatus(%d).String() = %q, want %q", int(tt.s), got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestVMID(t *testing.T) {
|
|
if got := VMID(); got != "cevm" {
|
|
t.Errorf("VMID() = %q, want %q", got, "cevm")
|
|
}
|
|
}
|
|
|
|
func TestPluginPath(t *testing.T) {
|
|
p := PluginPath()
|
|
if p == "" {
|
|
t.Skip("could not determine home directory")
|
|
}
|
|
const suffix = "work/luxcpp/evm/build/bin/cevm"
|
|
if len(p) < len(suffix) {
|
|
t.Fatalf("PluginPath() too short: %q", p)
|
|
}
|
|
got := p[len(p)-len(suffix):]
|
|
if got != suffix {
|
|
t.Errorf("PluginPath() suffix = %q, want %q", got, suffix)
|
|
}
|
|
}
|
|
|
|
func TestPluginExists(t *testing.T) {
|
|
// This test just verifies the function runs without panicking.
|
|
// Whether it returns true or false depends on the build environment.
|
|
_ = PluginExists()
|
|
}
|
|
|
|
// TestExecuteBlockEmpty must succeed on both cgo and nocgo paths: the API
|
|
// contract is "empty input ⇒ empty result, no error" regardless of build.
|
|
// It covers the bare call and both functional-option forms so every option
|
|
// path honours the empty-input fast-path.
|
|
func TestExecuteBlockEmpty(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
opts []BlockOption
|
|
}{
|
|
{"bare", nil},
|
|
{"with-threads", []BlockOption{WithThreads(0)}},
|
|
{"with-context", []BlockOption{WithThreads(0), WithContext(nil)}},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
result, err := ExecuteBlock(CPUSequential, nil, tc.opts...)
|
|
if err != nil {
|
|
t.Fatalf("ExecuteBlock(nil) returned error: %v", err)
|
|
}
|
|
if result.ABIVersion != ABIVersion {
|
|
t.Errorf("ABIVersion = %d, want %d", result.ABIVersion, ABIVersion)
|
|
}
|
|
if result.TotalGas != 0 {
|
|
t.Errorf("expected 0 total gas for empty block, got %d", result.TotalGas)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestAvailableBackends_NonEmpty: every build must expose at least one backend.
|
|
// Under nocgo, that's CPUSequential. Under cgo, it's whatever the loaded
|
|
// library reports — but never zero.
|
|
func TestAvailableBackends_NonEmpty(t *testing.T) {
|
|
bs := AvailableBackends()
|
|
if len(bs) == 0 {
|
|
t.Fatal("AvailableBackends() returned empty list")
|
|
}
|
|
}
|
|
|
|
func TestBackendName_NonEmpty(t *testing.T) {
|
|
for _, b := range []Backend{CPUSequential, CPUParallel, GPUMetal, GPUCUDA} {
|
|
if BackendName(b) == "" {
|
|
t.Errorf("BackendName(%d) is empty", int(b))
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestHealth_AlwaysReturnsReports: Health() must never return nil. Under
|
|
// nocgo it returns a single non-OK report. Under cgo it returns one report
|
|
// per available backend.
|
|
func TestHealth_AlwaysReturnsReports(t *testing.T) {
|
|
reports := Health()
|
|
if len(reports) == 0 {
|
|
t.Fatal("Health() returned no reports — even nocgo must report status")
|
|
}
|
|
}
|
|
|
|
// TestABIVersion locks the ABIVersion constant so a careless bump is caught
|
|
// by code review. Update both this test and ABIVersion together when the
|
|
// C ABI surface changes.
|
|
func TestABIVersion(t *testing.T) {
|
|
const want uint32 = 6
|
|
if ABIVersion != want {
|
|
t.Errorf("ABIVersion = %d, want %d (update C-side EVM_GPU_ABI_VERSION in lockstep)",
|
|
ABIVersion, want)
|
|
}
|
|
}
|
|
|
|
// TestBlockContextLayout asserts the Go BlockContext fields are the right
|
|
// widths in the right order. The C-side layout assertion lives in
|
|
// go_bridge.cpp (static_assert sizeof(BlockContext) == sizeof(CBlockContext));
|
|
// this test catches Go-side reordering before it reaches the C ABI.
|
|
func TestBlockContextLayout(t *testing.T) {
|
|
var ctx BlockContext
|
|
ctx.Origin[0] = 0xAA
|
|
ctx.Origin[19] = 0xBB
|
|
ctx.GasPrice = 1
|
|
ctx.Timestamp = 2
|
|
ctx.Number = 3
|
|
ctx.Prevrandao[0] = 0xCC
|
|
ctx.Prevrandao[31] = 0xDD
|
|
ctx.GasLimit = 4
|
|
ctx.ChainID = 96369
|
|
ctx.BaseFee = 5
|
|
ctx.BlobBaseFee = 6
|
|
ctx.Coinbase[0] = 0xEE
|
|
ctx.Coinbase[19] = 0xFF
|
|
ctx.BlobHashes[0][0] = 0x11
|
|
ctx.BlobHashes[7][31] = 0x22
|
|
ctx.NumBlobHashes = 8
|
|
|
|
// Sanity: the struct round-trips its own fields.
|
|
if ctx.ChainID != 96369 {
|
|
t.Errorf("ChainID round-trip failed: got %d", ctx.ChainID)
|
|
}
|
|
if ctx.Origin[0] != 0xAA || ctx.Origin[19] != 0xBB {
|
|
t.Errorf("Origin round-trip failed: got %x..%x", ctx.Origin[0], ctx.Origin[19])
|
|
}
|
|
if ctx.NumBlobHashes != 8 {
|
|
t.Errorf("NumBlobHashes round-trip failed: got %d", ctx.NumBlobHashes)
|
|
}
|
|
}
|