diff --git a/consensus/XDPoS/engines/engine_v1/engine.go b/consensus/XDPoS/engines/engine_v1/engine.go index ee0b0b44e7..d7b3c2c8b7 100644 --- a/consensus/XDPoS/engines/engine_v1/engine.go +++ b/consensus/XDPoS/engines/engine_v1/engine.go @@ -850,7 +850,7 @@ func (x *XDPoS_v1) Finalize(chain consensus.ChainReader, header *types.Header, s header.UncleHash = types.CalcUncleHash(nil) // Assemble and return the final block for sealing - return types.NewBlock(header, txs, nil, receipts, trie.NewStackTrie(nil)), nil + return types.NewBlock(header, &types.Body{Transactions: txs}, receipts, trie.NewStackTrie(nil)), nil } // Authorize injects a private key into the consensus engine to mint new blocks diff --git a/consensus/XDPoS/engines/engine_v2/engine.go b/consensus/XDPoS/engines/engine_v2/engine.go index 3bd54688b9..99dff1c73e 100644 --- a/consensus/XDPoS/engines/engine_v2/engine.go +++ b/consensus/XDPoS/engines/engine_v2/engine.go @@ -440,7 +440,7 @@ func (x *XDPoS_v2) Finalize(chain consensus.ChainReader, header *types.Header, s header.UncleHash = types.CalcUncleHash(nil) // Assemble and return the final block for sealing - return types.NewBlock(header, txs, nil, receipts, trie.NewStackTrie(nil)), nil + return types.NewBlock(header, &types.Body{Transactions: txs}, receipts, trie.NewStackTrie(nil)), nil } // Authorize injects a private key into the consensus engine to mint new blocks with. diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index df2b724293..65b99560d6 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -589,7 +589,7 @@ func (c *Clique) Finalize(chain consensus.ChainReader, header *types.Header, sta header.UncleHash = types.CalcUncleHash(nil) // Assemble and return the final block for sealing - return types.NewBlock(header, txs, nil, receipts, trie.NewStackTrie(nil)), nil + return types.NewBlock(header, &types.Body{Transactions: txs}, receipts, trie.NewStackTrie(nil)), nil } // Authorize injects a private key into the consensus engine to mint new blocks diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 68d01fce9f..0f7cfce248 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -437,7 +437,7 @@ func (ethash *Ethash) Finalize(chain consensus.ChainReader, header *types.Header header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) // Header seems complete, assemble into a block and return - return types.NewBlock(header, txs, uncles, receipts, trie.NewStackTrie(nil)), nil + return types.NewBlock(header, &types.Body{Transactions: txs, Uncles: uncles}, receipts, trie.NewStackTrie(nil)), nil } // Some weird constants to avoid constant memory allocs for them. diff --git a/consensus/tests/engine_v1_tests/helper.go b/consensus/tests/engine_v1_tests/helper.go index f798ac94c0..99d862372f 100644 --- a/consensus/tests/engine_v1_tests/helper.go +++ b/consensus/tests/engine_v1_tests/helper.go @@ -382,7 +382,7 @@ func createBlockFromHeader(bc *core.BlockChain, customHeader *types.Header, txs } header.GasUsed = *gasUsed - block = types.NewBlock(&header, txs, nil, receipts, trie.NewStackTrie(nil)) + block = types.NewBlock(&header, &types.Body{Transactions: txs}, receipts, trie.NewStackTrie(nil)) } return block, nil diff --git a/consensus/tests/engine_v2_tests/helper.go b/consensus/tests/engine_v2_tests/helper.go index fe54c87e1c..aa5b473d25 100644 --- a/consensus/tests/engine_v2_tests/helper.go +++ b/consensus/tests/engine_v2_tests/helper.go @@ -917,7 +917,7 @@ func createBlockFromHeader(bc *core.BlockChain, customHeader *types.Header, txs header.Coinbase = signerAddress sealHeader(bc, &header, signerAddress, signerFunction) - block = types.NewBlock(&header, txs, nil, receipts, trie.NewStackTrie(nil)) + block = types.NewBlock(&header, &types.Body{Transactions: txs}, receipts, trie.NewStackTrie(nil)) } return block, nil diff --git a/core/genesis.go b/core/genesis.go index d21c715510..873ca4e6c5 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -261,7 +261,7 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block { statedb.Commit(false) statedb.Database().TrieDB().Commit(root, true) - return types.NewBlock(head, nil, nil, nil, trie.NewStackTrie(nil)) + return types.NewBlock(head, nil, nil, trie.NewStackTrie(nil)) } // Commit writes the block and state of a genesis specification to the database. diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index 001ec8cbe0..0893a6f1d7 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -575,7 +575,7 @@ func ReadBlock(db ethdb.Reader, hash common.Hash, number uint64) *types.Block { return nil } // Reassemble the block and return - return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles) + return types.NewBlockWithHeader(header).WithBody(*body) } // WriteBlock serializes a block into the database, header and body separately. @@ -630,7 +630,11 @@ func ReadBadBlock(db ethdb.Reader, hash common.Hash) *types.Block { } for _, bad := range badBlocks { if bad.Header.Hash() == hash { - return types.NewBlockWithHeader(bad.Header).WithBody(bad.Body.Transactions, bad.Body.Uncles) + block := types.NewBlockWithHeader(bad.Header) + if bad.Body != nil { + block = block.WithBody(*bad.Body) + } + return block } } return nil @@ -649,7 +653,11 @@ func ReadAllBadBlocks(db ethdb.Reader) []*types.Block { } var blocks []*types.Block for _, bad := range badBlocks { - blocks = append(blocks, types.NewBlockWithHeader(bad.Header).WithBody(bad.Body.Transactions, bad.Body.Uncles)) + block := types.NewBlockWithHeader(bad.Header) + if bad.Body != nil { + block = block.WithBody(*bad.Body) + } + blocks = append(blocks, block) } return blocks } diff --git a/core/rawdb/accessors_indexes_test.go b/core/rawdb/accessors_indexes_test.go index 52e625e219..d216a2538c 100644 --- a/core/rawdb/accessors_indexes_test.go +++ b/core/rawdb/accessors_indexes_test.go @@ -97,7 +97,7 @@ func TestLookupStorage(t *testing.T) { tx3 := types.NewTransaction(3, common.BytesToAddress([]byte{0x33}), big.NewInt(333), 3333, big.NewInt(33333), []byte{0x33, 0x33, 0x33}) txs := []*types.Transaction{tx1, tx2, tx3} - block := types.NewBlock(&types.Header{Root: types.EmptyRootHash, Number: big.NewInt(314)}, txs, nil, nil, newHasher()) + block := types.NewBlock(&types.Header{Root: types.EmptyRootHash, Number: big.NewInt(314)}, &types.Body{Transactions: txs}, nil, newHasher()) // Check that no transactions entries are in a pristine database for i, tx := range txs { diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 7e43791c30..d6eb7d6f3f 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -287,5 +287,5 @@ func GenerateBadBlock(t *testing.T, parent *types.Block, engine consensus.Engine } header.Root = common.BytesToHash(hasher.Sum(nil)) // Assemble and return the final block for sealing - return types.NewBlock(header, txs, nil, receipts, trie.NewStackTrie(nil)) + return types.NewBlock(header, &types.Body{Transactions: txs}, receipts, trie.NewStackTrie(nil)) } diff --git a/core/txpool/txpool_test.go b/core/txpool/txpool_test.go index c1b4dff50f..3d930ed8f6 100644 --- a/core/txpool/txpool_test.go +++ b/core/txpool/txpool_test.go @@ -86,7 +86,7 @@ func (bc *testBlockChain) CurrentBlock() *types.Block { return types.NewBlock(&types.Header{ Root: types.EmptyRootHash, GasLimit: atomic.LoadUint64(&bc.gasLimit), - }, nil, nil, nil, trie.NewStackTrie(nil)) + }, nil, nil, trie.NewStackTrie(nil)) } func (bc *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block { diff --git a/core/types/block.go b/core/types/block.go index bd07d5e7c8..9803d344a0 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -23,6 +23,7 @@ import ( "io" "math/big" "reflect" + "slices" "sort" "sync/atomic" "time" @@ -226,17 +227,21 @@ type storageblock struct { TD *big.Int } -// NewBlock creates a new block. The input data is copied, -// changes to header and to the field values will not affect the -// block. +// 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), td: new(big.Int)} +// The body elements and the receipts are used to recompute and overwrite the +// relevant portions of the header. +func NewBlock(header *Header, body *Body, receipts []*Receipt, hasher TrieHasher) *Block { + if body == nil { + body = &Body{} + } + var ( + b = NewBlockWithHeader(header) + txs = body.Transactions + uncles = body.Uncles + ) - // TODO: panic if len(txs) != len(receipts) if len(txs) == 0 { b.header.TxHash = EmptyTxsHash } else { @@ -265,13 +270,6 @@ func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []* return b } -// 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)} -} - // CopyHeader creates a deep copy of a block header to prevent side effects from // modifying a header variable. func CopyHeader(h *Header) *Header { @@ -411,6 +409,13 @@ func CalcUncleHash(uncles []*Header) common.Hash { 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 { @@ -423,16 +428,16 @@ func (b *Block) WithSeal(header *Header) *Block { } } -// WithBody returns a new block with the given transaction and uncle contents. -func (b *Block) WithBody(transactions []*Transaction, uncles []*Header) *Block { +// WithBody returns a new block with the original header and a deep copy of the +// provided body. +func (b *Block) WithBody(body Body) *Block { block := &Block{ - header: CopyHeader(b.header), - transactions: make([]*Transaction, len(transactions)), - uncles: make([]*Header, len(uncles)), + header: b.header, + transactions: slices.Clone(body.Transactions), + uncles: make([]*Header, len(body.Uncles)), } - copy(block.transactions, transactions) - for i := range uncles { - block.uncles[i] = CopyHeader(uncles[i]) + for i := range body.Uncles { + block.uncles[i] = CopyHeader(body.Uncles[i]) } return block } diff --git a/core/types/block_test.go b/core/types/block_test.go index fd767e4df3..1b7587d3fd 100644 --- a/core/types/block_test.go +++ b/core/types/block_test.go @@ -210,5 +210,5 @@ func makeBenchBlock() *Block { Extra: []byte("benchmark uncle"), } } - return NewBlock(header, txs, uncles, receipts, newHasher()) + return NewBlock(header, &Body{Transactions: txs, Uncles: uncles}, receipts, newHasher()) } diff --git a/eth/backend.go b/eth/backend.go index 964a0359c2..ae7aee523a 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -325,7 +325,7 @@ func New(stack *node.Node, config *ethconfig.Config, XDCXServ *XDCx.XDCX, lendin return block, false, err } header.Validator = sighash - return types.NewBlockWithHeader(header).WithBody(block.Transactions(), block.Uncles()), true, nil + return types.NewBlockWithHeader(header).WithBody(*block.Body()), true, nil } return block, false, nil } diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index df033f1578..a10bc96fff 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -1526,7 +1526,7 @@ func (d *Downloader) importBlockResults(results []*fetchResult) error { ) blocks := make([]*types.Block, len(results)) for i, result := range results { - blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles) + blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.body()) } if index, err := d.blockchain.InsertChain(blocks); err != nil { if index < len(results) { @@ -1694,7 +1694,7 @@ func (d *Downloader) commitFastSyncData(results []*fetchResult, stateSync *state blocks := make([]*types.Block, len(results)) receipts := make([]types.Receipts, len(results)) for i, result := range results { - blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles) + blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.body()) receipts[i] = result.Receipts } if index, err := d.blockchain.InsertReceiptChain(blocks, receipts); err != nil { @@ -1705,7 +1705,7 @@ func (d *Downloader) commitFastSyncData(results []*fetchResult, stateSync *state } func (d *Downloader) commitPivotBlock(result *fetchResult) error { - block := types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles) + block := types.NewBlockWithHeader(result.Header).WithBody(result.body()) log.Debug("Committing fast sync pivot as new head", "number", block.Number(), "hash", block.Hash()) if _, err := d.blockchain.InsertReceiptChain([]*types.Block{block}, []types.Receipts{result.Receipts}); err != nil { return err diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go index 2fd36dcfe0..37638097ae 100644 --- a/eth/downloader/queue.go +++ b/eth/downloader/queue.go @@ -83,6 +83,14 @@ func newFetchResult(header *types.Header, fastSync bool) *fetchResult { return item } +// body returns a representation of the fetch result as a types.Body object. +func (f *fetchResult) body() types.Body { + return types.Body{ + Transactions: f.Transactions, + Uncles: f.Uncles, + } +} + // SetBodyDone flags the body as finished. func (f *fetchResult) SetBodyDone() { if v := atomic.LoadInt32(&f.pending); (v & (1 << bodyType)) != 0 { diff --git a/eth/fetcher/fetcher.go b/eth/fetcher/fetcher.go index ae0ead3e52..722392a945 100644 --- a/eth/fetcher/fetcher.go +++ b/eth/fetcher/fetcher.go @@ -556,7 +556,7 @@ func (f *Fetcher) loop() { // Mark the body matched, reassemble if still unknown matched = true if f.getBlock(hash) == nil { - block := types.NewBlockWithHeader(announce.header).WithBody(task.transactions[i], task.uncles[i]) + block := types.NewBlockWithHeader(announce.header).WithBody(types.Body{Transactions: task.transactions[i], Uncles: task.uncles[i]}) block.ReceivedAt = task.time blocks = append(blocks, block) } else { diff --git a/eth/fetcher/fetcher_test.go b/eth/fetcher/fetcher_test.go index 978392800d..f665338165 100644 --- a/eth/fetcher/fetcher_test.go +++ b/eth/fetcher/fetcher_test.go @@ -40,7 +40,7 @@ var ( testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") testAddress = crypto.PubkeyToAddress(testKey.PublicKey) genesis = core.GenesisBlockForTesting(testdb, testAddress, big.NewInt(1000000000)) - unknownBlock = types.NewBlock(&types.Header{Root: types.EmptyRootHash, GasLimit: params.GenesisGasLimit}, nil, nil, nil, trie.NewStackTrie(nil)) + unknownBlock = types.NewBlock(&types.Header{Root: types.EmptyRootHash, GasLimit: params.GenesisGasLimit}, nil, nil, trie.NewStackTrie(nil)) ) // makeChain creates a chain of n blocks starting at and including parent. diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 9d7343b599..6dcaeb4431 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -208,7 +208,11 @@ func (ec *Client) getBlock(ctx context.Context, method string, args ...interface } txs[i] = tx.tx } - return types.NewBlockWithHeader(head).WithBody(txs, uncles), nil + return types.NewBlockWithHeader(head).WithBody( + types.Body{ + Transactions: txs, + Uncles: uncles, + }), nil } // HeaderByHash returns the block header with the given hash. diff --git a/miner/worker.go b/miner/worker.go index 933b14ff5f..13fa1c5b0c 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -534,8 +534,7 @@ func (w *worker) updateSnapshot() { w.snapshotBlock = types.NewBlock( w.current.header, - w.current.txs, - nil, + &types.Body{Transactions: w.current.txs}, w.current.receipts, trie.NewStackTrie(nil), )