From c056136ccecc3890fb67f75b6062d159e622aa20 Mon Sep 17 00:00:00 2001 From: Somnath Date: Wed, 15 Jan 2025 15:52:05 +0400 Subject: [PATCH] Update Empty requests list behaviour for Pectra-5 (#12985) (#13439) The updated EIP-7685 says requests with empty `request_data` should be dropped from `executionRequests` field in the API and ignored for hash calculation. See https://github.com/ethereum/EIPs/pull/8989, https://github.com/ethereum/execution-apis/pull/599 Issue board: https://github.com/erigontech/erigon/issues/12401 Cherry pick https://github.com/erigontech/erigon/pull/12985 --- consensus/merge/merge.go | 20 +++++++++++------ consensus/misc/eip6110.go | 5 ++++- consensus/misc/eip7002.go | 8 +++---- consensus/misc/eip7251.go | 8 +++---- core/blockchain.go | 1 - core/types/block.go | 2 +- core/types/eip7685_requests.go | 6 +++--- core/types/requests_test.go | 30 ++++++++++++++++++++++++++ turbo/builder/block_builder.go | 7 +----- turbo/engineapi/engine_server.go | 28 +++++++----------------- turbo/execution/eth1/block_building.go | 22 +++++++------------ 11 files changed, 76 insertions(+), 61 deletions(-) create mode 100644 core/types/requests_test.go diff --git a/consensus/merge/merge.go b/consensus/merge/merge.go index bff972b02d1..40f662c2524 100644 --- a/consensus/merge/merge.go +++ b/consensus/merge/merge.go @@ -162,7 +162,7 @@ func (s *Merge) Finalize(config *chain.Config, header *types.Header, state *stat var rs types.FlatRequests if config.IsPrague(header.Time) { - rs = make(types.FlatRequests, len(types.KnownRequestTypes)) + rs = make(types.FlatRequests, 0) allLogs := make(types.Logs, 0) for _, rec := range receipts { allLogs = append(allLogs, rec.Logs...) @@ -171,11 +171,17 @@ func (s *Merge) Finalize(config *chain.Config, header *types.Header, state *stat if err != nil { return nil, nil, nil, fmt.Errorf("error: could not parse requests logs: %v", err) } - rs[0] = *depositReqs + if depositReqs != nil { + rs = append(rs, *depositReqs) + } withdrawalReq := misc.DequeueWithdrawalRequests7002(syscall) - rs[1] = *withdrawalReq + if withdrawalReq != nil { + rs = append(rs, *withdrawalReq) + } consolidations := misc.DequeueConsolidationRequests7251(syscall) - rs[2] = *consolidations + if consolidations != nil { + rs = append(rs, *consolidations) + } if header.RequestsHash != nil { rh := rs.Hash() if *header.RequestsHash != *rh { @@ -194,15 +200,15 @@ func (s *Merge) FinalizeAndAssemble(config *chain.Config, header *types.Header, return s.eth1Engine.FinalizeAndAssemble(config, header, state, txs, uncles, receipts, withdrawals, chain, syscall, call, logger) } header.RequestsHash = nil - outTxs, outReceipts, rs, err := s.Finalize(config, header, state, txs, uncles, receipts, withdrawals, chain, syscall, logger) + outTxs, outReceipts, outRequests, err := s.Finalize(config, header, state, txs, uncles, receipts, withdrawals, chain, syscall, logger) if err != nil { return nil, nil, nil, nil, err } if config.IsPrague(header.Time) { - header.RequestsHash = rs.Hash() + header.RequestsHash = outRequests.Hash() } - return types.NewBlockForAsembling(header, outTxs, uncles, outReceipts, withdrawals), outTxs, outReceipts, rs, nil + return types.NewBlockForAsembling(header, outTxs, uncles, outReceipts, withdrawals), outTxs, outReceipts, outRequests, nil } func (s *Merge) SealHash(header *types.Header) (hash libcommon.Hash) { diff --git a/consensus/misc/eip6110.go b/consensus/misc/eip6110.go index be2d06ab050..f516fcb1164 100644 --- a/consensus/misc/eip6110.go +++ b/consensus/misc/eip6110.go @@ -85,5 +85,8 @@ func ParseDepositLogs(logs []*types.Log, depositContractAddress libcommon.Addres reqData = append(reqData, d...) } } - return &types.FlatRequest{Type: types.DepositRequestType, RequestData: reqData}, nil + if len(reqData) > 0 { + return &types.FlatRequest{Type: types.DepositRequestType, RequestData: reqData}, nil + } + return nil, nil } diff --git a/consensus/misc/eip7002.go b/consensus/misc/eip7002.go index ae2272cc36a..588f149c6fc 100644 --- a/consensus/misc/eip7002.go +++ b/consensus/misc/eip7002.go @@ -14,9 +14,9 @@ func DequeueWithdrawalRequests7002(syscall consensus.SystemCall) *types.FlatRequ log.Warn("Err with syscall to WithdrawalRequestAddress", "err", err) return nil } - if res == nil { - res = make([]byte, 0) + if res != nil { + // Just append the contract output + return &types.FlatRequest{Type: types.WithdrawalRequestType, RequestData: res} } - // Just append the contract outputs - return &types.FlatRequest{Type: types.WithdrawalRequestType, RequestData: res} + return nil } diff --git a/consensus/misc/eip7251.go b/consensus/misc/eip7251.go index e756b53bd27..5ce5dbce049 100644 --- a/consensus/misc/eip7251.go +++ b/consensus/misc/eip7251.go @@ -14,9 +14,9 @@ func DequeueConsolidationRequests7251(syscall consensus.SystemCall) *types.FlatR log.Warn("Err with syscall to ConsolidationRequestAddress", "err", err) return nil } - if res == nil { - res = make([]byte, 0) + if res != nil { + // Just append the contract output as the request data + return &types.FlatRequest{Type: types.ConsolidationRequestType, RequestData: res} } - // Just append the contract outputs as the encoded request data - return &types.FlatRequest{Type: types.ConsolidationRequestType, RequestData: res} + return nil } diff --git a/core/blockchain.go b/core/blockchain.go index 93dcf5d31f2..d55b9cdc98f 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -327,7 +327,6 @@ func FinalizeBlockExecution( if isMining { newBlock, newTxs, newReceipt, retRequests, err = engine.FinalizeAndAssemble(cc, header, ibs, txs, uncles, receipts, withdrawals, chainReader, syscall, nil, logger) } else { - // var rss types.Requests newTxs, newReceipt, retRequests, err = engine.Finalize(cc, header, ibs, txs, uncles, receipts, withdrawals, chainReader, syscall, logger) } if err != nil { diff --git a/core/types/block.go b/core/types/block.go index 8fea9be4296..81837c28762 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -39,7 +39,7 @@ import ( var ( EmptyRootHash = libcommon.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") - EmptyRequestsHash = libcommon.HexToHash("6036c41849da9c076ed79654d434017387a88fb833c2856b32e18218b3341c5f") + EmptyRequestsHash = libcommon.HexToHash("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") // sha256.Sum256([]byte("")) EmptyUncleHash = rlpHash([]*Header(nil)) ExtraVanityLength = 32 // Fixed number of extra-data prefix bytes reserved for signer vanity diff --git a/core/types/eip7685_requests.go b/core/types/eip7685_requests.go index bb5c31a10ac..a8c1172d1f7 100644 --- a/core/types/eip7685_requests.go +++ b/core/types/eip7685_requests.go @@ -52,12 +52,12 @@ func (f *FlatRequest) copy() *FlatRequest { type FlatRequests []FlatRequest func (r FlatRequests) Hash() *libcommon.Hash { - if r == nil || len(r) < len(KnownRequestTypes) { + if r == nil { return nil } sha := sha256.New() - for i, t := range KnownRequestTypes { - hi := sha256.Sum256(append([]byte{t}, r[i].RequestData...)) + for i, t := range r { + hi := sha256.Sum256(append([]byte{t.Type}, r[i].RequestData...)) sha.Write(hi[:]) } h := libcommon.BytesToHash(sha.Sum(nil)) diff --git a/core/types/requests_test.go b/core/types/requests_test.go new file mode 100644 index 00000000000..22fe1686046 --- /dev/null +++ b/core/types/requests_test.go @@ -0,0 +1,30 @@ +// Copyright 2025 The Erigon Authors +// This file is part of Erigon. +// +// Erigon is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Erigon is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Erigon. If not, see . + +package types + +import ( + "testing" +) + +func TestEmptyRequestsHashCalculation(t *testing.T) { + reqs := make(FlatRequests, 0) + h := reqs.Hash() + testH := EmptyRequestsHash + if *h != testH { + t.Errorf("Requests Hash calculation error for empty hash, expected: %v, got: %v", testH, h) + } +} diff --git a/turbo/builder/block_builder.go b/turbo/builder/block_builder.go index e9d3a42d39c..20bdc9afd30 100644 --- a/turbo/builder/block_builder.go +++ b/turbo/builder/block_builder.go @@ -1,7 +1,6 @@ package builder import ( - "fmt" "sync" "sync/atomic" "time" @@ -34,11 +33,7 @@ func NewBlockBuilder(build BlockBuilderFunc, param *core.BlockBuilderParameters) log.Warn("Failed to build a block", "err", err) } else { block := result.Block - reqLenStr := "nil" - if len(result.Requests) == 3 { - reqLenStr = fmt.Sprint("Deposit Requests", len(result.Requests[0].RequestData), "Withdrawal Requests", len(result.Requests[1].RequestData), "Consolidation Requests", len(result.Requests[2].RequestData)) - } - log.Info("Built block", "hash", block.Hash(), "height", block.NumberU64(), "txs", len(block.Transactions()), "executionRequests", len(result.Requests), "Requests", reqLenStr, "gas used %", 100*float64(block.GasUsed())/float64(block.GasLimit()), "time", time.Since(t)) + log.Info("Built block", "hash", block.Hash(), "height", block.NumberU64(), "txs", len(block.Transactions()), "executionRequests", len(result.Requests), "gas used %", 100*float64(block.GasUsed())/float64(block.GasLimit()), "time", time.Since(t)) } builder.syncCond.L.Lock() diff --git a/turbo/engineapi/engine_server.go b/turbo/engineapi/engine_server.go index 43d569733de..eff517858d1 100644 --- a/turbo/engineapi/engine_server.go +++ b/turbo/engineapi/engine_server.go @@ -126,11 +126,6 @@ func (s *EngineServer) checkRequestsPresence(time uint64, executionRequests []he return &rpc.InvalidParamsError{Message: "requests before Prague"} } } - // if s.config.IsPrague(time) { - // if len(executionRequests) < 3 { - // return &rpc.InvalidParamsError{Message: "missing requests list"} - // } - // } return nil } @@ -182,12 +177,12 @@ func (s *EngineServer) newPayload(ctx context.Context, req *engine_types.Executi return nil, err } if version >= clparams.ElectraVersion { - requests = make(types.FlatRequests, len(types.KnownRequestTypes)) - for i, r := range types.KnownRequestTypes { - if len(executionRequests) == i { - executionRequests = append(executionRequests, []byte{}) + requests = make(types.FlatRequests, 0) + for i, r := range executionRequests { + if len(r) <= 1 { + return nil, &rpc.InvalidParamsError{Message: fmt.Sprintf("Invalid Request at index %d", i)} } - requests[i] = types.FlatRequest{Type: r, RequestData: executionRequests[i]} + requests = append(requests, types.FlatRequest{Type: r[0], RequestData: r}) } rh := requests.Hash() header.RequestsHash = rh @@ -460,16 +455,9 @@ func (s *EngineServer) getPayload(ctx context.Context, payloadId uint64, version data := resp.Data var executionRequests []hexutility.Bytes if version >= clparams.ElectraVersion { - executionRequests = make([]hexutility.Bytes, len(types.KnownRequestTypes)) - if len(data.Requests.Requests) != 3 { - s.logger.Warn("Error in getPayload - data.Requests.Requests len not 3") - } - for i := 0; i < len(types.KnownRequestTypes); i++ { - if len(data.Requests.Requests) < i+1 || data.Requests.Requests[i] == nil { - executionRequests[i] = make(hexutility.Bytes, 0) - } else { - executionRequests[i] = data.Requests.Requests[i] - } + executionRequests = make([]hexutility.Bytes, 0) + for _, r := range data.Requests.Requests { + executionRequests = append(executionRequests, r) } } diff --git a/turbo/execution/eth1/block_building.go b/turbo/execution/eth1/block_building.go index ec5f3cf29db..0a2b1f2b9d7 100644 --- a/turbo/execution/eth1/block_building.go +++ b/turbo/execution/eth1/block_building.go @@ -199,21 +199,15 @@ func (e *EthereumExecutionModule) GetAssembledBlock(ctx context.Context, req *ex } } - var requestsBundle types2.RequestsBundle + var requestsBundle *types2.RequestsBundle if blockWithReceipts.Requests != nil { - requests := make([][]byte, len(types.KnownRequestTypes)) - if len(blockWithReceipts.Requests) == len(types.KnownRequestTypes) { - for i, r := range blockWithReceipts.Requests { - requests[i] = make([]byte, 0) - requests[i] = append(requests[i], r.RequestData...) - } - } else { - e.logger.Error("Requests len SHOULD BE", "equal to", len(types.KnownRequestTypes), "got", len(blockWithReceipts.Requests)) - for i := 0; i < len(types.KnownRequestTypes); i++ { - requests[i] = make([]byte, 0) - } + requestsBundle = &types2.RequestsBundle{} + requests := make([][]byte, 0) + for i, r := range blockWithReceipts.Requests { + requests[i] = make([]byte, 0) + requests[i] = append(requests[i], r.RequestData...) } - requestsBundle = types2.RequestsBundle{Requests: requests} + requestsBundle.Requests = requests } return &execution.GetAssembledBlockResponse{ @@ -221,7 +215,7 @@ func (e *EthereumExecutionModule) GetAssembledBlock(ctx context.Context, req *ex ExecutionPayload: payload, BlockValue: gointerfaces.ConvertUint256IntToH256(blockValue), BlobsBundle: blobsBundle, - Requests: &requestsBundle, + Requests: requestsBundle, }, Busy: false, }, nil