From 87f5043b1146474a59eba7fc38f6fa6805822fac Mon Sep 17 00:00:00 2001 From: Quentin Mc Gaw Date: Fri, 17 Jan 2025 15:19:41 +0100 Subject: [PATCH] feat(core/types): `Body` hooks for RLP encoding --- accounts/abi/bind/bind_test.go | 2 +- core/rawdb/accessors_chain.go | 3 +- core/types/block.go | 19 ++++----- core/types/body_ext.go | 77 ++++++++++++++++++++++++++++++++++ core/types/imports.go | 1 + core/types/libevm.go | 14 ++++++- go.mod | 2 +- go.sum | 4 +- scripts/tests.e2e.sh | 2 +- 9 files changed, 107 insertions(+), 17 deletions(-) create mode 100644 core/types/body_ext.go diff --git a/accounts/abi/bind/bind_test.go b/accounts/abi/bind/bind_test.go index a622f7eb87..d71e602110 100644 --- a/accounts/abi/bind/bind_test.go +++ b/accounts/abi/bind/bind_test.go @@ -2179,7 +2179,7 @@ func golangBindings(t *testing.T, overload bool) { if out, err := replacer.CombinedOutput(); err != nil { t.Fatalf("failed to replace binding test dependency to current source tree: %v\n%s", err, out) } - replacer = exec.Command(gocmd, "mod", "edit", "-x", "-require", "github.com/ava-labs/libevm@v0.0.0", "-replace", "github.com/ava-labs/libevm=github.com/ava-labs/libevm@v0.0.0-20250113230013-d10c4a3d1ff2") + replacer = exec.Command(gocmd, "mod", "edit", "-x", "-require", "github.com/ava-labs/libevm@v0.0.0", "-replace", "github.com/ava-labs/libevm=github.com/ava-labs/libevm@v0.0.0-20250121171435-edebe134329f") replacer.Dir = pkg if out, err := replacer.CombinedOutput(); err != nil { t.Fatalf("failed to replace binding test dependency to current source tree: %v\n%s", err, out) diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index dba05750a7..3087e6a09f 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -522,7 +522,8 @@ func ReadBlock(db ethdb.Reader, hash common.Hash, number uint64) *types.Block { if body == nil { return nil } - return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles).WithExtData(body.Version, body.ExtData) + bodyExtra := types.GetBodyExtra(body) + return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles).WithExtData(bodyExtra.Version, bodyExtra.ExtData) } // WriteBlock serializes a block into the database, header and body separately. diff --git a/core/types/block.go b/core/types/block.go index 845becb288..27c8ad7e7d 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -37,15 +37,6 @@ import ( "github.com/ava-labs/libevm/rlp" ) -// Body is a simple (mutable, non-safe) data container for storing and moving -// a block's data contents (transactions and uncles) together. -type Body struct { - Transactions []*Transaction - Uncles []*Header - Version uint32 - ExtData *[]byte `rlp:"nil"` -} - // Block represents an Ethereum block. // // Note the Block type tries to be 'immutable', and contains certain caches that rely @@ -194,7 +185,15 @@ func (b *Block) EncodeRLP(w io.Writer) error { // Body returns the non-header content of the block. // Note the returned data is not an independent copy. func (b *Block) Body() *Body { - return &Body{b.transactions, b.uncles, b.version, b.extdata} + body := &Body{ + Transactions: b.transactions, + Uncles: b.uncles, + } + extra := &BodyExtra{ + Version: b.version, + ExtData: b.extdata, + } + return WithBodyExtra(body, extra) } // Accessors for body data. These do not return a copy because the content diff --git a/core/types/body_ext.go b/core/types/body_ext.go new file mode 100644 index 0000000000..7043bd2812 --- /dev/null +++ b/core/types/body_ext.go @@ -0,0 +1,77 @@ +// (c) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package types + +import ( + "io" + + ethtypes "github.com/ava-labs/libevm/core/types" + "github.com/ava-labs/libevm/rlp" +) + +// BodyExtra is a struct that contains extra fields used by Avalanche +// in the body. +// This type uses BodySerializable to encode and decode the extra fields +// along with the upstream type for compatibility with existing network blocks. +type BodyExtra struct { + Version uint32 + ExtData *[]byte + + // Fields removed from geth: + // - withdrawals Withdrawals +} + +func (b *BodyExtra) EncodeRLP(eth *ethtypes.Body, writer io.Writer) error { + out := new(bodySerializable) + + out.updateFromEth(eth) + out.updateFromExtras(b) + + return rlp.Encode(writer, out) +} + +func (b *BodyExtra) DecodeRLP(eth *ethtypes.Body, stream *rlp.Stream) error { + in := new(bodySerializable) + if err := stream.Decode(in); err != nil { + return err + } + + in.updateToEth(eth) + in.updateToExtras(b) + + return nil +} + +// bodySerializable defines the body in the Ethereum blockchain, +// as it is to be serialized into RLP. +type bodySerializable struct { + Transactions []*Transaction + Uncles []*Header + Version uint32 + ExtData *[]byte `rlp:"nil"` +} + +// updateFromEth updates the [*bodySerializable] from the [*ethtypes.Body]. +func (b *bodySerializable) updateFromEth(eth *ethtypes.Body) { + b.Transactions = eth.Transactions + b.Uncles = eth.Uncles +} + +// updateToEth updates the [*ethtypes.Body] from the [*bodySerializable]. +func (b *bodySerializable) updateToEth(eth *ethtypes.Body) { + eth.Transactions = b.Transactions + eth.Uncles = b.Uncles +} + +// updateFromExtras updates the [*bodySerializable] from the [*BodyExtra]. +func (b *bodySerializable) updateFromExtras(extras *BodyExtra) { + b.Version = extras.Version + b.ExtData = extras.ExtData +} + +// updateToExtras updates the [*BodyExtra] from the [*bodySerializable]. +func (b *bodySerializable) updateToExtras(extras *BodyExtra) { + extras.Version = b.Version + extras.ExtData = b.ExtData +} diff --git a/core/types/imports.go b/core/types/imports.go index dd1fa8a5c7..fc7ad3cffd 100644 --- a/core/types/imports.go +++ b/core/types/imports.go @@ -13,6 +13,7 @@ type ( AccessList = ethtypes.AccessList AccessTuple = ethtypes.AccessTuple AccessListTx = ethtypes.AccessListTx + Body = ethtypes.Body Bloom = ethtypes.Bloom Receipt = ethtypes.Receipt Receipts = ethtypes.Receipts diff --git a/core/types/libevm.go b/core/types/libevm.go index fc72c12492..7b08bc5dc9 100644 --- a/core/types/libevm.go +++ b/core/types/libevm.go @@ -10,7 +10,10 @@ import ( type isMultiCoin bool var ( - extras = ethtypes.RegisterExtras[HeaderExtra, *HeaderExtra, isMultiCoin]() + extras = ethtypes.RegisterExtras[ + HeaderExtra, *HeaderExtra, + BodyExtra, *BodyExtra, + isMultiCoin]() IsMultiCoinPayloads = extras.StateAccount ) @@ -26,3 +29,12 @@ func WithHeaderExtras(h *Header, extra *HeaderExtra) *Header { extras.Header.Set(h, extra) return h } + +func GetBodyExtra(b *Body) *BodyExtra { + return extras.Body.Get(b) +} + +func WithBodyExtra(b *Body, extra *BodyExtra) *Body { + extras.Body.Set(b, extra) + return b +} diff --git a/go.mod b/go.mod index 96908e2459..4efc30ae99 100644 --- a/go.mod +++ b/go.mod @@ -136,4 +136,4 @@ require ( rsc.io/tmplfunc v0.0.3 // indirect ) -replace github.com/ava-labs/libevm => github.com/ava-labs/libevm v0.0.0-20250113230013-d10c4a3d1ff2 +replace github.com/ava-labs/libevm => github.com/ava-labs/libevm v0.0.0-20250121171435-edebe134329f diff --git a/go.sum b/go.sum index f2564ad80a..4cf9aab51a 100644 --- a/go.sum +++ b/go.sum @@ -58,8 +58,8 @@ github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/ava-labs/avalanchego v1.12.1-0.20250107220127-32f58b4fa9c8 h1:qN3MOBHB//Ynhgt5Vys3iVe42Sr0EWSeN18VL3ecXzE= github.com/ava-labs/avalanchego v1.12.1-0.20250107220127-32f58b4fa9c8/go.mod h1:2B7+E5neLvkOr2zursGhebjU26d4AfB7RazPxBs8hHg= -github.com/ava-labs/libevm v0.0.0-20250113230013-d10c4a3d1ff2 h1:eLyCq3xjpS6CDcZaVdAQaUim9qThl3buQjOlmcER8oQ= -github.com/ava-labs/libevm v0.0.0-20250113230013-d10c4a3d1ff2/go.mod h1:M8TCw2g1D5GBB7hu7g1F4aot5bRHGSxnBawNVmHE9Z0= +github.com/ava-labs/libevm v0.0.0-20250121171435-edebe134329f h1:r83FXbNY2MeQ1SaKmmVTWkDTAtZOs4mX8nme+nzpZU0= +github.com/ava-labs/libevm v0.0.0-20250121171435-edebe134329f/go.mod h1:M8TCw2g1D5GBB7hu7g1F4aot5bRHGSxnBawNVmHE9Z0= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= diff --git a/scripts/tests.e2e.sh b/scripts/tests.e2e.sh index e56e80a9da..e89afbbce6 100755 --- a/scripts/tests.e2e.sh +++ b/scripts/tests.e2e.sh @@ -45,7 +45,7 @@ git checkout -B "test-${AVALANCHE_VERSION}" "${AVALANCHE_VERSION}" echo "updating coreth dependency to point to ${CORETH_PATH}" go mod edit -replace "github.com/ava-labs/coreth=${CORETH_PATH}" -go mod edit -replace "github.com/ava-labs/libevm=github.com/ava-labs/libevm@v0.0.0-20250113230013-d10c4a3d1ff2" +go mod edit -replace "github.com/ava-labs/libevm=github.com/ava-labs/libevm@v0.0.0-20250121171435-edebe134329f" go mod tidy echo "building avalanchego"