mirror of
https://github.com/luxfi/chains.git
synced 2026-09-24 00:26:00 +00:00
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]>
122 lines
4.0 KiB
Go
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
|
|
}
|