diff --git a/core/types/rlp_backwards_compat.libevm_test.go b/core/types/backwards_compat.libevm_test.go similarity index 64% rename from core/types/rlp_backwards_compat.libevm_test.go rename to core/types/backwards_compat.libevm_test.go index 673bf548c39..81b287177c4 100644 --- a/core/types/rlp_backwards_compat.libevm_test.go +++ b/core/types/backwards_compat.libevm_test.go @@ -14,7 +14,7 @@ // along with the go-ethereum library. If not, see // . -package types_test +package types import ( "encoding/hex" @@ -26,91 +26,9 @@ import ( "github.com/stretchr/testify/require" "github.com/ava-labs/libevm/common" - . "github.com/ava-labs/libevm/core/types" - "github.com/ava-labs/libevm/libevm/cmpeth" - "github.com/ava-labs/libevm/libevm/ethtest" "github.com/ava-labs/libevm/rlp" ) -func TestHeaderRLPBackwardsCompatibility(t *testing.T) { - tests := []struct { - name string - register func() - }{ - { - name: "no registered extras", - register: func() {}, - }, - { - name: "no-op header hooks", - register: func() { - RegisterExtras[NOOPHeaderHooks, *NOOPHeaderHooks, struct{}]() - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - TestOnlyClearRegisteredExtras() - defer TestOnlyClearRegisteredExtras() - tt.register() - testHeaderRLPBackwardsCompatibility(t) - }) - } -} - -//nolint:thelper -func testHeaderRLPBackwardsCompatibility(t *testing.T) { - // This is a deliberate change-detector test that locks in backwards - // compatibility of RLP encoding. - rng := ethtest.NewPseudoRand(42) - - const numExtraBytes = 16 - hdr := &Header{ - ParentHash: rng.Hash(), - UncleHash: rng.Hash(), - Coinbase: rng.Address(), - Root: rng.Hash(), - TxHash: rng.Hash(), - ReceiptHash: rng.Hash(), - Bloom: rng.Bloom(), - Difficulty: rng.Uint256().ToBig(), - Number: rng.BigUint64(), - GasLimit: rng.Uint64(), - GasUsed: rng.Uint64(), - Time: rng.Uint64(), - Extra: rng.Bytes(numExtraBytes), - MixDigest: rng.Hash(), - Nonce: rng.BlockNonce(), - - BaseFee: rng.BigUint64(), - WithdrawalsHash: rng.HashPtr(), - BlobGasUsed: rng.Uint64Ptr(), - ExcessBlobGas: rng.Uint64Ptr(), - ParentBeaconRoot: rng.HashPtr(), - } - t.Logf("%T:\n%+v", hdr, hdr) - - // WARNING: changing this hex might break backwards compatibility of RLP - // encoding (i.e. block hashes might change)! - const wantHex = `f9029aa01a571e7e4d774caf46053201cfe0001b3c355ffcc93f510e671e8809741f0eeda0756095410506ec72a2c287fe83ebf68efb0be177e61acec1c985277e90e52087941bfc3bc193012ba58912c01fb35a3454831a8971a00bc9f064144eb5965c5e5d1020f9f90392e7e06ded9225966abc7c754b410e61a0d942eab201424f4320ec1e1ffa9390baf941629b9349977b5d48e0502dbb9386a035d9d550a9c113f78689b4c161c4605609bb57b83061914c42ad244daa7fc38eb901004b31d39ae246d689f23176d679a62ff328f530407cbafd0146f45b2ed635282e2812f2705bfffe52576a6fb31df817f29efac71fa56b8e133334079f8e2a8fd2055451571021506f27190adb52a1313f6d28c77d66ae1aa3d3d6757a762476f4c8a2b7b2a37079a4b6a15d1bc44161190c82d5e1c8b55e05c7354f1e5f6512924c941fb3d93667dc3a8c304a3c164e6525dfc99b5f474110c5059485732153e20300c3482832d07b65f97958360da414cb438ce252aec6c2718d155798390a6c6782181d1bac1dd64cd956332b008412ddc735f2994e297c8a088c6bb4c637542295ba3cbc3cd399c8127076f4d834d74d5b11a36b6d02e2fe3a583216aa4ccea0f052df9a96e7a454256bebabdfc38c429079f25913e0f1d7416b2f056c4a115f88b85f0e9fd6d25717881f03d9985060087c88a2c54269dfd07ca388eb8f974b42a412da90c757012bf5479896165caf573cf82fb3a0aa10f6ebf6b62bef8ed36b8ea3d4b1ddb80c99afafa37cb8f3393eb6d802f5bc886c8cd6bcd168a7e0886d5b1345d948b818a0061a7182ff228a4e66bade4717e6f4d318ac98fca12a053af6f98805a764fb5d8890ed9cab2c5229908891c7e2f71857c77ca0523cb6f654ef3fc7294c7768cddd9ccf4bcda3066d382675f37dd1a18507b5fb` - wantRLP, err := hex.DecodeString(wantHex) - require.NoError(t, err, "hex.DecodeString()") - - t.Run("Encode", func(t *testing.T) { - got, err := rlp.EncodeToBytes(hdr) - require.NoErrorf(t, err, "rlp.EncodeToBytes(%T)", hdr) - assert.Equalf(t, wantRLP, got, "rlp.EncodeToBytes(%T)", hdr) - }) - - t.Run("Decode", func(t *testing.T) { - got := new(Header) - err := rlp.DecodeBytes(wantRLP, got) - require.NoErrorf(t, err, "rlp.DecodeBytes(..., %T)", hdr) - assert.Equal(t, hdr, got) - }) -} - func TestBodyRLPBackwardsCompatibility(t *testing.T) { newTx := func(nonce uint64) *Transaction { return NewTx(&LegacyTx{Nonce: nonce}) } newHdr := func(hashLow byte) *Header { return &Header{ParentHash: common.Hash{hashLow}} } @@ -176,8 +94,8 @@ func TestBodyRLPBackwardsCompatibility(t *testing.T) { } opts := cmp.Options{ - cmpeth.CompareHeadersByHash(), - cmpeth.CompareTransactionsByBinary(t), + cmp.Comparer((*Header).equalHash), + cmp.Comparer((*Transaction).equalHash), } if diff := cmp.Diff(body, got, opts); diff != "" { t.Errorf("rlp.DecodeBytes(rlp.EncodeToBytes(%#v)) diff (-want +got):\n%s", body, diff) @@ -292,8 +210,8 @@ func TestBodyRLPCChainCompat(t *testing.T) { assert.Equal(t, tt.extra, &extra, "rlp.DecodeBytes(%#x, [%T as registered extra in %T carrier])", wantRLP, &extra, got) opts := cmp.Options{ - cmpeth.CompareHeadersByHash(), - cmpeth.CompareTransactionsByBinary(t), + cmp.Comparer((*Header).equalHash), + cmp.Comparer((*Transaction).equalHash), } if diff := cmp.Diff(body, got, opts); diff != "" { t.Errorf("rlp.DecodeBytes(%#x, [%T while carrying registered %T extra payload]) diff (-want +got):\n%s", wantRLP, got, &extra, diff) @@ -302,3 +220,24 @@ func TestBodyRLPCChainCompat(t *testing.T) { }) } } + +// equalHash reports whether `a` and `b` have equal hashes. It allows for nil +// arguments, returning `true` if both are nil, `false` if only one is nil, +// otherwise `a.Hash() == b.Hash()`. +func equalHash[ + T any, P interface { + Hash() common.Hash + *T + }, +](a, b P) bool { + if a == nil && b == nil { + return true + } + if a == nil || b == nil { + return false + } + return a.Hash() == b.Hash() +} + +func (h *Header) equalHash(hh *Header) bool { return equalHash(h, hh) } +func (tx *Transaction) equalHash(u *Transaction) bool { return equalHash(tx, u) } diff --git a/core/types/backwards_compat_diffpkg.libevm_test.go b/core/types/backwards_compat_diffpkg.libevm_test.go new file mode 100644 index 00000000000..47c704c44c7 --- /dev/null +++ b/core/types/backwards_compat_diffpkg.libevm_test.go @@ -0,0 +1,108 @@ +// Copyright 2024-2025 the libevm authors. +// +// The libevm additions to go-ethereum are free software: you can redistribute +// them and/or modify them under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation, either version 3 of the License, +// or (at your option) any later version. +// +// The libevm additions are distributed in the hope that they will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +// General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see +// . + +package types_test + +import ( + "encoding/hex" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + . "github.com/ava-labs/libevm/core/types" + "github.com/ava-labs/libevm/libevm/ethtest" + "github.com/ava-labs/libevm/rlp" +) + +func TestHeaderRLPBackwardsCompatibility(t *testing.T) { + tests := []struct { + name string + register func() + }{ + { + name: "no registered extras", + register: func() {}, + }, + { + name: "no-op header hooks", + register: func() { + RegisterExtras[NOOPHeaderHooks, *NOOPHeaderHooks, struct{}]() + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + TestOnlyClearRegisteredExtras() + defer TestOnlyClearRegisteredExtras() + tt.register() + testHeaderRLPBackwardsCompatibility(t) + }) + } +} + +//nolint:thelper +func testHeaderRLPBackwardsCompatibility(t *testing.T) { + // This is a deliberate change-detector test that locks in backwards + // compatibility of RLP encoding. + rng := ethtest.NewPseudoRand(42) + + const numExtraBytes = 16 + hdr := &Header{ + ParentHash: rng.Hash(), + UncleHash: rng.Hash(), + Coinbase: rng.Address(), + Root: rng.Hash(), + TxHash: rng.Hash(), + ReceiptHash: rng.Hash(), + Bloom: rng.Bloom(), + Difficulty: rng.Uint256().ToBig(), + Number: rng.BigUint64(), + GasLimit: rng.Uint64(), + GasUsed: rng.Uint64(), + Time: rng.Uint64(), + Extra: rng.Bytes(numExtraBytes), + MixDigest: rng.Hash(), + Nonce: rng.BlockNonce(), + + BaseFee: rng.BigUint64(), + WithdrawalsHash: rng.HashPtr(), + BlobGasUsed: rng.Uint64Ptr(), + ExcessBlobGas: rng.Uint64Ptr(), + ParentBeaconRoot: rng.HashPtr(), + } + t.Logf("%T:\n%+v", hdr, hdr) + + // WARNING: changing this hex might break backwards compatibility of RLP + // encoding (i.e. block hashes might change)! + const wantHex = `f9029aa01a571e7e4d774caf46053201cfe0001b3c355ffcc93f510e671e8809741f0eeda0756095410506ec72a2c287fe83ebf68efb0be177e61acec1c985277e90e52087941bfc3bc193012ba58912c01fb35a3454831a8971a00bc9f064144eb5965c5e5d1020f9f90392e7e06ded9225966abc7c754b410e61a0d942eab201424f4320ec1e1ffa9390baf941629b9349977b5d48e0502dbb9386a035d9d550a9c113f78689b4c161c4605609bb57b83061914c42ad244daa7fc38eb901004b31d39ae246d689f23176d679a62ff328f530407cbafd0146f45b2ed635282e2812f2705bfffe52576a6fb31df817f29efac71fa56b8e133334079f8e2a8fd2055451571021506f27190adb52a1313f6d28c77d66ae1aa3d3d6757a762476f4c8a2b7b2a37079a4b6a15d1bc44161190c82d5e1c8b55e05c7354f1e5f6512924c941fb3d93667dc3a8c304a3c164e6525dfc99b5f474110c5059485732153e20300c3482832d07b65f97958360da414cb438ce252aec6c2718d155798390a6c6782181d1bac1dd64cd956332b008412ddc735f2994e297c8a088c6bb4c637542295ba3cbc3cd399c8127076f4d834d74d5b11a36b6d02e2fe3a583216aa4ccea0f052df9a96e7a454256bebabdfc38c429079f25913e0f1d7416b2f056c4a115f88b85f0e9fd6d25717881f03d9985060087c88a2c54269dfd07ca388eb8f974b42a412da90c757012bf5479896165caf573cf82fb3a0aa10f6ebf6b62bef8ed36b8ea3d4b1ddb80c99afafa37cb8f3393eb6d802f5bc886c8cd6bcd168a7e0886d5b1345d948b818a0061a7182ff228a4e66bade4717e6f4d318ac98fca12a053af6f98805a764fb5d8890ed9cab2c5229908891c7e2f71857c77ca0523cb6f654ef3fc7294c7768cddd9ccf4bcda3066d382675f37dd1a18507b5fb` + wantRLP, err := hex.DecodeString(wantHex) + require.NoError(t, err, "hex.DecodeString()") + + t.Run("Encode", func(t *testing.T) { + got, err := rlp.EncodeToBytes(hdr) + require.NoErrorf(t, err, "rlp.EncodeToBytes(%T)", hdr) + assert.Equalf(t, wantRLP, got, "rlp.EncodeToBytes(%T)", hdr) + }) + + t.Run("Decode", func(t *testing.T) { + got := new(Header) + err := rlp.DecodeBytes(wantRLP, got) + require.NoErrorf(t, err, "rlp.DecodeBytes(..., %T)", hdr) + assert.Equal(t, hdr, got) + }) +} diff --git a/libevm/cmpeth/cmpeth.go b/libevm/cmpeth/cmpeth.go deleted file mode 100644 index 8d17e3e5192..00000000000 --- a/libevm/cmpeth/cmpeth.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2025 the libevm authors. -// -// The libevm additions to go-ethereum are free software: you can redistribute -// them and/or modify them under the terms of the GNU Lesser General Public License -// as published by the Free Software Foundation, either version 3 of the License, -// or (at your option) any later version. -// -// The libevm additions are distributed in the hope that they will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see -// . - -// Package cmpeth provides ETH-specific options for the cmp package. -package cmpeth - -import ( - "bytes" - "testing" - - "github.com/google/go-cmp/cmp" - - "github.com/ava-labs/libevm/core/types" -) - -// CompareHeadersByHash returns an option to compare Headers based on -// [types.Header.Hash] equality. -func CompareHeadersByHash() cmp.Option { - return cmp.Comparer(func(a, b *types.Header) bool { - return a.Hash() == b.Hash() - }) -} - -// CompareTransactionsByBinary returns an option to compare Transactions based -// on [types.Transaction.MarshalBinary] equality. Two nil pointers are -// considered equal. -// -// If MarshalBinary() returns an error, it will be reported with -// [testing.TB.Fatal]. -func CompareTransactionsByBinary(tb testing.TB) cmp.Option { - tb.Helper() - return cmp.Comparer(func(a, b *types.Transaction) bool { - tb.Helper() - - if a == nil && b == nil { - return true - } - if a == nil || b == nil { - return false - } - - return bytes.Equal(marshalTxBinary(tb, a), marshalTxBinary(tb, b)) - }) -} - -func marshalTxBinary(tb testing.TB, tx *types.Transaction) []byte { - tb.Helper() - buf, err := tx.MarshalBinary() - if err != nil { - tb.Fatalf("%T.MarshalBinary() error %v", tx, err) - } - return buf -}