diff --git a/core/types/body_ext.go b/core/types/body_ext.go index 23ef0c00da..cca5777df6 100644 --- a/core/types/body_ext.go +++ b/core/types/body_ext.go @@ -45,7 +45,7 @@ func (b *BodyExtra) RLPFieldPointersForDecoding(body *Body) *rlp.Fields { &body.Transactions, &body.Uncles, &b.Version, - rlp.Nillable(&b.ExtData), // equivalent to `rlp:"nil"` + &b.ExtData, }, } } diff --git a/core/types/body_ext_test.go b/core/types/body_ext_test.go new file mode 100644 index 0000000000..ddfb707379 --- /dev/null +++ b/core/types/body_ext_test.go @@ -0,0 +1,97 @@ +// (c) 2025, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package types + +import ( + "math/big" + "testing" + + "github.com/ava-labs/libevm/common" + ethtypes "github.com/ava-labs/libevm/core/types" + "github.com/ava-labs/libevm/rlp" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestBodyExtraGetWith(t *testing.T) { + t.Parallel() + + b := &Body{} + + extra := GetBodyExtra(b) + require.NotNil(t, extra) + assert.Equal(t, &BodyExtra{}, extra) + + extra = &BodyExtra{ + Version: 1, + } + WithBodyExtra(b, extra) + + extra = GetBodyExtra(b) + wantExtra := &BodyExtra{ + Version: 1, + } + assert.Equal(t, wantExtra, extra) +} + +func TestBodyExtraRLP(t *testing.T) { + t.Parallel() + + testTx := NewTransaction(0, common.Address{1}, big.NewInt(2), 3, big.NewInt(4), []byte{5}) + + uncle := &Header{ParentHash: common.Hash{6}} + uncleExtra := &HeaderExtra{ExtDataHash: common.Hash{7}} + _ = WithHeaderExtra(uncle, uncleExtra) + + body := &Body{ + Transactions: []*Transaction{testTx}, + Uncles: []*ethtypes.Header{uncle}, + Withdrawals: []*ethtypes.Withdrawal{{Index: 7}}, // ignored + } + extra := &BodyExtra{ + Version: 1, + ExtData: ptrTo([]byte{2}), + } + _ = WithBodyExtra(body, extra) + + b, err := rlp.EncodeToBytes(body) + require.NoError(t, err) + + gotBody := new(Body) + err = rlp.DecodeBytes(b, gotBody) + require.NoError(t, err) + + // Check transactions in the following because unexported fields + // size and time are set by the RLP decoder. + require.Len(t, gotBody.Transactions, 1) + gotTx := gotBody.Transactions[0] + gotTxJSON, err := gotTx.MarshalJSON() + require.NoError(t, err) + wantTxJSON, err := testTx.MarshalJSON() + require.NoError(t, err) + assert.Equal(t, string(wantTxJSON), string(gotTxJSON)) + gotBody.Transactions = nil + + wantUncle := &Header{ + ParentHash: common.Hash{6}, + Difficulty: new(big.Int), + Number: new(big.Int), + Extra: []byte{}, + } + wantUncleExtra := &HeaderExtra{ExtDataHash: common.Hash{7}} + _ = WithHeaderExtra(wantUncle, wantUncleExtra) + + wantBody := &Body{ + Transactions: nil, // checked above + Uncles: []*ethtypes.Header{wantUncle}, + } + wantExtra := &BodyExtra{ + Version: 1, + ExtData: ptrTo([]byte{2}), + } + _ = WithBodyExtra(wantBody, wantExtra) + + assert.Equal(t, wantBody, gotBody) + assert.Equal(t, wantExtra, GetBodyExtra(gotBody)) +}