Files
chains/evm/cevm/parallel/parallel_test.go
zeekayandHanzo Dev 1d08088efd The binding sends a tx's fee cap and tip, as ABI 7's CGpuTx carries them
go_bridge.h's CGpuTx has max_fee_per_gas and max_priority_fee_per_gas in
place of gas_price, 120 bytes on LP64. cevm.Transaction has GasFeeCap and
GasTipCap for them, both the gas price of a legacy or access-list tx, and
buildTxs sets both; the size check reads 120. cevm charges min(cap, base
fee + tip), as the EVM does, where it charged the cap whole, and declines
a tip above the cap.

The executor shapes tx.GasFeeCap() and tx.GasTipCap(), each held to 64
bits. The device test sends a transfer with its tip above its cap, which
the device declines.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-23 13:45:07 -07:00

122 lines
4.0 KiB
Go

// Copyright (C) 2025-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
//go:build cgo && lux_cevm_native
package parallel
import (
"errors"
"math/big"
"os"
"path/filepath"
"runtime"
"testing"
"github.com/holiman/uint256"
"github.com/luxfi/chains/evm/cevm"
"github.com/luxfi/geth/common"
"github.com/luxfi/geth/core/tracing"
"github.com/luxfi/geth/core/types"
)
// These run against the linked library and hold it to go_bridge.h (ABI 7).
// A batch that carries code is declined on every backend the library offers:
// gpu_execute_block passes no host, so it would run the code as a message on
// its whole limit, which is not the tx's gas. Declined means ErrDeclined and
// no result.
func TestABatchWithCodeIsDeclinedOnEveryBackend(t *testing.T) {
tx := cevm.Transaction{
From: [20]byte{0x11},
To: [20]byte{0x22},
HasTo: true,
Code: []byte{0x60, 0x01, 0x60, 0x01, 0x01, 0x50, 0x00}, // 1+1, POP, STOP
GasLimit: 100_000,
GasFeeCap: 1,
GasTipCap: 1,
}
for _, b := range cevm.AvailableBackends() {
t.Run(cevm.BackendName(b), func(t *testing.T) {
r, err := cevm.ExecuteBlock(b, 0, []cevm.Transaction{tx}, nil, nil)
if !errors.Is(err, cevm.ErrDeclined) {
t.Fatalf("ExecuteBlock = %v, want ErrDeclined", err)
}
if r != nil {
t.Errorf("a declined block came back with a result: %+v", r)
}
})
}
}
// A block of plain transfers from funded senders, end to end through the
// executor: a GPU lane runs it and receipts every transfer at 21000 gas; a
// CPU lane, which runs nothing through the Go entry, declines it to the Go
// EVM. Neither is an error. A GPU lane is listed when the library was built
// with it, whether or not this host has the device: a lane whose device this
// host lacks is skipped, and one whose device it has must run the block.
func TestAPlainTransferBlockIsReceiptedOrDeclined(t *testing.T) {
const n = 8
sdb := newState(t)
header := newHeader()
header.BaseFee = big.NewInt(1)
header.Coinbase = common.Address{0xC0}
txs := make(types.Transactions, n)
from := senders(n)
for i := range txs {
sdb.AddBalance(from[i], uint256.NewInt(1_000_000_000_000_000_000), tracing.BalanceChangeUnspecified)
to := common.Address{0xB0, byte(i + 1)} // fresh: not in the state
txs[i] = types.NewTx(&types.LegacyTx{To: &to, Value: big.NewInt(1), Gas: 21000, GasPrice: big.NewInt(1)})
}
for _, b := range cevm.AvailableBackends() {
t.Run(cevm.BackendName(b), func(t *testing.T) {
if (b == cevm.GPUMetal || b == cevm.GPUCUDA) && !hasDevice(b) {
t.Skipf("this host has no %s device", cevm.BackendName(b))
}
receipts, err := (&Executor{CevmBackend: b}).run(chainConfig(), header, txs, from, sdb)
if err != nil {
t.Fatalf("run: %v", err)
}
if b != cevm.GPUMetal && b != cevm.GPUCUDA {
if receipts != nil {
t.Fatalf("CPU lane %s receipted a block; it runs none", cevm.BackendName(b))
}
return
}
if receipts == nil {
t.Fatalf("GPU lane %s declined a block of funded plain transfers", cevm.BackendName(b))
}
if len(receipts) != n {
t.Fatalf("%d receipts for %d transactions", len(receipts), n)
}
for i, r := range receipts {
if r.Status != types.ReceiptStatusSuccessful || r.GasUsed != 21000 {
t.Errorf("receipt %d: status %d gas %d, want success at 21000", i, r.Status, r.GasUsed)
}
}
})
}
}
// hasDevice reports whether this host has the device GPU lane b runs on: the
// GPU every Apple silicon Mac has for Metal, and for CUDA an NVIDIA driver's
// control device with at least one GPU node this process can see (a container
// can be given the first without the second). The library lists a lane it
// was built with either way.
func hasDevice(b cevm.Backend) bool {
switch b {
case cevm.GPUMetal:
return runtime.GOOS == "darwin" && runtime.GOARCH == "arm64"
case cevm.GPUCUDA:
if _, err := os.Stat("/dev/nvidiactl"); err != nil {
return false
}
gpus, _ := filepath.Glob("/dev/nvidia[0-9]*")
return len(gpus) > 0
}
return false
}