diff --git a/accounts/abi/bind/bind_test.go b/accounts/abi/bind/bind_test.go index c1035f6b8a..649b3178da 100644 --- a/accounts/abi/bind/bind_test.go +++ b/accounts/abi/bind/bind_test.go @@ -2179,6 +2179,11 @@ 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-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) + } tidier := exec.Command(gocmd, "mod", "tidy", "-compat=1.22") tidier.Dir = pkg if out, err := tidier.CombinedOutput(); err != nil { diff --git a/consensus/dummy/consensus.go b/consensus/dummy/consensus.go index 822ea8fe22..c4422d9edd 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.HeaderExtras(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.HeaderExtras(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 @@ -403,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 @@ -417,17 +418,17 @@ func (eng *DummyEngine) Finalize(chain consensus.ChainHeaderReader, block *types ApricotPhase4MinBlockGasCost, ApricotPhase4MaxBlockGasCost, blockGasCostStep, - parent.BlockGasCost, + types.HeaderExtras(parent).BlockGasCost, 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, @@ -454,28 +455,29 @@ func (eng *DummyEngine) FinalizeAndAssemble(chain consensus.ChainHeaderReader, h } } chainConfigExtra := params.GetExtra(chain.Config()) + headerExtra := types.HeaderExtras(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.HeaderExtras(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..e4c332afcf 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.HeaderExtras(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.HeaderExtras(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..6ec6ddaf25 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.WithHeaderExtras(&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/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 dba05750a7..f0072cbbbd 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -522,7 +522,10 @@ 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) + block := types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles) + bodyExtra := types.GetBodyExtra(body) + block = types.WithBlockExtra(block, bodyExtra.Version, bodyExtra.ExtData, false) + 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/state_processor_test.go b/core/state_processor_test.go index 64179f4290..2e611e12f8 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.HeaderExtras(header).BlockGasCost = big.NewInt(0) + types.HeaderExtras(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 f7cf4da018..ab1254f4c2 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -1,458 +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" - "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 { - 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 -// 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 -} - -// CopyHeader creates a deep copy of a block header. -func CopyHeader(h *Header) *Header { - cpy := *h - if cpy.Difficulty = new(big.Int); h.Difficulty != nil { - cpy.Difficulty.Set(h.Difficulty) - } - if cpy.Number = new(big.Int); h.Number != nil { - cpy.Number.Set(h.Number) - } - 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 h.BlockGasCost != nil { - cpy.BlockGasCost = new(big.Int).Set(h.BlockGasCost) - } - if len(h.Extra) > 0 { - cpy.Extra = make([]byte, len(h.Extra)) - copy(cpy.Extra, h.Extra) - } - if h.ExcessBlobGas != nil { - cpy.ExcessBlobGas = new(uint64) - *cpy.ExcessBlobGas = *h.ExcessBlobGas - } - if h.BlobGasUsed != nil { - cpy.BlobGasUsed = new(uint64) - *cpy.BlobGasUsed = *h.BlobGasUsed - } - if h.ParentBeaconRoot != nil { - cpy.ParentBeaconRoot = new(common.Hash) - *cpy.ParentBeaconRoot = *h.ParentBeaconRoot - } - return &cpy -} - -// 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 { - return &Body{b.transactions, b.uncles, b.version, b.extdata} -} - -// 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 b.header.BlockGasCost == nil { - return nil - } - return new(big.Int).Set(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 c186e5d241..6e123beb43 100644 --- a/core/types/block_ext.go +++ b/core/types/block_ext.go @@ -4,50 +4,117 @@ 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) - return b +// 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 *Block) setExtDataHelper(data *[]byte, recalc bool) { - if data == nil { - b.setExtData(nil, recalc) - return +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 } - b.setExtData(*data, recalc) + + in.updateToEth(eth) + in.updateToExtras(b) + + return nil } -func (b *Block) setExtData(data []byte, recalc bool) { - _data := make([]byte, len(data)) - b.extdata = &_data - copy(*b.extdata, data) - if recalc { - b.header.ExtDataHash = CalcExtDataHash(*b.extdata) +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) } -func (b *Block) ExtData() []byte { - if b.extdata == nil { +// 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 BlockExtData(b *Block) []byte { + extras := GetBlockExtra(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 GetBlockExtra(b).version } -func (b *Block) ExtDataGasUsed() *big.Int { - if b.header.ExtDataGasUsed == nil { +func BlockExtDataGasUsed(b *Block) *big.Int { + if HeaderExtras(b.Header()).ExtDataGasUsed == nil { return nil } - return new(big.Int).Set(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 { @@ -62,6 +129,18 @@ func NewBlockWithExtData( hasher TrieHasher, extdata []byte, recalc bool, ) *Block { b := NewBlock(header, txs, uncles, receipts, hasher) - b.setExtData(extdata, recalc) - return b + const version = 0 + return WithBlockExtra(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 75bb428853..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", 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", 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", 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/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/gen_header_json.go b/core/types/gen_header_json.go index 0c1f588944..a584331b8b 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 +func (h HeaderSerializable) MarshalJSON() ([]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 @@ -68,85 +69,85 @@ func (h Header) MarshalJSON() ([]byte, error) { } // 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 +func (h *HeaderSerializable) UnmarshalJSON(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 new file mode 100644 index 0000000000..961ad097c1 --- /dev/null +++ b/core/types/header_ext.go @@ -0,0 +1,216 @@ +// (c) 2025, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +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" +) + +// 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 { + out := new(HeaderSerializable) + + out.updateFromEth(eth) + out.updateFromExtras(h) + + return rlp.Encode(writer, out) +} + +func (h *HeaderExtra) DecodeRLP(eth *ethtypes.Header, stream *rlp.Stream) error { + in := new(HeaderSerializable) + if err := stream.Decode(in); err != nil { + return err + } + + in.updateToEth(eth) + in.updateToExtras(h) + + return nil +} + +//nolint:stdmethods +func (h *HeaderExtra) MarshalJSON(eth *ethtypes.Header) ([]byte, error) { + out := new(HeaderSerializable) + + out.updateFromEth(eth) + out.updateFromExtras(h) + + return out.MarshalJSON() +} + +//nolint:stdmethods +func (h *HeaderExtra) UnmarshalJSON(eth *ethtypes.Header, input []byte) error { + in := new(HeaderSerializable) + if err := in.UnmarshalJSON(input); err != nil { + return err + } + + in.updateToEth(eth) + in.updateToExtras(h) + + return nil +} + +func (h *HeaderExtra) Copy(header *Header) *Header { + extraCopy := &HeaderExtra{ + ExtDataHash: h.ExtDataHash, + } + + if h.BlockGasCost != nil { + extraCopy.BlockGasCost = big.NewInt(0) + extraCopy.BlockGasCost.SetBytes(h.BlockGasCost.Bytes()) + } + + if h.ExtDataGasUsed != nil { + extraCopy.ExtDataGasUsed = big.NewInt(0) + extraCopy.ExtDataGasUsed.SetBytes(h.ExtDataGasUsed.Bytes()) + } + + cpy := ethtypes.CopyEthHeader(header) + return WithHeaderExtras(cpy, extraCopy) +} + +//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. +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) +} + +// updateFromEth updates the HeaderSerializable from the ethtypes.Header +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 +} + +// updateToEth updates the ethtypes.Header from the HeaderSerializable +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 +} + +// updateFromExtras updates the HeaderSerializable from the 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 (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 e286bc9b4c..3e710f520b 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 @@ -23,11 +24,16 @@ type ( BlobTxSidecar = ethtypes.BlobTxSidecar Signer = ethtypes.Signer HomesteadSigner = ethtypes.HomesteadSigner - - Transaction = ethtypes.Transaction - Transactions = ethtypes.Transactions - TxByNonce = ethtypes.TxByNonce - TxData = ethtypes.TxData + StateAccount = ethtypes.StateAccount + SlimAccount = ethtypes.SlimAccount + Header = ethtypes.Header + Block = ethtypes.Block + Blocks = ethtypes.Blocks + BlockNonce = ethtypes.BlockNonce + Transaction = ethtypes.Transaction + Transactions = ethtypes.Transactions + TxByNonce = ethtypes.TxByNonce + TxData = ethtypes.TxData ) // The following constants are used directly as their upstream definitions. @@ -46,12 +52,21 @@ const ( // The following functions are used directly as their upstream definitions. var ( - BloomLookup = ethtypes.BloomLookup - BytesToBloom = ethtypes.BytesToBloom - CreateBloom = ethtypes.CreateBloom - NewReceipt = ethtypes.NewReceipt - NewContractCreation = ethtypes.NewContractCreation - NewTransaction = ethtypes.NewTransaction + 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 + NewEmptyStateAccount = ethtypes.NewEmptyStateAccount + SlimAccountRLP = ethtypes.SlimAccountRLP + FullAccount = ethtypes.FullAccount + FullAccountRLP = ethtypes.FullAccountRLP // Signers NewEIP155Signer = ethtypes.NewEIP155Signer diff --git a/core/types/libevm.go b/core/types/libevm.go new file mode 100644 index 0000000000..2dfb2c528a --- /dev/null +++ b/core/types/libevm.go @@ -0,0 +1,67 @@ +// (c) 2024-2025, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package types + +import ( + ethtypes "github.com/ava-labs/libevm/core/types" +) + +type isMultiCoin bool + +var ( + extras = ethtypes.RegisterExtras[ + HeaderExtra, *HeaderExtra, + BodyExtra, *BodyExtra, + BlockExtra, *BlockExtra, + isMultiCoin]() + IsMultiCoinPayloads = extras.StateAccount +) + +func IsMultiCoin(s ethtypes.StateOrSlimAccount) bool { + return bool(extras.StateAccount.Get(s)) +} + +func HeaderExtras(h *Header) *HeaderExtra { + return extras.Header.Get(h) +} + +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 +} + +func GetBlockExtra(b *Block) *BlockExtra { + return extras.Block.Get(b) +} + +func WithBlockExtra(b *Block, version uint32, extdata *[]byte, recalc bool) *Block { + extras := GetBlockExtra(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 +} diff --git a/core/types/state_account.go b/core/types/state_account.go deleted file mode 100644 index 9af3d4ce15..0000000000 --- a/core/types/state_account.go +++ /dev/null @@ -1,53 +0,0 @@ -// (c) 2019-2021, 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 2021 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 - -import ( - ethtypes "github.com/ava-labs/libevm/core/types" -) - -type ( - // Import these types from the go-ethereum package - StateAccount = ethtypes.StateAccount - SlimAccount = ethtypes.SlimAccount -) - -var ( - // Import these functions from the go-ethereum package - NewEmptyStateAccount = ethtypes.NewEmptyStateAccount - SlimAccountRLP = ethtypes.SlimAccountRLP - FullAccount = ethtypes.FullAccount - FullAccountRLP = ethtypes.FullAccountRLP -) - -type isMultiCoin bool - -var IsMultiCoinPayloads = ethtypes.RegisterExtras[isMultiCoin]() - -func IsMultiCoin(a ethtypes.ExtraPayloadCarrier) bool { - return bool(IsMultiCoinPayloads.FromPayloadCarrier(a)) -} 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..0e2b97dac5 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.WithBlockExtra(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 7b23e789b0..55d7d5d5e7 100644 --- a/go.mod +++ b/go.mod @@ -135,3 +135,5 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect rsc.io/tmplfunc v0.0.3 // indirect ) + +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 2c5b99975c..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 v1.13.14-0.1.0.rc-2 h1:CVbn0hSsPCl6gCkTCnqwuN4vtJgdVbkCqLXzYAE7qF8= -github.com/ava-labs/libevm v1.13.14-0.1.0.rc-2/go.mod h1:yBctIV/wnxXTF38h95943jvpuk4aj07TrjbpoGor6LQ= +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 a39fd3fbef..0aa764c012 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.HeaderExtras(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) @@ -1271,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/nativeasset/contract.go b/nativeasset/contract.go index e08e0d652e..523e55b33c 100644 --- a/nativeasset/contract.go +++ b/nativeasset/contract.go @@ -141,7 +141,7 @@ func (c *NativeAssetCall) Run(accessibleState contract.AccessibleState, caller c stateDB.SubBalanceMultiCoin(caller, assetID, assetAmount) stateDB.AddBalanceMultiCoin(to, assetID, assetAmount) - ret, remainingGas, err = accessibleState.Call(to, callData, remainingGas, new(uint256.Int), vm.WithUNSAFECallerAddressProxying()) + ret, err = accessibleState.Call(to, callData, remainingGas, new(uint256.Int), vm.WithUNSAFECallerAddressProxying()) // When an error was returned by the EVM or when setting the creation code // above we revert to the snapshot and consume any gas remaining. Additionally diff --git a/params/config_extra.go b/params/config_extra.go index a9e5b0bdd9..17cee401e0 100644 --- a/params/config_extra.go +++ b/params/config_extra.go @@ -59,10 +59,10 @@ func SetEthUpgrades(c *ChainConfig) { } func GetExtra(c *ChainConfig) *extras.ChainConfig { - ex := payloads.FromChainConfig(c) + ex := payloads.ChainConfig.Get(c) if ex == nil { ex = &extras.ChainConfig{} - payloads.SetOnChainConfig(c, ex) + payloads.ChainConfig.Set(c, ex) } return ex } @@ -75,7 +75,7 @@ func Copy(c *ChainConfig) ChainConfig { // WithExtra sets the extra payload on `c` and returns the modified argument. func WithExtra(c *ChainConfig, extra *extras.ChainConfig) *ChainConfig { - payloads.SetOnChainConfig(c, extra) + payloads.ChainConfig.Set(c, extra) return c } diff --git a/params/hooks_libevm.go b/params/hooks_libevm.go index b26a7a36b3..759bd189cb 100644 --- a/params/hooks_libevm.go +++ b/params/hooks_libevm.go @@ -16,6 +16,7 @@ import ( "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/vm" "github.com/ava-labs/libevm/libevm" + "github.com/ava-labs/libevm/libevm/legacy" "github.com/holiman/uint256" "golang.org/x/exp/maps" ) @@ -23,7 +24,7 @@ import ( type RulesExtra extras.Rules func GetRulesExtra(r Rules) *extras.Rules { - rules := payloads.PointerFromRules(&r) + rules := payloads.Rules.GetPointer(&r) return (*extras.Rules)(rules) } @@ -125,7 +126,7 @@ func makePrecompile(contract contract.StatefulPrecompiledContract) libevm.Precom } return contract.Run(accessableState, env.Addresses().Caller, env.Addresses().Self, input, suppliedGas, env.ReadOnly()) } - return vm.NewStatefulPrecompile(run) + return vm.NewStatefulPrecompile(legacy.PrecompiledStatefulContract(run).Upgrade()) } func (r RulesExtra) PrecompileOverride(addr common.Address) (libevm.PrecompiledContract, bool) { @@ -171,7 +172,7 @@ func (a accessableState) GetSnowContext() *snow.Context { return GetExtra(a.env.ChainConfig()).SnowCtx } -func (a accessableState) Call(addr common.Address, input []byte, gas uint64, value *uint256.Int, opts ...vm.CallOption) (ret []byte, gasRemaining uint64, _ error) { +func (a accessableState) Call(addr common.Address, input []byte, gas uint64, value *uint256.Int, opts ...vm.CallOption) (ret []byte, err error) { return a.env.Call(addr, input, gas, value, opts...) } 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 9b6eeaae65..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. @@ -73,15 +73,18 @@ 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()); ethHeader.ExtDataHash != hash { - return fmt.Errorf("extra data hash mismatch: have %x, want %x", ethHeader.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 { - 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, ) } } @@ -154,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 @@ -222,16 +225,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 +253,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/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 b1acd489b6..1be3b3b10f 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.HeaderExtras(header).ExtDataGasUsed.Mul(common.Big2, types.HeaderExtras(header).ExtDataGasUsed) internalConflictBlock := types.NewBlockWithExtData( header, @@ -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 || 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/precompile/contract/interfaces.go b/precompile/contract/interfaces.go index 7de1423a02..a1ae9d5682 100644 --- a/precompile/contract/interfaces.go +++ b/precompile/contract/interfaces.go @@ -61,7 +61,7 @@ type AccessibleState interface { GetBlockContext() BlockContext GetSnowContext() *snow.Context GetChainConfig() precompileconfig.ChainConfig - Call(addr common.Address, input []byte, gas uint64, value *uint256.Int, opts ...vm.CallOption) (ret []byte, gasRemaining uint64, _ error) + Call(addr common.Address, input []byte, gas uint64, value *uint256.Int, opts ...vm.CallOption) (ret []byte, _ error) } // ConfigurationBlockContext defines the interface required to configure a precompile. diff --git a/precompile/contract/mocks.go b/precompile/contract/mocks.go index 6a83011623..6da91cc237 100644 --- a/precompile/contract/mocks.go +++ b/precompile/contract/mocks.go @@ -306,7 +306,7 @@ func (m *MockAccessibleState) EXPECT() *MockAccessibleStateMockRecorder { } // Call mocks base method. -func (m *MockAccessibleState) Call(addr common.Address, input []byte, gas uint64, value *uint256.Int, opts ...vm.CallOption) ([]byte, uint64, error) { +func (m *MockAccessibleState) Call(addr common.Address, input []byte, gas uint64, value *uint256.Int, opts ...vm.CallOption) ([]byte, error) { m.ctrl.T.Helper() varargs := []any{addr, input, gas, value} for _, a := range opts { @@ -314,9 +314,8 @@ func (m *MockAccessibleState) Call(addr common.Address, input []byte, gas uint64 } ret := m.ctrl.Call(m, "Call", varargs...) ret0, _ := ret[0].([]byte) - ret1, _ := ret[1].(uint64) - ret2, _ := ret[2].(error) - return ret0, ret1, ret2 + ret1, _ := ret[1].(error) + return ret0, ret1 } // Call indicates an expected call of Call. diff --git a/scripts/eth-allowed-packages.txt b/scripts/eth-allowed-packages.txt index 6f69e52bcd..0f200f77f5 100644 --- a/scripts/eth-allowed-packages.txt +++ b/scripts/eth-allowed-packages.txt @@ -25,6 +25,7 @@ "github.com/ava-labs/libevm/ethdb/pebble" "github.com/ava-labs/libevm/event" "github.com/ava-labs/libevm/libevm" +"github.com/ava-labs/libevm/libevm/legacy" "github.com/ava-labs/libevm/libevm/stateconf" "github.com/ava-labs/libevm/log" "github.com/ava-labs/libevm/params" 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}" diff --git a/scripts/tests.e2e.sh b/scripts/tests.e2e.sh index 85f5bd3d48..e68a0f19d0 100755 --- a/scripts/tests.e2e.sh +++ b/scripts/tests.e2e.sh @@ -45,6 +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-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 {