Skip to content

Commit ab9623e

Browse files
committed
Update ProposeBeaconBlock Prysm RPC for Deneb (Non builder) (#12495)
1 parent 3ed7fa6 commit ab9623e

File tree

7 files changed

+170
-52
lines changed

7 files changed

+170
-52
lines changed

beacon-chain/blockchain/setup_test.go

+5
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ func (mb *mockBroadcaster) BroadcastSyncCommitteeMessage(_ context.Context, _ ui
5252
return nil
5353
}
5454

55+
func (mb *mockBroadcaster) BroadcastBlob(_ context.Context, _ uint64, _ *ethpb.SignedBlobSidecar) error {
56+
mb.broadcastCalled = true
57+
return nil
58+
}
59+
5560
func (mb *mockBroadcaster) BroadcastBLSChanges(_ context.Context, _ []*ethpb.SignedBLSToExecutionChange) {
5661
}
5762

beacon-chain/p2p/interfaces.go

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ type Broadcaster interface {
3535
Broadcast(context.Context, proto.Message) error
3636
BroadcastAttestation(ctx context.Context, subnet uint64, att *ethpb.Attestation) error
3737
BroadcastSyncCommitteeMessage(ctx context.Context, subnet uint64, sMsg *ethpb.SyncCommitteeMessage) error
38+
BroadcastBlob(ctx context.Context, subnet uint64, blob *ethpb.SignedBlobSidecar) error
3839
}
3940

4041
// SetStreamHandler configures p2p to handle streams of a certain topic ID.

beacon-chain/p2p/testing/fuzz_p2p.go

+5
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,11 @@ func (_ *FakeP2P) BroadcastSyncCommitteeMessage(_ context.Context, _ uint64, _ *
143143
return nil
144144
}
145145

146+
// BroadcastBlob -- fake.
147+
func (_ *FakeP2P) BroadcastBlob(_ context.Context, _ uint64, _ *ethpb.SignedBlobSidecar) error {
148+
return nil
149+
}
150+
146151
// InterceptPeerDial -- fake.
147152
func (_ *FakeP2P) InterceptPeerDial(peer.ID) (allow bool) {
148153
return true

beacon-chain/p2p/testing/mock_broadcaster.go

+6
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,9 @@ func (m *MockBroadcaster) BroadcastSyncCommitteeMessage(_ context.Context, _ uin
3333
m.BroadcastCalled = true
3434
return nil
3535
}
36+
37+
// BroadcastBlob broadcasts a blob for mock.
38+
func (m *MockBroadcaster) BroadcastBlob(context.Context, uint64, *ethpb.SignedBlobSidecar) error {
39+
m.BroadcastCalled = true
40+
return nil
41+
}

beacon-chain/p2p/testing/p2p.go

+6
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,12 @@ func (p *TestP2P) BroadcastSyncCommitteeMessage(_ context.Context, _ uint64, _ *
176176
return nil
177177
}
178178

179+
// BroadcastBlob broadcasts a blob for mock.
180+
func (p *TestP2P) BroadcastBlob(context.Context, uint64, *ethpb.SignedBlobSidecar) error {
181+
p.BroadcastCalled = true
182+
return nil
183+
}
184+
179185
// SetStreamHandler for RPC.
180186
func (p *TestP2P) SetStreamHandler(topic string, handler network.StreamHandler) {
181187
p.BHost.SetStreamHandler(protocol.ID(topic), handler)

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

+69-49
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@ import (
1919
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/helpers"
2020
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/transition"
2121
"github.com/prysmaticlabs/prysm/v4/beacon-chain/db/kv"
22+
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
2223
"github.com/prysmaticlabs/prysm/v4/config/params"
2324
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
2425
"github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces"
2526
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
2627
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
2728
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
29+
"github.com/prysmaticlabs/prysm/v4/runtime/version"
2830
"github.com/prysmaticlabs/prysm/v4/time/slots"
2931
"github.com/sirupsen/logrus"
3032
"go.opencensus.io/trace"
@@ -215,11 +217,77 @@ func (vs *Server) GetBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (
215217
func (vs *Server) ProposeBeaconBlock(ctx context.Context, req *ethpb.GenericSignedBeaconBlock) (*ethpb.ProposeResponse, error) {
216218
ctx, span := trace.StartSpan(ctx, "ProposerServer.ProposeBeaconBlock")
217219
defer span.End()
220+
218221
blk, err := blocks.NewSignedBeaconBlock(req.Block)
219222
if err != nil {
220223
return nil, status.Errorf(codes.InvalidArgument, "%s: %v", CouldNotDecodeBlock, err)
221224
}
222-
return vs.proposeGenericBeaconBlock(ctx, blk)
225+
226+
unblinder, err := newUnblinder(blk, vs.BlockBuilder)
227+
if err != nil {
228+
return nil, errors.Wrap(err, "could not create unblinder")
229+
}
230+
blk, err = unblinder.unblindBuilderBlock(ctx)
231+
if err != nil {
232+
return nil, errors.Wrap(err, "could not unblind builder block")
233+
}
234+
235+
// Broadcast the new block to the network.
236+
blkPb, err := blk.Proto()
237+
if err != nil {
238+
return nil, errors.Wrap(err, "could not get protobuf block")
239+
}
240+
if err := vs.P2P.Broadcast(ctx, blkPb); err != nil {
241+
return nil, fmt.Errorf("could not broadcast block: %v", err)
242+
}
243+
244+
root, err := blk.Block().HashTreeRoot()
245+
if err != nil {
246+
return nil, fmt.Errorf("could not tree hash block: %v", err)
247+
}
248+
log.WithFields(logrus.Fields{
249+
"blockRoot": hex.EncodeToString(root[:]),
250+
}).Debug("Broadcasting block")
251+
252+
if blk.Version() >= version.Deneb {
253+
b, ok := req.GetBlock().(*ethpb.GenericSignedBeaconBlock_Deneb)
254+
if !ok {
255+
return nil, status.Error(codes.Internal, "Could not cast block to Deneb")
256+
}
257+
if len(b.Deneb.Blobs) > fieldparams.MaxBlobsPerBlock {
258+
return nil, status.Errorf(codes.InvalidArgument, "Too many blobs in block: %d", len(b.Deneb.Blobs))
259+
}
260+
scs := make([]*ethpb.BlobSidecar, len(b.Deneb.Blobs))
261+
for i, blob := range b.Deneb.Blobs {
262+
if err := vs.P2P.BroadcastBlob(ctx, blob.Message.Index, blob); err != nil {
263+
log.WithError(err).Errorf("Could not broadcast blob index %d / %d", i, len(b.Deneb.Blobs))
264+
}
265+
scs[i] = blob.Message
266+
}
267+
if len(scs) > 0 {
268+
if err := vs.BeaconDB.SaveBlobSidecar(ctx, scs); err != nil {
269+
return nil, err
270+
}
271+
}
272+
}
273+
274+
// Do not block proposal critical path with debug logging or block feed updates.
275+
defer func() {
276+
log.WithField("blockRoot", fmt.Sprintf("%#x", bytesutil.Trunc(root[:]))).Debugf(
277+
"Block proposal received via RPC")
278+
vs.BlockNotifier.BlockFeed().Send(&feed.Event{
279+
Type: blockfeed.ReceivedBlock,
280+
Data: &blockfeed.ReceivedBlockData{SignedBlock: blk},
281+
})
282+
}()
283+
284+
if err := vs.BlockReceiver.ReceiveBlock(ctx, blk, root); err != nil {
285+
return nil, fmt.Errorf("could not process beacon block: %v", err)
286+
}
287+
288+
return &ethpb.ProposeResponse{
289+
BlockRoot: root[:],
290+
}, nil
223291
}
224292

225293
// PrepareBeaconProposer caches and updates the fee recipient for the given proposer.
@@ -301,54 +369,6 @@ func (vs *Server) GetFeeRecipientByPubKey(ctx context.Context, request *ethpb.Fe
301369
}, nil
302370
}
303371

304-
func (vs *Server) proposeGenericBeaconBlock(ctx context.Context, blk interfaces.SignedBeaconBlock) (*ethpb.ProposeResponse, error) {
305-
ctx, span := trace.StartSpan(ctx, "ProposerServer.proposeGenericBeaconBlock")
306-
defer span.End()
307-
root, err := blk.Block().HashTreeRoot()
308-
if err != nil {
309-
return nil, fmt.Errorf("could not tree hash block: %v", err)
310-
}
311-
312-
unblinder, err := newUnblinder(blk, vs.BlockBuilder)
313-
if err != nil {
314-
return nil, errors.Wrap(err, "could not create unblinder")
315-
}
316-
blk, err = unblinder.unblindBuilderBlock(ctx)
317-
if err != nil {
318-
return nil, errors.Wrap(err, "could not unblind builder block")
319-
}
320-
321-
// Do not block proposal critical path with debug logging or block feed updates.
322-
defer func() {
323-
log.WithField("blockRoot", fmt.Sprintf("%#x", bytesutil.Trunc(root[:]))).Debugf(
324-
"Block proposal received via RPC")
325-
vs.BlockNotifier.BlockFeed().Send(&feed.Event{
326-
Type: blockfeed.ReceivedBlock,
327-
Data: &blockfeed.ReceivedBlockData{SignedBlock: blk},
328-
})
329-
}()
330-
331-
// Broadcast the new block to the network.
332-
blkPb, err := blk.Proto()
333-
if err != nil {
334-
return nil, errors.Wrap(err, "could not get protobuf block")
335-
}
336-
if err := vs.P2P.Broadcast(ctx, blkPb); err != nil {
337-
return nil, fmt.Errorf("could not broadcast block: %v", err)
338-
}
339-
log.WithFields(logrus.Fields{
340-
"blockRoot": hex.EncodeToString(root[:]),
341-
}).Debug("Broadcasting block")
342-
343-
if err := vs.BlockReceiver.ReceiveBlock(ctx, blk, root); err != nil {
344-
return nil, fmt.Errorf("could not process beacon block: %v", err)
345-
}
346-
347-
return &ethpb.ProposeResponse{
348-
BlockRoot: root[:],
349-
}, nil
350-
}
351-
352372
// computeStateRoot computes the state root after a block has been processed through a state transition and
353373
// returns it to the validator client.
354374
func (vs *Server) computeStateRoot(ctx context.Context, block interfaces.ReadOnlySignedBeaconBlock) ([]byte, error) {

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

+78-3
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,7 @@ func TestProposer_ProposeBlock_OK(t *testing.T) {
631631
tests := []struct {
632632
name string
633633
block func([32]byte) *ethpb.GenericSignedBeaconBlock
634+
err string
634635
}{
635636
{
636637
name: "phase0",
@@ -678,6 +679,66 @@ func TestProposer_ProposeBlock_OK(t *testing.T) {
678679
return &ethpb.GenericSignedBeaconBlock{Block: blk}
679680
},
680681
},
682+
{
683+
name: "bellatrix",
684+
block: func(parent [32]byte) *ethpb.GenericSignedBeaconBlock {
685+
blockToPropose := util.NewBeaconBlockBellatrix()
686+
blockToPropose.Block.Slot = 5
687+
blockToPropose.Block.ParentRoot = parent[:]
688+
blk := &ethpb.GenericSignedBeaconBlock_Bellatrix{Bellatrix: blockToPropose}
689+
return &ethpb.GenericSignedBeaconBlock{Block: blk}
690+
},
691+
},
692+
{
693+
name: "deneb block no blob",
694+
block: func(parent [32]byte) *ethpb.GenericSignedBeaconBlock {
695+
blockToPropose := util.NewBeaconBlockDeneb()
696+
blockToPropose.Block.Slot = 5
697+
blockToPropose.Block.ParentRoot = parent[:]
698+
blk := &ethpb.GenericSignedBeaconBlock_Deneb{Deneb: &ethpb.SignedBeaconBlockAndBlobsDeneb{
699+
Block: blockToPropose,
700+
}}
701+
return &ethpb.GenericSignedBeaconBlock{Block: blk}
702+
},
703+
},
704+
{
705+
name: "deneb block has blobs",
706+
block: func(parent [32]byte) *ethpb.GenericSignedBeaconBlock {
707+
blockToPropose := util.NewBeaconBlockDeneb()
708+
blockToPropose.Block.Slot = 5
709+
blockToPropose.Block.ParentRoot = parent[:]
710+
blk := &ethpb.GenericSignedBeaconBlock_Deneb{Deneb: &ethpb.SignedBeaconBlockAndBlobsDeneb{
711+
Block: blockToPropose,
712+
Blobs: []*ethpb.SignedBlobSidecar{
713+
{Message: &ethpb.BlobSidecar{Index: 0, Slot: 5, BlockParentRoot: parent[:]}},
714+
{Message: &ethpb.BlobSidecar{Index: 1, Slot: 5, BlockParentRoot: parent[:]}},
715+
{Message: &ethpb.BlobSidecar{Index: 2, Slot: 5, BlockParentRoot: parent[:]}},
716+
{Message: &ethpb.BlobSidecar{Index: 3, Slot: 5, BlockParentRoot: parent[:]}},
717+
},
718+
}}
719+
return &ethpb.GenericSignedBeaconBlock{Block: blk}
720+
},
721+
},
722+
{
723+
name: "deneb block has too many blobs",
724+
err: "Too many blobs in block: 5",
725+
block: func(parent [32]byte) *ethpb.GenericSignedBeaconBlock {
726+
blockToPropose := util.NewBeaconBlockDeneb()
727+
blockToPropose.Block.Slot = 5
728+
blockToPropose.Block.ParentRoot = parent[:]
729+
blk := &ethpb.GenericSignedBeaconBlock_Deneb{Deneb: &ethpb.SignedBeaconBlockAndBlobsDeneb{
730+
Block: blockToPropose,
731+
Blobs: []*ethpb.SignedBlobSidecar{
732+
{Message: &ethpb.BlobSidecar{Index: 0, Slot: 5, BlockParentRoot: parent[:]}},
733+
{Message: &ethpb.BlobSidecar{Index: 1, Slot: 5, BlockParentRoot: parent[:]}},
734+
{Message: &ethpb.BlobSidecar{Index: 2, Slot: 5, BlockParentRoot: parent[:]}},
735+
{Message: &ethpb.BlobSidecar{Index: 3, Slot: 5, BlockParentRoot: parent[:]}},
736+
{Message: &ethpb.BlobSidecar{Index: 4, Slot: 5, BlockParentRoot: parent[:]}},
737+
},
738+
}}
739+
return &ethpb.GenericSignedBeaconBlock{Block: blk}
740+
},
741+
},
681742
}
682743

683744
for _, tt := range tests {
@@ -690,17 +751,31 @@ func TestProposer_ProposeBlock_OK(t *testing.T) {
690751
require.NoError(t, err)
691752

692753
c := &mock.ChainService{Root: bsRoot[:], State: beaconState}
754+
db := dbutil.SetupDB(t)
693755
proposerServer := &Server{
694756
BlockReceiver: c,
695757
BlockNotifier: c.BlockNotifier(),
696758
P2P: mockp2p.NewTestP2P(t),
697759
BlockBuilder: &builderTest.MockBuilderService{HasConfigured: true, PayloadCapella: emptyPayloadCapella()},
760+
BeaconDB: db,
698761
}
699762
blockToPropose := tt.block(bsRoot)
700763
res, err := proposerServer.ProposeBeaconBlock(context.Background(), blockToPropose)
701-
assert.NoError(t, err, "Could not propose block correctly")
702-
if res == nil || len(res.BlockRoot) == 0 {
703-
t.Error("No block root was returned")
764+
if tt.err != "" { // Expecting an error
765+
require.ErrorContains(t, tt.err, err)
766+
} else {
767+
assert.NoError(t, err, "Could not propose block correctly")
768+
if res == nil || len(res.BlockRoot) == 0 {
769+
t.Error("No block root was returned")
770+
}
771+
}
772+
if tt.name == "deneb block has blobs" {
773+
scs, err := db.BlobSidecarsBySlot(ctx, blockToPropose.GetDeneb().Block.Block.Slot)
774+
require.NoError(t, err)
775+
assert.Equal(t, 4, len(scs))
776+
for i, sc := range scs {
777+
require.Equal(t, uint64(i), sc.Index)
778+
}
704779
}
705780
})
706781
}

0 commit comments

Comments
 (0)