From d52d44f089dcac1e91008082e89e944184131f4a Mon Sep 17 00:00:00 2001 From: Quentin Mc Gaw Date: Mon, 10 Feb 2025 17:07:18 +0100 Subject: [PATCH] chore(core/types): header hooks JSON and RLP serialization - Implement `HeaderExtra` RLP and JSON serialization methods - remove `BlockNonce` - remove `EncodeNonce` - new functions `GetHeaderExtra` and `WithHeaderExtra` - Migrate existing custom `Header` to `HeaderSerializable` in block_ext.go with only `Hash` method for RLP code generation --- consensus/dummy/consensus.go | 38 +++--- consensus/dummy/dynamic_fees.go | 20 +-- consensus/dummy/dynamic_fees_test.go | 15 +-- core/state_processor_test.go | 4 +- core/types/block.go | 138 ++------------------ core/types/block_ext.go | 6 +- core/types/block_test.go | 6 +- core/types/gen_header_json.go | 139 ++++++++++---------- core/types/gen_header_rlp.go | 2 +- core/types/header_ext.go | 181 ++++++++++++++++++++++++++- core/types/imports.go | 3 + core/types/libevm.go | 2 +- internal/ethapi/api.go | 11 +- plugin/evm/block_verification.go | 29 ++--- plugin/evm/vm_test.go | 4 +- scripts/lint_allowed_eth_imports.sh | 2 +- 16 files changed, 333 insertions(+), 267 deletions(-) diff --git a/consensus/dummy/consensus.go b/consensus/dummy/consensus.go index 822ea8fe22..9f605494d7 100644 --- a/consensus/dummy/consensus.go +++ b/consensus/dummy/consensus.go @@ -168,12 +168,13 @@ func (eng *DummyEngine) verifyHeaderGasFields(config *params.ChainConfig, header } // Verify BlockGasCost, ExtDataGasUsed not present before AP4 + headerExtra := types.GetHeaderExtra(header) if !configExtra.IsApricotPhase4(header.Time) { - if header.BlockGasCost != nil { - return fmt.Errorf("invalid blockGasCost before fork: have %d, want ", header.BlockGasCost) + if headerExtra.BlockGasCost != nil { + return fmt.Errorf("invalid blockGasCost before fork: have %d, want ", headerExtra.BlockGasCost) } - if header.ExtDataGasUsed != nil { - return fmt.Errorf("invalid extDataGasUsed before fork: have %d, want ", header.ExtDataGasUsed) + if headerExtra.ExtDataGasUsed != nil { + return fmt.Errorf("invalid extDataGasUsed before fork: have %d, want ", headerExtra.ExtDataGasUsed) } return nil } @@ -188,24 +189,24 @@ func (eng *DummyEngine) verifyHeaderGasFields(config *params.ChainConfig, header ApricotPhase4MinBlockGasCost, ApricotPhase4MaxBlockGasCost, blockGasCostStep, - parent.BlockGasCost, + types.GetHeaderExtra(parent).BlockGasCost, parent.Time, header.Time, ) - if header.BlockGasCost == nil { + if headerExtra.BlockGasCost == nil { return errBlockGasCostNil } - if !header.BlockGasCost.IsUint64() { + if !headerExtra.BlockGasCost.IsUint64() { return errBlockGasCostTooLarge } - if header.BlockGasCost.Cmp(expectedBlockGasCost) != 0 { - return fmt.Errorf("invalid block gas cost: have %d, want %d", header.BlockGasCost, expectedBlockGasCost) + if headerExtra.BlockGasCost.Cmp(expectedBlockGasCost) != 0 { + return fmt.Errorf("invalid block gas cost: have %d, want %d", headerExtra.BlockGasCost, expectedBlockGasCost) } // ExtDataGasUsed correctness is checked during block validation // (when the validator has access to the block contents) - if header.ExtDataGasUsed == nil { + if headerExtra.ExtDataGasUsed == nil { return errExtDataGasUsedNil } - if !header.ExtDataGasUsed.IsUint64() { + if !headerExtra.ExtDataGasUsed.IsUint64() { return errExtDataGasUsedTooLarge } return nil @@ -417,7 +418,7 @@ func (eng *DummyEngine) Finalize(chain consensus.ChainHeaderReader, block *types ApricotPhase4MinBlockGasCost, ApricotPhase4MaxBlockGasCost, blockGasCostStep, - parent.BlockGasCost, + types.GetHeaderExtra(parent).BlockGasCost, parent.Time, block.Time(), ) // Verify the BlockGasCost set in the header matches the calculated value. @@ -454,28 +455,29 @@ func (eng *DummyEngine) FinalizeAndAssemble(chain consensus.ChainHeaderReader, h } } chainConfigExtra := params.GetExtra(chain.Config()) + headerExtra := types.GetHeaderExtra(header) if chainConfigExtra.IsApricotPhase4(header.Time) { - header.ExtDataGasUsed = extDataGasUsed - if header.ExtDataGasUsed == nil { - header.ExtDataGasUsed = new(big.Int).Set(common.Big0) + headerExtra.ExtDataGasUsed = extDataGasUsed + if headerExtra.ExtDataGasUsed == nil { + headerExtra.ExtDataGasUsed = new(big.Int).Set(common.Big0) } blockGasCostStep := ApricotPhase4BlockGasCostStep if chainConfigExtra.IsApricotPhase5(header.Time) { blockGasCostStep = ApricotPhase5BlockGasCostStep } // Calculate the required block gas cost for this block. - header.BlockGasCost = calcBlockGasCost( + headerExtra.BlockGasCost = calcBlockGasCost( ApricotPhase4TargetBlockRate, ApricotPhase4MinBlockGasCost, ApricotPhase4MaxBlockGasCost, blockGasCostStep, - parent.BlockGasCost, + types.GetHeaderExtra(parent).BlockGasCost, parent.Time, header.Time, ) // Verify that this block covers the block fee. if err := eng.verifyBlockFee( header.BaseFee, - header.BlockGasCost, + headerExtra.BlockGasCost, txs, receipts, contribution, diff --git a/consensus/dummy/dynamic_fees.go b/consensus/dummy/dynamic_fees.go index 0d3355a97f..c5def40eb8 100644 --- a/consensus/dummy/dynamic_fees.go +++ b/consensus/dummy/dynamic_fees.go @@ -90,14 +90,15 @@ func CalcBaseFee(config *params.ChainConfig, parent *types.Header, timestamp uin // gas in. if roll < rollupWindow { var blockGasCost, parentExtraStateGasUsed uint64 + parentExtra := types.GetHeaderExtra(parent) switch { case isApricotPhase5: // [blockGasCost] has been removed in AP5, so it is left as 0. // At the start of a new network, the parent // may not have a populated [ExtDataGasUsed]. - if parent.ExtDataGasUsed != nil { - parentExtraStateGasUsed = parent.ExtDataGasUsed.Uint64() + if parentExtra.ExtDataGasUsed != nil { + parentExtraStateGasUsed = parentExtra.ExtDataGasUsed.Uint64() } case isApricotPhase4: // The [blockGasCost] is paid by the effective tips in the block using @@ -107,14 +108,14 @@ func CalcBaseFee(config *params.ChainConfig, parent *types.Header, timestamp uin ApricotPhase4MinBlockGasCost, ApricotPhase4MaxBlockGasCost, ApricotPhase4BlockGasCostStep, - parent.BlockGasCost, + parentExtra.BlockGasCost, parent.Time, timestamp, ).Uint64() // On the boundary of AP3 and AP4 or at the start of a new network, the parent // may not have a populated [ExtDataGasUsed]. - if parent.ExtDataGasUsed != nil { - parentExtraStateGasUsed = parent.ExtDataGasUsed.Uint64() + if parentExtra.ExtDataGasUsed != nil { + parentExtraStateGasUsed = parentExtra.ExtDataGasUsed.Uint64() } default: blockGasCost = ApricotPhase3BlockGasFee @@ -339,21 +340,22 @@ func MinRequiredTip(config *params.ChainConfig, header *types.Header) (*big.Int, if header.BaseFee == nil { return nil, errBaseFeeNil } - if header.BlockGasCost == nil { + headerExtra := types.GetHeaderExtra(header) + if headerExtra.BlockGasCost == nil { return nil, errBlockGasCostNil } - if header.ExtDataGasUsed == nil { + if headerExtra.ExtDataGasUsed == nil { return nil, errExtDataGasUsedNil } // minTip = requiredBlockFee/blockGasUsage requiredBlockFee := new(big.Int).Mul( - header.BlockGasCost, + headerExtra.BlockGasCost, header.BaseFee, ) blockGasUsage := new(big.Int).Add( new(big.Int).SetUint64(header.GasUsed), - header.ExtDataGasUsed, + headerExtra.ExtDataGasUsed, ) return new(big.Int).Div(requiredBlockFee, blockGasUsage), nil } diff --git a/consensus/dummy/dynamic_fees_test.go b/consensus/dummy/dynamic_fees_test.go index 69f148eea4..bb02e85b0a 100644 --- a/consensus/dummy/dynamic_fees_test.go +++ b/consensus/dummy/dynamic_fees_test.go @@ -425,14 +425,15 @@ func TestCalcBaseFeeAP4(t *testing.T) { nextExtraData, nextBaseFee, err = CalcBaseFee(params.TestApricotPhase4Config, extDataHeader, block.timestamp) assert.NoError(t, err) log.Info("Update", "baseFee (w/extData)", nextBaseFee) - extDataHeader = &types.Header{ - Time: block.timestamp, - GasUsed: block.gasUsed, - Number: big.NewInt(int64(index) + 1), - BaseFee: nextBaseFee, - Extra: nextExtraData, + extDataHeader = types.WithHeaderExtra(&types.Header{ + Time: block.timestamp, + GasUsed: block.gasUsed, + Number: big.NewInt(int64(index) + 1), + BaseFee: nextBaseFee, + Extra: nextExtraData, + }, &types.HeaderExtra{ ExtDataGasUsed: block.extDataGasUsed, - } + }) assert.Equal(t, event.extDataFeeGreater, extDataHeader.BaseFee.Cmp(header.BaseFee) == 1, "unexpected cmp for index %d", index) } diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 64179f4290..fab8ed0f1f 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -376,8 +376,8 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr header.Extra, header.BaseFee, _ = dummy.CalcBaseFee(config, parent.Header(), header.Time) } if params.GetExtra(config).IsApricotPhase4(header.Time) { - header.BlockGasCost = big.NewInt(0) - header.ExtDataGasUsed = big.NewInt(0) + types.GetHeaderExtra(header).BlockGasCost = big.NewInt(0) + types.GetHeaderExtra(header).ExtDataGasUsed = big.NewInt(0) } var receipts []*types.Receipt // The post-state result doesn't need to be correct (this is a bad block), but we do need something there diff --git a/core/types/block.go b/core/types/block.go index b47048fa62..babdd5f6f4 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -31,132 +31,12 @@ import ( "encoding/binary" "io" "math/big" - "reflect" "sync/atomic" "github.com/ava-labs/libevm/common" - "github.com/ava-labs/libevm/common/hexutil" "github.com/ava-labs/libevm/rlp" ) -// A BlockNonce is a 64-bit hash which proves (combined with the -// mix-hash) that a sufficient amount of computation has been carried -// out on a block. -type BlockNonce [8]byte - -// EncodeNonce converts the given integer to a block nonce. -func EncodeNonce(i uint64) BlockNonce { - var n BlockNonce - binary.BigEndian.PutUint64(n[:], i) - return n -} - -// Uint64 returns the integer value of a block nonce. -func (n BlockNonce) Uint64() uint64 { - return binary.BigEndian.Uint64(n[:]) -} - -// MarshalText encodes n as a hex string with 0x prefix. -func (n BlockNonce) MarshalText() ([]byte, error) { - return hexutil.Bytes(n[:]).MarshalText() -} - -// UnmarshalText implements encoding.TextUnmarshaler. -func (n *BlockNonce) UnmarshalText(input []byte) error { - return hexutil.UnmarshalFixedText("BlockNonce", input, n[:]) -} - -//go:generate go run github.com/fjl/gencodec -type Header -field-override headerMarshaling -out gen_header_json.go -//go:generate go run github.com/ava-labs/libevm/rlp/rlpgen -type Header -out gen_header_rlp.go - -// Header represents a block header in the Ethereum blockchain. -type Header struct { - ParentHash common.Hash `json:"parentHash" gencodec:"required"` - UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"` - Coinbase common.Address `json:"miner" gencodec:"required"` - Root common.Hash `json:"stateRoot" gencodec:"required"` - TxHash common.Hash `json:"transactionsRoot" gencodec:"required"` - ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"` - Bloom Bloom `json:"logsBloom" gencodec:"required"` - Difficulty *big.Int `json:"difficulty" gencodec:"required"` - Number *big.Int `json:"number" gencodec:"required"` - GasLimit uint64 `json:"gasLimit" gencodec:"required"` - GasUsed uint64 `json:"gasUsed" gencodec:"required"` - Time uint64 `json:"timestamp" gencodec:"required"` - Extra []byte `json:"extraData" gencodec:"required"` - MixDigest common.Hash `json:"mixHash"` - Nonce BlockNonce `json:"nonce"` - ExtDataHash common.Hash `json:"extDataHash" gencodec:"required"` - - // BaseFee was added by EIP-1559 and is ignored in legacy headers. - BaseFee *big.Int `json:"baseFeePerGas" rlp:"optional"` - - // ExtDataGasUsed was added by Apricot Phase 4 and is ignored in legacy - // headers. - // - // It is not a uint64 like GasLimit or GasUsed because it is not possible to - // correctly encode this field optionally with uint64. - ExtDataGasUsed *big.Int `json:"extDataGasUsed" rlp:"optional"` - - // BlockGasCost was added by Apricot Phase 4 and is ignored in legacy - // headers. - BlockGasCost *big.Int `json:"blockGasCost" rlp:"optional"` - - // BlobGasUsed was added by EIP-4844 and is ignored in legacy headers. - BlobGasUsed *uint64 `json:"blobGasUsed" rlp:"optional"` - - // ExcessBlobGas was added by EIP-4844 and is ignored in legacy headers. - ExcessBlobGas *uint64 `json:"excessBlobGas" rlp:"optional"` - - // ParentBeaconRoot was added by EIP-4788 and is ignored in legacy headers. - ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"` -} - -// field type overrides for gencodec -type headerMarshaling struct { - Difficulty *hexutil.Big - Number *hexutil.Big - GasLimit hexutil.Uint64 - GasUsed hexutil.Uint64 - Time hexutil.Uint64 - Extra hexutil.Bytes - BaseFee *hexutil.Big - ExtDataGasUsed *hexutil.Big - BlockGasCost *hexutil.Big - Hash common.Hash `json:"hash"` // adds call to Hash() in MarshalJSON - BlobGasUsed *hexutil.Uint64 - ExcessBlobGas *hexutil.Uint64 -} - -// Hash returns the block hash of the header, which is simply the keccak256 hash of its -// RLP encoding. -func (h *Header) Hash() common.Hash { - return rlpHash(h) -} - -var headerSize = common.StorageSize(reflect.TypeOf(Header{}).Size()) - -// Size returns the approximate memory used by all internal contents. It is used -// to approximate and limit the memory consumption of various caches. -func (h *Header) Size() common.StorageSize { - var baseFeeBits int - if h.BaseFee != nil { - baseFeeBits = h.BaseFee.BitLen() - } - return headerSize + common.StorageSize(len(h.Extra)+(h.Difficulty.BitLen()+h.Number.BitLen()+baseFeeBits)/8) -} - -// EmptyBody returns true if there is no additional 'body' to complete the header -// that is: no transactions and no uncles. -func (h *Header) EmptyBody() bool { - return h.TxHash == EmptyTxsHash && h.UncleHash == EmptyUncleHash -} - -// EmptyReceipts returns true if there are no receipts for this header/block. -func (h *Header) EmptyReceipts() bool { - return h.ReceiptHash == EmptyReceiptsHash -} - // 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 { @@ -249,6 +129,12 @@ func NewBlock( // CopyHeader creates a deep copy of a block header. func CopyHeader(h *Header) *Header { cpy := *h + hExtra := GetHeaderExtra(h) + cpyExtra := &HeaderExtra{ + ExtDataHash: hExtra.ExtDataHash, + } + cpy = *WithHeaderExtra(&cpy, cpyExtra) + if cpy.Difficulty = new(big.Int); h.Difficulty != nil { cpy.Difficulty.Set(h.Difficulty) } @@ -258,11 +144,11 @@ func CopyHeader(h *Header) *Header { if h.BaseFee != nil { cpy.BaseFee = new(big.Int).Set(h.BaseFee) } - if h.ExtDataGasUsed != nil { - cpy.ExtDataGasUsed = new(big.Int).Set(h.ExtDataGasUsed) + if hExtra.ExtDataGasUsed != nil { + cpyExtra.ExtDataGasUsed = new(big.Int).Set(hExtra.ExtDataGasUsed) } - if h.BlockGasCost != nil { - cpy.BlockGasCost = new(big.Int).Set(h.BlockGasCost) + if hExtra.BlockGasCost != nil { + cpyExtra.BlockGasCost = new(big.Int).Set(hExtra.BlockGasCost) } if len(h.Extra) > 0 { cpy.Extra = make([]byte, len(h.Extra)) @@ -380,10 +266,10 @@ func (b *Block) BlobGasUsed() *uint64 { } func (b *Block) BlockGasCost() *big.Int { - if b.header.BlockGasCost == nil { + if GetHeaderExtra(b.header).BlockGasCost == nil { return nil } - return new(big.Int).Set(b.header.BlockGasCost) + return new(big.Int).Set(GetHeaderExtra(b.header).BlockGasCost) } // Size returns the true RLP encoded storage size of the block, either by encoding diff --git a/core/types/block_ext.go b/core/types/block_ext.go index c186e5d241..40ff4c268a 100644 --- a/core/types/block_ext.go +++ b/core/types/block_ext.go @@ -28,7 +28,7 @@ func (b *Block) setExtData(data []byte, recalc bool) { b.extdata = &_data copy(*b.extdata, data) if recalc { - b.header.ExtDataHash = CalcExtDataHash(*b.extdata) + GetHeaderExtra(b.header).ExtDataHash = CalcExtDataHash(*b.extdata) } } @@ -44,10 +44,10 @@ func (b *Block) Version() uint32 { } func (b *Block) ExtDataGasUsed() *big.Int { - if b.header.ExtDataGasUsed == nil { + if GetHeaderExtra(b.header).ExtDataGasUsed == nil { return nil } - return new(big.Int).Set(b.header.ExtDataGasUsed) + return new(big.Int).Set(GetHeaderExtra(b.header).ExtDataGasUsed) } func CalcExtDataHash(extdata []byte) common.Hash { diff --git a/core/types/block_test.go b/core/types/block_test.go index 75bb428853..95546c83c3 100644 --- a/core/types/block_test.go +++ b/core/types/block_test.go @@ -69,7 +69,7 @@ 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", block.header.ExtDataHash, common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")) + check("ExtDataHash", GetHeaderExtra(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)) @@ -177,7 +177,7 @@ 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", block.header.ExtDataHash, common.HexToHash("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")) + check("ExtDataHash", GetHeaderExtra(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)) @@ -252,7 +252,7 @@ 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", block.header.ExtDataHash, common.HexToHash("296ff3bfdebf7c4b1fb71f589d69ed03b1c59b278d1780d54dc86ea7cb87cf17")) + check("ExtDataHash", GetHeaderExtra(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)) diff --git a/core/types/gen_header_json.go b/core/types/gen_header_json.go index 0c1f588944..971f37109b 100644 --- a/core/types/gen_header_json.go +++ b/core/types/gen_header_json.go @@ -9,38 +9,39 @@ import ( "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/common/hexutil" + "github.com/ava-labs/libevm/core/types" ) var _ = (*headerMarshaling)(nil) -// MarshalJSON marshals as JSON. -func (h Header) MarshalJSON() ([]byte, error) { - type Header struct { - ParentHash common.Hash `json:"parentHash" gencodec:"required"` - UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"` - Coinbase common.Address `json:"miner" gencodec:"required"` - Root common.Hash `json:"stateRoot" gencodec:"required"` - TxHash common.Hash `json:"transactionsRoot" gencodec:"required"` - ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"` - Bloom Bloom `json:"logsBloom" gencodec:"required"` - Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"` - Number *hexutil.Big `json:"number" gencodec:"required"` - GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"` - GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"` - Time hexutil.Uint64 `json:"timestamp" gencodec:"required"` - Extra hexutil.Bytes `json:"extraData" gencodec:"required"` - MixDigest common.Hash `json:"mixHash"` - Nonce BlockNonce `json:"nonce"` - ExtDataHash common.Hash `json:"extDataHash" gencodec:"required"` - BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"` - ExtDataGasUsed *hexutil.Big `json:"extDataGasUsed" rlp:"optional"` - BlockGasCost *hexutil.Big `json:"blockGasCost" rlp:"optional"` - BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed" rlp:"optional"` - ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas" rlp:"optional"` - ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"` - Hash common.Hash `json:"hash"` - } - var enc Header +// EncodeJSON marshals as JSON. +func (h HeaderSerializable) EncodeJSON() ([]byte, error) { + type HeaderSerializable struct { + ParentHash common.Hash `json:"parentHash" gencodec:"required"` + UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"` + Coinbase common.Address `json:"miner" gencodec:"required"` + Root common.Hash `json:"stateRoot" gencodec:"required"` + TxHash common.Hash `json:"transactionsRoot" gencodec:"required"` + ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"` + Bloom types.Bloom `json:"logsBloom" gencodec:"required"` + Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"` + Number *hexutil.Big `json:"number" gencodec:"required"` + GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"` + GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"` + Time hexutil.Uint64 `json:"timestamp" gencodec:"required"` + Extra hexutil.Bytes `json:"extraData" gencodec:"required"` + MixDigest common.Hash `json:"mixHash"` + Nonce types.BlockNonce `json:"nonce"` + ExtDataHash common.Hash `json:"extDataHash" gencodec:"required"` + BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"` + ExtDataGasUsed *hexutil.Big `json:"extDataGasUsed" rlp:"optional"` + BlockGasCost *hexutil.Big `json:"blockGasCost" rlp:"optional"` + BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed" rlp:"optional"` + ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas" rlp:"optional"` + ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"` + Hash common.Hash `json:"hash"` + } + var enc HeaderSerializable enc.ParentHash = h.ParentHash enc.UncleHash = h.UncleHash enc.Coinbase = h.Coinbase @@ -67,86 +68,86 @@ func (h Header) MarshalJSON() ([]byte, error) { return json.Marshal(&enc) } -// UnmarshalJSON unmarshals from JSON. -func (h *Header) UnmarshalJSON(input []byte) error { - type Header struct { - ParentHash *common.Hash `json:"parentHash" gencodec:"required"` - UncleHash *common.Hash `json:"sha3Uncles" gencodec:"required"` - Coinbase *common.Address `json:"miner" gencodec:"required"` - Root *common.Hash `json:"stateRoot" gencodec:"required"` - TxHash *common.Hash `json:"transactionsRoot" gencodec:"required"` - ReceiptHash *common.Hash `json:"receiptsRoot" gencodec:"required"` - Bloom *Bloom `json:"logsBloom" gencodec:"required"` - Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"` - Number *hexutil.Big `json:"number" gencodec:"required"` - GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"` - GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"` - Time *hexutil.Uint64 `json:"timestamp" gencodec:"required"` - Extra *hexutil.Bytes `json:"extraData" gencodec:"required"` - MixDigest *common.Hash `json:"mixHash"` - Nonce *BlockNonce `json:"nonce"` - ExtDataHash *common.Hash `json:"extDataHash" gencodec:"required"` - BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"` - ExtDataGasUsed *hexutil.Big `json:"extDataGasUsed" rlp:"optional"` - BlockGasCost *hexutil.Big `json:"blockGasCost" rlp:"optional"` - BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed" rlp:"optional"` - ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas" rlp:"optional"` - ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"` - } - var dec Header +// DecodeJSON unmarshals from JSON. +func (h *HeaderSerializable) DecodeJSON(input []byte) error { + type HeaderSerializable struct { + ParentHash *common.Hash `json:"parentHash" gencodec:"required"` + UncleHash *common.Hash `json:"sha3Uncles" gencodec:"required"` + Coinbase *common.Address `json:"miner" gencodec:"required"` + Root *common.Hash `json:"stateRoot" gencodec:"required"` + TxHash *common.Hash `json:"transactionsRoot" gencodec:"required"` + ReceiptHash *common.Hash `json:"receiptsRoot" gencodec:"required"` + Bloom *types.Bloom `json:"logsBloom" gencodec:"required"` + Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"` + Number *hexutil.Big `json:"number" gencodec:"required"` + GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"` + GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"` + Time *hexutil.Uint64 `json:"timestamp" gencodec:"required"` + Extra *hexutil.Bytes `json:"extraData" gencodec:"required"` + MixDigest *common.Hash `json:"mixHash"` + Nonce *types.BlockNonce `json:"nonce"` + ExtDataHash *common.Hash `json:"extDataHash" gencodec:"required"` + BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"` + ExtDataGasUsed *hexutil.Big `json:"extDataGasUsed" rlp:"optional"` + BlockGasCost *hexutil.Big `json:"blockGasCost" rlp:"optional"` + BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed" rlp:"optional"` + ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas" rlp:"optional"` + ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"` + } + var dec HeaderSerializable if err := json.Unmarshal(input, &dec); err != nil { return err } if dec.ParentHash == nil { - return errors.New("missing required field 'parentHash' for Header") + return errors.New("missing required field 'parentHash' for HeaderSerializable") } h.ParentHash = *dec.ParentHash if dec.UncleHash == nil { - return errors.New("missing required field 'sha3Uncles' for Header") + return errors.New("missing required field 'sha3Uncles' for HeaderSerializable") } h.UncleHash = *dec.UncleHash if dec.Coinbase == nil { - return errors.New("missing required field 'miner' for Header") + return errors.New("missing required field 'miner' for HeaderSerializable") } h.Coinbase = *dec.Coinbase if dec.Root == nil { - return errors.New("missing required field 'stateRoot' for Header") + return errors.New("missing required field 'stateRoot' for HeaderSerializable") } h.Root = *dec.Root if dec.TxHash == nil { - return errors.New("missing required field 'transactionsRoot' for Header") + return errors.New("missing required field 'transactionsRoot' for HeaderSerializable") } h.TxHash = *dec.TxHash if dec.ReceiptHash == nil { - return errors.New("missing required field 'receiptsRoot' for Header") + return errors.New("missing required field 'receiptsRoot' for HeaderSerializable") } h.ReceiptHash = *dec.ReceiptHash if dec.Bloom == nil { - return errors.New("missing required field 'logsBloom' for Header") + return errors.New("missing required field 'logsBloom' for HeaderSerializable") } h.Bloom = *dec.Bloom if dec.Difficulty == nil { - return errors.New("missing required field 'difficulty' for Header") + return errors.New("missing required field 'difficulty' for HeaderSerializable") } h.Difficulty = (*big.Int)(dec.Difficulty) if dec.Number == nil { - return errors.New("missing required field 'number' for Header") + return errors.New("missing required field 'number' for HeaderSerializable") } h.Number = (*big.Int)(dec.Number) if dec.GasLimit == nil { - return errors.New("missing required field 'gasLimit' for Header") + return errors.New("missing required field 'gasLimit' for HeaderSerializable") } h.GasLimit = uint64(*dec.GasLimit) if dec.GasUsed == nil { - return errors.New("missing required field 'gasUsed' for Header") + return errors.New("missing required field 'gasUsed' for HeaderSerializable") } h.GasUsed = uint64(*dec.GasUsed) if dec.Time == nil { - return errors.New("missing required field 'timestamp' for Header") + return errors.New("missing required field 'timestamp' for HeaderSerializable") } h.Time = uint64(*dec.Time) if dec.Extra == nil { - return errors.New("missing required field 'extraData' for Header") + return errors.New("missing required field 'extraData' for HeaderSerializable") } h.Extra = *dec.Extra if dec.MixDigest != nil { @@ -156,7 +157,7 @@ func (h *Header) UnmarshalJSON(input []byte) error { h.Nonce = *dec.Nonce } if dec.ExtDataHash == nil { - return errors.New("missing required field 'extDataHash' for Header") + return errors.New("missing required field 'extDataHash' for HeaderSerializable") } h.ExtDataHash = *dec.ExtDataHash if dec.BaseFee != nil { diff --git a/core/types/gen_header_rlp.go b/core/types/gen_header_rlp.go index e7c98e851f..a2641fb4b3 100644 --- a/core/types/gen_header_rlp.go +++ b/core/types/gen_header_rlp.go @@ -5,7 +5,7 @@ package types import "github.com/ava-labs/libevm/rlp" import "io" -func (obj *Header) EncodeRLP(_w io.Writer) error { +func (obj *HeaderSerializable) EncodeRLP(_w io.Writer) error { w := rlp.NewEncoderBuffer(_w) _tmp0 := w.List() w.WriteBytes(obj.ParentHash[:]) diff --git a/core/types/header_ext.go b/core/types/header_ext.go index 1096777d6f..a32dc43c92 100644 --- a/core/types/header_ext.go +++ b/core/types/header_ext.go @@ -5,32 +5,201 @@ package types import ( "io" + "math/big" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" ethtypes "github.com/ava-labs/libevm/core/types" "github.com/ava-labs/libevm/rlp" ) +func GetHeaderExtra(h *Header) *HeaderExtra { + return extras.Header.Get(h) +} + +func WithHeaderExtra(h *Header, extra *HeaderExtra) *Header { + extras.Header.Set(h, extra) + return h +} + // HeaderExtra is a struct that contains extra fields used by Avalanche // in the block header. +// This type uses [HeaderSerializable] to encode and decode the extra fields +// along with the upstream type for compatibility with existing network blocks. type HeaderExtra struct { + ExtDataHash common.Hash + ExtDataGasUsed *big.Int + BlockGasCost *big.Int } func (h *HeaderExtra) EncodeRLP(eth *ethtypes.Header, writer io.Writer) error { - panic("not implemented") + temp := new(HeaderSerializable) + + temp.updateFromEth(eth) + temp.updateFromExtras(h) + + return rlp.Encode(writer, temp) } func (h *HeaderExtra) DecodeRLP(eth *ethtypes.Header, stream *rlp.Stream) error { - panic("not implemented") + temp := new(HeaderSerializable) + if err := stream.Decode(temp); err != nil { + return err + } + + temp.updateToEth(eth) + temp.updateToExtras(h) + + return nil } -func (h *HeaderExtra) MarshalJSON(eth *ethtypes.Header) ([]byte, error) { - panic("not implemented") +func (h *HeaderExtra) EncodeJSON(eth *ethtypes.Header) ([]byte, error) { + temp := new(HeaderSerializable) + + temp.updateFromEth(eth) + temp.updateFromExtras(h) + + return temp.EncodeJSON() } -func (h *HeaderExtra) UnmarshalJSON(eth *ethtypes.Header, input []byte) error { - panic("not implemented") +func (h *HeaderExtra) DecodeJSON(eth *ethtypes.Header, input []byte) error { + temp := new(HeaderSerializable) + if err := temp.DecodeJSON(input); err != nil { + return err + } + + temp.updateToEth(eth) + temp.updateToExtras(h) + + return nil } func (h *HeaderExtra) PostCopy(dst *ethtypes.Header) { panic("not implemented") } + +func (h *HeaderSerializable) updateFromEth(eth *ethtypes.Header) { + h.ParentHash = eth.ParentHash + h.UncleHash = eth.UncleHash + h.Coinbase = eth.Coinbase + h.Root = eth.Root + h.TxHash = eth.TxHash + h.ReceiptHash = eth.ReceiptHash + h.Bloom = eth.Bloom + h.Difficulty = eth.Difficulty + h.Number = eth.Number + h.GasLimit = eth.GasLimit + h.GasUsed = eth.GasUsed + h.Time = eth.Time + h.Extra = eth.Extra + h.MixDigest = eth.MixDigest + h.Nonce = eth.Nonce + h.BaseFee = eth.BaseFee + h.BlobGasUsed = eth.BlobGasUsed + h.ExcessBlobGas = eth.ExcessBlobGas + h.ParentBeaconRoot = eth.ParentBeaconRoot +} + +func (h *HeaderSerializable) updateToEth(eth *ethtypes.Header) { + eth.ParentHash = h.ParentHash + eth.UncleHash = h.UncleHash + eth.Coinbase = h.Coinbase + eth.Root = h.Root + eth.TxHash = h.TxHash + eth.ReceiptHash = h.ReceiptHash + eth.Bloom = h.Bloom + eth.Difficulty = h.Difficulty + eth.Number = h.Number + eth.GasLimit = h.GasLimit + eth.GasUsed = h.GasUsed + eth.Time = h.Time + eth.Extra = h.Extra + eth.MixDigest = h.MixDigest + eth.Nonce = h.Nonce + eth.BaseFee = h.BaseFee + eth.BlobGasUsed = h.BlobGasUsed + eth.ExcessBlobGas = h.ExcessBlobGas + eth.ParentBeaconRoot = h.ParentBeaconRoot +} + +func (h *HeaderSerializable) updateFromExtras(extras *HeaderExtra) { + h.ExtDataHash = extras.ExtDataHash + h.ExtDataGasUsed = extras.ExtDataGasUsed + h.BlockGasCost = extras.BlockGasCost +} + +func (h *HeaderSerializable) updateToExtras(extras *HeaderExtra) { + extras.ExtDataHash = h.ExtDataHash + extras.ExtDataGasUsed = h.ExtDataGasUsed + extras.BlockGasCost = h.BlockGasCost +} + +//go:generate go run github.com/fjl/gencodec -type HeaderSerializable -field-override headerMarshaling -out gen_header_json.go +//go:generate go run github.com/ava-labs/libevm/rlp/rlpgen -type HeaderSerializable -out gen_header_rlp.go + +// HeaderSerializable defines the header of a block in the Ethereum blockchain, +// as it is to be serialized into RLP and JSON. Note it must be exported so that +// rlpgen can generate the serialization code from it. +type HeaderSerializable struct { + ParentHash common.Hash `json:"parentHash" gencodec:"required"` + UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"` + Coinbase common.Address `json:"miner" gencodec:"required"` + Root common.Hash `json:"stateRoot" gencodec:"required"` + TxHash common.Hash `json:"transactionsRoot" gencodec:"required"` + ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"` + Bloom Bloom `json:"logsBloom" gencodec:"required"` + Difficulty *big.Int `json:"difficulty" gencodec:"required"` + Number *big.Int `json:"number" gencodec:"required"` + GasLimit uint64 `json:"gasLimit" gencodec:"required"` + GasUsed uint64 `json:"gasUsed" gencodec:"required"` + Time uint64 `json:"timestamp" gencodec:"required"` + Extra []byte `json:"extraData" gencodec:"required"` + MixDigest common.Hash `json:"mixHash"` + Nonce BlockNonce `json:"nonce"` + ExtDataHash common.Hash `json:"extDataHash" gencodec:"required"` + + // BaseFee was added by EIP-1559 and is ignored in legacy headers. + BaseFee *big.Int `json:"baseFeePerGas" rlp:"optional"` + + // ExtDataGasUsed was added by Apricot Phase 4 and is ignored in legacy + // headers. + // + // It is not a uint64 like GasLimit or GasUsed because it is not possible to + // correctly encode this field optionally with uint64. + ExtDataGasUsed *big.Int `json:"extDataGasUsed" rlp:"optional"` + + // BlockGasCost was added by Apricot Phase 4 and is ignored in legacy + // headers. + BlockGasCost *big.Int `json:"blockGasCost" rlp:"optional"` + + // BlobGasUsed was added by EIP-4844 and is ignored in legacy headers. + BlobGasUsed *uint64 `json:"blobGasUsed" rlp:"optional"` + + // ExcessBlobGas was added by EIP-4844 and is ignored in legacy headers. + ExcessBlobGas *uint64 `json:"excessBlobGas" rlp:"optional"` + + // ParentBeaconRoot was added by EIP-4788 and is ignored in legacy headers. + ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"` +} + +// field type overrides for gencodec +type headerMarshaling struct { + Difficulty *hexutil.Big + Number *hexutil.Big + GasLimit hexutil.Uint64 + GasUsed hexutil.Uint64 + Time hexutil.Uint64 + Extra hexutil.Bytes + BaseFee *hexutil.Big + ExtDataGasUsed *hexutil.Big + BlockGasCost *hexutil.Big + Hash common.Hash `json:"hash"` // adds call to Hash() in MarshalJSON + BlobGasUsed *hexutil.Uint64 + ExcessBlobGas *hexutil.Uint64 +} + +// Hash returns the block hash of the header, which is simply the keccak256 hash of its +// RLP encoding. +func (h *HeaderSerializable) Hash() common.Hash { + return rlpHash(h) +} diff --git a/core/types/imports.go b/core/types/imports.go index 552a501f30..cc25fa9a8e 100644 --- a/core/types/imports.go +++ b/core/types/imports.go @@ -15,8 +15,10 @@ type ( AccessTuple = ethtypes.AccessTuple BlobTx = ethtypes.BlobTx BlobTxSidecar = ethtypes.BlobTxSidecar + BlockNonce = ethtypes.BlockNonce Bloom = ethtypes.Bloom DynamicFeeTx = ethtypes.DynamicFeeTx + Header = ethtypes.Header HomesteadSigner = ethtypes.HomesteadSigner LegacyTx = ethtypes.LegacyTx Receipt = ethtypes.Receipt @@ -50,6 +52,7 @@ var ( BloomLookup = ethtypes.BloomLookup BytesToBloom = ethtypes.BytesToBloom CreateBloom = ethtypes.CreateBloom + EncodeNonce = ethtypes.EncodeNonce FullAccount = ethtypes.FullAccount FullAccountRLP = ethtypes.FullAccountRLP NewContractCreation = ethtypes.NewContractCreation diff --git a/core/types/libevm.go b/core/types/libevm.go index c6dffc51d7..fab0434afd 100644 --- a/core/types/libevm.go +++ b/core/types/libevm.go @@ -8,7 +8,7 @@ import ( ) var extras = ethtypes.RegisterExtras[ - ethtypes.NOOPHeaderHooks, *ethtypes.NOOPHeaderHooks, + HeaderExtra, *HeaderExtra, ethtypes.NOOPBodyHooks, *ethtypes.NOOPBodyHooks, isMultiCoin, ]() diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index a39fd3fbef..2458511a82 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1225,6 +1225,7 @@ func (s *BlockChainAPI) EstimateGas(ctx context.Context, args TransactionArgs, b // RPCMarshalHeader converts the given header to the RPC output . func RPCMarshalHeader(head *types.Header) map[string]interface{} { + headExtra := types.GetHeaderExtra(head) result := map[string]interface{}{ "number": (*hexutil.Big)(head.Number), "hash": head.Hash(), @@ -1242,16 +1243,16 @@ func RPCMarshalHeader(head *types.Header) map[string]interface{} { "timestamp": hexutil.Uint64(head.Time), "transactionsRoot": head.TxHash, "receiptsRoot": head.ReceiptHash, - "extDataHash": head.ExtDataHash, + "extDataHash": headExtra.ExtDataHash, } if head.BaseFee != nil { result["baseFeePerGas"] = (*hexutil.Big)(head.BaseFee) } - if head.ExtDataGasUsed != nil { - result["extDataGasUsed"] = (*hexutil.Big)(head.ExtDataGasUsed) + if headExtra.ExtDataGasUsed != nil { + result["extDataGasUsed"] = (*hexutil.Big)(headExtra.ExtDataGasUsed) } - if head.BlockGasCost != nil { - result["blockGasCost"] = (*hexutil.Big)(head.BlockGasCost) + if headExtra.BlockGasCost != nil { + result["blockGasCost"] = (*hexutil.Big)(headExtra.BlockGasCost) } if head.BlobGasUsed != nil { result["blobGasUsed"] = hexutil.Uint64(*head.BlobGasUsed) diff --git a/plugin/evm/block_verification.go b/plugin/evm/block_verification.go index 9b6eeaae65..aeb0382585 100644 --- a/plugin/evm/block_verification.go +++ b/plugin/evm/block_verification.go @@ -73,15 +73,16 @@ func (v blockValidator) SyntacticVerify(b *Block, rules params.Rules) error { } // Verify the ExtDataHash field + headerExtra := types.GetHeaderExtra(ethHeader) if rulesExtra.IsApricotPhase1 { - if hash := types.CalcExtDataHash(b.ethBlock.ExtData()); ethHeader.ExtDataHash != hash { - return fmt.Errorf("extra data hash mismatch: have %x, want %x", ethHeader.ExtDataHash, hash) + if hash := types.CalcExtDataHash(b.ethBlock.ExtData()); headerExtra.ExtDataHash != hash { + return fmt.Errorf("extra data hash mismatch: have %x, want %x", headerExtra.ExtDataHash, hash) } } else { - if ethHeader.ExtDataHash != (common.Hash{}) { + if headerExtra.ExtDataHash != (common.Hash{}) { return fmt.Errorf( "expected ExtDataHash to be empty but got %x", - ethHeader.ExtDataHash, + headerExtra.ExtDataHash, ) } } @@ -222,16 +223,16 @@ func (v blockValidator) SyntacticVerify(b *Block, rules params.Rules) error { // If we are in ApricotPhase4, ensure that ExtDataGasUsed is populated correctly. if rulesExtra.IsApricotPhase4 { // Make sure ExtDataGasUsed is not nil and correct - if ethHeader.ExtDataGasUsed == nil { + if headerExtra.ExtDataGasUsed == nil { return errNilExtDataGasUsedApricotPhase4 } if rulesExtra.IsApricotPhase5 { - if ethHeader.ExtDataGasUsed.Cmp(params.AtomicGasLimit) == 1 { - return fmt.Errorf("too large extDataGasUsed: %d", ethHeader.ExtDataGasUsed) + if headerExtra.ExtDataGasUsed.Cmp(params.AtomicGasLimit) == 1 { + return fmt.Errorf("too large extDataGasUsed: %d", headerExtra.ExtDataGasUsed) } } else { - if !ethHeader.ExtDataGasUsed.IsUint64() { - return fmt.Errorf("too large extDataGasUsed: %d", ethHeader.ExtDataGasUsed) + if !headerExtra.ExtDataGasUsed.IsUint64() { + return fmt.Errorf("too large extDataGasUsed: %d", headerExtra.ExtDataGasUsed) } } var totalGasUsed uint64 @@ -250,15 +251,15 @@ func (v blockValidator) SyntacticVerify(b *Block, rules params.Rules) error { } switch { - case ethHeader.ExtDataGasUsed.Cmp(new(big.Int).SetUint64(totalGasUsed)) != 0: - return fmt.Errorf("invalid extDataGasUsed: have %d, want %d", ethHeader.ExtDataGasUsed, totalGasUsed) + case headerExtra.ExtDataGasUsed.Cmp(new(big.Int).SetUint64(totalGasUsed)) != 0: + return fmt.Errorf("invalid extDataGasUsed: have %d, want %d", headerExtra.ExtDataGasUsed, totalGasUsed) // Make sure BlockGasCost is not nil // NOTE: ethHeader.BlockGasCost correctness is checked in header verification - case ethHeader.BlockGasCost == nil: + case headerExtra.BlockGasCost == nil: return errNilBlockGasCostApricotPhase4 - case !ethHeader.BlockGasCost.IsUint64(): - return fmt.Errorf("too large blockGasCost: %d", ethHeader.BlockGasCost) + case !headerExtra.BlockGasCost.IsUint64(): + return fmt.Errorf("too large blockGasCost: %d", headerExtra.BlockGasCost) } } diff --git a/plugin/evm/vm_test.go b/plugin/evm/vm_test.go index b1acd489b6..c7f5b8c8f8 100644 --- a/plugin/evm/vm_test.go +++ b/plugin/evm/vm_test.go @@ -980,7 +980,7 @@ func testConflictingImportTxs(t *testing.T, genesis string) { } header := types.CopyHeader(validEthBlock.Header()) - header.ExtDataGasUsed.Mul(common.Big2, header.ExtDataGasUsed) + types.GetHeaderExtra(header).ExtDataGasUsed.Mul(common.Big2, types.GetHeaderExtra(header).ExtDataGasUsed) internalConflictBlock := types.NewBlockWithExtData( header, @@ -2450,7 +2450,7 @@ func TestEmptyBlock(t *testing.T) { false, ) - if len(emptyEthBlock.ExtData()) != 0 || emptyEthBlock.Header().ExtDataHash != (common.Hash{}) { + if len(emptyEthBlock.ExtData()) != 0 || types.GetHeaderExtra(emptyEthBlock.Header()).ExtDataHash != (common.Hash{}) { t.Fatalf("emptyEthBlock should not have any extra data") } diff --git a/scripts/lint_allowed_eth_imports.sh b/scripts/lint_allowed_eth_imports.sh index fcbfe7c6f4..731201d26f 100755 --- a/scripts/lint_allowed_eth_imports.sh +++ b/scripts/lint_allowed_eth_imports.sh @@ -11,7 +11,7 @@ set -o pipefail # 4. Print out the difference between the search results and the list of specified allowed package imports from libevm. libevm_regexp='"github.com/ava-labs/libevm/.*"' allow_named_imports='eth\w\+ "' -extra_imports=$(grep -r --include='*.go' --exclude=mocks.go "${libevm_regexp}" -h | grep -v "${allow_named_imports}" | grep -o "${libevm_regexp}" | sort -u | comm -23 - ./scripts/eth-allowed-packages.txt) +extra_imports=$(grep -r --include='*.go' --exclude=mocks.go --exclude='gen_*.go' "${libevm_regexp}" -h | grep -v "${allow_named_imports}" | grep -o "${libevm_regexp}" | sort -u | comm -23 - ./scripts/eth-allowed-packages.txt) if [ -n "${extra_imports}" ]; then echo "new ethereum imports should be added to ./scripts/eth-allowed-packages.txt to prevent accidental imports:" echo "${extra_imports}"