Files

370 lines
8.1 KiB
Go

// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package header
import (
"math/big"
"testing"
"github.com/luxfi/evmgpu/params/extras"
"github.com/luxfi/evmgpu/plugin/evm/customtypes"
"github.com/luxfi/evmgpu/plugin/evm/upgrade/feewindow"
"github.com/luxfi/evmgpu/utils"
"github.com/luxfi/geth/core/types"
"github.com/stretchr/testify/require"
)
const (
targetGas = 10_000_000
blockGas = 1_000_000
)
func TestExtraPrefix(t *testing.T) {
tests := []struct {
name string
upgrades extras.NetworkUpgrades
parent *types.Header
header *types.Header
want []byte
wantErr error
}{
{
name: "pre_chain_evm",
upgrades: extras.TestPreEVMChainConfig.NetworkUpgrades,
header: &types.Header{},
want: nil,
wantErr: nil,
},
{
name: "chain_evm_first_block",
upgrades: extras.NetworkUpgrades{
EVMTimestamp: utils.NewUint64(1),
},
parent: &types.Header{
Number: big.NewInt(1),
},
header: &types.Header{
Time: 1,
},
want: (&feewindow.Window{}).Bytes(),
},
{
name: "chain_evm_genesis_block",
upgrades: extras.TestEVMChainConfig.NetworkUpgrades,
parent: &types.Header{
Number: big.NewInt(0),
},
header: &types.Header{},
want: (&feewindow.Window{}).Bytes(),
},
{
name: "chain_evm_invalid_fee_window",
upgrades: extras.TestEVMChainConfig.NetworkUpgrades,
parent: &types.Header{
Number: big.NewInt(1),
},
header: &types.Header{},
wantErr: feewindow.ErrWindowInsufficientLength,
},
{
name: "chain_evm_invalid_timestamp",
upgrades: extras.TestEVMChainConfig.NetworkUpgrades,
parent: &types.Header{
Number: big.NewInt(1),
Time: 1,
Extra: (&feewindow.Window{}).Bytes(),
},
header: &types.Header{
Time: 0,
},
wantErr: errInvalidTimestamp,
},
{
name: "chain_evm_normal",
upgrades: extras.TestEVMChainConfig.NetworkUpgrades,
parent: customtypes.WithHeaderExtra(
&types.Header{
Number: big.NewInt(1),
GasUsed: targetGas,
Extra: (&feewindow.Window{
1, 2, 3, 4,
}).Bytes(),
},
&customtypes.HeaderExtra{
BlockGasCost: big.NewInt(blockGas),
},
),
header: &types.Header{
Time: 1,
},
want: func() []byte {
window := feewindow.Window{
1, 2, 3, 4,
}
window.Add(targetGas)
window.Shift(1)
return window.Bytes()
}(),
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
require := require.New(t)
config := &extras.ChainConfig{
NetworkUpgrades: test.upgrades,
}
got, err := ExtraPrefix(config, test.parent, test.header)
require.ErrorIs(err, test.wantErr)
require.Equal(test.want, got)
})
}
}
func TestVerifyExtraPrefix(t *testing.T) {
tests := []struct {
name string
upgrades extras.NetworkUpgrades
parent *types.Header
header *types.Header
wantErr error
}{
{
name: "pre_chain_evm",
upgrades: extras.TestPreEVMChainConfig.NetworkUpgrades,
header: &types.Header{},
wantErr: nil,
},
{
name: "chain_evm_invalid_parent_header",
upgrades: extras.TestEVMChainConfig.NetworkUpgrades,
parent: &types.Header{
Number: big.NewInt(1),
},
header: &types.Header{},
wantErr: feewindow.ErrWindowInsufficientLength,
},
{
name: "chain_evm_invalid_header",
upgrades: extras.TestEVMChainConfig.NetworkUpgrades,
parent: &types.Header{
Number: big.NewInt(0),
},
header: &types.Header{},
wantErr: errInvalidExtraPrefix,
},
{
name: "chain_evm_valid",
upgrades: extras.TestEVMChainConfig.NetworkUpgrades,
parent: &types.Header{
Number: big.NewInt(0),
},
header: &types.Header{
Extra: (&feewindow.Window{}).Bytes(),
},
wantErr: nil,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
config := &extras.ChainConfig{
NetworkUpgrades: test.upgrades,
}
err := VerifyExtraPrefix(config, test.parent, test.header)
require.ErrorIs(t, err, test.wantErr)
})
}
}
func TestVerifyExtra(t *testing.T) {
tests := []struct {
name string
rules extras.LuxRules
extra []byte
expected error
}{
{
name: "initial_valid",
rules: extras.LuxRules{},
extra: make([]byte, maximumExtraDataSize),
expected: nil,
},
{
name: "initial_invalid",
rules: extras.LuxRules{},
extra: make([]byte, maximumExtraDataSize+1),
expected: errInvalidExtraLength,
},
{
name: "chain_evm_valid",
rules: extras.LuxRules{
IsEVM: true,
},
extra: make([]byte, feewindow.WindowSize),
expected: nil,
},
{
name: "chain_evm_invalid_less",
rules: extras.LuxRules{
IsEVM: true,
},
extra: make([]byte, feewindow.WindowSize-1),
expected: errInvalidExtraLength,
},
{
name: "chain_evm_invalid_more",
rules: extras.LuxRules{
IsEVM: true,
},
extra: make([]byte, feewindow.WindowSize+1),
expected: errInvalidExtraLength,
},
{
name: "durango_valid_min",
rules: extras.LuxRules{
IsDurango: true,
},
extra: make([]byte, feewindow.WindowSize),
expected: nil,
},
{
name: "durango_valid_extra",
rules: extras.LuxRules{
IsDurango: true,
},
extra: make([]byte, feewindow.WindowSize+1),
expected: nil,
},
{
name: "durango_invalid",
rules: extras.LuxRules{
IsDurango: true,
},
extra: make([]byte, feewindow.WindowSize-1),
expected: errInvalidExtraLength,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
err := VerifyExtra(test.rules, test.extra)
require.ErrorIs(t, err, test.expected)
})
}
}
func TestPredicateBytesFromExtra(t *testing.T) {
tests := []struct {
name string
extra []byte
expected []byte
}{
{
name: "empty_extra",
extra: nil,
expected: nil,
},
{
name: "too_short",
extra: make([]byte, feewindow.WindowSize-1),
expected: nil,
},
{
name: "empty_predicate",
extra: make([]byte, feewindow.WindowSize),
expected: nil,
},
{
name: "non_empty_predicate",
extra: []byte{
feewindow.WindowSize: 5,
},
expected: []byte{5},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
got := PredicateBytesFromExtra(test.extra)
require.Equal(t, test.expected, got)
})
}
}
func TestSetPredicateBytesInExtra(t *testing.T) {
tests := []struct {
name string
extra []byte
predicate []byte
want []byte
}{
{
name: "empty_extra_predicate",
want: make([]byte, feewindow.WindowSize),
},
{
name: "extra_too_short",
extra: []byte{1},
predicate: []byte{2},
want: []byte{
0: 1,
feewindow.WindowSize: 2,
},
},
{
name: "extra_too_long",
extra: []byte{
feewindow.WindowSize: 1,
},
predicate: []byte{2},
want: []byte{
feewindow.WindowSize: 2,
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
got := SetPredicateBytesInExtra(test.extra, test.predicate)
require.Equal(t, test.want, got)
})
}
}
func TestPredicateBytesExtra(t *testing.T) {
tests := []struct {
name string
extra []byte
predicate []byte
wantExtraWithPredicate []byte
wantPredicateBytes []byte
}{
{
name: "empty_extra_predicate",
extra: nil,
predicate: nil,
wantExtraWithPredicate: make([]byte, feewindow.WindowSize),
wantPredicateBytes: nil,
},
{
name: "extra_too_short",
extra: []byte{
0: 1,
feewindow.WindowSize - 1: 0,
},
predicate: []byte{2},
wantExtraWithPredicate: []byte{
0: 1,
feewindow.WindowSize: 2,
},
wantPredicateBytes: []byte{2},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
gotExtra := SetPredicateBytesInExtra(test.extra, test.predicate)
require.Equal(t, test.wantExtraWithPredicate, gotExtra)
gotPredicateBytes := PredicateBytesFromExtra(gotExtra)
require.Equal(t, test.wantPredicateBytes, gotPredicateBytes)
})
}
}