Skip to content

Commit 4cd1f9d

Browse files
committed
Execution api: add and use blobs_bundle_v2
1 parent 2d46d6f commit 4cd1f9d

File tree

15 files changed

+388
-75
lines changed

15 files changed

+388
-75
lines changed

beacon-chain/execution/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,5 +146,6 @@ go_test(
146146
"@com_github_prometheus_client_golang//prometheus:go_default_library",
147147
"@com_github_sirupsen_logrus//:go_default_library",
148148
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
149+
"@org_golang_google_protobuf//encoding/protojson:go_default_library",
149150
],
150151
)

beacon-chain/execution/engine_client.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ func (s *Service) ForkchoiceUpdated(
275275
func getPayloadMethodAndMessage(slot primitives.Slot) (string, proto.Message) {
276276
pe := slots.ToEpoch(slot)
277277
if pe >= params.BeaconConfig().FuluForkEpoch {
278-
return GetPayloadMethodV5, &pb.ExecutionBundleElectra{}
278+
return GetPayloadMethodV5, &pb.ExecutionBundleFulu{}
279279
}
280280
if pe >= params.BeaconConfig().ElectraForkEpoch {
281281
return GetPayloadMethodV4, &pb.ExecutionBundleElectra{}

beacon-chain/execution/engine_client_test.go

Lines changed: 59 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import (
3838
"github.com/prysmaticlabs/prysm/v5/testing/util"
3939
"github.com/prysmaticlabs/prysm/v5/time/slots"
4040
logTest "github.com/sirupsen/logrus/hooks/test"
41+
"google.golang.org/protobuf/encoding/protojson"
4142
)
4243

4344
var (
@@ -168,6 +169,7 @@ func TestClient_HTTP(t *testing.T) {
168169
cfg.CapellaForkEpoch = 1
169170
cfg.DenebForkEpoch = 2
170171
cfg.ElectraForkEpoch = 3
172+
cfg.FuluForkEpoch = 4
171173
params.OverrideBeaconConfig(cfg)
172174

173175
t.Run(GetPayloadMethod, func(t *testing.T) {
@@ -406,7 +408,48 @@ func TestClient_HTTP(t *testing.T) {
406408

407409
require.DeepEqual(t, requests, resp.ExecutionRequests)
408410
})
411+
t.Run(GetPayloadMethodV5, func(t *testing.T) {
412+
payloadId := [8]byte{1}
413+
want, ok := fix["ExecutionBundleFulu"].(*pb.ExecutionBundleFulu)
414+
require.Equal(t, true, ok)
415+
416+
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
417+
w.Header().Set("Content-Type", "application/json")
418+
defer func() {
419+
require.NoError(t, r.Body.Close())
420+
}()
421+
// Read and verify request
422+
enc, err := io.ReadAll(r.Body)
423+
require.NoError(t, err)
424+
jsonRequestString := string(enc)
425+
reqArg, err := json.Marshal(pb.PayloadIDBytes(payloadId))
426+
require.NoError(t, err)
427+
require.Equal(t, strings.Contains(jsonRequestString, string(reqArg)), true)
428+
429+
// Use protojson to marshal the result correctly
430+
marshaled, err := protojson.Marshal(want)
431+
require.NoError(t, err)
432+
433+
response := `{"jsonrpc":"2.0","id":1,"result":` + string(marshaled) + `}`
434+
_, err = w.Write([]byte(response))
435+
require.NoError(t, err)
436+
}))
437+
defer srv.Close()
409438

439+
rpcClient, err := rpc.DialHTTP(srv.URL)
440+
require.NoError(t, err)
441+
defer rpcClient.Close()
442+
443+
client := &Service{rpcClient: rpcClient}
444+
resp, err := client.GetPayload(ctx, payloadId, 4*params.BeaconConfig().SlotsPerEpoch)
445+
require.NoError(t, err)
446+
447+
_, ok = resp.BlobsBundle.(*pb.BlobsBundleV2)
448+
if !ok {
449+
t.Logf("resp.BlobsBundle has unexpected type: %T", resp.BlobsBundle)
450+
}
451+
require.Equal(t, true, ok)
452+
})
410453
t.Run(ForkchoiceUpdatedMethod+" VALID status", func(t *testing.T) {
411454
forkChoiceState := &pb.ForkchoiceState{
412455
HeadBlockHash: []byte("head"),
@@ -1540,6 +1583,7 @@ func fixtures() map[string]interface{} {
15401583
"ExecutionPayloadCapellaWithValue": s.ExecutionPayloadWithValueCapella,
15411584
"ExecutionPayloadDenebWithValue": s.ExecutionPayloadWithValueDeneb,
15421585
"ExecutionBundleElectra": s.ExecutionBundleElectra,
1586+
"ExecutionBundleFulu": s.ExecutionBundleFulu,
15431587
"ValidPayloadStatus": s.ValidPayloadStatus,
15441588
"InvalidBlockHashStatus": s.InvalidBlockHashStatus,
15451589
"AcceptedStatus": s.AcceptedStatus,
@@ -1860,15 +1904,20 @@ func fixturesStruct() *payloadFixtures {
18601904
LatestValidHash: foo[:],
18611905
}
18621906
return &payloadFixtures{
1863-
ExecutionBlock: executionBlock,
1864-
ExecutionPayloadBody: executionPayloadBodyFixture,
1865-
ExecutionPayload: executionPayloadFixture,
1866-
ExecutionPayloadCapella: executionPayloadFixtureCapella,
1867-
ExecutionPayloadDeneb: executionPayloadFixtureDeneb,
1868-
EmptyExecutionPayloadDeneb: emptyExecutionPayloadDeneb,
1869-
ExecutionPayloadWithValueCapella: executionPayloadWithValueFixtureCapella,
1870-
ExecutionPayloadWithValueDeneb: executionPayloadWithValueFixtureDeneb,
1871-
ExecutionBundleElectra: executionBundleFixtureElectra,
1907+
ExecutionBlock: executionBlock,
1908+
ExecutionPayloadBody: executionPayloadBodyFixture,
1909+
ExecutionPayload: executionPayloadFixture,
1910+
ExecutionPayloadCapella: executionPayloadFixtureCapella,
1911+
ExecutionPayloadDeneb: executionPayloadFixtureDeneb,
1912+
EmptyExecutionPayloadDeneb: emptyExecutionPayloadDeneb,
1913+
ExecutionPayloadWithValueCapella: executionPayloadWithValueFixtureCapella,
1914+
ExecutionPayloadWithValueDeneb: executionPayloadWithValueFixtureDeneb,
1915+
ExecutionBundleElectra: executionBundleFixtureElectra,
1916+
ExecutionBundleFulu: &pb.ExecutionBundleFulu{
1917+
Payload: &pb.ExecutionPayloadDeneb{},
1918+
BlobsBundle: &pb.BlobsBundleV2{},
1919+
ExecutionRequests: [][]byte{},
1920+
},
18721921
ValidPayloadStatus: validStatus,
18731922
InvalidBlockHashStatus: inValidBlockHashStatus,
18741923
AcceptedStatus: acceptedStatus,
@@ -1893,6 +1942,7 @@ type payloadFixtures struct {
18931942
ExecutionPayloadWithValueCapella *pb.GetPayloadV2ResponseJson
18941943
ExecutionPayloadWithValueDeneb *pb.GetPayloadV3ResponseJson
18951944
ExecutionBundleElectra *pb.GetPayloadV4ResponseJson
1945+
ExecutionBundleFulu *pb.ExecutionBundleFulu
18961946
ValidPayloadStatus *pb.PayloadStatus
18971947
InvalidBlockHashStatus *pb.PayloadStatus
18981948
AcceptedStatus *pb.PayloadStatus

beacon-chain/rpc/prysm/v1alpha1/validator/construct_generic_block.go

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package validator
33
import (
44
"fmt"
55

6+
"github.com/pkg/errors"
67
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
78
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
89
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
@@ -12,9 +13,13 @@ import (
1213
)
1314

1415
// constructGenericBeaconBlock constructs a `GenericBeaconBlock` based on the block version and other parameters.
15-
func (vs *Server) constructGenericBeaconBlock(sBlk interfaces.SignedBeaconBlock, blobsBundle *enginev1.BlobsBundle, winningBid primitives.Wei) (*ethpb.GenericBeaconBlock, error) {
16+
func (vs *Server) constructGenericBeaconBlock(
17+
sBlk interfaces.SignedBeaconBlock,
18+
blobsBundle enginev1.BlobsBundler,
19+
winningBid primitives.Wei,
20+
) (*ethpb.GenericBeaconBlock, error) {
1621
if sBlk == nil || sBlk.Block() == nil {
17-
return nil, fmt.Errorf("block cannot be nil")
22+
return nil, errors.New("block cannot be nil")
1823
}
1924

2025
blockProto, err := sBlk.Block().Proto()
@@ -34,12 +39,21 @@ func (vs *Server) constructGenericBeaconBlock(sBlk interfaces.SignedBeaconBlock,
3439
return vs.constructBellatrixBlock(blockProto, isBlinded, bidStr), nil
3540
case version.Capella:
3641
return vs.constructCapellaBlock(blockProto, isBlinded, bidStr), nil
37-
case version.Deneb:
38-
return vs.constructDenebBlock(blockProto, isBlinded, bidStr, blobsBundle), nil
39-
case version.Electra:
40-
return vs.constructElectraBlock(blockProto, isBlinded, bidStr, blobsBundle), nil
42+
case version.Deneb, version.Electra:
43+
bundle, ok := blobsBundle.(*enginev1.BlobsBundle)
44+
if blobsBundle != nil && !ok {
45+
return nil, fmt.Errorf("expected *BlobsBundle, got %T", blobsBundle)
46+
}
47+
if sBlk.Version() == version.Deneb {
48+
return vs.constructDenebBlock(blockProto, isBlinded, bidStr, bundle), nil
49+
}
50+
return vs.constructElectraBlock(blockProto, isBlinded, bidStr, bundle), nil
4151
case version.Fulu:
42-
return vs.constructFuluBlock(blockProto, isBlinded, bidStr, blobsBundle), nil
52+
bundle, ok := blobsBundle.(*enginev1.BlobsBundleV2)
53+
if blobsBundle != nil && !ok {
54+
return nil, fmt.Errorf("expected *BlobsBundleV2, got %T", blobsBundle)
55+
}
56+
return vs.constructFuluBlock(blockProto, isBlinded, bidStr, bundle), nil
4357
default:
4458
return nil, fmt.Errorf("unknown block version: %d", sBlk.Version())
4559
}
@@ -92,7 +106,7 @@ func (vs *Server) constructElectraBlock(blockProto proto.Message, isBlinded bool
92106
return &ethpb.GenericBeaconBlock{Block: &ethpb.GenericBeaconBlock_Electra{Electra: electraContents}, IsBlinded: false, PayloadValue: payloadValue}
93107
}
94108

95-
func (vs *Server) constructFuluBlock(blockProto proto.Message, isBlinded bool, payloadValue string, bundle *enginev1.BlobsBundle) *ethpb.GenericBeaconBlock {
109+
func (vs *Server) constructFuluBlock(blockProto proto.Message, isBlinded bool, payloadValue string, bundle *enginev1.BlobsBundleV2) *ethpb.GenericBeaconBlock {
96110
if isBlinded {
97111
return &ethpb.GenericBeaconBlock{Block: &ethpb.GenericBeaconBlock_BlindedFulu{BlindedFulu: blockProto.(*ethpb.BlindedBeaconBlockFulu)}, IsBlinded: true, PayloadValue: payloadValue}
98112
}

beacon-chain/rpc/prysm/v1alpha1/validator/construct_generic_block_test.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,19 @@ func TestConstructGenericBeaconBlock(t *testing.T) {
2929
require.NoError(t, err)
3030
r1, err := eb.Block.HashTreeRoot()
3131
require.NoError(t, err)
32-
result, err := vs.constructGenericBeaconBlock(b, nil, primitives.ZeroWei())
32+
bundle := &enginev1.BlobsBundleV2{
33+
KzgCommitments: [][]byte{{1, 2, 3}},
34+
Proofs: [][]byte{{4, 5, 6}},
35+
Blobs: [][]byte{{7, 8, 9}},
36+
}
37+
result, err := vs.constructGenericBeaconBlock(b, bundle, primitives.ZeroWei())
3338
require.NoError(t, err)
3439
r2, err := result.GetFulu().Block.HashTreeRoot()
3540
require.NoError(t, err)
3641
require.Equal(t, r1, r2)
3742
require.Equal(t, result.IsBlinded, false)
43+
require.DeepEqual(t, bundle.Blobs, result.GetFulu().GetBlobs())
44+
require.DeepEqual(t, bundle.Proofs, result.GetFulu().GetKzgProofs())
3845
})
3946

4047
// Test for Electra version

beacon-chain/rpc/prysm/v1alpha1/validator/proposer.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ func (vs *Server) BuildBlockParallel(ctx context.Context, sBlk interfaces.Signed
238238
}()
239239

240240
winningBid := primitives.ZeroWei()
241-
var bundle *enginev1.BlobsBundle
241+
var bundle enginev1.BlobsBundler
242242
if sBlk.Version() >= version.Bellatrix {
243243
local, err := vs.getLocalPayload(ctx, sBlk.Block(), head)
244244
if err != nil {
@@ -369,7 +369,7 @@ func (vs *Server) handleBlindedBlock(ctx context.Context, block interfaces.Signe
369369
}
370370

371371
if isPeerDASEnabled {
372-
dataColumnSideCars, err := peerdas.ConstructDataColumnSidecars(block, bundle.Blobs, bundle.Proofs)
372+
dataColumnSideCars, err := peerdas.ConstructDataColumnSidecars(block, bundle.GetBlobs(), bundle.GetProofs())
373373
if err != nil {
374374
return nil, nil, nil, errors.Wrap(err, "construct data column sidecars")
375375
}

beacon-chain/rpc/prysm/v1alpha1/validator/proposer_bellatrix.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ const blockBuilderTimeout = 1 * time.Second
5454
const gasLimitAdjustmentFactor = 1024
5555

5656
// Sets the execution data for the block. Execution data can come from local EL client or remote builder depends on validator registration and circuit breaker conditions.
57-
func setExecutionData(ctx context.Context, blk interfaces.SignedBeaconBlock, local *blocks.GetPayloadResponse, bid builder.Bid, builderBoostFactor primitives.Gwei) (primitives.Wei, *enginev1.BlobsBundle, error) {
57+
func setExecutionData(ctx context.Context, blk interfaces.SignedBeaconBlock, local *blocks.GetPayloadResponse, bid builder.Bid, builderBoostFactor primitives.Gwei) (primitives.Wei, enginev1.BlobsBundler, error) {
5858
_, span := trace.StartSpan(ctx, "ProposerServer.setExecutionData")
5959
defer span.End()
6060

@@ -376,7 +376,7 @@ func matchingWithdrawalsRoot(local, builder interfaces.ExecutionData) (bool, err
376376
func setLocalExecution(blk interfaces.SignedBeaconBlock, local *blocks.GetPayloadResponse) error {
377377
var kzgCommitments [][]byte
378378
if local.BlobsBundle != nil {
379-
kzgCommitments = local.BlobsBundle.KzgCommitments
379+
kzgCommitments = local.BlobsBundle.GetKzgCommitments()
380380
}
381381
if local.ExecutionRequests != nil {
382382
if err := blk.SetExecutionRequests(local.ExecutionRequests); err != nil {

consensus-types/blocks/execution.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ func NewWrappedExecutionData(v proto.Message) (interfaces.ExecutionData, error)
4141
case *enginev1.ExecutionBundleElectra:
4242
// note: no payload changes in electra so using deneb
4343
return WrappedExecutionPayloadDeneb(pbStruct.Payload)
44+
case *enginev1.ExecutionBundleFulu:
45+
return WrappedExecutionPayloadDeneb(pbStruct.Payload)
4446
default:
4547
// return nil, errors.Wrapf(ErrUnsupportedVersion, "type %T", pbStruct)
4648
return nil, errs.Wrapf(ErrUnsupportedVersion, "type %T", pbStruct)

consensus-types/blocks/get_payload.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212
// GetPayloadResponseV(1|2|3|4) value.
1313
type GetPayloadResponse struct {
1414
ExecutionData interfaces.ExecutionData
15-
BlobsBundle *pb.BlobsBundle
15+
BlobsBundle pb.BlobsBundler
1616
OverrideBuilder bool
1717
// todo: should we convert this to Gwei up front?
1818
Bid primitives.Wei
@@ -24,6 +24,10 @@ type bundleGetter interface {
2424
GetBlobsBundle() *pb.BlobsBundle
2525
}
2626

27+
type bundleV2Getter interface {
28+
GetBlobsBundle() *pb.BlobsBundleV2
29+
}
30+
2731
// bidValueGetter is an interface satisfied by get payload responses that have a bid value.
2832
type bidValueGetter interface {
2933
GetValue() []byte
@@ -43,6 +47,10 @@ func NewGetPayloadResponse(msg proto.Message) (*GetPayloadResponse, error) {
4347
if hasBundle {
4448
r.BlobsBundle = bundleGetter.GetBlobsBundle()
4549
}
50+
bundleV2Getter, hasBundle := msg.(bundleV2Getter)
51+
if hasBundle {
52+
r.BlobsBundle = bundleV2Getter.GetBlobsBundle()
53+
}
4654
bidValueGetter, hasBid := msg.(bidValueGetter)
4755
executionRequestsGetter, hasExecutionRequests := msg.(executionRequestsGetter)
4856
wei := primitives.ZeroWei()

proto/engine/v1/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ go_proto_library(
7474
go_library(
7575
name = "go_default_library",
7676
srcs = [
77+
"blobs_bundle.go",
7778
"electra.go",
7879
"execution_engine.go",
7980
"json_marshal_unmarshal.go",

0 commit comments

Comments
 (0)