chore(core/types): add Test_CopyHeader test

This commit is contained in:
Quentin Mc Gaw 2025-02-06 14:29:45 +01:00
parent 04a336aee8
commit 5e413e4ab7
No known key found for this signature in database
GPG key ID: 6B26BAFFE648CAFB

View file

@ -22,6 +22,8 @@ import (
"math/big" "math/big"
"reflect" "reflect"
"testing" "testing"
"unicode"
"unsafe"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/common/math"
@ -29,6 +31,8 @@ import (
"github.com/ethereum/go-ethereum/internal/blocktest" "github.com/ethereum/go-ethereum/internal/blocktest"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
// from bcValidBlockTest.json, "SimpleTx" // from bcValidBlockTest.json, "SimpleTx"
@ -318,3 +322,140 @@ func TestRlpDecodeParentHash(t *testing.T) {
} }
} }
} }
func TestCopyHeader(t *testing.T) {
t.Parallel()
t.Run("empty_header", func(t *testing.T) {
t.Parallel()
empty := Header{}
cpy := CopyHeader(&empty)
want := &Header{
Difficulty: new(big.Int),
Number: new(big.Int),
}
assert.Equal(t, want, cpy)
})
t.Run("filled_header", func(t *testing.T) {
t.Parallel()
h := Header{
ParentHash: common.Hash{1},
UncleHash: common.Hash{2},
Coinbase: common.Address{3},
Root: common.Hash{4},
TxHash: common.Hash{5},
ReceiptHash: common.Hash{6},
Bloom: Bloom{7},
Difficulty: big.NewInt(8),
Number: big.NewInt(9),
GasLimit: 10,
GasUsed: 11,
Time: 12,
Extra: []byte{13},
MixDigest: common.Hash{14},
Nonce: BlockNonce{15},
BaseFee: big.NewInt(16),
WithdrawalsHash: &common.Hash{17},
BlobGasUsed: ptrTo(uint64(18)),
ExcessBlobGas: ptrTo(uint64(19)),
ParentBeaconRoot: &common.Hash{20},
RequestsHash: &common.Hash{21},
}
allFieldsAreSet(t, h)
cpy := CopyHeader(&h)
want := &Header{
ParentHash: common.Hash{1},
UncleHash: common.Hash{2},
Coinbase: common.Address{3},
Root: common.Hash{4},
TxHash: common.Hash{5},
ReceiptHash: common.Hash{6},
Bloom: Bloom{7},
Difficulty: big.NewInt(8),
Number: big.NewInt(9),
GasLimit: 10,
GasUsed: 11,
Time: 12,
Extra: []byte{13},
MixDigest: common.Hash{14},
Nonce: BlockNonce{15},
BaseFee: big.NewInt(16),
WithdrawalsHash: &common.Hash{17},
BlobGasUsed: ptrTo(uint64(18)),
ExcessBlobGas: ptrTo(uint64(19)),
ParentBeaconRoot: &common.Hash{20},
RequestsHash: &common.Hash{21},
}
assert.Equal(t, want, cpy)
// Mutate each non-value field to ensure they are not shared
v := reflect.ValueOf(&h).Elem()
for i := 0; i < v.NumField(); i++ {
field := v.Field(i)
fieldName := v.Type().Field(i).Name
if unicode.IsLower(rune(fieldName[0])) {
field = reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem()
}
var originalField any
switch field.Kind() {
case reflect.Array, reflect.Uint64: // values
case reflect.Slice:
originalField = field.Interface()
switch originalField.(type) {
case []byte:
field.Set(reflect.Append(field, reflect.ValueOf(byte(1))))
default:
t.Fatalf("unexpected slice type %T for %q", originalField, fieldName)
}
originalField = field.Interface()
case reflect.Pointer:
originalField = field.Interface()
switch ptr := originalField.(type) {
case *big.Int:
ptr.Add(ptr, big.NewInt(1))
case *uint64:
*ptr++
case *common.Hash:
ptr[0]++
default:
t.Fatalf("unexpected pointer type %T for %q", ptr, fieldName)
}
default:
t.Fatalf("unexpected field kind %v for %q", field.Kind(), fieldName)
}
cpyField := reflect.ValueOf(*cpy).Field(i).Interface()
assert.NotEqualf(t, originalField, cpyField, "field %q", fieldName)
}
})
}
func ptrTo[T any](x T) *T { return &x }
func allFieldsAreSet(t *testing.T, x any) {
v := reflect.ValueOf(x)
typ := v.Type()
require.Equal(t, reflect.Struct, typ.Kind())
for i := 0; i < v.NumField(); i++ {
field := v.Field(i)
fieldName := typ.Field(i).Name
fieldValue := field
if unicode.IsLower(rune(fieldName[0])) { // unexported
require.Falsef(t, field.IsNil(), "field %q is nil", fieldName)
field = reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem()
fieldValue = field
}
if field.Kind() == reflect.Pointer {
require.NotNilf(t, field.Interface(), "field %q is nil", fieldName)
fieldValue = field.Elem()
}
isSet := fieldValue.IsValid() && !fieldValue.IsZero()
require.True(t, isSet, "field %q is not set", fieldName)
}
}