From 7027a4202893b231f03c0f624a1dba9faea9563e Mon Sep 17 00:00:00 2001 From: Quentin Mc Gaw Date: Fri, 17 Jan 2025 15:19:41 +0100 Subject: [PATCH 1/5] 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 b016a042ff..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-20250121162040-b9e5186290df") + 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 a88d733a2e..452446a378 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 @@ -152,7 +143,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 cf59a72c1d..090504555f 100644 --- a/core/types/imports.go +++ b/core/types/imports.go @@ -14,6 +14,7 @@ type ( AccessTuple = ethtypes.AccessTuple AccessListTx = ethtypes.AccessListTx Bloom = ethtypes.Bloom + Body = ethtypes.Body Receipt = ethtypes.Receipt Receipts = ethtypes.Receipts ReceiptForStorage = ethtypes.ReceiptForStorage 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 59360a063d..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-20250121162040-b9e5186290df +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 6f32dd08a6..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-20250121162040-b9e5186290df h1:qCro69yW9HuKksYBitRy68Ana8w+621MXEW+0+PySio= -github.com/ava-labs/libevm v0.0.0-20250121162040-b9e5186290df/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 d36583bb79..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-20250121162040-b9e5186290df" +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" From 76eca080a6ae70a975cf266f2c131f6babe3c7fb Mon Sep 17 00:00:00 2001 From: Quentin Mc Gaw Date: Thu, 16 Jan 2025 16:45:41 +0100 Subject: [PATCH 2/5] feat(core/types): `Block` hooks for RLP encoding --- accounts/abi/bind/bind_test.go | 2 +- consensus/dummy/consensus.go | 6 +- core/blockchain.go | 2 +- core/genesis.go | 3 +- core/rawdb/accessors_chain.go | 4 +- core/state_processor.go | 2 +- core/types/block.go | 299 -------------------- core/types/block_ext.go | 148 ++++++++-- core/types/block_test.go | 37 +-- core/types/header_ext.go | 24 +- core/types/imports.go | 5 + core/types/libevm.go | 11 + eth/state_accessor.go | 2 +- eth/tracers/api.go | 2 +- eth/tracers/api_test.go | 2 +- ethclient/ethclient.go | 4 +- go.mod | 2 +- go.sum | 4 +- internal/ethapi/api.go | 2 +- internal/ethapi/api_test.go | 4 +- miner/worker.go | 3 +- plugin/evm/block.go | 8 +- plugin/evm/block_verification.go | 10 +- plugin/evm/mempool_atomic_gossiping_test.go | 3 +- plugin/evm/syncervm_test.go | 2 +- plugin/evm/vm.go | 2 +- plugin/evm/vm_test.go | 32 +-- scripts/tests.e2e.sh | 2 +- sync/client/client_test.go | 4 +- 29 files changed, 233 insertions(+), 398 deletions(-) diff --git a/accounts/abi/bind/bind_test.go b/accounts/abi/bind/bind_test.go index d71e602110..649b3178da 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-20250121171435-edebe134329f") + 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-20250122094956-11c780f117f8") 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/consensus/dummy/consensus.go b/consensus/dummy/consensus.go index eef3486012..c4422d9edd 100644 --- a/consensus/dummy/consensus.go +++ b/consensus/dummy/consensus.go @@ -404,7 +404,7 @@ func (eng *DummyEngine) Finalize(chain consensus.ChainHeaderReader, block *types if extDataGasUsed == nil { extDataGasUsed = new(big.Int).Set(common.Big0) } - if blockExtDataGasUsed := block.ExtDataGasUsed(); blockExtDataGasUsed == nil || !blockExtDataGasUsed.IsUint64() || blockExtDataGasUsed.Cmp(extDataGasUsed) != 0 { + if blockExtDataGasUsed := types.BlockExtDataGasUsed(block); blockExtDataGasUsed == nil || !blockExtDataGasUsed.IsUint64() || blockExtDataGasUsed.Cmp(extDataGasUsed) != 0 { return fmt.Errorf("invalid extDataGasUsed: have %d, want %d", blockExtDataGasUsed, extDataGasUsed) } blockGasCostStep := ApricotPhase4BlockGasCostStep @@ -422,13 +422,13 @@ func (eng *DummyEngine) Finalize(chain consensus.ChainHeaderReader, block *types parent.Time, block.Time(), ) // Verify the BlockGasCost set in the header matches the calculated value. - if blockBlockGasCost := block.BlockGasCost(); blockBlockGasCost == nil || !blockBlockGasCost.IsUint64() || blockBlockGasCost.Cmp(blockGasCost) != 0 { + if blockBlockGasCost := types.BlockGasCost(block); blockBlockGasCost == nil || !blockBlockGasCost.IsUint64() || blockBlockGasCost.Cmp(blockGasCost) != 0 { return fmt.Errorf("invalid blockGasCost: have %d, want %d", blockBlockGasCost, blockGasCost) } // Verify the block fee was paid. if err := eng.verifyBlockFee( block.BaseFee(), - block.BlockGasCost(), + types.BlockGasCost(block), block.Transactions(), receipts, contribution, diff --git a/core/blockchain.go b/core/blockchain.go index 6998fbb57a..d172b0f85e 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1367,7 +1367,7 @@ func (bc *BlockChain) insertBlock(block *types.Block, writes bool) error { "parentHash", block.ParentHash(), "uncles", len(block.Uncles()), "txs", len(block.Transactions()), "gas", block.GasUsed(), "elapsed", common.PrettyDuration(time.Since(start)), - "root", block.Root(), "baseFeePerGas", block.BaseFee(), "blockGasCost", block.BlockGasCost(), + "root", block.Root(), "baseFeePerGas", block.BaseFee(), "blockGasCost", types.BlockGasCost(block), ) processedBlockGasUsedCounter.Inc(int64(block.GasUsed())) diff --git a/core/genesis.go b/core/genesis.go index ae3dca01cb..81729f773c 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -246,7 +246,8 @@ func (g *Genesis) toBlock(db ethdb.Database, triedb *triedb.Database) *types.Blo } // Configure any stateful precompiles that should be enabled in the genesis. - err = ApplyPrecompileActivations(g.Config, nil, types.NewBlockWithHeader(head), statedb) + block := types.NewBlockWithHeader(head) + err = ApplyPrecompileActivations(g.Config, nil, types.WrapWithTimestamp(block), statedb) if err != nil { panic(fmt.Sprintf("unable to configure precompiles in genesis block: %v", err)) } diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index 3087e6a09f..a5cd029a07 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -522,8 +522,10 @@ func ReadBlock(db ethdb.Reader, hash common.Hash, number uint64) *types.Block { if body == nil { return nil } + block := types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles) bodyExtra := types.GetBodyExtra(body) - return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles).WithExtData(bodyExtra.Version, bodyExtra.ExtData) + block = types.BlockWithExtData(block, bodyExtra.Version, bodyExtra.ExtData) + return block } // WriteBlock serializes a block into the database, header and body separately. diff --git a/core/state_processor.go b/core/state_processor.go index bfc42c78f8..f886d3a945 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -82,7 +82,7 @@ func (p *StateProcessor) Process(block *types.Block, parent *types.Header, state ) // Configure any upgrades that should go into effect during this block. - err := ApplyUpgrades(p.config, &parent.Time, block, statedb) + err := ApplyUpgrades(p.config, &parent.Time, types.WrapWithTimestamp(block), statedb) if err != nil { log.Error("failed to configure precompiles processing block", "hash", block.Hash(), "number", block.NumberU64(), "timestamp", block.Time(), "err", err) return nil, nil, 0, err diff --git a/core/types/block.go b/core/types/block.go index 452446a378..ab1254f4c2 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -1,300 +1 @@ -// (c) 2019-2020, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2014 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 contains data types related to Ethereum consensus. package types - -import ( - "encoding/binary" - "io" - "math/big" - "sync/atomic" - - "github.com/ava-labs/libevm/common" - "github.com/ava-labs/libevm/rlp" -) - -// Block represents an Ethereum block. -// -// Note the Block type tries to be 'immutable', and contains certain caches that rely -// on that. The rules around block immutability are as follows: -// -// - We copy all data when the block is constructed. This makes references held inside -// the block independent of whatever value was passed in. -// -// - We copy all header data on access. This is because any change to the header would mess -// up the cached hash and size values in the block. Calling code is expected to take -// advantage of this to avoid over-allocating! -// -// - When new body data is attached to the block, a shallow copy of the block is returned. -// This ensures block modifications are race-free. -// -// - We do not copy body data on access because it does not affect the caches, and also -// because it would be too expensive. -type Block struct { - header *Header - uncles []*Header - transactions Transactions - - // Coreth specific data structures to support atomic transactions - version uint32 - extdata *[]byte - - // caches - hash atomic.Value - size atomic.Value -} - -// "external" block encoding. used for eth protocol, etc. -type extblock struct { - Header *Header - Txs []*Transaction - Uncles []*Header - Version uint32 - ExtData *[]byte `rlp:"nil"` -} - -// NewBlock creates a new block. The input data is copied, changes to header and to the -// field values will not affect the block. -// -// The values of TxHash, UncleHash, ReceiptHash and Bloom in header -// are ignored and set to values derived from the given txs, uncles -// and receipts. -func NewBlock( - header *Header, txs []*Transaction, uncles []*Header, receipts []*Receipt, hasher TrieHasher, -) *Block { - b := &Block{header: CopyHeader(header)} - - // TODO: panic if len(txs) != len(receipts) - if len(txs) == 0 { - b.header.TxHash = EmptyTxsHash - } else { - b.header.TxHash = DeriveSha(Transactions(txs), hasher) - b.transactions = make(Transactions, len(txs)) - copy(b.transactions, txs) - } - - if len(receipts) == 0 { - b.header.ReceiptHash = EmptyReceiptsHash - } else { - b.header.ReceiptHash = DeriveSha(Receipts(receipts), hasher) - b.header.Bloom = CreateBloom(receipts) - } - - if len(uncles) == 0 { - b.header.UncleHash = EmptyUncleHash - } else { - b.header.UncleHash = CalcUncleHash(uncles) - b.uncles = make([]*Header, len(uncles)) - for i := range uncles { - b.uncles[i] = CopyHeader(uncles[i]) - } - } - - return b -} - -// DecodeRLP decodes a block from RLP. -func (b *Block) DecodeRLP(s *rlp.Stream) error { - var eb extblock - _, size, _ := s.Kind() - if err := s.Decode(&eb); err != nil { - return err - } - b.header, b.uncles, b.transactions, b.version, b.extdata = eb.Header, eb.Uncles, eb.Txs, eb.Version, eb.ExtData - b.size.Store(rlp.ListSize(size)) - return nil -} - -// EncodeRLP serializes a block as RLP. -func (b *Block) EncodeRLP(w io.Writer) error { - return rlp.Encode(w, &extblock{ - Header: b.header, - Txs: b.transactions, - Uncles: b.uncles, - Version: b.version, - ExtData: b.extdata, - }) -} - -// Body returns the non-header content of the block. -// Note the returned data is not an independent copy. -func (b *Block) Body() *Body { - 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 -// of the body slices does not affect the cached hash/size in block. - -func (b *Block) Uncles() []*Header { return b.uncles } -func (b *Block) Transactions() Transactions { return b.transactions } - -func (b *Block) Transaction(hash common.Hash) *Transaction { - for _, transaction := range b.transactions { - if transaction.Hash() == hash { - return transaction - } - } - return nil -} - -// Header returns the block header (as a copy). -func (b *Block) Header() *Header { - return CopyHeader(b.header) -} - -// Header value accessors. These do copy! - -func (b *Block) Number() *big.Int { return new(big.Int).Set(b.header.Number) } -func (b *Block) GasLimit() uint64 { return b.header.GasLimit } -func (b *Block) GasUsed() uint64 { return b.header.GasUsed } -func (b *Block) Difficulty() *big.Int { return new(big.Int).Set(b.header.Difficulty) } -func (b *Block) Time() uint64 { return b.header.Time } -func (b *Block) Timestamp() uint64 { return b.header.Time } - -func (b *Block) NumberU64() uint64 { return b.header.Number.Uint64() } -func (b *Block) MixDigest() common.Hash { return b.header.MixDigest } -func (b *Block) Nonce() uint64 { return binary.BigEndian.Uint64(b.header.Nonce[:]) } -func (b *Block) Bloom() Bloom { return b.header.Bloom } -func (b *Block) Coinbase() common.Address { return b.header.Coinbase } -func (b *Block) Root() common.Hash { return b.header.Root } -func (b *Block) ParentHash() common.Hash { return b.header.ParentHash } -func (b *Block) TxHash() common.Hash { return b.header.TxHash } -func (b *Block) ReceiptHash() common.Hash { return b.header.ReceiptHash } -func (b *Block) UncleHash() common.Hash { return b.header.UncleHash } -func (b *Block) Extra() []byte { return common.CopyBytes(b.header.Extra) } - -func (b *Block) BaseFee() *big.Int { - if b.header.BaseFee == nil { - return nil - } - return new(big.Int).Set(b.header.BaseFee) -} - -func (b *Block) BeaconRoot() *common.Hash { return b.header.ParentBeaconRoot } - -func (b *Block) ExcessBlobGas() *uint64 { - var excessBlobGas *uint64 - if b.header.ExcessBlobGas != nil { - excessBlobGas = new(uint64) - *excessBlobGas = *b.header.ExcessBlobGas - } - return excessBlobGas -} - -func (b *Block) BlobGasUsed() *uint64 { - var blobGasUsed *uint64 - if b.header.BlobGasUsed != nil { - blobGasUsed = new(uint64) - *blobGasUsed = *b.header.BlobGasUsed - } - return blobGasUsed -} - -func (b *Block) BlockGasCost() *big.Int { - if HeaderExtras(b.header).BlockGasCost == nil { - return nil - } - return new(big.Int).Set(HeaderExtras(b.header).BlockGasCost) -} - -// Size returns the true RLP encoded storage size of the block, either by encoding -// and returning it, or returning a previously cached value. -func (b *Block) Size() uint64 { - if size := b.size.Load(); size != nil { - return size.(uint64) - } - c := writeCounter(0) - rlp.Encode(&c, b) - b.size.Store(uint64(c)) - return uint64(c) -} - -type writeCounter uint64 - -func (c *writeCounter) Write(b []byte) (int, error) { - *c += writeCounter(len(b)) - return len(b), nil -} - -func CalcUncleHash(uncles []*Header) common.Hash { - if len(uncles) == 0 { - return EmptyUncleHash - } - return rlpHash(uncles) -} - -// NewBlockWithHeader creates a block with the given header data. The -// header data is copied, changes to header and to the field values -// will not affect the block. -func NewBlockWithHeader(header *Header) *Block { - return &Block{header: CopyHeader(header)} -} - -// WithSeal returns a new block with the data from b but the header replaced with -// the sealed one. -func (b *Block) WithSeal(header *Header) *Block { - return &Block{ - header: CopyHeader(header), - transactions: b.transactions, - uncles: b.uncles, - } -} - -// WithBody returns a copy of the block with the given transaction and uncle contents. -func (b *Block) WithBody(transactions []*Transaction, uncles []*Header) *Block { - block := &Block{ - header: b.header, - transactions: make([]*Transaction, len(transactions)), - uncles: make([]*Header, len(uncles)), - } - copy(block.transactions, transactions) - for i := range uncles { - block.uncles[i] = CopyHeader(uncles[i]) - } - return block -} - -// Hash returns the keccak256 hash of b's header. -// The hash is computed on the first call and cached thereafter. -func (b *Block) Hash() common.Hash { - if hash := b.hash.Load(); hash != nil { - return hash.(common.Hash) - } - v := b.header.Hash() - b.hash.Store(v) - return v -} - -type Blocks []*Block diff --git a/core/types/block_ext.go b/core/types/block_ext.go index 5bec259297..21d9318f4c 100644 --- a/core/types/block_ext.go +++ b/core/types/block_ext.go @@ -4,50 +4,144 @@ package types import ( + "io" "math/big" "github.com/ava-labs/libevm/common" + ethtypes "github.com/ava-labs/libevm/core/types" + "github.com/ava-labs/libevm/rlp" ) -func (b *Block) WithExtData(version uint32, extdata *[]byte) *Block { - b.version = version - b.setExtDataHelper(extdata, false) +// BlockExtra is a struct that contains extra fields used by Avalanche +// in the block. +// This type uses BlockSerializable to encode and decode the extra fields +// along with the upstream type for compatibility with existing network blocks. +type BlockExtra struct { + version uint32 + extdata *[]byte + + // Fields removed from geth: + // - withdrawals Withdrawals + // - ReceivedAt time.Time + // - ReceivedFrom interface{} +} + +func (b *BlockExtra) EncodeRLP(eth *ethtypes.Block, writer io.Writer) error { + out := new(blockSerializable) + + out.updateFromEth(eth) + out.updateFromExtras(b) + + return rlp.Encode(writer, out) +} + +func (b *BlockExtra) DecodeRLP(eth *ethtypes.Block, stream *rlp.Stream) error { + in := new(blockSerializable) + if err := stream.Decode(in); err != nil { + return err + } + + in.updateToEth(eth) + in.updateToExtras(b) + + return nil +} + +func (b *BlockExtra) Body(block *Block) *Body { + body := block.EthBody() + extra := &BodyExtra{ + Version: b.version, + ExtData: b.extdata, + } + return WithBodyExtra(body, extra) +} + +// blockSerializable defines the block in the Ethereum blockchain, +// as it is to be serialized into RLP. +type blockSerializable struct { + Header *Header + Txs []*Transaction + Uncles []*Header + Version uint32 + ExtData *[]byte `rlp:"nil"` +} + +// updateFromEth updates the [*blockSerializable] from the [*ethtypes.Block]. +func (b *blockSerializable) updateFromEth(eth *ethtypes.Block) { + b.Header = eth.Header() // note this deep copies the header + b.Uncles = eth.Uncles() + b.Txs = eth.Transactions() +} + +// updateToEth updates the [*ethtypes.Block] from the [*blockSerializable]. +func (b *blockSerializable) updateToEth(eth *ethtypes.Block) { + eth.SetHeader(b.Header) + eth.SetTransactions(b.Txs) + eth.SetUncles(b.Uncles) +} + +// updateFromExtras updates the [*blockSerializable] from the [*BlockExtra]. +func (b *blockSerializable) updateFromExtras(extras *BlockExtra) { + b.Version = extras.version + b.ExtData = extras.extdata +} + +// updateToExtras updates the [*BlockExtra] from the [*blockSerializable]. +func (b *blockSerializable) updateToExtras(extras *BlockExtra) { + extras.version = b.Version + extras.extdata = b.ExtData +} + +func BlockWithExtData(b *Block, version uint32, extdata *[]byte) *Block { + BlockExtras(b).version = version + setExtDataHelper(b, extdata, false) return b } -func (b *Block) setExtDataHelper(data *[]byte, recalc bool) { +func setExtDataHelper(b *Block, data *[]byte, recalc bool) { if data == nil { - b.setExtData(nil, recalc) + setExtData(b, nil, recalc) return } - b.setExtData(*data, recalc) + setExtData(b, *data, recalc) } -func (b *Block) setExtData(data []byte, recalc bool) { +func setExtData(b *Block, data []byte, recalc bool) { _data := make([]byte, len(data)) - b.extdata = &_data - copy(*b.extdata, data) + extras := BlockExtras(b) + extras.extdata = &_data + copy(*extras.extdata, data) if recalc { - HeaderExtras(b.header).ExtDataHash = CalcExtDataHash(*b.extdata) + header := b.Header() + headerExtra := HeaderExtras(header) + headerExtra.ExtDataHash = CalcExtDataHash(_data) + b.SetHeader(header) } } -func (b *Block) ExtData() []byte { - if b.extdata == nil { +func BlockExtData(b *Block) []byte { + extras := BlockExtras(b) + if extras.extdata == nil { return nil } - return *b.extdata + return *extras.extdata } -func (b *Block) Version() uint32 { - return b.version +func BlockVersion(b *Block) uint32 { + return BlockExtras(b).version } -func (b *Block) ExtDataGasUsed() *big.Int { - if HeaderExtras(b.header).ExtDataGasUsed == nil { +func BlockExtDataGasUsed(b *Block) *big.Int { + if HeaderExtras(b.Header()).ExtDataGasUsed == nil { return nil } - return new(big.Int).Set(HeaderExtras(b.header).ExtDataGasUsed) + return new(big.Int).Set(HeaderExtras(b.Header()).ExtDataGasUsed) +} + +func BlockGasCost(b *Block) *big.Int { + header := b.Header() // note this deep copies headerExtra.BlockGasCost + headerExtra := HeaderExtras(header) + return headerExtra.BlockGasCost } func CalcExtDataHash(extdata []byte) common.Hash { @@ -61,7 +155,19 @@ func NewBlockWithExtData( header *Header, txs []*Transaction, uncles []*Header, receipts []*Receipt, hasher TrieHasher, extdata []byte, recalc bool, ) *Block { - b := NewBlock(header, txs, uncles, receipts, hasher) - b.setExtData(extdata, recalc) - return b + b := ethtypes.NewBlock(header, txs, uncles, receipts, hasher) + const version = 0 + return WithBlockExtras(b, version, &extdata, recalc) +} + +func WrapWithTimestamp(b *Block) *BlockWithTimestamp { + return &BlockWithTimestamp{Block: b} +} + +type BlockWithTimestamp struct { + *Block +} + +func (b *BlockWithTimestamp) Timestamp() uint64 { + return b.Time() } diff --git a/core/types/block_test.go b/core/types/block_test.go index 9a4434c8ae..cc19081267 100644 --- a/core/types/block_test.go +++ b/core/types/block_test.go @@ -35,6 +35,7 @@ import ( "github.com/ava-labs/coreth/internal/blocktest" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/common/math" + ethtypes "github.com/ava-labs/libevm/core/types" "github.com/ava-labs/libevm/crypto" "github.com/ava-labs/libevm/params" "github.com/ava-labs/libevm/rlp" @@ -69,10 +70,10 @@ func TestBlockEncoding(t *testing.T) { check("Extra", block.Extra(), common.FromHex("")) check("MixDigest", block.MixDigest(), common.HexToHash("0000000000000000000000000000000000000000000000000000000000000000")) check("Nonce", block.Nonce(), uint64(0)) - check("ExtDataHash", HeaderExtras(block.header).ExtDataHash, common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")) + check("ExtDataHash", HeaderExtras(block.Header()).ExtDataHash, common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")) check("BaseFee", block.BaseFee(), (*big.Int)(nil)) - check("ExtDataGasUsed", block.ExtDataGasUsed(), (*big.Int)(nil)) - check("BlockGasCost", block.BlockGasCost(), (*big.Int)(nil)) + check("ExtDataGasUsed", BlockExtDataGasUsed(&block), (*big.Int)(nil)) + check("BlockGasCost", BlockGasCost(&block), (*big.Int)(nil)) check("Size", block.Size(), uint64(len(blockEnc))) check("BlockHash", block.Hash(), common.HexToHash("0608e5d5e13c337f226b621a0b08b3d50470f1961329826fd59f5a241d1df49e")) @@ -113,8 +114,8 @@ func TestEIP1559BlockEncoding(t *testing.T) { check("Time", block.Time(), uint64(1426516743)) check("Size", block.Size(), uint64(len(blockEnc))) check("BaseFee", block.BaseFee(), new(big.Int).SetUint64(1_000_000_000)) - check("ExtDataGasUsed", block.ExtDataGasUsed(), (*big.Int)(nil)) - check("BlockGasCost", block.BlockGasCost(), (*big.Int)(nil)) + check("ExtDataGasUsed", BlockExtDataGasUsed(&block), (*big.Int)(nil)) + check("BlockGasCost", BlockGasCost(&block), (*big.Int)(nil)) tx1 := NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(10), 50000, big.NewInt(10), nil) tx1, _ = tx1.WithSignature(HomesteadSigner{}, common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b100")) @@ -177,10 +178,10 @@ func TestEIP2718BlockEncoding(t *testing.T) { check("Nonce", block.Nonce(), uint64(0xa13a5a8c8f2bb1c4)) check("Time", block.Time(), uint64(1426516743)) check("Size", block.Size(), uint64(len(blockEnc))) - check("ExtDataHash", HeaderExtras(block.header).ExtDataHash, common.HexToHash("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")) + check("ExtDataHash", HeaderExtras(block.Header()).ExtDataHash, common.HexToHash("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")) check("BaseFee", block.BaseFee(), (*big.Int)(nil)) - check("ExtDataGasUsed", block.ExtDataGasUsed(), (*big.Int)(nil)) - check("BlockGasCost", block.BlockGasCost(), (*big.Int)(nil)) + check("ExtDataGasUsed", BlockExtDataGasUsed(&block), (*big.Int)(nil)) + check("BlockGasCost", BlockGasCost(&block), (*big.Int)(nil)) // Create legacy tx. to := common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87") @@ -212,8 +213,8 @@ func TestEIP2718BlockEncoding(t *testing.T) { check("Transactions[1].Hash", block.Transactions()[1].Hash(), tx2.Hash()) check("Transactions[1].Type()", block.Transactions()[1].Type(), uint8(AccessListTxType)) - if !bytes.Equal(block.ExtData(), []byte{}) { - t.Errorf("Block ExtraData field mismatch, expected empty byte array, but found 0x%x", block.ExtData()) + if !bytes.Equal(BlockExtData(&block), []byte{}) { + t.Errorf("Block ExtraData field mismatch, expected empty byte array, but found 0x%x", BlockExtData(&block)) } ourBlockEnc, err := rlp.EncodeToBytes(&block) @@ -252,10 +253,10 @@ func TestBlockEncodingWithExtraData(t *testing.T) { check("Extra", block.Extra(), common.FromHex("")) check("MixDigest", block.MixDigest(), common.HexToHash("0000000000000000000000000000000000000000000000000000000000000000")) check("Nonce", block.Nonce(), uint64(0)) - check("ExtDataHash", HeaderExtras(block.header).ExtDataHash, common.HexToHash("296ff3bfdebf7c4b1fb71f589d69ed03b1c59b278d1780d54dc86ea7cb87cf17")) + check("ExtDataHash", HeaderExtras(block.Header()).ExtDataHash, common.HexToHash("296ff3bfdebf7c4b1fb71f589d69ed03b1c59b278d1780d54dc86ea7cb87cf17")) check("BaseFee", block.BaseFee(), (*big.Int)(nil)) - check("ExtDataGasUsed", block.ExtDataGasUsed(), (*big.Int)(nil)) - check("BlockGasCost", block.BlockGasCost(), (*big.Int)(nil)) + check("ExtDataGasUsed", BlockExtDataGasUsed(&block), (*big.Int)(nil)) + check("BlockGasCost", BlockGasCost(&block), (*big.Int)(nil)) check("Size", block.Size(), uint64(len(blockEnc))) check("BlockHash", block.Hash(), common.HexToHash("4504ee98a94d16dbd70a35370501a3cb00c2965b012672085fbd328a72962902")) @@ -263,8 +264,8 @@ func TestBlockEncodingWithExtraData(t *testing.T) { check("len(Transactions)", len(block.Transactions()), 0) expectedBlockExtraData := common.FromHex("00000000000000003039c85fc1980a77c5da78fe5486233fc09a769bb812bcb2cc548cf9495d046b3f1bd891ad56056d9c01f18f43f58b5c784ad07a4a49cf3d1f11623804b5cba2c6bf000000028a0f7c3e4d840143671a4c4ecacccb4d60fb97dce97a7aa5d60dfd072a7509cf00000001dbcf890f77f49b96857648b72b77f9f82937f28a68704af05da0dc12ba53f2db0000000500002d79883d20000000000100000000e0d5c4edc78f594b79025a56c44933c28e8ba3e51e6e23318727eeaac10eb27d00000001dbcf890f77f49b96857648b72b77f9f82937f28a68704af05da0dc12ba53f2db0000000500002d79883d20000000000100000000000000016dc8ea73dd39ab12fa2ecbc3427abaeb87d56fd800005af3107a4000dbcf890f77f49b96857648b72b77f9f82937f28a68704af05da0dc12ba53f2db0000000200000009000000010d9f115cd63c3ab78b5b82cfbe4339cd6be87f21cda14cf192b269c7a6cb2d03666aa8f8b23ca0a2ceee4050e75c9b05525a17aa1dd0e9ea391a185ce395943f0000000009000000010d9f115cd63c3ab78b5b82cfbe4339cd6be87f21cda14cf192b269c7a6cb2d03666aa8f8b23ca0a2ceee4050e75c9b05525a17aa1dd0e9ea391a185ce395943f00") - if !bytes.Equal(block.ExtData(), expectedBlockExtraData) { - t.Errorf("Block ExtraData field mismatch, expected 0x%x, but found 0x%x", block.ExtData(), expectedBlockExtraData) + if !bytes.Equal(BlockExtData(&block), expectedBlockExtraData) { + t.Errorf("Block ExtraData field mismatch, expected 0x%x, but found 0x%x", BlockExtData(&block), expectedBlockExtraData) } ourBlockEnc, err := rlp.EncodeToBytes(&block) @@ -337,7 +338,7 @@ func makeBenchBlock() *Block { Extra: []byte("benchmark uncle"), } } - return NewBlock(header, txs, uncles, receipts, blocktest.NewHasher()) + return ethtypes.NewBlock(header, txs, uncles, receipts, blocktest.NewHasher()) } func TestAP4BlockEncoding(t *testing.T) { @@ -365,8 +366,8 @@ func TestAP4BlockEncoding(t *testing.T) { check("Time", block.Time(), uint64(1426516743)) check("Size", block.Size(), uint64(len(blockEnc))) check("BaseFee", block.BaseFee(), big.NewInt(1_000_000_000)) - check("ExtDataGasUsed", block.ExtDataGasUsed(), big.NewInt(25_000)) - check("BlockGasCost", block.BlockGasCost(), big.NewInt(1_000_000)) + check("ExtDataGasUsed", BlockExtDataGasUsed(&block), big.NewInt(25_000)) + check("BlockGasCost", BlockGasCost(&block), big.NewInt(1_000_000)) tx1 := NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(10), 50000, big.NewInt(10), nil) tx1, _ = tx1.WithSignature(HomesteadSigner{}, common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b100")) diff --git a/core/types/header_ext.go b/core/types/header_ext.go index 113a7b70ad..961ad097c1 100644 --- a/core/types/header_ext.go +++ b/core/types/header_ext.go @@ -26,8 +26,8 @@ type HeaderExtra struct { func (h *HeaderExtra) EncodeRLP(eth *ethtypes.Header, writer io.Writer) error { out := new(HeaderSerializable) - updateFromEth(out, eth) - updateFromExtras(out, h) + out.updateFromEth(eth) + out.updateFromExtras(h) return rlp.Encode(writer, out) } @@ -38,8 +38,8 @@ func (h *HeaderExtra) DecodeRLP(eth *ethtypes.Header, stream *rlp.Stream) error return err } - updateToEth(in, eth) - updateToExtras(in, h) + in.updateToEth(eth) + in.updateToExtras(h) return nil } @@ -48,8 +48,8 @@ func (h *HeaderExtra) DecodeRLP(eth *ethtypes.Header, stream *rlp.Stream) error func (h *HeaderExtra) MarshalJSON(eth *ethtypes.Header) ([]byte, error) { out := new(HeaderSerializable) - updateFromEth(out, eth) - updateFromExtras(out, h) + out.updateFromEth(eth) + out.updateFromExtras(h) return out.MarshalJSON() } @@ -61,8 +61,8 @@ func (h *HeaderExtra) UnmarshalJSON(eth *ethtypes.Header, input []byte) error { return err } - updateToEth(in, eth) - updateToExtras(in, h) + in.updateToEth(eth) + in.updateToExtras(h) return nil } @@ -156,7 +156,7 @@ func (h *HeaderSerializable) Hash() common.Hash { } // updateFromEth updates the HeaderSerializable from the ethtypes.Header -func updateFromEth(h *HeaderSerializable, eth *ethtypes.Header) { +func (h *HeaderSerializable) updateFromEth(eth *ethtypes.Header) { h.ParentHash = eth.ParentHash h.UncleHash = eth.UncleHash h.Coinbase = eth.Coinbase @@ -179,7 +179,7 @@ func updateFromEth(h *HeaderSerializable, eth *ethtypes.Header) { } // updateToEth updates the ethtypes.Header from the HeaderSerializable -func updateToEth(h *HeaderSerializable, eth *ethtypes.Header) { +func (h *HeaderSerializable) updateToEth(eth *ethtypes.Header) { eth.ParentHash = h.ParentHash eth.UncleHash = h.UncleHash eth.Coinbase = h.Coinbase @@ -202,14 +202,14 @@ func updateToEth(h *HeaderSerializable, eth *ethtypes.Header) { } // updateFromExtras updates the HeaderSerializable from the HeaderExtra -func updateFromExtras(h *HeaderSerializable, extras *HeaderExtra) { +func (h *HeaderSerializable) updateFromExtras(extras *HeaderExtra) { h.ExtDataHash = extras.ExtDataHash h.ExtDataGasUsed = extras.ExtDataGasUsed h.BlockGasCost = extras.BlockGasCost } // updateToExtras updates the HeaderExtra from the HeaderSerializable -func updateToExtras(h *HeaderSerializable, extras *HeaderExtra) { +func (h *HeaderSerializable) updateToExtras(extras *HeaderExtra) { extras.ExtDataHash = h.ExtDataHash extras.ExtDataGasUsed = h.ExtDataGasUsed extras.BlockGasCost = h.BlockGasCost diff --git a/core/types/imports.go b/core/types/imports.go index 090504555f..3e710f520b 100644 --- a/core/types/imports.go +++ b/core/types/imports.go @@ -27,6 +27,8 @@ type ( StateAccount = ethtypes.StateAccount SlimAccount = ethtypes.SlimAccount Header = ethtypes.Header + Block = ethtypes.Block + Blocks = ethtypes.Blocks BlockNonce = ethtypes.BlockNonce Transaction = ethtypes.Transaction Transactions = ethtypes.Transactions @@ -52,9 +54,12 @@ const ( var ( BloomLookup = ethtypes.BloomLookup BytesToBloom = ethtypes.BytesToBloom + CalcUncleHash = ethtypes.CalcUncleHash CreateBloom = ethtypes.CreateBloom CopyHeader = ethtypes.CopyHeader NewReceipt = ethtypes.NewReceipt + NewBlock = ethtypes.NewBlock + NewBlockWithHeader = ethtypes.NewBlockWithHeader NewContractCreation = ethtypes.NewContractCreation NewTransaction = ethtypes.NewTransaction EncodeNonce = ethtypes.EncodeNonce diff --git a/core/types/libevm.go b/core/types/libevm.go index 7b08bc5dc9..65509cd394 100644 --- a/core/types/libevm.go +++ b/core/types/libevm.go @@ -13,6 +13,7 @@ var ( extras = ethtypes.RegisterExtras[ HeaderExtra, *HeaderExtra, BodyExtra, *BodyExtra, + BlockExtra, *BlockExtra, isMultiCoin]() IsMultiCoinPayloads = extras.StateAccount ) @@ -38,3 +39,13 @@ func WithBodyExtra(b *Body, extra *BodyExtra) *Body { extras.Body.Set(b, extra) return b } + +func BlockExtras(b *Block) *BlockExtra { + return extras.Block.Get(b) +} + +func WithBlockExtras(b *Block, version uint32, extdata *[]byte, recalc bool) *Block { + BlockExtras(b).version = version + setExtDataHelper(b, extdata, recalc) + return b +} diff --git a/eth/state_accessor.go b/eth/state_accessor.go index ea5afa3b85..d1a2ba65bf 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -284,7 +284,7 @@ func (eth *Ethereum) StateAtNextBlock(ctx context.Context, parent *types.Block, } // Apply upgrades here for the [nextBlock] - err = core.ApplyUpgrades(eth.blockchain.Config(), &parent.Header().Time, nextBlock, statedb) + err = core.ApplyUpgrades(eth.blockchain.Config(), &parent.Header().Time, types.WrapWithTimestamp(nextBlock), statedb) if err != nil { release() return nil, nil, err diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 2f3eef2fc1..ef49e50a62 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -966,7 +966,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc config.BlockOverrides.Apply(&vmctx) // Apply all relevant upgrades from [originalTime] to the block time set in the override. // Should be applied before the state overrides. - err = core.ApplyUpgrades(api.backend.ChainConfig(), &originalTime, block, statedb) + err = core.ApplyUpgrades(api.backend.ChainConfig(), &originalTime, types.WrapWithTimestamp(block), statedb) if err != nil { return nil, err } diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index e1b5641869..b48ff49c18 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -181,7 +181,7 @@ func (b *testBackend) StateAtNextBlock(ctx context.Context, parent, nextBlock *t return nil, nil, err } // Apply upgrades to the parent state - err = core.ApplyUpgrades(b.chainConfig, &parent.Header().Time, nextBlock, statedb) + err = core.ApplyUpgrades(b.chainConfig, &parent.Header().Time, types.WrapWithTimestamp(nextBlock), statedb) if err != nil { release() return nil, nil, err diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index fda588e45b..00b3c7499f 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -265,7 +265,9 @@ func (ec *client) getBlock(ctx context.Context, method string, args ...interface } txs[i] = tx.tx } - return types.NewBlockWithHeader(head).WithBody(txs, uncles).WithExtData(body.Version, (*[]byte)(body.BlockExtraData)), nil + block := types.NewBlockWithHeader(head).WithBody(txs, uncles) + block = types.WithBlockExtras(block, body.Version, (*[]byte)(body.BlockExtraData), false) + return block, nil } // HeaderByHash returns the block header with the given hash. diff --git a/go.mod b/go.mod index 4efc30ae99..55d7d5d5e7 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-20250121171435-edebe134329f +replace github.com/ava-labs/libevm => github.com/ava-labs/libevm v0.0.0-20250122094956-11c780f117f8 diff --git a/go.sum b/go.sum index 4cf9aab51a..a71dc0f262 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-20250121171435-edebe134329f h1:r83FXbNY2MeQ1SaKmmVTWkDTAtZOs4mX8nme+nzpZU0= -github.com/ava-labs/libevm v0.0.0-20250121171435-edebe134329f/go.mod h1:M8TCw2g1D5GBB7hu7g1F4aot5bRHGSxnBawNVmHE9Z0= +github.com/ava-labs/libevm v0.0.0-20250122094956-11c780f117f8 h1:koH85Ew+1o1oaZotJy6BVJsuigu0Am3dHexS24WMFb0= +github.com/ava-labs/libevm v0.0.0-20250122094956-11c780f117f8/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/internal/ethapi/api.go b/internal/ethapi/api.go index d2603d1d52..0aa764c012 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1272,7 +1272,7 @@ func RPCMarshalHeader(head *types.Header) map[string]interface{} { func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *params.ChainConfig) map[string]interface{} { fields := RPCMarshalHeader(block.Header()) fields["size"] = hexutil.Uint64(block.Size()) - fields["blockExtraData"] = hexutil.Bytes(block.ExtData()) + fields["blockExtraData"] = hexutil.Bytes(types.BlockExtData(block)) if inclTx { formatTx := func(idx int, tx *types.Transaction) interface{} { diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index c3a6c7c880..d42ffef71b 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -526,8 +526,10 @@ func (b testBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc. panic("unknown type rpc.BlockNumberOrHash") } func (b testBackend) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) { - return b.chain.GetBlock(hash, uint64(number.Int64())).Body(), nil + block := b.chain.GetBlock(hash, uint64(number.Int64())) + return block.Body(), nil } + func (b testBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) { if number == rpc.PendingBlockNumber { panic("pending state not implemented") diff --git a/miner/worker.go b/miner/worker.go index b73190f9e3..429a140a83 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -212,7 +212,8 @@ func (w *worker) commitNewWork(predicateContext *precompileconfig.PredicateConte env.state.StopPrefetcher() }() // Configure any upgrades that should go into effect during this block. - err = core.ApplyUpgrades(w.chainConfig, &parent.Time, types.NewBlockWithHeader(header), env.state) + block := types.WrapWithTimestamp(types.NewBlockWithHeader(header)) + err = core.ApplyUpgrades(w.chainConfig, &parent.Time, block, env.state) if err != nil { log.Error("failed to configure precompiles mining new block", "parent", parent.Hash(), "number", header.Number, "timestamp", header.Time, "err", err) return nil, err diff --git a/plugin/evm/block.go b/plugin/evm/block.go index bcc7e7e995..274928cf8d 100644 --- a/plugin/evm/block.go +++ b/plugin/evm/block.go @@ -120,7 +120,7 @@ type Block struct { // newBlock returns a new Block wrapping the ethBlock type and implementing the snowman.Block interface func (vm *VM) newBlock(ethBlock *types.Block) (*Block, error) { isApricotPhase5 := vm.chainConfigExtra().IsApricotPhase5(ethBlock.Time()) - atomicTxs, err := atomic.ExtractAtomicTxs(ethBlock.ExtData(), isApricotPhase5, atomic.Codec) + atomicTxs, err := atomic.ExtractAtomicTxs(types.BlockExtData(ethBlock), isApricotPhase5, atomic.Codec) if err != nil { return nil, err } @@ -151,7 +151,7 @@ func (b *Block) Accept(context.Context) error { // Call Accept for relevant precompile logs. Note we do this prior to // calling Accept on the blockChain so any side effects (eg warp signatures) // take place before the accepted log is emitted to subscribers. - rules := b.vm.chainConfig.Rules(b.ethBlock.Number(), params.IsMergeTODO, b.ethBlock.Timestamp()) + rules := b.vm.chainConfig.Rules(b.ethBlock.Number(), params.IsMergeTODO, b.ethBlock.Time()) if err := b.handlePrecompileAccept(*params.GetRulesExtra(rules)); err != nil { return err } @@ -279,7 +279,7 @@ func (b *Block) Verify(context.Context) error { // ShouldVerifyWithContext implements the block.WithVerifyContext interface func (b *Block) ShouldVerifyWithContext(context.Context) (bool, error) { - rules := params.GetRulesExtra(b.vm.chainConfig.Rules(b.ethBlock.Number(), params.IsMergeTODO, b.ethBlock.Timestamp())) + rules := params.GetRulesExtra(b.vm.chainConfig.Rules(b.ethBlock.Number(), params.IsMergeTODO, b.ethBlock.Time())) predicates := rules.Predicaters // Short circuit early if there are no predicates to verify if len(predicates) == 0 { @@ -360,7 +360,7 @@ func (b *Block) verify(predicateContext *precompileconfig.PredicateContext, writ // verifyPredicates verifies the predicates in the block are valid according to predicateContext. func (b *Block) verifyPredicates(predicateContext *precompileconfig.PredicateContext) error { - rules := b.vm.chainConfig.Rules(b.ethBlock.Number(), params.IsMergeTODO, b.ethBlock.Timestamp()) + rules := b.vm.chainConfig.Rules(b.ethBlock.Number(), params.IsMergeTODO, b.ethBlock.Time()) rulesExtra := params.GetRulesExtra(rules) switch { diff --git a/plugin/evm/block_verification.go b/plugin/evm/block_verification.go index a08b235533..83925cae4c 100644 --- a/plugin/evm/block_verification.go +++ b/plugin/evm/block_verification.go @@ -48,7 +48,7 @@ func (v blockValidator) SyntacticVerify(b *Block, rules params.Rules) error { if !rulesExtra.IsApricotPhase1 { if v.extDataHashes != nil { - extData := b.ethBlock.ExtData() + extData := types.BlockExtData(b.ethBlock) extDataHash := types.CalcExtDataHash(extData) // If there is no extra data, check that there is no extra data in the hash map either to ensure we do not // have a block that is unexpectedly missing extra data. @@ -75,7 +75,9 @@ func (v blockValidator) SyntacticVerify(b *Block, rules params.Rules) error { // Verify the ExtDataHash field headerExtra := types.HeaderExtras(ethHeader) if rulesExtra.IsApricotPhase1 { - if hash := types.CalcExtDataHash(b.ethBlock.ExtData()); headerExtra.ExtDataHash != hash { + extraData := types.BlockExtData(b.ethBlock) + hash := types.CalcExtDataHash(extraData) + if headerExtra.ExtDataHash != hash { return fmt.Errorf("extra data hash mismatch: have %x, want %x", headerExtra.ExtDataHash, hash) } } else { @@ -155,8 +157,8 @@ func (v blockValidator) SyntacticVerify(b *Block, rules params.Rules) error { } } - if b.ethBlock.Version() != 0 { - return fmt.Errorf("invalid version: %d", b.ethBlock.Version()) + if types.BlockVersion(b.ethBlock) != 0 { + return fmt.Errorf("invalid version: %d", types.BlockVersion(b.ethBlock)) } // Check that the tx hash in the header matches the body diff --git a/plugin/evm/mempool_atomic_gossiping_test.go b/plugin/evm/mempool_atomic_gossiping_test.go index 9f2cc89535..61ad99a5e5 100644 --- a/plugin/evm/mempool_atomic_gossiping_test.go +++ b/plugin/evm/mempool_atomic_gossiping_test.go @@ -16,6 +16,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) // shows that a locally generated AtomicTx can be added to mempool and then @@ -67,7 +68,7 @@ func TestMempoolAddLocallyCreateAtomicTx(t *testing.T) { // Show that BuildBlock generates a block containing [txID] and that it is // still present in the mempool. blk, err := vm.BuildBlock(context.Background()) - assert.NoError(err, "could not build block out of mempool") + require.NoError(t, err, "could not build block out of mempool") evmBlk, ok := blk.(*chain.BlockWrapper).Block.(*Block) assert.True(ok, "unknown block type") diff --git a/plugin/evm/syncervm_test.go b/plugin/evm/syncervm_test.go index 65aff9b080..f880a821e6 100644 --- a/plugin/evm/syncervm_test.go +++ b/plugin/evm/syncervm_test.go @@ -607,7 +607,7 @@ func patchBlock(blk *types.Block, root common.Hash, db ethdb.Database) *types.Bl header.Root = root receipts := rawdb.ReadRawReceipts(db, blk.Hash(), blk.NumberU64()) newBlk := types.NewBlockWithExtData( - header, blk.Transactions(), blk.Uncles(), receipts, trie.NewStackTrie(nil), blk.ExtData(), true, + header, blk.Transactions(), blk.Uncles(), receipts, trie.NewStackTrie(nil), types.BlockExtData(blk), true, ) rawdb.WriteBlock(db, newBlk) rawdb.WriteCanonicalHash(db, newBlk.Hash(), newBlk.NumberU64()) diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 99374fc3ab..21aed57c6a 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -942,7 +942,7 @@ func (vm *VM) onExtraStateChange(block *types.Block, state *state.StateDB) (*big rulesExtra = *params.GetRulesExtra(rules) ) - txs, err := atomic.ExtractAtomicTxs(block.ExtData(), rulesExtra.IsApricotPhase5, atomic.Codec) + txs, err := atomic.ExtractAtomicTxs(types.BlockExtData(block), rulesExtra.IsApricotPhase5, atomic.Codec) if err != nil { return nil, nil, err } diff --git a/plugin/evm/vm_test.go b/plugin/evm/vm_test.go index eb9453b6c7..1be3b3b10f 100644 --- a/plugin/evm/vm_test.go +++ b/plugin/evm/vm_test.go @@ -2389,7 +2389,7 @@ func TestUncleBlock(t *testing.T) { uncles, nil, trie.NewStackTrie(nil), - blkDEthBlock.ExtData(), + types.BlockExtData(blkDEthBlock), false, ) uncleBlock, err := vm2.newBlock(uncleEthBlock) @@ -2450,7 +2450,7 @@ func TestEmptyBlock(t *testing.T) { false, ) - if len(emptyEthBlock.ExtData()) != 0 || types.HeaderExtras(emptyEthBlock.Header()).ExtDataHash != (common.Hash{}) { + if len(types.BlockExtData(emptyEthBlock)) != 0 || types.HeaderExtras(emptyEthBlock.Header()).ExtDataHash != (common.Hash{}) { t.Fatalf("emptyEthBlock should not have any extra data") } @@ -2716,7 +2716,7 @@ func TestFutureBlock(t *testing.T) { nil, nil, new(trie.Trie), - internalBlkA.ethBlock.ExtData(), + types.BlockExtData(internalBlkA.ethBlock), false, ) @@ -3271,10 +3271,10 @@ func TestBuildApricotPhase4Block(t *testing.T) { } ethBlk := blk.(*chain.BlockWrapper).Block.(*Block).ethBlock - if eBlockGasCost := ethBlk.BlockGasCost(); eBlockGasCost == nil || eBlockGasCost.Cmp(common.Big0) != 0 { + if eBlockGasCost := types.BlockGasCost(ethBlk); eBlockGasCost == nil || eBlockGasCost.Cmp(common.Big0) != 0 { t.Fatalf("expected blockGasCost to be 0 but got %d", eBlockGasCost) } - if eExtDataGasUsed := ethBlk.ExtDataGasUsed(); eExtDataGasUsed == nil || eExtDataGasUsed.Cmp(big.NewInt(1230)) != 0 { + if eExtDataGasUsed := types.BlockExtDataGasUsed(ethBlk); eExtDataGasUsed == nil || eExtDataGasUsed.Cmp(big.NewInt(1230)) != 0 { t.Fatalf("expected extDataGasUsed to be 1000 but got %d", eExtDataGasUsed) } minRequiredTip, err := dummy.MinRequiredTip(vm.chainConfig, ethBlk.Header()) @@ -3330,11 +3330,11 @@ func TestBuildApricotPhase4Block(t *testing.T) { } ethBlk = blk.(*chain.BlockWrapper).Block.(*Block).ethBlock - if ethBlk.BlockGasCost() == nil || ethBlk.BlockGasCost().Cmp(big.NewInt(100)) < 0 { - t.Fatalf("expected blockGasCost to be at least 100 but got %d", ethBlk.BlockGasCost()) + if types.BlockGasCost(ethBlk) == nil || types.BlockGasCost(ethBlk).Cmp(big.NewInt(100)) < 0 { + t.Fatalf("expected blockGasCost to be at least 100 but got %d", types.BlockGasCost(ethBlk)) } - if ethBlk.ExtDataGasUsed() == nil || ethBlk.ExtDataGasUsed().Cmp(common.Big0) != 0 { - t.Fatalf("expected extDataGasUsed to be 0 but got %d", ethBlk.ExtDataGasUsed()) + if types.BlockExtDataGasUsed(ethBlk) == nil || types.BlockExtDataGasUsed(ethBlk).Cmp(common.Big0) != 0 { + t.Fatalf("expected extDataGasUsed to be 0 but got %d", types.BlockExtDataGasUsed(ethBlk)) } minRequiredTip, err = dummy.MinRequiredTip(vm.chainConfig, ethBlk.Header()) if err != nil { @@ -3441,10 +3441,10 @@ func TestBuildApricotPhase5Block(t *testing.T) { } ethBlk := blk.(*chain.BlockWrapper).Block.(*Block).ethBlock - if eBlockGasCost := ethBlk.BlockGasCost(); eBlockGasCost == nil || eBlockGasCost.Cmp(common.Big0) != 0 { + if eBlockGasCost := types.BlockGasCost(ethBlk); eBlockGasCost == nil || eBlockGasCost.Cmp(common.Big0) != 0 { t.Fatalf("expected blockGasCost to be 0 but got %d", eBlockGasCost) } - if eExtDataGasUsed := ethBlk.ExtDataGasUsed(); eExtDataGasUsed == nil || eExtDataGasUsed.Cmp(big.NewInt(11230)) != 0 { + if eExtDataGasUsed := types.BlockExtDataGasUsed(ethBlk); eExtDataGasUsed == nil || eExtDataGasUsed.Cmp(big.NewInt(11230)) != 0 { t.Fatalf("expected extDataGasUsed to be 11230 but got %d", eExtDataGasUsed) } minRequiredTip, err := dummy.MinRequiredTip(vm.chainConfig, ethBlk.Header()) @@ -3492,11 +3492,11 @@ func TestBuildApricotPhase5Block(t *testing.T) { } ethBlk = blk.(*chain.BlockWrapper).Block.(*Block).ethBlock - if ethBlk.BlockGasCost() == nil || ethBlk.BlockGasCost().Cmp(big.NewInt(100)) < 0 { - t.Fatalf("expected blockGasCost to be at least 100 but got %d", ethBlk.BlockGasCost()) + if types.BlockGasCost(ethBlk) == nil || types.BlockGasCost(ethBlk).Cmp(big.NewInt(100)) < 0 { + t.Fatalf("expected blockGasCost to be at least 100 but got %d", types.BlockGasCost(ethBlk)) } - if ethBlk.ExtDataGasUsed() == nil || ethBlk.ExtDataGasUsed().Cmp(common.Big0) != 0 { - t.Fatalf("expected extDataGasUsed to be 0 but got %d", ethBlk.ExtDataGasUsed()) + if types.BlockExtDataGasUsed(ethBlk) == nil || types.BlockExtDataGasUsed(ethBlk).Cmp(common.Big0) != 0 { + t.Fatalf("expected extDataGasUsed to be 0 but got %d", types.BlockExtDataGasUsed(ethBlk)) } minRequiredTip, err = dummy.MinRequiredTip(vm.chainConfig, ethBlk.Header()) if err != nil { @@ -3909,7 +3909,7 @@ func TestParentBeaconRootBlock(t *testing.T) { nil, nil, new(trie.Trie), - ethBlock.ExtData(), + types.BlockExtData(ethBlock), false, ) diff --git a/scripts/tests.e2e.sh b/scripts/tests.e2e.sh index e89afbbce6..e68a0f19d0 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-20250121171435-edebe134329f" +go mod edit -replace "github.com/ava-labs/libevm=github.com/ava-labs/libevm@v0.0.0-20250122094956-11c780f117f8" go mod tidy echo "building avalanchego" diff --git a/sync/client/client_test.go b/sync/client/client_test.go index 70c7f6f118..876bfdced4 100644 --- a/sync/client/client_test.go +++ b/sync/client/client_test.go @@ -266,7 +266,7 @@ func TestGetBlocks(t *testing.T) { return responseBytes }, - expectedErr: "failed to unmarshal response: rlp: expected input list for types.extblock", + expectedErr: "failed to unmarshal response: rlp: expected input list for types.blockSerializable", }, "incorrect starting point": { request: message.BlockRequest{ @@ -381,7 +381,7 @@ func TestGetBlocks(t *testing.T) { if err == nil { t.Fatalf("Expected error: %s, but found no error", test.expectedErr) } - assert.True(t, strings.Contains(err.Error(), test.expectedErr), "expected error to contain [%s], but found [%s]", test.expectedErr, err) + assert.ErrorContains(t, err, test.expectedErr) return } if err != nil { From 5d97c3bb131f9b2a8a1a34d6e29196a35cc67e50 Mon Sep 17 00:00:00 2001 From: Quentin Mc Gaw Date: Fri, 17 Jan 2025 17:53:34 +0100 Subject: [PATCH 3/5] remove `BlockWithExtData` in favor of `WithBlockExtras` taking a recalc argument --- core/rawdb/accessors_chain.go | 2 +- core/types/block_ext.go | 29 +---------------------------- core/types/libevm.go | 20 ++++++++++++++++++-- 3 files changed, 20 insertions(+), 31 deletions(-) diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index a5cd029a07..33fe7be76d 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -524,7 +524,7 @@ func ReadBlock(db ethdb.Reader, hash common.Hash, number uint64) *types.Block { } block := types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles) bodyExtra := types.GetBodyExtra(body) - block = types.BlockWithExtData(block, bodyExtra.Version, bodyExtra.ExtData) + block = types.WithBlockExtras(block, bodyExtra.Version, bodyExtra.ExtData, false) return block } diff --git a/core/types/block_ext.go b/core/types/block_ext.go index 21d9318f4c..05b51cbbef 100644 --- a/core/types/block_ext.go +++ b/core/types/block_ext.go @@ -92,33 +92,6 @@ func (b *blockSerializable) updateToExtras(extras *BlockExtra) { extras.extdata = b.ExtData } -func BlockWithExtData(b *Block, version uint32, extdata *[]byte) *Block { - BlockExtras(b).version = version - setExtDataHelper(b, extdata, false) - return b -} - -func setExtDataHelper(b *Block, data *[]byte, recalc bool) { - if data == nil { - setExtData(b, nil, recalc) - return - } - setExtData(b, *data, recalc) -} - -func setExtData(b *Block, data []byte, recalc bool) { - _data := make([]byte, len(data)) - extras := BlockExtras(b) - extras.extdata = &_data - copy(*extras.extdata, data) - if recalc { - header := b.Header() - headerExtra := HeaderExtras(header) - headerExtra.ExtDataHash = CalcExtDataHash(_data) - b.SetHeader(header) - } -} - func BlockExtData(b *Block) []byte { extras := BlockExtras(b) if extras.extdata == nil { @@ -155,7 +128,7 @@ func NewBlockWithExtData( header *Header, txs []*Transaction, uncles []*Header, receipts []*Receipt, hasher TrieHasher, extdata []byte, recalc bool, ) *Block { - b := ethtypes.NewBlock(header, txs, uncles, receipts, hasher) + b := NewBlock(header, txs, uncles, receipts, hasher) const version = 0 return WithBlockExtras(b, version, &extdata, recalc) } diff --git a/core/types/libevm.go b/core/types/libevm.go index 65509cd394..ddd1459d7f 100644 --- a/core/types/libevm.go +++ b/core/types/libevm.go @@ -45,7 +45,23 @@ func BlockExtras(b *Block) *BlockExtra { } func WithBlockExtras(b *Block, version uint32, extdata *[]byte, recalc bool) *Block { - BlockExtras(b).version = version - setExtDataHelper(b, extdata, recalc) + extras := BlockExtras(b) + + extras.version = version + + cpy := make([]byte, 0) + if extdata != nil { + cpy = make([]byte, len(*extdata)) + copy(cpy, *extdata) + } + + extras.extdata = &cpy + if recalc { + header := b.Header() + headerExtra := HeaderExtras(header) + headerExtra.ExtDataHash = CalcExtDataHash(cpy) + b.SetHeader(header) + } + return b } From 923b496d6d8813c0415e97a6b8ef95d65fae4053 Mon Sep 17 00:00:00 2001 From: Quentin Mc Gaw Date: Tue, 21 Jan 2025 17:55:20 +0100 Subject: [PATCH 4/5] BlockExtras -> GetBlockExtra --- core/types/block_ext.go | 4 ++-- core/types/libevm.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/types/block_ext.go b/core/types/block_ext.go index 05b51cbbef..968bb2f0cd 100644 --- a/core/types/block_ext.go +++ b/core/types/block_ext.go @@ -93,7 +93,7 @@ func (b *blockSerializable) updateToExtras(extras *BlockExtra) { } func BlockExtData(b *Block) []byte { - extras := BlockExtras(b) + extras := GetBlockExtra(b) if extras.extdata == nil { return nil } @@ -101,7 +101,7 @@ func BlockExtData(b *Block) []byte { } func BlockVersion(b *Block) uint32 { - return BlockExtras(b).version + return GetBlockExtra(b).version } func BlockExtDataGasUsed(b *Block) *big.Int { diff --git a/core/types/libevm.go b/core/types/libevm.go index ddd1459d7f..639c59a630 100644 --- a/core/types/libevm.go +++ b/core/types/libevm.go @@ -40,12 +40,12 @@ func WithBodyExtra(b *Body, extra *BodyExtra) *Body { return b } -func BlockExtras(b *Block) *BlockExtra { +func GetBlockExtra(b *Block) *BlockExtra { return extras.Block.Get(b) } func WithBlockExtras(b *Block, version uint32, extdata *[]byte, recalc bool) *Block { - extras := BlockExtras(b) + extras := GetBlockExtra(b) extras.version = version From a3593f6f73aa93a5d77e9bb56860d3c90b56ca9c Mon Sep 17 00:00:00 2001 From: Quentin Mc Gaw Date: Tue, 21 Jan 2025 17:55:40 +0100 Subject: [PATCH 5/5] `WithBlockExtras` -> `WithBlockExtra` --- core/rawdb/accessors_chain.go | 2 +- core/types/block_ext.go | 2 +- core/types/libevm.go | 2 +- ethclient/ethclient.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index 33fe7be76d..f0072cbbbd 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -524,7 +524,7 @@ func ReadBlock(db ethdb.Reader, hash common.Hash, number uint64) *types.Block { } block := types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles) bodyExtra := types.GetBodyExtra(body) - block = types.WithBlockExtras(block, bodyExtra.Version, bodyExtra.ExtData, false) + block = types.WithBlockExtra(block, bodyExtra.Version, bodyExtra.ExtData, false) return block } diff --git a/core/types/block_ext.go b/core/types/block_ext.go index 968bb2f0cd..6e123beb43 100644 --- a/core/types/block_ext.go +++ b/core/types/block_ext.go @@ -130,7 +130,7 @@ func NewBlockWithExtData( ) *Block { b := NewBlock(header, txs, uncles, receipts, hasher) const version = 0 - return WithBlockExtras(b, version, &extdata, recalc) + return WithBlockExtra(b, version, &extdata, recalc) } func WrapWithTimestamp(b *Block) *BlockWithTimestamp { diff --git a/core/types/libevm.go b/core/types/libevm.go index 639c59a630..2dfb2c528a 100644 --- a/core/types/libevm.go +++ b/core/types/libevm.go @@ -44,7 +44,7 @@ func GetBlockExtra(b *Block) *BlockExtra { return extras.Block.Get(b) } -func WithBlockExtras(b *Block, version uint32, extdata *[]byte, recalc bool) *Block { +func WithBlockExtra(b *Block, version uint32, extdata *[]byte, recalc bool) *Block { extras := GetBlockExtra(b) extras.version = version diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 00b3c7499f..0e2b97dac5 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -266,7 +266,7 @@ func (ec *client) getBlock(ctx context.Context, method string, args ...interface txs[i] = tx.tx } block := types.NewBlockWithHeader(head).WithBody(txs, uncles) - block = types.WithBlockExtras(block, body.Version, (*[]byte)(body.BlockExtraData), false) + block = types.WithBlockExtra(block, body.Version, (*[]byte)(body.BlockExtraData), false) return block, nil }