Skip to content

Commit

Permalink
Move atomic hash from Block to Header (#12462)
Browse files Browse the repository at this point in the history
Cherry pick #11513 into `release/2.61`

Co-authored-by: Alex Sharov <[email protected]>
  • Loading branch information
yperbasis and AskAlexSharov authored Oct 24, 2024
1 parent 7a65be6 commit 1502825
Show file tree
Hide file tree
Showing 17 changed files with 108 additions and 96 deletions.
4 changes: 2 additions & 2 deletions cmd/devnet/blocks/waiter.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ func BlockWaiter(ctx context.Context, handler BlockHandler) (Waiter, context.Can

var err error

headers := make(chan types.Header)
headers := make(chan *types.Header)
waiter.headersSub, err = node.Subscribe(ctx, requests.Methods.ETHNewHeads, headers)

if err != nil {
Expand All @@ -117,7 +117,7 @@ func BlockWaiter(ctx context.Context, handler BlockHandler) (Waiter, context.Can
return wait{waiter}, cancel
}

func (c *blockWaiter) receive(ctx context.Context, node devnet.Node, headers chan types.Header) {
func (c *blockWaiter) receive(ctx context.Context, node devnet.Node, headers chan *types.Header) {
blockMap := map[libcommon.Hash]*requests.Block{}

defer close(c.result)
Expand Down
2 changes: 1 addition & 1 deletion consensus/aura/aura.go
Original file line number Diff line number Diff line change
Expand Up @@ -846,7 +846,7 @@ func (c *AuRa) FinalizeAndAssemble(config *chain.Config, header *types.Header, s
}

// Assemble and return the final block for sealing
return types.NewBlock(header, outTxs, uncles, outReceipts, withdrawals, requests), outTxs, outReceipts, nil
return types.NewBlockForAsembling(header, outTxs, uncles, outReceipts, withdrawals, requests), outTxs, outReceipts, nil
}

// Authorize injects a private key into the consensus engine to mint new blocks
Expand Down
9 changes: 2 additions & 7 deletions consensus/clique/clique.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ var (
NonceAuthVote = hexutil.MustDecode("0xffffffffffffffff") // Magic nonce number to vote on adding a new signer
nonceDropVote = hexutil.MustDecode("0x0000000000000000") // Magic nonce number to vote on removing a signer.

uncleHash = types.CalcUncleHash(nil) // Always Keccak256(RLP([])) as uncles are meaningless outside of PoW.
emptyUncleHash = types.CalcUncleHash(nil) // Always Keccak256(RLP([])) as uncles are meaningless outside of PoW.

DiffInTurn = big.NewInt(2) // Block difficulty for in-turn signatures
diffNoTurn = big.NewInt(1) // Block difficulty for out-of-turn signatures
Expand Down Expand Up @@ -381,8 +381,6 @@ func (c *Clique) Finalize(config *chain.Config, header *types.Header, state *sta
txs types.Transactions, uncles []*types.Header, r types.Receipts, withdrawals []*types.Withdrawal, requests types.Requests,
chain consensus.ChainReader, syscall consensus.SystemCall, logger log.Logger,
) (types.Transactions, types.Receipts, types.Requests, error) {
// No block rewards in PoA, so the state remains as is and uncles are dropped
header.UncleHash = types.CalcUncleHash(nil)
return txs, r, nil, nil
}

Expand All @@ -391,11 +389,8 @@ func (c *Clique) Finalize(config *chain.Config, header *types.Header, state *sta
func (c *Clique) FinalizeAndAssemble(chainConfig *chain.Config, header *types.Header, state *state.IntraBlockState,
txs types.Transactions, uncles []*types.Header, receipts types.Receipts, withdrawals []*types.Withdrawal, requests types.Requests, chain consensus.ChainReader, syscall consensus.SystemCall, call consensus.Call, logger log.Logger,
) (*types.Block, types.Transactions, types.Receipts, error) {
// No block rewards in PoA, so the state remains as is and uncles are dropped
header.UncleHash = types.CalcUncleHash(nil)

// Assemble and return the final block for sealing
return types.NewBlock(header, txs, nil, receipts, withdrawals, requests), txs, receipts, nil
return types.NewBlockForAsembling(header, txs, nil, receipts, withdrawals, requests), txs, receipts, nil
}

// Authorize injects a private key into the consensus engine to mint new blocks
Expand Down
2 changes: 1 addition & 1 deletion consensus/clique/verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func (c *Clique) verifyHeader(chain consensus.ChainHeaderReader, header *types.H
return errInvalidMixDigest
}
// Ensure that the block doesn't contain any uncles which are meaningless in PoA
if header.UncleHash != uncleHash {
if header.UncleHash != emptyUncleHash {
return errInvalidUncleHash
}
// Ensure that the block's difficulty is meaningful (may not be correct at this point)
Expand Down
3 changes: 0 additions & 3 deletions consensus/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,6 @@ type EngineWriter interface {

// Finalize runs any post-transaction state modifications (e.g. block rewards)
// but does not assemble the block.
//
// Note: The block header and state database might be updated to reflect any
// consensus rules that happen at finalization (e.g. block rewards).
Finalize(config *chain.Config, header *types.Header, state *state.IntraBlockState,
txs types.Transactions, uncles []*types.Header, receipts types.Receipts, withdrawals []*types.Withdrawal, requests types.Requests, chain ChainReader, syscall SystemCall, logger log.Logger,
) (types.Transactions, types.Receipts, types.Requests, error)
Expand Down
4 changes: 2 additions & 2 deletions consensus/merge/merge.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ func (s *Merge) FinalizeAndAssemble(config *chain.Config, header *types.Header,
rs = make(types.Requests, 0)
}
}
return types.NewBlock(header, outTxs, uncles, outReceipts, withdrawals, rs), outTxs, outReceipts, nil
return types.NewBlockForAsembling(header, outTxs, uncles, outReceipts, withdrawals, rs), outTxs, outReceipts, nil
}

func (s *Merge) SealHash(header *types.Header) (hash libcommon.Hash) {
Expand Down Expand Up @@ -307,7 +307,7 @@ func (s *Merge) verifyHeader(chain consensus.ChainHeaderReader, header, parent *
}

func (s *Merge) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
if !misc.IsPoSHeader(block.Header()) {
if !misc.IsPoSHeader(block.HeaderNoCopy()) {
return s.eth1Engine.Seal(chain, block, results, stop)
}
return nil
Expand Down
15 changes: 7 additions & 8 deletions core/chain_makers.go
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ func GenerateChain(config *chain.Config, parent *types.Block, engine consensus.E
return nil, nil, fmt.Errorf("call to CalcTrieRoot: %w", err)
}
// Recreating block to make sure Root makes it into the header
block := types.NewBlock(b.header, b.txs, b.uncles, b.receipts, nil /* withdrawals */, nil /*requests*/)
block := types.NewBlockForAsembling(b.header, b.txs, b.uncles, b.receipts, nil /* withdrawals */, nil /*requests*/)
return block, b.receipts, nil
}
return nil, nil, fmt.Errorf("no engine to generate blocks")
Expand Down Expand Up @@ -578,13 +578,12 @@ func CalcHashRootForTests(tx kv.RwTx, header *types.Header, histV4 bool) (hashRo
}

func MakeEmptyHeader(parent *types.Header, chainConfig *chain.Config, timestamp uint64, targetGasLimit *uint64) *types.Header {
header := &types.Header{
Root: parent.Root,
ParentHash: parent.Hash(),
Number: new(big.Int).Add(parent.Number, libcommon.Big1),
Difficulty: libcommon.Big0,
Time: timestamp,
}
header := types.NewEmptyHeaderForAssembling()
header.Root = parent.Root
header.ParentHash = parent.Hash()
header.Number = new(big.Int).Add(parent.Number, libcommon.Big1)
header.Difficulty = libcommon.Big0
header.Time = timestamp

parentGasLimit := parent.GasLimit
// Set baseFee and GasLimit if we are on an EIP-1559 chain
Expand Down
63 changes: 43 additions & 20 deletions core/types/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,19 @@ type Header struct {
Verkle bool
VerkleProof []byte
VerkleKeyVals []verkle.KeyValuePair

// by default all headers are immutable
// but assembling/mining may use `NewEmptyHeaderForAssembling` to create temporary mutable Header object
// then pass it to `block.WithSeal(header)` - to produce new block with immutable `Header`
mutable bool
hash atomic.Pointer[libcommon.Hash]
}

// NewEmptyHeaderForAssembling - returns mutable header object - for assembling/sealing/etc...
// when sealing done - `block.WithSeal(header)` called - which producing new block with immutable `Header`
// by default all headers are immutable
func NewEmptyHeaderForAssembling() *Header {
return &Header{mutable: true}
}

func (h *Header) EncodingSize() int {
Expand Down Expand Up @@ -564,8 +577,17 @@ type headerMarshaling struct {

// Hash returns the block hash of the header, which is simply the keccak256 hash of its
// RLP encoding.
func (h *Header) Hash() libcommon.Hash {
return rlpHash(h)
func (h *Header) Hash() (hash libcommon.Hash) {
if !h.mutable {
if hash := h.hash.Load(); hash != nil {
return *hash
}
}
hash = rlpHash(h)
if !h.mutable {
h.hash.Store(&hash)
}
return hash
}

var headerSize = common.StorageSize(reflect.TypeOf(Header{}).Size())
Expand Down Expand Up @@ -681,7 +703,6 @@ type Block struct {
requests Requests

// caches
hash atomic.Pointer[libcommon.Hash]
size atomic.Uint64
}

Expand Down Expand Up @@ -1055,14 +1076,22 @@ func NewBlock(header *Header, txs []Transaction, uncles []*Header, receipts []*R
}
}

b.header.mutable = false //Force immutability of block and header. Use `NewBlockForAsembling` if you need mutable block
return b
}

// NewBlockForAsembling - creating new block - which allow mutation of fileds. Use it for block-assembly
func NewBlockForAsembling(header *Header, txs []Transaction, uncles []*Header, receipts []*Receipt, withdrawals []*Withdrawal, requests Requests) *Block {
b := NewBlock(header, txs, uncles, receipts, withdrawals, requests)
b.header.mutable = true
return b
}

// NewBlockFromStorage like NewBlock but used to create Block object when read it from DB
// in this case no reason to copy parts, or re-calculate headers fields - they are all stored in DB
func NewBlockFromStorage(hash libcommon.Hash, header *Header, txs []Transaction, uncles []*Header, withdrawals []*Withdrawal, requests Requests) *Block {
header.hash.Store(&hash)
b := &Block{header: header, transactions: txs, uncles: uncles, withdrawals: withdrawals, requests: requests}
b.hash.Store(&hash)
return b
}

Expand All @@ -1088,7 +1117,7 @@ func NewBlockFromNetwork(header *Header, body *Body) *Block {
// CopyHeader creates a deep copy of a block header to prevent side effects from
// modifying a header variable.
func CopyHeader(h *Header) *Header {
cpy := *h
cpy := *h //nolint
if cpy.Difficulty = new(big.Int); h.Difficulty != nil {
cpy.Difficulty.Set(h.Difficulty)
}
Expand Down Expand Up @@ -1127,6 +1156,11 @@ func CopyHeader(h *Header) *Header {
cpy.RequestsHash = new(libcommon.Hash)
cpy.RequestsHash.SetBytes(h.RequestsHash.Bytes())
}
cpy.mutable = h.mutable
if hash := h.hash.Load(); hash != nil {
hashCopy := *hash
cpy.hash.Store(&hashCopy)
}
return &cpy
}

Expand Down Expand Up @@ -1454,10 +1488,6 @@ func (b *Block) Copy() *Block {
withdrawals: withdrawals,
requests: requests,
}
if h := b.hash.Load(); h != nil {
hashCopy := *h
newB.hash.Store(&hashCopy)
}
szCopy := b.size.Load()
newB.size.Store(szCopy)
return newB
Expand All @@ -1466,10 +1496,10 @@ func (b *Block) Copy() *Block {
// 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 {
cpy := *header

headerCopy := CopyHeader(header)
headerCopy.mutable = false
return &Block{
header: &cpy,
header: headerCopy,
transactions: b.transactions,
uncles: b.uncles,
withdrawals: b.withdrawals,
Expand All @@ -1479,14 +1509,7 @@ func (b *Block) WithSeal(header *Header) *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() libcommon.Hash {
if hash := b.hash.Load(); hash != nil {
return *hash
}
h := b.header.Hash()
b.hash.Store(&h)
return h
}
func (b *Block) Hash() libcommon.Hash { return b.header.Hash() }

type Blocks []*Block

Expand Down
4 changes: 3 additions & 1 deletion core/types/block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"reflect"
"testing"

"github.com/go-test/deep"
"github.com/holiman/uint256"
libcommon "github.com/ledgerwatch/erigon-lib/common"
"github.com/ledgerwatch/erigon-lib/common/hexutility"
Expand Down Expand Up @@ -473,7 +474,8 @@ func TestAuRaHeaderEncoding(t *testing.T) {
var decoded Header
require.NoError(t, rlp.DecodeBytes(encoded, &decoded))

assert.Equal(t, header, decoded)
deep.CompareUnexportedFields = true
require.Nil(t, deep.Equal(&header, &decoded))
}

func TestWithdrawalsEncoding(t *testing.T) {
Expand Down
3 changes: 1 addition & 2 deletions core/vm/runtime/runtime_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ func BenchmarkEVM_CREATE2_1200(bench *testing.B) {
}

func fakeHeader(n uint64, parentHash libcommon.Hash) *types.Header {
header := types.Header{
return &types.Header{
Coinbase: libcommon.HexToAddress("0x00000000000000000000000000000000deadbeef"),
Number: big.NewInt(int64(n)),
ParentHash: parentHash,
Expand All @@ -243,7 +243,6 @@ func fakeHeader(n uint64, parentHash libcommon.Hash) *types.Header {
Difficulty: big.NewInt(0),
GasLimit: 100000,
}
return &header
}

// FakeChainHeaderReader implements consensus.ChainHeaderReader interface
Expand Down
2 changes: 1 addition & 1 deletion eth/stagedsync/stage_mining_finish.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func SpawnMiningFinishStage(s *StageState, tx kv.RwTx, cfg MiningFinishCfg, quit
// continue
//}

block := types.NewBlock(current.Header, current.Txs, current.Uncles, current.Receipts, current.Withdrawals, current.Requests)
block := types.NewBlockForAsembling(current.Header, current.Txs, current.Uncles, current.Receipts, current.Withdrawals, current.Requests)
blockWithReceipts := &types.BlockWithReceipts{Block: block, Receipts: current.Receipts}
*current = MiningBlock{} // hack to clean global data

Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ require (
github.com/gfx-labs/sse v0.0.0-20231226060816-f747e26a9baa
github.com/go-chi/chi/v5 v5.0.12
github.com/go-chi/cors v1.2.1
github.com/go-test/deep v1.1.1
github.com/goccy/go-json v0.9.11
github.com/gofrs/flock v0.8.1
github.com/golang-jwt/jwt/v4 v4.5.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,8 @@ github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U=
github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
Expand Down
16 changes: 4 additions & 12 deletions polygon/bor/bor.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ var (
"0": 64,
} // Default number of blocks after which to checkpoint and reset the pending votes

uncleHash = types.CalcUncleHash(nil) // Always Keccak256(RLP([])) as uncles are meaningless outside of PoW.
emptyUncleHash = types.CalcUncleHash(nil) // Always Keccak256(RLP([])) as uncles are meaningless outside of PoW.

// diffInTurn = big.NewInt(2) // Block difficulty for in-turn signatures
// diffNoTurn = big.NewInt(1) // Block difficulty for out-of-turn signatures
Expand Down Expand Up @@ -545,7 +545,7 @@ func ValidateHeaderUnusedFields(header *types.Header) error {
}

// Ensure that the block doesn't contain any uncles which are meaningless in PoA
if header.UncleHash != uncleHash {
if header.UncleHash != emptyUncleHash {
return errInvalidUncleHash
}

Expand Down Expand Up @@ -1018,10 +1018,6 @@ func (c *Bor) Finalize(config *chain.Config, header *types.Header, state *state.
return nil, types.Receipts{}, nil, err
}

// No block rewards in PoA, so the state remains as is and uncles are dropped
// header.Root = state.IntermediateRoot(chain.Config().IsSpuriousDragon(header.Number.Uint64()))
header.UncleHash = types.CalcUncleHash(nil)

// Set state sync data to blockchain
// bc := chain.(*core.BlockChain)
// bc.SetStateSync(stateSyncData)
Expand Down Expand Up @@ -1088,12 +1084,8 @@ func (c *Bor) FinalizeAndAssemble(chainConfig *chain.Config, header *types.Heade
return nil, nil, types.Receipts{}, err
}

// No block rewards in PoA, so the state remains as is and uncles are dropped
// header.Root = state.IntermediateRoot(chain.Config().IsSpuriousDragon(header.Number))
header.UncleHash = types.CalcUncleHash(nil)

// Assemble block
block := types.NewBlock(header, txs, nil, receipts, withdrawals, requests)
block := types.NewBlockForAsembling(header, txs, nil, receipts, withdrawals, requests)

// set state sync
// bc := chain.(*core.BlockChain)
Expand Down Expand Up @@ -1123,7 +1115,7 @@ func (c *Bor) Authorize(currentSigner libcommon.Address, signFn SignerFn) {
// Seal implements consensus.Engine, attempting to create a sealed block using
// the local signing credentials.
func (c *Bor) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
header := block.Header()
header := block.HeaderNoCopy()
// Sealing the genesis block is not supported
number := header.Number.Uint64()

Expand Down
Loading

0 comments on commit 1502825

Please sign in to comment.