Skip to content

Commit 78429f7

Browse files
beacon/engine: don't omit empty withdrawals in ExecutionPayloadBodies (#26698)
This ensures the "withdrawals" field will always be present in responses to getPayloadBodiesByRangeV1 and getPayloadBodiesByHashV1. --------- Co-authored-by: Felix Lange <[email protected]>
1 parent 1e3177d commit 78429f7

File tree

2 files changed

+77
-33
lines changed

2 files changed

+77
-33
lines changed

beacon/engine/types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,5 +233,5 @@ func BlockToExecutableData(block *types.Block, fees *big.Int) *ExecutionPayloadE
233233
// ExecutionPayloadBodyV1 is used in the response to GetPayloadBodiesByHashV1 and GetPayloadBodiesByRangeV1
234234
type ExecutionPayloadBodyV1 struct {
235235
TransactionData []hexutil.Bytes `json:"transactions"`
236-
Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"`
236+
Withdrawals []*types.Withdrawal `json:"withdrawals"`
237237
}

eth/catalyst/api_test.go

Lines changed: 76 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@ package catalyst
1919
import (
2020
"bytes"
2121
"context"
22+
crand "crypto/rand"
2223
"fmt"
2324
"math/big"
25+
"math/rand"
26+
"reflect"
2427
"sync"
2528
"testing"
2629
"time"
@@ -41,7 +44,6 @@ import (
4144
"github.com/ethereum/go-ethereum/node"
4245
"github.com/ethereum/go-ethereum/p2p"
4346
"github.com/ethereum/go-ethereum/params"
44-
"github.com/ethereum/go-ethereum/rlp"
4547
"github.com/ethereum/go-ethereum/rpc"
4648
"github.com/ethereum/go-ethereum/trie"
4749
)
@@ -473,18 +475,21 @@ func TestFullAPI(t *testing.T) {
473475
ethservice.TxPool().AddLocal(tx)
474476
}
475477

476-
setupBlocks(t, ethservice, 10, parent, callback)
478+
setupBlocks(t, ethservice, 10, parent, callback, nil)
477479
}
478480

479-
func setupBlocks(t *testing.T, ethservice *eth.Ethereum, n int, parent *types.Header, callback func(parent *types.Header)) []*types.Header {
481+
func setupBlocks(t *testing.T, ethservice *eth.Ethereum, n int, parent *types.Header, callback func(parent *types.Header), withdrawals [][]*types.Withdrawal) []*types.Header {
480482
api := NewConsensusAPI(ethservice)
481483
var blocks []*types.Header
482484
for i := 0; i < n; i++ {
483485
callback(parent)
486+
var w []*types.Withdrawal
487+
if withdrawals != nil {
488+
w = withdrawals[i]
489+
}
484490

485-
payload := getNewPayload(t, api, parent)
486-
487-
execResp, err := api.NewPayloadV1(*payload)
491+
payload := getNewPayload(t, api, parent, w)
492+
execResp, err := api.NewPayloadV2(*payload)
488493
if err != nil {
489494
t.Fatalf("can't execute payload: %v", err)
490495
}
@@ -676,10 +681,10 @@ func TestEmptyBlocks(t *testing.T) {
676681
api := NewConsensusAPI(ethservice)
677682

678683
// Setup 10 blocks on the canonical chain
679-
setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Header) {})
684+
setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Header) {}, nil)
680685

681686
// (1) check LatestValidHash by sending a normal payload (P1'')
682-
payload := getNewPayload(t, api, commonAncestor)
687+
payload := getNewPayload(t, api, commonAncestor, nil)
683688

684689
status, err := api.NewPayloadV1(*payload)
685690
if err != nil {
@@ -693,7 +698,7 @@ func TestEmptyBlocks(t *testing.T) {
693698
}
694699

695700
// (2) Now send P1' which is invalid
696-
payload = getNewPayload(t, api, commonAncestor)
701+
payload = getNewPayload(t, api, commonAncestor, nil)
697702
payload.GasUsed += 1
698703
payload = setBlockhash(payload)
699704
// Now latestValidHash should be the common ancestor
@@ -711,7 +716,7 @@ func TestEmptyBlocks(t *testing.T) {
711716
}
712717

713718
// (3) Now send a payload with unknown parent
714-
payload = getNewPayload(t, api, commonAncestor)
719+
payload = getNewPayload(t, api, commonAncestor, nil)
715720
payload.ParentHash = common.Hash{1}
716721
payload = setBlockhash(payload)
717722
// Now latestValidHash should be the common ancestor
@@ -727,11 +732,12 @@ func TestEmptyBlocks(t *testing.T) {
727732
}
728733
}
729734

730-
func getNewPayload(t *testing.T, api *ConsensusAPI, parent *types.Header) *engine.ExecutableData {
735+
func getNewPayload(t *testing.T, api *ConsensusAPI, parent *types.Header, withdrawals []*types.Withdrawal) *engine.ExecutableData {
731736
params := engine.PayloadAttributes{
732737
Timestamp: parent.Time + 1,
733738
Random: crypto.Keccak256Hash([]byte{byte(1)}),
734739
SuggestedFeeRecipient: parent.Coinbase,
740+
Withdrawals: withdrawals,
735741
}
736742

737743
payload, err := assembleBlock(api, parent.Hash(), &params)
@@ -799,7 +805,7 @@ func TestTrickRemoteBlockCache(t *testing.T) {
799805
commonAncestor := ethserviceA.BlockChain().CurrentBlock()
800806

801807
// Setup 10 blocks on the canonical chain
802-
setupBlocks(t, ethserviceA, 10, commonAncestor, func(parent *types.Header) {})
808+
setupBlocks(t, ethserviceA, 10, commonAncestor, func(parent *types.Header) {}, nil)
803809
commonAncestor = ethserviceA.BlockChain().CurrentBlock()
804810

805811
var invalidChain []*engine.ExecutableData
@@ -808,7 +814,7 @@ func TestTrickRemoteBlockCache(t *testing.T) {
808814
//invalidChain = append(invalidChain, payload1)
809815

810816
// create an invalid payload2 (P2)
811-
payload2 := getNewPayload(t, apiA, commonAncestor)
817+
payload2 := getNewPayload(t, apiA, commonAncestor, nil)
812818
//payload2.ParentHash = payload1.BlockHash
813819
payload2.GasUsed += 1
814820
payload2 = setBlockhash(payload2)
@@ -817,7 +823,7 @@ func TestTrickRemoteBlockCache(t *testing.T) {
817823
head := payload2
818824
// create some valid payloads on top
819825
for i := 0; i < 10; i++ {
820-
payload := getNewPayload(t, apiA, commonAncestor)
826+
payload := getNewPayload(t, apiA, commonAncestor, nil)
821827
payload.ParentHash = head.BlockHash
822828
payload = setBlockhash(payload)
823829
invalidChain = append(invalidChain, payload)
@@ -855,10 +861,10 @@ func TestInvalidBloom(t *testing.T) {
855861
api := NewConsensusAPI(ethservice)
856862

857863
// Setup 10 blocks on the canonical chain
858-
setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Header) {})
864+
setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Header) {}, nil)
859865

860866
// (1) check LatestValidHash by sending a normal payload (P1'')
861-
payload := getNewPayload(t, api, commonAncestor)
867+
payload := getNewPayload(t, api, commonAncestor, nil)
862868
payload.LogsBloom = append(payload.LogsBloom, byte(1))
863869
status, err := api.NewPayloadV1(*payload)
864870
if err != nil {
@@ -1233,8 +1239,10 @@ func TestNilWithdrawals(t *testing.T) {
12331239
}
12341240

12351241
func setupBodies(t *testing.T) (*node.Node, *eth.Ethereum, []*types.Block) {
1236-
genesis, preMergeBlocks := generateMergeChain(10, false)
1237-
n, ethservice := startEthService(t, genesis, preMergeBlocks)
1242+
genesis, blocks := generateMergeChain(10, true)
1243+
n, ethservice := startEthService(t, genesis, blocks)
1244+
// enable shanghai on the last block
1245+
ethservice.BlockChain().Config().ShanghaiTime = &blocks[len(blocks)-1].Header().Time
12381246

12391247
var (
12401248
parent = ethservice.BlockChain().CurrentBlock()
@@ -1249,12 +1257,38 @@ func setupBodies(t *testing.T) (*node.Node, *eth.Ethereum, []*types.Block) {
12491257
ethservice.TxPool().AddLocal(tx)
12501258
}
12511259

1252-
postMergeHeaders := setupBlocks(t, ethservice, 10, parent, callback)
1253-
postMergeBlocks := make([]*types.Block, len(postMergeHeaders))
1254-
for i, header := range postMergeHeaders {
1255-
postMergeBlocks[i] = ethservice.BlockChain().GetBlock(header.Hash(), header.Number.Uint64())
1260+
withdrawals := make([][]*types.Withdrawal, 10)
1261+
withdrawals[0] = nil // should be filtered out by miner
1262+
withdrawals[1] = make([]*types.Withdrawal, 0)
1263+
for i := 2; i < len(withdrawals); i++ {
1264+
addr := make([]byte, 20)
1265+
crand.Read(addr)
1266+
withdrawals[i] = []*types.Withdrawal{
1267+
{Index: rand.Uint64(), Validator: rand.Uint64(), Amount: rand.Uint64(), Address: common.BytesToAddress(addr)},
1268+
}
1269+
}
1270+
1271+
postShanghaiHeaders := setupBlocks(t, ethservice, 10, parent, callback, withdrawals)
1272+
postShanghaiBlocks := make([]*types.Block, len(postShanghaiHeaders))
1273+
for i, header := range postShanghaiHeaders {
1274+
postShanghaiBlocks[i] = ethservice.BlockChain().GetBlock(header.Hash(), header.Number.Uint64())
12561275
}
1257-
return n, ethservice, append(preMergeBlocks, postMergeBlocks...)
1276+
return n, ethservice, append(blocks, postShanghaiBlocks...)
1277+
}
1278+
1279+
func allHashes(blocks []*types.Block) []common.Hash {
1280+
var hashes []common.Hash
1281+
for _, b := range blocks {
1282+
hashes = append(hashes, b.Hash())
1283+
}
1284+
return hashes
1285+
}
1286+
func allBodies(blocks []*types.Block) []*types.Body {
1287+
var bodies []*types.Body
1288+
for _, b := range blocks {
1289+
bodies = append(bodies, b.Body())
1290+
}
1291+
return bodies
12581292
}
12591293

12601294
func TestGetBlockBodiesByHash(t *testing.T) {
@@ -1296,6 +1330,11 @@ func TestGetBlockBodiesByHash(t *testing.T) {
12961330
results: []*types.Body{blocks[0].Body(), nil, blocks[0].Body(), blocks[0].Body()},
12971331
hashes: []common.Hash{blocks[0].Hash(), {1, 2}, blocks[0].Hash(), blocks[0].Hash()},
12981332
},
1333+
// all blocks
1334+
{
1335+
results: allBodies(blocks),
1336+
hashes: allHashes(blocks),
1337+
},
12991338
}
13001339

13011340
for k, test := range tests {
@@ -1364,6 +1403,12 @@ func TestGetBlockBodiesByRange(t *testing.T) {
13641403
start: 22,
13651404
count: 2,
13661405
},
1406+
// allBlocks
1407+
{
1408+
results: allBodies(blocks),
1409+
start: 1,
1410+
count: hexutil.Uint64(len(blocks)),
1411+
},
13671412
}
13681413

13691414
for k, test := range tests {
@@ -1434,15 +1479,14 @@ func equalBody(a *types.Body, b *engine.ExecutionPayloadBodyV1) bool {
14341479
} else if a == nil || b == nil {
14351480
return false
14361481
}
1437-
var want []hexutil.Bytes
1438-
for _, tx := range a.Transactions {
1439-
data, _ := tx.MarshalBinary()
1440-
want = append(want, hexutil.Bytes(data))
1441-
}
1442-
aBytes, errA := rlp.EncodeToBytes(want)
1443-
bBytes, errB := rlp.EncodeToBytes(b.TransactionData)
1444-
if errA != errB {
1482+
if len(a.Transactions) != len(b.TransactionData) {
14451483
return false
14461484
}
1447-
return bytes.Equal(aBytes, bBytes)
1485+
for i, tx := range a.Transactions {
1486+
data, _ := tx.MarshalBinary()
1487+
if !bytes.Equal(data, b.TransactionData[i]) {
1488+
return false
1489+
}
1490+
}
1491+
return reflect.DeepEqual(a.Withdrawals, b.Withdrawals)
14481492
}

0 commit comments

Comments
 (0)