Skip to content

Commit

Permalink
Fix Blobs By Range RPC Handler (#14910)
Browse files Browse the repository at this point in the history
* Add tests for TestSendBlobsByRangeRequest. Currently not working with sequential blob validation.

* Copy Root First

* Allow Test For Maximum Amount of Blobs

* Fails with the Same error

* Fix Last Test Assertion

* Add in Fix

* Changelog

---------

Co-authored-by: Preston Van Loon <[email protected]>
  • Loading branch information
nisdas and prestonvanloon authored Feb 11, 2025
1 parent 4b43f13 commit 8c4ea85
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 1 deletion.
2 changes: 1 addition & 1 deletion beacon-chain/sync/rpc_send_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ func SendBlobsByRangeRequest(ctx context.Context, tor blockchain.TemporalOracle,
}
defer closeStream(stream, log)

maxBlobsPerBlock := uint64(params.BeaconConfig().MaxBlobsPerBlock(req.StartSlot))
maxBlobsPerBlock := uint64(params.BeaconConfig().MaxBlobsPerBlock(req.StartSlot + primitives.Slot(req.Count)))
max := params.BeaconConfig().MaxRequestBlobSidecars
if slots.ToEpoch(req.StartSlot) >= params.BeaconConfig().ElectraForkEpoch {
max = params.BeaconConfig().MaxRequestBlobSidecarsElectra
Expand Down
120 changes: 120 additions & 0 deletions beacon-chain/sync/rpc_send_request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/prysmaticlabs/prysm/v5/testing/assert"
"github.com/prysmaticlabs/prysm/v5/testing/require"
"github.com/prysmaticlabs/prysm/v5/testing/util"
"github.com/prysmaticlabs/prysm/v5/time/slots"
)

func TestSendRequest_SendBeaconBlocksByRangeRequest(t *testing.T) {
Expand Down Expand Up @@ -691,3 +692,122 @@ func TestSeqBlobValid(t *testing.T) {
})
}
}

func TestSendBlobsByRangeRequest(t *testing.T) {
topic := fmt.Sprintf("%s/ssz_snappy", p2p.RPCBlobSidecarsByRangeTopicV1)
ctx := context.Background()

t.Run("single blob - Deneb", func(t *testing.T) {
// Setup genesis such that we are currently in deneb.
s := uint64(slots.UnsafeEpochStart(params.BeaconConfig().DenebForkEpoch)) * params.BeaconConfig().SecondsPerSlot
clock := startup.NewClock(time.Now().Add(-time.Second*time.Duration(s)), [32]byte{})
ctxByte, err := ContextByteVersionsForValRoot(clock.GenesisValidatorsRoot())
require.NoError(t, err)
// Setup peers
p1 := p2ptest.NewTestP2P(t)
p2 := p2ptest.NewTestP2P(t)
p1.Connect(p2)
// Set current slot to a deneb slot.
slot := slots.UnsafeEpochStart(params.BeaconConfig().DenebForkEpoch + 1)
// Create a simple handler that will return a valid response.
p2.SetStreamHandler(topic, func(stream network.Stream) {
defer func() {
assert.NoError(t, stream.Close())
}()

req := &ethpb.BlobSidecarsByRangeRequest{}
assert.NoError(t, p2.Encoding().DecodeWithMaxLength(stream, req))
assert.Equal(t, slot, req.StartSlot)
assert.Equal(t, uint64(1), req.Count)

// Create a sequential set of blobs with the appropriate header information.
var prevRoot [32]byte
for i := req.StartSlot; i < req.StartSlot+primitives.Slot(req.Count); i++ {
b := util.HydrateBlobSidecar(&ethpb.BlobSidecar{})
b.SignedBlockHeader.Header.Slot = i
b.SignedBlockHeader.Header.ParentRoot = prevRoot[:]
ro, err := blocks.NewROBlob(b)
require.NoError(t, err)
vro := blocks.NewVerifiedROBlob(ro)
prevRoot = vro.BlockRoot()
assert.NoError(t, WriteBlobSidecarChunk(stream, clock, p2.Encoding(), vro))
}
})
req := &ethpb.BlobSidecarsByRangeRequest{
StartSlot: slot,
Count: 1,
}

blobs, err := SendBlobsByRangeRequest(ctx, clock, p1, p2.PeerID(), ctxByte, req)
assert.NoError(t, err)
assert.Equal(t, 1, len(blobs))
})

t.Run("Deneb - Electra epoch boundary crossing", func(t *testing.T) {
cfg := params.BeaconConfig()
cfg.ElectraForkEpoch = cfg.DenebForkEpoch + 1
undo, err := params.SetActiveWithUndo(cfg)
require.NoError(t, err)
defer func() {
require.NoError(t, undo())
}()
// Setup genesis such that we are currently in deneb.
s := uint64(slots.UnsafeEpochStart(params.BeaconConfig().DenebForkEpoch)) * params.BeaconConfig().SecondsPerSlot
clock := startup.NewClock(time.Now().Add(-time.Second*time.Duration(s)), [32]byte{})
ctxByte, err := ContextByteVersionsForValRoot(clock.GenesisValidatorsRoot())
require.NoError(t, err)
// Setup peers
p1 := p2ptest.NewTestP2P(t)
p2 := p2ptest.NewTestP2P(t)
p1.Connect(p2)
// Set current slot to the first slot of the last deneb epoch.
slot := slots.UnsafeEpochStart(params.BeaconConfig().DenebForkEpoch)
// Create a simple handler that will return a valid response.
p2.SetStreamHandler(topic, func(stream network.Stream) {
defer func() {
assert.NoError(t, stream.Close())
}()

req := &ethpb.BlobSidecarsByRangeRequest{}
assert.NoError(t, p2.Encoding().DecodeWithMaxLength(stream, req))
assert.Equal(t, slot, req.StartSlot)
assert.Equal(t, uint64(params.BeaconConfig().SlotsPerEpoch)*3, req.Count)

// Create a sequential set of blobs with the appropriate header information.
var prevRoot [32]byte
for i := req.StartSlot; i < req.StartSlot+primitives.Slot(req.Count); i++ {
maxBlobsForSlot := cfg.MaxBlobsPerBlock(i)
parentRoot := prevRoot
header := util.HydrateSignedBeaconHeader(&ethpb.SignedBeaconBlockHeader{})
header.Header.Slot = i
header.Header.ParentRoot = parentRoot[:]
bRoot, err := header.Header.HashTreeRoot()
require.NoError(t, err)
prevRoot = bRoot
// Send the maximum possible blobs per slot.
for j := 0; j < maxBlobsForSlot; j++ {
b := util.HydrateBlobSidecar(&ethpb.BlobSidecar{})
b.SignedBlockHeader = header
b.Index = uint64(j)
ro, err := blocks.NewROBlob(b)
require.NoError(t, err)
vro := blocks.NewVerifiedROBlob(ro)
assert.NoError(t, WriteBlobSidecarChunk(stream, clock, p2.Encoding(), vro))
}
}
})
req := &ethpb.BlobSidecarsByRangeRequest{
StartSlot: slot,
Count: uint64(params.BeaconConfig().SlotsPerEpoch) * 3,
}
maxDenebBlobs := cfg.MaxBlobsPerBlockAtEpoch(cfg.DenebForkEpoch)
maxElectraBlobs := cfg.MaxBlobsPerBlockAtEpoch(cfg.ElectraForkEpoch)
totalDenebBlobs := primitives.Slot(maxDenebBlobs) * params.BeaconConfig().SlotsPerEpoch
totalElectraBlobs := primitives.Slot(maxElectraBlobs) * 2 * params.BeaconConfig().SlotsPerEpoch
totalExpectedBlobs := totalDenebBlobs + totalElectraBlobs

blobs, err := SendBlobsByRangeRequest(ctx, clock, p1, p2.PeerID(), ctxByte, req)
assert.NoError(t, err)
assert.Equal(t, int(totalExpectedBlobs), len(blobs))
})
}
3 changes: 3 additions & 0 deletions changelog/nisdas_fix_blobs_by_range.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### Fixed

- We now use the correct maximum value when serving blobs for electra blocks.

0 comments on commit 8c4ea85

Please sign in to comment.