fix: ensure empty withdrawals after cancun (#2384)

This commit is contained in:
buddho 2024-04-10 14:42:16 +08:00 committed by GitHub
parent 26f50099f4
commit a75e82367d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 21 additions and 13 deletions

@ -599,9 +599,7 @@ func (p *Parlia) verifyHeader(chain consensus.ChainHeaderReader, header *types.H
switch { switch {
case header.ParentBeaconRoot != nil: case header.ParentBeaconRoot != nil:
return fmt.Errorf("invalid parentBeaconRoot, have %#x, expected nil", header.ParentBeaconRoot) return fmt.Errorf("invalid parentBeaconRoot, have %#x, expected nil", header.ParentBeaconRoot)
// types.EmptyWithdrawalsHash represents a empty value when EIP-4895 enabled, case !header.EmptyWithdrawalsHash():
// here, EIP-4895 still be disabled, value expected to be `types.EmptyWithdrawalsHash` is only to feet the demand of rlp encode/decode
case header.WithdrawalsHash == nil || *header.WithdrawalsHash != types.EmptyWithdrawalsHash:
return errors.New("header has wrong WithdrawalsHash") return errors.New("header has wrong WithdrawalsHash")
} }
if err := eip4844.VerifyEIP4844Header(parent, header); err != nil { if err := eip4844.VerifyEIP4844Header(parent, header); err != nil {

@ -96,7 +96,7 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
}, },
func() error { func() error {
// Withdrawals are present after the Shanghai fork. // Withdrawals are present after the Shanghai fork.
if !header.EmptyWithdrawalsHash() { if header.WithdrawalsHash != nil {
// Withdrawals list must be present in body after Shanghai. // Withdrawals list must be present in body after Shanghai.
if block.Withdrawals() == nil { if block.Withdrawals() == nil {
return errors.New("missing withdrawals in block body") return errors.New("missing withdrawals in block body")
@ -104,7 +104,7 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
if hash := types.DeriveSha(block.Withdrawals(), trie.NewStackTrie(nil)); hash != *header.WithdrawalsHash { if hash := types.DeriveSha(block.Withdrawals(), trie.NewStackTrie(nil)); hash != *header.WithdrawalsHash {
return fmt.Errorf("withdrawals root hash mismatch (header value %x, calculated %x)", *header.WithdrawalsHash, hash) return fmt.Errorf("withdrawals root hash mismatch (header value %x, calculated %x)", *header.WithdrawalsHash, hash)
} }
} else if len(block.Withdrawals()) != 0 { // Withdrawals turn into empty from nil when BlockBody has Sidecars } else if block.Withdrawals() != nil { // Withdrawals turn into empty from nil when BlockBody has Sidecars
// Withdrawals are not allowed prior to shanghai fork // Withdrawals are not allowed prior to shanghai fork
return errors.New("withdrawals present in block body") return errors.New("withdrawals present in block body")
} }

@ -372,6 +372,9 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
if err != nil { if err != nil {
panic(err) panic(err)
} }
if block.Header().EmptyWithdrawalsHash() {
block = block.WithWithdrawals(make([]*types.Withdrawal, 0))
}
if config.IsCancun(block.Number(), block.Time()) { if config.IsCancun(block.Number(), block.Time()) {
for _, s := range b.sidecars { for _, s := range b.sidecars {
s.BlockNumber = block.Number() s.BlockNumber = block.Number()

@ -193,9 +193,9 @@ func (h *Header) EmptyReceipts() bool {
return h.ReceiptHash == EmptyReceiptsHash return h.ReceiptHash == EmptyReceiptsHash
} }
// EmptyWithdrawalsHash returns true if there are no WithdrawalsHash for this header/block. // EmptyWithdrawalsHash returns true if the WithdrawalsHash is EmptyWithdrawalsHash.
func (h *Header) EmptyWithdrawalsHash() bool { func (h *Header) EmptyWithdrawalsHash() bool {
return h.WithdrawalsHash == nil || *h.WithdrawalsHash == EmptyWithdrawalsHash return h.WithdrawalsHash != nil && *h.WithdrawalsHash == EmptyWithdrawalsHash
} }
// Body is a simple (mutable, non-safe) data container for storing and moving // Body is a simple (mutable, non-safe) data container for storing and moving

@ -81,7 +81,7 @@ func newFetchResult(header *types.Header, fastSync bool, pid string) *fetchResul
} }
if !header.EmptyBody() { if !header.EmptyBody() {
item.pending.Store(item.pending.Load() | (1 << bodyType)) item.pending.Store(item.pending.Load() | (1 << bodyType))
} else if !header.EmptyWithdrawalsHash() { } else if header.WithdrawalsHash != nil {
item.Withdrawals = make(types.Withdrawals, 0) item.Withdrawals = make(types.Withdrawals, 0)
} }
if fastSync && !header.EmptyReceipts() { if fastSync && !header.EmptyReceipts() {
@ -788,9 +788,9 @@ func (q *queue) DeliverBodies(id string, txLists [][]*types.Transaction, txListH
if uncleListHashes[index] != header.UncleHash { if uncleListHashes[index] != header.UncleHash {
return errInvalidBody return errInvalidBody
} }
if header.EmptyWithdrawalsHash() { if header.WithdrawalsHash == nil {
// nil hash means that withdrawals should not be present in body // nil hash means that withdrawals should not be present in body
if len(withdrawalLists[index]) != 0 { if withdrawalLists[index] != nil {
return errInvalidBody return errInvalidBody
} }
} else { // non-nil hash: body must have withdrawals } else { // non-nil hash: body must have withdrawals

@ -576,7 +576,7 @@ func (f *BlockFetcher) loop() {
select { select {
case res := <-resCh: case res := <-resCh:
res.Done <- nil res.Done <- nil
// Ignoring withdrawals here, since the block fetcher is not used post-merge. // Ignoring withdrawals here, will set it to empty later if EmptyWithdrawalsHash in header.
txs, uncles, _, sidecars := res.Res.(*eth.BlockBodiesResponse).Unpack() txs, uncles, _, sidecars := res.Res.(*eth.BlockBodiesResponse).Unpack()
f.FilterBodies(peer, txs, uncles, sidecars, time.Now()) f.FilterBodies(peer, txs, uncles, sidecars, time.Now())
@ -723,6 +723,9 @@ func (f *BlockFetcher) loop() {
matched = true matched = true
if f.getBlock(hash) == nil { if f.getBlock(hash) == nil {
block := types.NewBlockWithHeader(announce.header).WithBody(task.transactions[i], task.uncles[i]) block := types.NewBlockWithHeader(announce.header).WithBody(task.transactions[i], task.uncles[i])
if block.Header().EmptyWithdrawalsHash() {
block = block.WithWithdrawals(make([]*types.Withdrawal, 0))
}
block = block.WithSidecars(task.sidecars[i]) block = block.WithSidecars(task.sidecars[i])
block.ReceivedAt = task.time block.ReceivedAt = task.time
blocks = append(blocks, block) blocks = append(blocks, block)

@ -367,7 +367,7 @@ func handleBlockBodies(backend Backend, msg Decoder, peer *Peer) error {
txsHashes[i] = types.DeriveSha(types.Transactions(body.Transactions), hasher) txsHashes[i] = types.DeriveSha(types.Transactions(body.Transactions), hasher)
uncleHashes[i] = types.CalcUncleHash(body.Uncles) uncleHashes[i] = types.CalcUncleHash(body.Uncles)
// Withdrawals may be not nil, but a empty value when Sidecars not empty // Withdrawals may be not nil, but a empty value when Sidecars not empty
if len(body.Withdrawals) > 0 { if body.Withdrawals != nil {
withdrawalHashes[i] = types.DeriveSha(types.Withdrawals(body.Withdrawals), hasher) withdrawalHashes[i] = types.DeriveSha(types.Withdrawals(body.Withdrawals), hasher)
} }
} }

@ -1053,7 +1053,7 @@ func (b *Block) Withdrawals(ctx context.Context) (*[]*Withdrawal, error) {
return nil, err return nil, err
} }
// Pre-shanghai blocks // Pre-shanghai blocks
if block.Header().EmptyWithdrawalsHash() { if block.Header().WithdrawalsHash == nil {
return nil, nil return nil, nil
} }
ret := make([]*Withdrawal, 0, len(block.Withdrawals())) ret := make([]*Withdrawal, 0, len(block.Withdrawals()))

@ -1367,6 +1367,10 @@ func (w *worker) commit(env *environment, interval func(), update bool, start ti
// env.receipts = receipts // env.receipts = receipts
finalizeBlockTimer.UpdateSince(finalizeStart) finalizeBlockTimer.UpdateSince(finalizeStart)
if block.Header().EmptyWithdrawalsHash() {
block = block.WithWithdrawals(make([]*types.Withdrawal, 0))
}
// If Cancun enabled, sidecars can't be nil then. // If Cancun enabled, sidecars can't be nil then.
if w.chainConfig.IsCancun(env.header.Number, env.header.Time) && env.sidecars == nil { if w.chainConfig.IsCancun(env.header.Number, env.header.Time) && env.sidecars == nil {
env.sidecars = make(types.BlobSidecars, 0) env.sidecars = make(types.BlobSidecars, 0)