diff --git a/cmd/hack/hack.go b/cmd/hack/hack.go index c19f9d325..abad2b7b9 100644 --- a/cmd/hack/hack.go +++ b/cmd/hack/hack.go @@ -3679,8 +3679,8 @@ func scanReceipts(chaindata string, block uint64) error { fix := true if chainConfig.IsByzantium(blockNum) { receiptSha := types.DeriveSha(receipts1) - if receiptSha != block.Header().ReceiptHash { - fmt.Printf("(retrace) mismatched receipt headers for block %d: %x, %x\n", block.NumberU64(), receiptSha, block.Header().ReceiptHash) + if receiptSha != block.ReceiptHash() { + fmt.Printf("(retrace) mismatched receipt headers for block %d: %x, %x\n", block.NumberU64(), receiptSha, block.ReceiptHash()) fix = false } } diff --git a/cmd/integration/commands/state_stages.go b/cmd/integration/commands/state_stages.go index b21ea229b..0923330a5 100644 --- a/cmd/integration/commands/state_stages.go +++ b/cmd/integration/commands/state_stages.go @@ -303,9 +303,9 @@ func syncBySmallSteps(db kv.RwDB, miningConfig params.MiningConfig, ctx context. panic(err) } - if miner.MiningConfig.Enabled && nextBlock != nil && nextBlock.Header().Coinbase != (common.Address{}) { - miner.MiningConfig.Etherbase = nextBlock.Header().Coinbase - miner.MiningConfig.ExtraData = nextBlock.Header().Extra + if miner.MiningConfig.Enabled && nextBlock != nil && nextBlock.Coinbase() != (common.Address{}) { + miner.MiningConfig.Etherbase = nextBlock.Coinbase() + miner.MiningConfig.ExtraData = nextBlock.Extra() miningStages.MockExecFunc(stages.MiningCreateBlock, func(firstCycle bool, badBlockUnwind bool, s *stagedsync.StageState, u stagedsync.Unwinder, tx kv.RwTx) error { err = stagedsync.SpawnMiningCreateBlockStage(s, tx, stagedsync.StageMiningCreateBlockCfg(db, miner, *chainConfig, engine, nil, nil, tmpDir), @@ -314,10 +314,10 @@ func syncBySmallSteps(db kv.RwDB, miningConfig params.MiningConfig, ctx context. return err } miner.MiningBlock.Uncles = nextBlock.Uncles() - miner.MiningBlock.Header.Time = nextBlock.Header().Time - miner.MiningBlock.Header.GasLimit = nextBlock.Header().GasLimit - miner.MiningBlock.Header.Difficulty = nextBlock.Header().Difficulty - miner.MiningBlock.Header.Nonce = nextBlock.Header().Nonce + miner.MiningBlock.Header.Time = nextBlock.Time() + miner.MiningBlock.Header.GasLimit = nextBlock.GasLimit() + miner.MiningBlock.Header.Difficulty = nextBlock.Difficulty() + miner.MiningBlock.Header.Nonce = nextBlock.Nonce() miner.MiningBlock.LocalTxs = types.NewTransactionsFixedOrder(nextBlock.Transactions()) miner.MiningBlock.RemoteTxs = types.NewTransactionsFixedOrder(nil) //debugprint.Headers(miningWorld.Block.Header, nextBlock.Header()) @@ -390,16 +390,15 @@ func checkChanges(expectedAccountChanges map[uint64]*changeset.ChangeSet, tx kv. } func checkMinedBlock(b1, b2 *types.Block, chainConfig *params.ChainConfig) { - h1 := b1.Header() - h2 := b2.Header() - if h1.Root != h2.Root || - (chainConfig.IsByzantium(b1.NumberU64()) && h1.ReceiptHash != h2.ReceiptHash) || - h1.TxHash != h2.TxHash || - h1.ParentHash != h2.ParentHash || - h1.UncleHash != h2.UncleHash || - h1.GasUsed != h2.GasUsed || - !bytes.Equal(h1.Extra, h2.Extra) { - debugprint.Headers(h1, h2) + if b1.Root() != b2.Root() || + (chainConfig.IsByzantium(b1.NumberU64()) && b1.ReceiptHash() != b2.ReceiptHash()) || + b1.TxHash() != b2.TxHash() || + b1.ParentHash() != b2.ParentHash() || + b1.UncleHash() != b2.UncleHash() || + b1.GasUsed() != b2.GasUsed() || + !bytes.Equal(b1.Extra(), b2.Extra()) { // TODO: Extra() doesn't need to be a copy for a read-only compare + // Header()'s deep-copy doesn't matter here since it will panic anyway + debugprint.Headers(b1.Header(), b2.Header()) panic("blocks are not same") } } diff --git a/cmd/state/commands/check_change_sets.go b/cmd/state/commands/check_change_sets.go index ea9d50cc6..fae3c8c2b 100644 --- a/cmd/state/commands/check_change_sets.go +++ b/cmd/state/commands/check_change_sets.go @@ -147,7 +147,7 @@ func CheckChangeSets(genesis *core.Genesis, logger log.Logger, blockNum uint64, if writeReceipts { if chainConfig.IsByzantium(block.Number().Uint64()) { receiptSha := types.DeriveSha(receipts) - if receiptSha != block.Header().ReceiptHash { + if receiptSha != block.ReceiptHash() { return fmt.Errorf("mismatched receipt headers for block %d", block.NumberU64()) } } diff --git a/cmd/state/commands/opcode_tracer.go b/cmd/state/commands/opcode_tracer.go index 557ee5b7c..41baa630f 100644 --- a/cmd/state/commands/opcode_tracer.go +++ b/cmd/state/commands/opcode_tracer.go @@ -557,7 +557,7 @@ func OpcodeTracer(genesis *core.Genesis, blockNum uint64, chaindata string, numB } if chainConfig.IsByzantium(block.Number().Uint64()) { receiptSha := types.DeriveSha(receipts) - if receiptSha != block.Header().ReceiptHash { + if receiptSha != block.ReceiptHash() { return fmt.Errorf("mismatched receipt headers for block %d", block.NumberU64()) } } diff --git a/consensus/ethash/sealer_test.go b/consensus/ethash/sealer_test.go index 1691f0753..67391b0f4 100644 --- a/consensus/ethash/sealer_test.go +++ b/consensus/ethash/sealer_test.go @@ -293,20 +293,20 @@ func TestStaleSubmission(t *testing.T) { } select { case res := <-results: - if res.Header().Nonce != fakeNonce { - t.Errorf("case %d block nonce mismatch, want %x, get %x", id+1, fakeNonce, res.Header().Nonce) + if res.Nonce() != fakeNonce { + t.Errorf("case %d block nonce mismatch, want %x, get %x", id+1, fakeNonce, res.Nonce()) } - if res.Header().MixDigest != fakeDigest { - t.Errorf("case %d block digest mismatch, want %x, get %x", id+1, fakeDigest, res.Header().MixDigest) + if res.MixDigest() != fakeDigest { + t.Errorf("case %d block digest mismatch, want %x, get %x", id+1, fakeDigest, res.MixDigest()) } - if res.Header().Difficulty.Uint64() != c.headers[c.submitIndex].Difficulty.Uint64() { - t.Errorf("case %d block difficulty mismatch, want %d, get %d", id+1, c.headers[c.submitIndex].Difficulty, res.Header().Difficulty) + if res.Difficulty().Uint64() != c.headers[c.submitIndex].Difficulty.Uint64() { + t.Errorf("case %d block difficulty mismatch, want %d, get %d", id+1, c.headers[c.submitIndex].Difficulty, res.Difficulty()) } - if res.Header().Number.Uint64() != c.headers[c.submitIndex].Number.Uint64() { - t.Errorf("case %d block number mismatch, want %d, get %d", id+1, c.headers[c.submitIndex].Number.Uint64(), res.Header().Number.Uint64()) + if res.Number().Uint64() != c.headers[c.submitIndex].Number.Uint64() { + t.Errorf("case %d block number mismatch, want %d, get %d", id+1, c.headers[c.submitIndex].Number.Uint64(), res.Number().Uint64()) } - if res.Header().ParentHash != c.headers[c.submitIndex].ParentHash { - t.Errorf("case %d block parent hash mismatch, want %s, get %s", id+1, c.headers[c.submitIndex].ParentHash.Hex(), res.Header().ParentHash.Hex()) + if res.ParentHash() != c.headers[c.submitIndex].ParentHash { + t.Errorf("case %d block parent hash mismatch, want %s, get %s", id+1, c.headers[c.submitIndex].ParentHash.Hex(), res.ParentHash().Hex()) } case <-time.NewTimer(time.Second).C: t.Errorf("case %d fetch ethash result timeout", id+1) diff --git a/core/blockchain.go b/core/blockchain.go index 9ad460934..8985419f3 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -152,7 +152,7 @@ func ExecuteBlockEphemerally( if chainConfig.IsByzantium(header.Number.Uint64()) && !vmConfig.NoReceipts { receiptSha := types.DeriveSha(receipts) - if receiptSha != block.Header().ReceiptHash { + if receiptSha != block.ReceiptHash() { return nil, fmt.Errorf("mismatched receipt headers for block %d", block.NumberU64()) } } diff --git a/core/chain_makers.go b/core/chain_makers.go index b2f7da73a..92a740e3e 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -185,12 +185,21 @@ func (b *BlockGen) PrevBlock(index int) *types.Block { // tied to chain length directly. func (b *BlockGen) OffsetTime(seconds int64) { b.header.Time += uint64(seconds) - if b.header.Time <= b.parent.Header().Time { + parent := b.parent + if b.header.Time <= parent.Time() { panic("block time out of range") } chainreader := &FakeChainReader{Cfg: b.config} - parent := b.parent.Header() - b.header.Difficulty = b.engine.CalcDifficulty(chainreader, b.header.Time, parent.Time, parent.Difficulty, parent.Number.Uint64(), parent.Hash(), parent.UncleHash, parent.Seal) + b.header.Difficulty = b.engine.CalcDifficulty( + chainreader, + b.header.Time, + parent.Time(), + parent.Difficulty(), + parent.NumberU64(), + parent.Hash(), + parent.UncleHash(), + parent.Seal(), + ) } func (b *BlockGen) GetHeader() *types.Header { @@ -402,7 +411,7 @@ func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.I parent.Number().Uint64(), parent.Hash(), parent.UncleHash(), - parent.Header().Seal, + parent.Seal(), ), GasLimit: CalcGasLimit(parent.GasUsed(), parent.GasLimit(), parent.GasLimit(), parent.GasLimit()), Number: new(big.Int).Add(parent.Number(), common.Big1), diff --git a/core/rawdb/accessors_chain_test.go b/core/rawdb/accessors_chain_test.go index ea7022b14..2bfde5c5b 100644 --- a/core/rawdb/accessors_chain_test.go +++ b/core/rawdb/accessors_chain_test.go @@ -154,7 +154,7 @@ func TestBlockStorage(t *testing.T) { } if entry := ReadHeader(tx, block.Hash(), block.NumberU64()); entry == nil { t.Fatalf("Stored header not found") - } else if entry.Hash() != block.Header().Hash() { + } else if entry.Hash() != block.Hash() { t.Fatalf("Retrieved header mismatch: have %v, want %v", entry, block.Header()) } if entry := ReadBodyWithTransactions(tx, block.Hash(), block.NumberU64()); entry == nil { @@ -186,8 +186,10 @@ func TestPartialBlockStorage(t *testing.T) { TxHash: types.EmptyRootHash, ReceiptHash: types.EmptyRootHash, }) + header := block.Header() // Not identical to struct literal above, due to other fields + // Store a header and check that it's not recognized as a block - WriteHeader(tx, block.Header()) + WriteHeader(tx, header) if entry := ReadBlock(tx, block.Hash(), block.NumberU64()); entry != nil { t.Fatalf("Non existent block returned: %v", entry) } @@ -203,7 +205,7 @@ func TestPartialBlockStorage(t *testing.T) { DeleteBody(tx, block.Hash(), block.NumberU64()) // Store a header and a body separately and check reassembly - WriteHeader(tx, block.Header()) + WriteHeader(tx, header) if err := WriteBody(tx, block.Hash(), block.NumberU64(), block.Body()); err != nil { t.Fatal(err) } diff --git a/core/types/block.go b/core/types/block.go index dccd167b8..0f808920d 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -629,6 +629,17 @@ func (h *Header) EmptyReceipts() bool { return h.ReceiptHash == EmptyRootHash } +func (h *Header) copySeal() []rlp.RawValue { + seal := h.Seal + if len(seal) > 0 { + seal = make([]rlp.RawValue, len(seal)) + for i, s := range h.Seal { + seal[i] = common.CopyBytes(s) + } + } + return seal +} + // 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 { @@ -1016,12 +1027,7 @@ func CopyHeader(h *Header) *Header { cpy.Extra = make([]byte, len(h.Extra)) copy(cpy.Extra, h.Extra) } - if len(h.Seal) > 0 { - cpy.Seal = make([]rlp.RawValue, len(h.Seal)) - for i := range h.Seal { - cpy.Seal[i] = common.CopyBytes(h.Seal[i]) - } - } + cpy.Seal = h.copySeal() return &cpy } @@ -1203,7 +1209,8 @@ func (b *Block) Time() 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) Nonce() BlockNonce { return b.header.Nonce } +func (b *Block) NonceU64() uint64 { return b.header.Nonce.Uint64() } 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 } @@ -1218,7 +1225,9 @@ func (b *Block) BaseFee() *big.Int { } return new(big.Int).Set(b.header.BaseFee) } +func (b *Block) Seal() (seal []rlp.RawValue) { return b.header.copySeal() } +// Header returns a deep-copy of the entire block header using CopyHeader() func (b *Block) Header() *Header { return CopyHeader(b.header) } // Body returns the non-header content of the block. diff --git a/core/types/block_test.go b/core/types/block_test.go index e8f01f1c4..b3ecefd15 100644 --- a/core/types/block_test.go +++ b/core/types/block_test.go @@ -52,7 +52,7 @@ func TestBlockEncoding(t *testing.T) { check("MixDigest", block.MixDigest(), common.HexToHash("bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff498")) check("Root", block.Root(), common.HexToHash("ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017")) check("Hash", block.Hash(), common.HexToHash("0a5843ac1cb04865017cb35a57b50b07084e5fcee39b5acadade33149f4fff9e")) - check("Nonce", block.Nonce(), uint64(0xa13a5a8c8f2bb1c4)) + check("Nonce", block.NonceU64(), uint64(0xa13a5a8c8f2bb1c4)) check("Time", block.Time(), uint64(1426516743)) check("Size", block.Size(), common.StorageSize(len(blockEnc))) @@ -89,7 +89,7 @@ func TestEIP1559BlockEncoding(t *testing.T) { check("MixDigest", block.MixDigest(), common.HexToHash("bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff498")) check("Root", block.Root(), common.HexToHash("ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017")) check("Hash", block.Hash(), common.HexToHash("c7252048cd273fe0dac09650027d07f0e3da4ee0675ebbb26627cea92729c372")) - check("Nonce", block.Nonce(), uint64(0xa13a5a8c8f2bb1c4)) + check("Nonce", block.NonceU64(), uint64(0xa13a5a8c8f2bb1c4)) check("Time", block.Time(), uint64(1426516743)) check("Size", block.Size(), common.StorageSize(len(blockEnc))) check("BaseFee", block.BaseFee(), new(big.Int).SetUint64(params.InitialBaseFee)) @@ -154,7 +154,7 @@ func TestEIP2718BlockEncoding(t *testing.T) { check("Coinbase", block.Coinbase(), common.HexToAddress("8888f1f195afa192cfee860698584c030f4c9db1")) check("MixDigest", block.MixDigest(), common.HexToHash("bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff498")) check("Root", block.Root(), common.HexToHash("ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017")) - check("Nonce", block.Nonce(), uint64(0xa13a5a8c8f2bb1c4)) + check("Nonce", block.NonceU64(), uint64(0xa13a5a8c8f2bb1c4)) check("Time", block.Time(), uint64(1426516743)) check("Size", block.Size(), common.StorageSize(len(blockEnc))) diff --git a/eth/stagedsync/stage_mining_finish.go b/eth/stagedsync/stage_mining_finish.go index 2e293d348..14afe5e1c 100644 --- a/eth/stagedsync/stage_mining_finish.go +++ b/eth/stagedsync/stage_mining_finish.go @@ -55,7 +55,7 @@ func SpawnMiningFinishStage(s *StageState, tx kv.RwTx, cfg MiningFinishCfg, quit //prev = sealHash // Tests may set pre-calculated nonce - if block.Header().Nonce.Uint64() != 0 { + if block.NonceU64() != 0 { cfg.miningState.MiningResultCh <- block return nil } diff --git a/migrations/receipt_repair.go b/migrations/receipt_repair.go index d1ee62d59..435a9d5cc 100644 --- a/migrations/receipt_repair.go +++ b/migrations/receipt_repair.go @@ -123,8 +123,8 @@ var ReceiptRepair = Migration{ fix := true if chainConfig.IsByzantium(block.Number().Uint64()) { receiptSha := types.DeriveSha(receipts1) - if receiptSha != block.Header().ReceiptHash { - fmt.Printf("(retrace) mismatched receipt headers for block %d: %x, %x\n", block.NumberU64(), receiptSha, block.Header().ReceiptHash) + if receiptSha != block.ReceiptHash() { + fmt.Printf("(retrace) mismatched receipt headers for block %d: %x, %x\n", block.NumberU64(), receiptSha, block.ReceiptHash()) fix = false } } diff --git a/tests/block_test_util.go b/tests/block_test_util.go index bdde49857..13885cbce 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -307,7 +307,7 @@ func (t *BlockTest) validateImportedHeaders(tx kv.Tx, validBlocks []btBlock) err if err := validateHeader(bmap[b.Hash()].BlockHeader, b.Header()); err != nil { return fmt.Errorf("imported block header validation failed: %w", err) } - b, _ = rawdb.ReadBlockByHash(tx, b.Header().ParentHash) + b, _ = rawdb.ReadBlockByHash(tx, b.ParentHash()) } return nil } diff --git a/turbo/stages/headerdownload/header_algos.go b/turbo/stages/headerdownload/header_algos.go index cf1ad0105..28a426eef 100644 --- a/turbo/stages/headerdownload/header_algos.go +++ b/turbo/stages/headerdownload/header_algos.go @@ -1024,11 +1024,12 @@ func (hd *HeaderDownload) Fetching() bool { } func (hd *HeaderDownload) AddMinedBlock(block *types.Block) error { + header := block.Header() buf := bytes.NewBuffer(nil) - if err := block.Header().EncodeRLP(buf); err != nil { + if err := header.EncodeRLP(buf); err != nil { return err } - segments, _, err := hd.SingleHeaderAsSegment(buf.Bytes(), block.Header()) + segments, _, err := hd.SingleHeaderAsSegment(buf.Bytes(), header) if err != nil { return err } diff --git a/turbo/transactions/tracing.go b/turbo/transactions/tracing.go index 66ea3420f..c7341802f 100644 --- a/turbo/transactions/tracing.go +++ b/turbo/transactions/tracing.go @@ -54,7 +54,7 @@ func ComputeTxEnv(ctx context.Context, block *types.Block, cfg *params.ChainConf statedb.Prepare(tx.Hash(), blockHash, idx) // Assemble the transaction call message and return if the requested offset - msg, _ := tx.AsMessage(*signer, block.Header().BaseFee) + msg, _ := tx.AsMessage(*signer, block.BaseFee()) TxContext := core.NewEVMTxContext(msg) if idx == int(txIndex) { return msg, BlockContext, TxContext, statedb, reader, nil