Skip to content
This repository was archived by the owner on Nov 25, 2025. It is now read-only.

Commit 76eca08

Browse files
committed
feat(core/types): Block hooks for RLP encoding
1 parent 7027a42 commit 76eca08

29 files changed

+233
-398
lines changed

accounts/abi/bind/bind_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2179,7 +2179,7 @@ func golangBindings(t *testing.T, overload bool) {
21792179
if out, err := replacer.CombinedOutput(); err != nil {
21802180
t.Fatalf("failed to replace binding test dependency to current source tree: %v\n%s", err, out)
21812181
}
2182-
replacer = exec.Command(gocmd, "mod", "edit", "-x", "-require", "github.com/ava-labs/libevm@v0.0.0", "-replace", "github.com/ava-labs/libevm=github.com/ava-labs/libevm@v0.0.0-20250121171435-edebe134329f")
2182+
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")
21832183
replacer.Dir = pkg
21842184
if out, err := replacer.CombinedOutput(); err != nil {
21852185
t.Fatalf("failed to replace binding test dependency to current source tree: %v\n%s", err, out)

consensus/dummy/consensus.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ func (eng *DummyEngine) Finalize(chain consensus.ChainHeaderReader, block *types
404404
if extDataGasUsed == nil {
405405
extDataGasUsed = new(big.Int).Set(common.Big0)
406406
}
407-
if blockExtDataGasUsed := block.ExtDataGasUsed(); blockExtDataGasUsed == nil || !blockExtDataGasUsed.IsUint64() || blockExtDataGasUsed.Cmp(extDataGasUsed) != 0 {
407+
if blockExtDataGasUsed := types.BlockExtDataGasUsed(block); blockExtDataGasUsed == nil || !blockExtDataGasUsed.IsUint64() || blockExtDataGasUsed.Cmp(extDataGasUsed) != 0 {
408408
return fmt.Errorf("invalid extDataGasUsed: have %d, want %d", blockExtDataGasUsed, extDataGasUsed)
409409
}
410410
blockGasCostStep := ApricotPhase4BlockGasCostStep
@@ -422,13 +422,13 @@ func (eng *DummyEngine) Finalize(chain consensus.ChainHeaderReader, block *types
422422
parent.Time, block.Time(),
423423
)
424424
// Verify the BlockGasCost set in the header matches the calculated value.
425-
if blockBlockGasCost := block.BlockGasCost(); blockBlockGasCost == nil || !blockBlockGasCost.IsUint64() || blockBlockGasCost.Cmp(blockGasCost) != 0 {
425+
if blockBlockGasCost := types.BlockGasCost(block); blockBlockGasCost == nil || !blockBlockGasCost.IsUint64() || blockBlockGasCost.Cmp(blockGasCost) != 0 {
426426
return fmt.Errorf("invalid blockGasCost: have %d, want %d", blockBlockGasCost, blockGasCost)
427427
}
428428
// Verify the block fee was paid.
429429
if err := eng.verifyBlockFee(
430430
block.BaseFee(),
431-
block.BlockGasCost(),
431+
types.BlockGasCost(block),
432432
block.Transactions(),
433433
receipts,
434434
contribution,

core/blockchain.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1367,7 +1367,7 @@ func (bc *BlockChain) insertBlock(block *types.Block, writes bool) error {
13671367
"parentHash", block.ParentHash(),
13681368
"uncles", len(block.Uncles()), "txs", len(block.Transactions()), "gas", block.GasUsed(),
13691369
"elapsed", common.PrettyDuration(time.Since(start)),
1370-
"root", block.Root(), "baseFeePerGas", block.BaseFee(), "blockGasCost", block.BlockGasCost(),
1370+
"root", block.Root(), "baseFeePerGas", block.BaseFee(), "blockGasCost", types.BlockGasCost(block),
13711371
)
13721372

13731373
processedBlockGasUsedCounter.Inc(int64(block.GasUsed()))

core/genesis.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,8 @@ func (g *Genesis) toBlock(db ethdb.Database, triedb *triedb.Database) *types.Blo
246246
}
247247

248248
// Configure any stateful precompiles that should be enabled in the genesis.
249-
err = ApplyPrecompileActivations(g.Config, nil, types.NewBlockWithHeader(head), statedb)
249+
block := types.NewBlockWithHeader(head)
250+
err = ApplyPrecompileActivations(g.Config, nil, types.WrapWithTimestamp(block), statedb)
250251
if err != nil {
251252
panic(fmt.Sprintf("unable to configure precompiles in genesis block: %v", err))
252253
}

core/rawdb/accessors_chain.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -522,8 +522,10 @@ func ReadBlock(db ethdb.Reader, hash common.Hash, number uint64) *types.Block {
522522
if body == nil {
523523
return nil
524524
}
525+
block := types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles)
525526
bodyExtra := types.GetBodyExtra(body)
526-
return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles).WithExtData(bodyExtra.Version, bodyExtra.ExtData)
527+
block = types.BlockWithExtData(block, bodyExtra.Version, bodyExtra.ExtData)
528+
return block
527529
}
528530

529531
// WriteBlock serializes a block into the database, header and body separately.

core/state_processor.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ func (p *StateProcessor) Process(block *types.Block, parent *types.Header, state
8282
)
8383

8484
// Configure any upgrades that should go into effect during this block.
85-
err := ApplyUpgrades(p.config, &parent.Time, block, statedb)
85+
err := ApplyUpgrades(p.config, &parent.Time, types.WrapWithTimestamp(block), statedb)
8686
if err != nil {
8787
log.Error("failed to configure precompiles processing block", "hash", block.Hash(), "number", block.NumberU64(), "timestamp", block.Time(), "err", err)
8888
return nil, nil, 0, err

core/types/block.go

Lines changed: 0 additions & 299 deletions
Original file line numberDiff line numberDiff line change
@@ -1,300 +1 @@
1-
// (c) 2019-2020, Ava Labs, Inc.
2-
//
3-
// This file is a derived work, based on the go-ethereum library whose original
4-
// notices appear below.
5-
//
6-
// It is distributed under a license compatible with the licensing terms of the
7-
// original code from which it is derived.
8-
//
9-
// Much love to the original authors for their work.
10-
// **********
11-
// Copyright 2014 The go-ethereum Authors
12-
// This file is part of the go-ethereum library.
13-
//
14-
// The go-ethereum library is free software: you can redistribute it and/or modify
15-
// it under the terms of the GNU Lesser General Public License as published by
16-
// the Free Software Foundation, either version 3 of the License, or
17-
// (at your option) any later version.
18-
//
19-
// The go-ethereum library is distributed in the hope that it will be useful,
20-
// but WITHOUT ANY WARRANTY; without even the implied warranty of
21-
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22-
// GNU Lesser General Public License for more details.
23-
//
24-
// You should have received a copy of the GNU Lesser General Public License
25-
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
26-
27-
// Package types contains data types related to Ethereum consensus.
281
package types
29-
30-
import (
31-
"encoding/binary"
32-
"io"
33-
"math/big"
34-
"sync/atomic"
35-
36-
"github.com/ava-labs/libevm/common"
37-
"github.com/ava-labs/libevm/rlp"
38-
)
39-
40-
// Block represents an Ethereum block.
41-
//
42-
// Note the Block type tries to be 'immutable', and contains certain caches that rely
43-
// on that. The rules around block immutability are as follows:
44-
//
45-
// - We copy all data when the block is constructed. This makes references held inside
46-
// the block independent of whatever value was passed in.
47-
//
48-
// - We copy all header data on access. This is because any change to the header would mess
49-
// up the cached hash and size values in the block. Calling code is expected to take
50-
// advantage of this to avoid over-allocating!
51-
//
52-
// - When new body data is attached to the block, a shallow copy of the block is returned.
53-
// This ensures block modifications are race-free.
54-
//
55-
// - We do not copy body data on access because it does not affect the caches, and also
56-
// because it would be too expensive.
57-
type Block struct {
58-
header *Header
59-
uncles []*Header
60-
transactions Transactions
61-
62-
// Coreth specific data structures to support atomic transactions
63-
version uint32
64-
extdata *[]byte
65-
66-
// caches
67-
hash atomic.Value
68-
size atomic.Value
69-
}
70-
71-
// "external" block encoding. used for eth protocol, etc.
72-
type extblock struct {
73-
Header *Header
74-
Txs []*Transaction
75-
Uncles []*Header
76-
Version uint32
77-
ExtData *[]byte `rlp:"nil"`
78-
}
79-
80-
// NewBlock creates a new block. The input data is copied, changes to header and to the
81-
// field values will not affect the block.
82-
//
83-
// The values of TxHash, UncleHash, ReceiptHash and Bloom in header
84-
// are ignored and set to values derived from the given txs, uncles
85-
// and receipts.
86-
func NewBlock(
87-
header *Header, txs []*Transaction, uncles []*Header, receipts []*Receipt, hasher TrieHasher,
88-
) *Block {
89-
b := &Block{header: CopyHeader(header)}
90-
91-
// TODO: panic if len(txs) != len(receipts)
92-
if len(txs) == 0 {
93-
b.header.TxHash = EmptyTxsHash
94-
} else {
95-
b.header.TxHash = DeriveSha(Transactions(txs), hasher)
96-
b.transactions = make(Transactions, len(txs))
97-
copy(b.transactions, txs)
98-
}
99-
100-
if len(receipts) == 0 {
101-
b.header.ReceiptHash = EmptyReceiptsHash
102-
} else {
103-
b.header.ReceiptHash = DeriveSha(Receipts(receipts), hasher)
104-
b.header.Bloom = CreateBloom(receipts)
105-
}
106-
107-
if len(uncles) == 0 {
108-
b.header.UncleHash = EmptyUncleHash
109-
} else {
110-
b.header.UncleHash = CalcUncleHash(uncles)
111-
b.uncles = make([]*Header, len(uncles))
112-
for i := range uncles {
113-
b.uncles[i] = CopyHeader(uncles[i])
114-
}
115-
}
116-
117-
return b
118-
}
119-
120-
// DecodeRLP decodes a block from RLP.
121-
func (b *Block) DecodeRLP(s *rlp.Stream) error {
122-
var eb extblock
123-
_, size, _ := s.Kind()
124-
if err := s.Decode(&eb); err != nil {
125-
return err
126-
}
127-
b.header, b.uncles, b.transactions, b.version, b.extdata = eb.Header, eb.Uncles, eb.Txs, eb.Version, eb.ExtData
128-
b.size.Store(rlp.ListSize(size))
129-
return nil
130-
}
131-
132-
// EncodeRLP serializes a block as RLP.
133-
func (b *Block) EncodeRLP(w io.Writer) error {
134-
return rlp.Encode(w, &extblock{
135-
Header: b.header,
136-
Txs: b.transactions,
137-
Uncles: b.uncles,
138-
Version: b.version,
139-
ExtData: b.extdata,
140-
})
141-
}
142-
143-
// Body returns the non-header content of the block.
144-
// Note the returned data is not an independent copy.
145-
func (b *Block) Body() *Body {
146-
body := &Body{
147-
Transactions: b.transactions,
148-
Uncles: b.uncles,
149-
}
150-
extra := &BodyExtra{
151-
Version: b.version,
152-
ExtData: b.extdata,
153-
}
154-
return WithBodyExtra(body, extra)
155-
}
156-
157-
// Accessors for body data. These do not return a copy because the content
158-
// of the body slices does not affect the cached hash/size in block.
159-
160-
func (b *Block) Uncles() []*Header { return b.uncles }
161-
func (b *Block) Transactions() Transactions { return b.transactions }
162-
163-
func (b *Block) Transaction(hash common.Hash) *Transaction {
164-
for _, transaction := range b.transactions {
165-
if transaction.Hash() == hash {
166-
return transaction
167-
}
168-
}
169-
return nil
170-
}
171-
172-
// Header returns the block header (as a copy).
173-
func (b *Block) Header() *Header {
174-
return CopyHeader(b.header)
175-
}
176-
177-
// Header value accessors. These do copy!
178-
179-
func (b *Block) Number() *big.Int { return new(big.Int).Set(b.header.Number) }
180-
func (b *Block) GasLimit() uint64 { return b.header.GasLimit }
181-
func (b *Block) GasUsed() uint64 { return b.header.GasUsed }
182-
func (b *Block) Difficulty() *big.Int { return new(big.Int).Set(b.header.Difficulty) }
183-
func (b *Block) Time() uint64 { return b.header.Time }
184-
func (b *Block) Timestamp() uint64 { return b.header.Time }
185-
186-
func (b *Block) NumberU64() uint64 { return b.header.Number.Uint64() }
187-
func (b *Block) MixDigest() common.Hash { return b.header.MixDigest }
188-
func (b *Block) Nonce() uint64 { return binary.BigEndian.Uint64(b.header.Nonce[:]) }
189-
func (b *Block) Bloom() Bloom { return b.header.Bloom }
190-
func (b *Block) Coinbase() common.Address { return b.header.Coinbase }
191-
func (b *Block) Root() common.Hash { return b.header.Root }
192-
func (b *Block) ParentHash() common.Hash { return b.header.ParentHash }
193-
func (b *Block) TxHash() common.Hash { return b.header.TxHash }
194-
func (b *Block) ReceiptHash() common.Hash { return b.header.ReceiptHash }
195-
func (b *Block) UncleHash() common.Hash { return b.header.UncleHash }
196-
func (b *Block) Extra() []byte { return common.CopyBytes(b.header.Extra) }
197-
198-
func (b *Block) BaseFee() *big.Int {
199-
if b.header.BaseFee == nil {
200-
return nil
201-
}
202-
return new(big.Int).Set(b.header.BaseFee)
203-
}
204-
205-
func (b *Block) BeaconRoot() *common.Hash { return b.header.ParentBeaconRoot }
206-
207-
func (b *Block) ExcessBlobGas() *uint64 {
208-
var excessBlobGas *uint64
209-
if b.header.ExcessBlobGas != nil {
210-
excessBlobGas = new(uint64)
211-
*excessBlobGas = *b.header.ExcessBlobGas
212-
}
213-
return excessBlobGas
214-
}
215-
216-
func (b *Block) BlobGasUsed() *uint64 {
217-
var blobGasUsed *uint64
218-
if b.header.BlobGasUsed != nil {
219-
blobGasUsed = new(uint64)
220-
*blobGasUsed = *b.header.BlobGasUsed
221-
}
222-
return blobGasUsed
223-
}
224-
225-
func (b *Block) BlockGasCost() *big.Int {
226-
if HeaderExtras(b.header).BlockGasCost == nil {
227-
return nil
228-
}
229-
return new(big.Int).Set(HeaderExtras(b.header).BlockGasCost)
230-
}
231-
232-
// Size returns the true RLP encoded storage size of the block, either by encoding
233-
// and returning it, or returning a previously cached value.
234-
func (b *Block) Size() uint64 {
235-
if size := b.size.Load(); size != nil {
236-
return size.(uint64)
237-
}
238-
c := writeCounter(0)
239-
rlp.Encode(&c, b)
240-
b.size.Store(uint64(c))
241-
return uint64(c)
242-
}
243-
244-
type writeCounter uint64
245-
246-
func (c *writeCounter) Write(b []byte) (int, error) {
247-
*c += writeCounter(len(b))
248-
return len(b), nil
249-
}
250-
251-
func CalcUncleHash(uncles []*Header) common.Hash {
252-
if len(uncles) == 0 {
253-
return EmptyUncleHash
254-
}
255-
return rlpHash(uncles)
256-
}
257-
258-
// NewBlockWithHeader creates a block with the given header data. The
259-
// header data is copied, changes to header and to the field values
260-
// will not affect the block.
261-
func NewBlockWithHeader(header *Header) *Block {
262-
return &Block{header: CopyHeader(header)}
263-
}
264-
265-
// WithSeal returns a new block with the data from b but the header replaced with
266-
// the sealed one.
267-
func (b *Block) WithSeal(header *Header) *Block {
268-
return &Block{
269-
header: CopyHeader(header),
270-
transactions: b.transactions,
271-
uncles: b.uncles,
272-
}
273-
}
274-
275-
// WithBody returns a copy of the block with the given transaction and uncle contents.
276-
func (b *Block) WithBody(transactions []*Transaction, uncles []*Header) *Block {
277-
block := &Block{
278-
header: b.header,
279-
transactions: make([]*Transaction, len(transactions)),
280-
uncles: make([]*Header, len(uncles)),
281-
}
282-
copy(block.transactions, transactions)
283-
for i := range uncles {
284-
block.uncles[i] = CopyHeader(uncles[i])
285-
}
286-
return block
287-
}
288-
289-
// Hash returns the keccak256 hash of b's header.
290-
// The hash is computed on the first call and cached thereafter.
291-
func (b *Block) Hash() common.Hash {
292-
if hash := b.hash.Load(); hash != nil {
293-
return hash.(common.Hash)
294-
}
295-
v := b.header.Hash()
296-
b.hash.Store(v)
297-
return v
298-
}
299-
300-
type Blocks []*Block

0 commit comments

Comments
 (0)