Skip to content

Commit 9d7e3a3

Browse files
rkapkaprylabs-bulldozer[bot]
authored andcommitted
Reconstruct full Capella block (OffchainLabs#11732)
* Merge branch 'reconstruct-capella-block' into capella (cherry picked from commit b060158) # Conflicts: # beacon-chain/rpc/eth/beacon/blocks.go # proto/engine/v1/json_marshal_unmarshal.go * remove unneeded test * rename methods * add doc to interface * deepsource (cherry picked from commit 903cab7) # Conflicts: # beacon-chain/execution/testing/mock_engine_client.go * bzl * fix failing tests * single ExecutionBlockByHash function * fix engine mock * deepsource * reorder checks * single execution block type * update tests * update doc * bytes test * remove toWithdrawalJSON Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
1 parent 2a0b8f8 commit 9d7e3a3

File tree

12 files changed

+293
-34
lines changed

12 files changed

+293
-34
lines changed

beacon-chain/blockchain/pow_block.go

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
1616
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
1717
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
18+
"github.com/prysmaticlabs/prysm/v3/runtime/version"
1819
"github.com/prysmaticlabs/prysm/v3/time/slots"
1920
"github.com/sirupsen/logrus"
2021
)
@@ -92,6 +93,7 @@ func (s *Service) getBlkParentHashAndTD(ctx context.Context, blkHash []byte) ([]
9293
if blk == nil {
9394
return nil, nil, errors.New("pow block is nil")
9495
}
96+
blk.Version = version.Bellatrix
9597
blkTDBig, err := hexutil.DecodeBig(blk.TotalDifficulty)
9698
if err != nil {
9799
return nil, nil, errors.Wrap(err, "could not decode merge block total difficulty")

beacon-chain/execution/BUILD.bazel

+1
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ go_test(
121121
"//network/authorization:go_default_library",
122122
"//proto/engine/v1:go_default_library",
123123
"//proto/prysm/v1alpha1:go_default_library",
124+
"//runtime/version:go_default_library",
124125
"//testing/assert:go_default_library",
125126
"//testing/require:go_default_library",
126127
"//testing/util:go_default_library",

beacon-chain/execution/engine_client.go

+36-13
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ type ForkchoiceUpdatedResponse struct {
5757
// block with an execution payload from a signed beacon block and a connection
5858
// to an execution client's engine API.
5959
type ExecutionPayloadReconstructor interface {
60-
ReconstructFullBellatrixBlock(
60+
ReconstructFullBlock(
6161
ctx context.Context, blindedBlock interfaces.SignedBeaconBlock,
6262
) (interfaces.SignedBeaconBlock, error)
6363
ReconstructFullBellatrixBlockBatch(
@@ -403,9 +403,9 @@ func (s *Service) HeaderByNumber(ctx context.Context, number *big.Int) (*types.H
403403
return hdr, err
404404
}
405405

406-
// ReconstructFullBellatrixBlock takes in a blinded beacon block and reconstructs
406+
// ReconstructFullBlock takes in a blinded beacon block and reconstructs
407407
// a beacon block with a full execution payload via the engine API.
408-
func (s *Service) ReconstructFullBellatrixBlock(
408+
func (s *Service) ReconstructFullBlock(
409409
ctx context.Context, blindedBlock interfaces.SignedBeaconBlock,
410410
) (interfaces.SignedBeaconBlock, error) {
411411
if err := blocks.BeaconBlockIsNil(blindedBlock); err != nil {
@@ -437,11 +437,12 @@ func (s *Service) ReconstructFullBellatrixBlock(
437437
if executionBlock == nil {
438438
return nil, fmt.Errorf("received nil execution block for request by hash %#x", executionBlockHash)
439439
}
440+
executionBlock.Version = blindedBlock.Version()
440441
payload, err := fullPayloadFromExecutionBlock(header, executionBlock)
441442
if err != nil {
442443
return nil, err
443444
}
444-
fullBlock, err := blocks.BuildSignedBeaconBlockFromExecutionPayload(blindedBlock, payload)
445+
fullBlock, err := blocks.BuildSignedBeaconBlockFromExecutionPayload(blindedBlock, payload.Proto())
445446
if err != nil {
446447
return nil, err
447448
}
@@ -504,7 +505,7 @@ func (s *Service) ReconstructFullBellatrixBlockBatch(
504505
if err != nil {
505506
return nil, err
506507
}
507-
fullBlock, err := blocks.BuildSignedBeaconBlockFromExecutionPayload(blindedBlocks[realIdx], payload)
508+
fullBlock, err := blocks.BuildSignedBeaconBlockFromExecutionPayload(blindedBlocks[realIdx], payload.Proto())
508509
if err != nil {
509510
return nil, err
510511
}
@@ -526,26 +527,47 @@ func (s *Service) ReconstructFullBellatrixBlockBatch(
526527

527528
func fullPayloadFromExecutionBlock(
528529
header interfaces.ExecutionData, block *pb.ExecutionBlock,
529-
) (*pb.ExecutionPayload, error) {
530+
) (interfaces.ExecutionData, error) {
530531
if header.IsNil() || block == nil {
531532
return nil, errors.New("execution block and header cannot be nil")
532533
}
533-
if !bytes.Equal(header.BlockHash(), block.Hash[:]) {
534+
blockHash := block.Hash
535+
if !bytes.Equal(header.BlockHash(), blockHash[:]) {
534536
return nil, fmt.Errorf(
535537
"block hash field in execution header %#x does not match execution block hash %#x",
536538
header.BlockHash(),
537-
block.Hash,
539+
blockHash,
538540
)
539541
}
540-
txs := make([][]byte, len(block.Transactions))
541-
for i, tx := range block.Transactions {
542+
blockTransactions := block.Transactions
543+
txs := make([][]byte, len(blockTransactions))
544+
for i, tx := range blockTransactions {
542545
txBin, err := tx.MarshalBinary()
543546
if err != nil {
544547
return nil, err
545548
}
546549
txs[i] = txBin
547550
}
548-
return &pb.ExecutionPayload{
551+
552+
if block.Version == version.Bellatrix {
553+
return blocks.WrappedExecutionPayload(&pb.ExecutionPayload{
554+
ParentHash: header.ParentHash(),
555+
FeeRecipient: header.FeeRecipient(),
556+
StateRoot: header.StateRoot(),
557+
ReceiptsRoot: header.ReceiptsRoot(),
558+
LogsBloom: header.LogsBloom(),
559+
PrevRandao: header.PrevRandao(),
560+
BlockNumber: header.BlockNumber(),
561+
GasLimit: header.GasLimit(),
562+
GasUsed: header.GasUsed(),
563+
Timestamp: header.Timestamp(),
564+
ExtraData: header.ExtraData(),
565+
BaseFeePerGas: header.BaseFeePerGas(),
566+
BlockHash: blockHash[:],
567+
Transactions: txs,
568+
})
569+
}
570+
return blocks.WrappedExecutionPayloadCapella(&pb.ExecutionPayloadCapella{
549571
ParentHash: header.ParentHash(),
550572
FeeRecipient: header.FeeRecipient(),
551573
StateRoot: header.StateRoot(),
@@ -558,9 +580,10 @@ func fullPayloadFromExecutionBlock(
558580
Timestamp: header.Timestamp(),
559581
ExtraData: header.ExtraData(),
560582
BaseFeePerGas: header.BaseFeePerGas(),
561-
BlockHash: block.Hash[:],
583+
BlockHash: blockHash[:],
562584
Transactions: txs,
563-
}, nil
585+
Withdrawals: block.Withdrawals,
586+
})
564587
}
565588

566589
// Handles errors received from the RPC server according to the specification.

beacon-chain/execution/engine_client_test.go

+23-12
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
payloadattribute "github.com/prysmaticlabs/prysm/v3/consensus-types/payload-attribute"
2828
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
2929
pb "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
30+
"github.com/prysmaticlabs/prysm/v3/runtime/version"
3031
"github.com/prysmaticlabs/prysm/v3/testing/assert"
3132
"github.com/prysmaticlabs/prysm/v3/testing/require"
3233
"github.com/prysmaticlabs/prysm/v3/testing/util"
@@ -493,7 +494,7 @@ func TestReconstructFullBellatrixBlock(t *testing.T) {
493494
t.Run("nil block", func(t *testing.T) {
494495
service := &Service{}
495496

496-
_, err := service.ReconstructFullBellatrixBlock(ctx, nil)
497+
_, err := service.ReconstructFullBlock(ctx, nil)
497498
require.ErrorContains(t, "nil data", err)
498499
})
499500
t.Run("only blinded block", func(t *testing.T) {
@@ -502,7 +503,7 @@ func TestReconstructFullBellatrixBlock(t *testing.T) {
502503
bellatrixBlock := util.NewBeaconBlockBellatrix()
503504
wrapped, err := blocks.NewSignedBeaconBlock(bellatrixBlock)
504505
require.NoError(t, err)
505-
_, err = service.ReconstructFullBellatrixBlock(ctx, wrapped)
506+
_, err = service.ReconstructFullBlock(ctx, wrapped)
506507
require.ErrorContains(t, want, err)
507508
})
508509
t.Run("pre-merge execution payload", func(t *testing.T) {
@@ -517,7 +518,7 @@ func TestReconstructFullBellatrixBlock(t *testing.T) {
517518
require.NoError(t, err)
518519
wantedWrapped, err := blocks.NewSignedBeaconBlock(wanted)
519520
require.NoError(t, err)
520-
reconstructed, err := service.ReconstructFullBellatrixBlock(ctx, wrapped)
521+
reconstructed, err := service.ReconstructFullBlock(ctx, wrapped)
521522
require.NoError(t, err)
522523
require.DeepEqual(t, wantedWrapped, reconstructed)
523524
})
@@ -590,7 +591,7 @@ func TestReconstructFullBellatrixBlock(t *testing.T) {
590591
blindedBlock.Block.Body.ExecutionPayloadHeader = header
591592
wrapped, err := blocks.NewSignedBeaconBlock(blindedBlock)
592593
require.NoError(t, err)
593-
reconstructed, err := service.ReconstructFullBellatrixBlock(ctx, wrapped)
594+
reconstructed, err := service.ReconstructFullBlock(ctx, wrapped)
594595
require.NoError(t, err)
595596

596597
got, err := reconstructed.Block().Body().Execution()
@@ -1149,6 +1150,7 @@ func fixtures() map[string]interface{} {
11491150
receiptsRoot := bytesutil.PadTo([]byte("receiptsRoot"), fieldparams.RootLength)
11501151
logsBloom := bytesutil.PadTo([]byte("logs"), fieldparams.LogsBloomLength)
11511152
executionBlock := &pb.ExecutionBlock{
1153+
Version: version.Bellatrix,
11521154
Header: gethtypes.Header{
11531155
ParentHash: common.BytesToHash(parent),
11541156
UncleHash: common.BytesToHash(sha3Uncles),
@@ -1257,7 +1259,7 @@ func Test_fullPayloadFromExecutionBlock(t *testing.T) {
12571259
tests := []struct {
12581260
name string
12591261
args args
1260-
want *pb.ExecutionPayload
1262+
want func() interfaces.ExecutionData
12611263
err string
12621264
}{
12631265
{
@@ -1267,7 +1269,8 @@ func Test_fullPayloadFromExecutionBlock(t *testing.T) {
12671269
BlockHash: []byte("foo"),
12681270
},
12691271
block: &pb.ExecutionBlock{
1270-
Hash: common.BytesToHash([]byte("bar")),
1272+
Version: version.Bellatrix,
1273+
Hash: common.BytesToHash([]byte("bar")),
12711274
},
12721275
},
12731276
err: "does not match execution block hash",
@@ -1279,22 +1282,30 @@ func Test_fullPayloadFromExecutionBlock(t *testing.T) {
12791282
BlockHash: wantedHash[:],
12801283
},
12811284
block: &pb.ExecutionBlock{
1282-
Hash: wantedHash,
1285+
Version: version.Bellatrix,
1286+
Hash: wantedHash,
12831287
},
12841288
},
1285-
want: &pb.ExecutionPayload{
1286-
BlockHash: wantedHash[:],
1289+
want: func() interfaces.ExecutionData {
1290+
p, err := blocks.WrappedExecutionPayload(&pb.ExecutionPayload{
1291+
BlockHash: wantedHash[:],
1292+
Transactions: [][]byte{},
1293+
})
1294+
require.NoError(t, err)
1295+
return p
12871296
},
12881297
},
12891298
}
12901299
for _, tt := range tests {
12911300
t.Run(tt.name, func(t *testing.T) {
12921301
wrapped, err := blocks.WrappedExecutionPayloadHeader(tt.args.header)
1302+
require.NoError(t, err)
12931303
got, err := fullPayloadFromExecutionBlock(wrapped, tt.args.block)
1294-
if (err != nil) && !strings.Contains(err.Error(), tt.err) {
1295-
t.Fatalf("Wanted err %s got %v", tt.err, err)
1304+
if err != nil {
1305+
assert.ErrorContains(t, tt.err, err)
1306+
} else {
1307+
assert.DeepEqual(t, tt.want(), got)
12961308
}
1297-
require.DeepEqual(t, tt.want, got)
12981309
})
12991310
}
13001311
}

beacon-chain/execution/testing/mock_engine_client.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ func (e *EngineClient) ExecutionBlockByHash(_ context.Context, h common.Hash, _
7676
return b, e.ErrExecBlockByHash
7777
}
7878

79-
func (e *EngineClient) ReconstructFullBellatrixBlock(
79+
// ReconstructFullBlock --
80+
func (e *EngineClient) ReconstructFullBlock(
8081
_ context.Context, blindedBlock interfaces.SignedBeaconBlock,
8182
) (interfaces.SignedBeaconBlock, error) {
8283
if !blindedBlock.Block().IsBlinded() {
@@ -94,12 +95,13 @@ func (e *EngineClient) ReconstructFullBellatrixBlock(
9495
return blocks.BuildSignedBeaconBlockFromExecutionPayload(blindedBlock, payload)
9596
}
9697

98+
// ReconstructFullBellatrixBlockBatch --
9799
func (e *EngineClient) ReconstructFullBellatrixBlockBatch(
98100
ctx context.Context, blindedBlocks []interfaces.SignedBeaconBlock,
99101
) ([]interfaces.SignedBeaconBlock, error) {
100102
fullBlocks := make([]interfaces.SignedBeaconBlock, 0, len(blindedBlocks))
101103
for _, b := range blindedBlocks {
102-
newBlock, err := e.ReconstructFullBellatrixBlock(ctx, b)
104+
newBlock, err := e.ReconstructFullBlock(ctx, b)
103105
if err != nil {
104106
return nil, err
105107
}

beacon-chain/rpc/eth/beacon/blocks.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@ func (bs *Server) GetBlockV2(ctx context.Context, req *ethpbv2.BlockRequestV2) (
506506
if blindedBellatrixBlk == nil {
507507
return nil, status.Error(codes.Internal, "Nil block")
508508
}
509-
signedFullBlock, err := bs.ExecutionPayloadReconstructor.ReconstructFullBellatrixBlock(ctx, blk)
509+
signedFullBlock, err := bs.ExecutionPayloadReconstructor.ReconstructFullBlock(ctx, blk)
510510
if err != nil {
511511
return nil, status.Errorf(
512512
codes.Internal,
@@ -641,7 +641,7 @@ func (bs *Server) GetBlockSSZV2(ctx context.Context, req *ethpbv2.BlockRequestV2
641641
if blindedBellatrixBlk == nil {
642642
return nil, status.Error(codes.Internal, "Nil block")
643643
}
644-
signedFullBlock, err := bs.ExecutionPayloadReconstructor.ReconstructFullBellatrixBlock(ctx, blk)
644+
signedFullBlock, err := bs.ExecutionPayloadReconstructor.ReconstructFullBlock(ctx, blk)
645645
if err != nil {
646646
return nil, status.Errorf(
647647
codes.Internal,

beacon-chain/sync/rpc_beacon_blocks_by_root.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ func (s *Service) beaconBlocksRootRPCHandler(ctx context.Context, msg interface{
7575
}
7676

7777
if blk.Block().IsBlinded() {
78-
blk, err = s.cfg.executionPayloadReconstructor.ReconstructFullBellatrixBlock(ctx, blk)
78+
blk, err = s.cfg.executionPayloadReconstructor.ReconstructFullBlock(ctx, blk)
7979
if err != nil {
8080
log.WithError(err).Error("Could not get reconstruct full bellatrix block from blinded body")
8181
s.writeErrorResponseToStream(responseCodeServerError, types.ErrGeneric.Error(), stream)

encoding/bytesutil/bytes.go

+9
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,15 @@ func ToBytes4(x []byte) [4]byte {
100100
return y
101101
}
102102

103+
// ToBytes20 is a convenience method for converting a byte slice to a fix
104+
// sized 20 byte array. This method will truncate the input if it is larger
105+
// than 20 bytes.
106+
func ToBytes20(x []byte) [20]byte {
107+
var y [20]byte
108+
copy(y[:], x)
109+
return y
110+
}
111+
103112
// ToBytes32 is a convenience method for converting a byte slice to a fix
104113
// sized 32 byte array. This method will truncate the input if it is larger
105114
// than 32 bytes.

encoding/bytesutil/bytes_test.go

+18
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,24 @@ func TestToBytes48Array(t *testing.T) {
637637
}
638638
}
639639

640+
func TestToBytes20(t *testing.T) {
641+
tests := []struct {
642+
a []byte
643+
b [20]byte
644+
}{
645+
{nil, [20]byte{}},
646+
{[]byte{}, [20]byte{}},
647+
{[]byte{1}, [20]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
648+
{[]byte{1, 2, 3}, [20]byte{1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
649+
{[]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}, [20]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}},
650+
{[]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21}, [20]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}},
651+
}
652+
for _, tt := range tests {
653+
b := bytesutil.ToBytes20(tt.a)
654+
assert.DeepEqual(t, tt.b, b)
655+
}
656+
}
657+
640658
func TestLittleEndianBytesToBigInt(t *testing.T) {
641659
bytes := make([]byte, 8)
642660
binary.LittleEndian.PutUint64(bytes, 1234567890)

proto/engine/v1/BUILD.bazel

+4
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,17 @@ go_library(
7676
deps = [
7777
"//config/fieldparams:go_default_library",
7878
"//config/params:go_default_library",
79+
"//consensus-types/primitives:go_default_library",
7980
"//encoding/bytesutil:go_default_library",
8081
"//proto/eth/ext:go_default_library",
82+
"//runtime/version:go_default_library",
8183
"@com_github_ethereum_go_ethereum//common:go_default_library",
8284
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
8385
"@com_github_ethereum_go_ethereum//core/types:go_default_library",
8486
"@com_github_golang_protobuf//proto:go_default_library",
8587
"@com_github_pkg_errors//:go_default_library",
8688
"@com_github_prysmaticlabs_fastssz//:go_default_library",
89+
"@com_github_sirupsen_logrus//:go_default_library",
8790
"@go_googleapis//google/api:annotations_go_proto",
8891
"@io_bazel_rules_go//proto/wkt:descriptor_go_proto",
8992
"@io_bazel_rules_go//proto/wkt:timestamp_go_proto",
@@ -114,6 +117,7 @@ go_test(
114117
":go_default_library",
115118
"//config/fieldparams:go_default_library",
116119
"//config/params:go_default_library",
120+
"//consensus-types/primitives:go_default_library",
117121
"//encoding/bytesutil:go_default_library",
118122
"//testing/require:go_default_library",
119123
"@com_github_ethereum_go_ethereum//common:go_default_library",

0 commit comments

Comments
 (0)