Implement PeerDAS sync (#15564)

* PeerDAS: Implement sync

* Fix Potuz's comment.

* Fix Potuz's comment.

* Fix Potuz's comment.

* Fix Satyajit's comment.

* Partially fix Potuz's comment.

* Fix Potuz's comment.

* Fix Potuz's comment.

* Fix Potuz's comment.

* Fix Potuz's comment.

* Fix Potuz's comment.

* Fix Potuz's comment.

* Fix Potuz's comment.

* Add tests for `sendDataColumnSidecarsRequest`.

* Fix Satyajit's comment.

* Implement `TestSendDataColumnSidecarsRequest`.

* Implement `TestFetchDataColumnSidecarsFromPeers`.

* Implement `TestUpdateResults`.

* Implement `TestSelectPeers`.

* Implement `TestCategorizeIndices`.

* Fix James' comment.

* Fix James's comment.

* Fix James' commit.

* Fix James' comment.

* Fix James' comment.

* Fix flakiness in `TestSelectPeers`.

* Update cmd/beacon-chain/flags/config.go

Co-authored-by: Preston Van Loon <pvanloon@offchainlabs.com>

* Fix Preston's comment.

* Fix James's comment.

* Implement `TestFetchDataColumnSidecars`.

* Revert "Fix Potuz's comment."

This reverts commit c45230b455.

* Fix Potuz's comment.

* Revert "Fix James' comment."

This reverts commit a3f919205a.

* Fix James' comment.

* Fix Preston's comment.

* Fix James' comment.

* `selectPeers`: Avoid map with key but empty value.

* Fix typo.

* Fix Potuz's comment.

* Fix Potuz's comment.

* Fix James' comment.

* Add DataColumnStorage and SubscribeAllDataSubnets flag.

* Add extra flags

* Fix Potuz's and Preston's comment.

* Add rate limiter check.

---------

Co-authored-by: Preston Van Loon <pvanloon@offchainlabs.com>
Co-authored-by: Kasey Kirkham <kasey@users.noreply.github.com>
This commit is contained in:
Manu NALEPA
2025-08-18 16:36:07 +02:00
committed by GitHub
parent 6528fb9cea
commit 00cf1f2507
52 changed files with 3351 additions and 1127 deletions

View File

@@ -13,7 +13,6 @@ go_library(
"roblob.go",
"roblock.go",
"rodatacolumn.go",
"rosidecar.go",
"setters.go",
"types.go",
],
@@ -54,7 +53,6 @@ go_test(
"roblob_test.go",
"roblock_test.go",
"rodatacolumn_test.go",
"rosidecar_test.go",
],
embed = [":go_default_library"],
deps = [
@@ -74,6 +72,5 @@ go_test(
"@com_github_prysmaticlabs_fastssz//:go_default_library",
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
"@com_github_prysmaticlabs_gohashtree//:go_default_library",
"@com_github_stretchr_testify//require:go_default_library",
],
)

View File

@@ -1,6 +1,8 @@
package blocks
import (
"fmt"
consensus_types "github.com/OffchainLabs/prysm/v6/consensus-types"
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
enginev1 "github.com/OffchainLabs/prysm/v6/proto/engine/v1"
@@ -398,7 +400,7 @@ func (b *BeaconBlock) Proto() (proto.Message, error) { // nolint:gocognit
Body: body,
}, nil
default:
return nil, errors.New("unsupported beacon block version")
return nil, fmt.Errorf("unsupported beacon block version: %s", version.String(b.version))
}
}

View File

@@ -96,16 +96,17 @@ func (s ROBlockSlice) Len() int {
return len(s)
}
// BlockWithROBlobs is a wrapper that collects the block and blob values together.
// BlockWithROSidecars is a wrapper that collects the block and blob values together.
// This is helpful because these values are collated from separate RPC requests.
type BlockWithROBlobs struct {
Block ROBlock
Blobs []ROBlob
type BlockWithROSidecars struct {
Block ROBlock
Blobs []ROBlob
Columns []VerifiedRODataColumn
}
// BlockWithROBlobsSlice gives convenient access to getting a slice of just the ROBlocks,
// and defines sorting helpers.
type BlockWithROBlobsSlice []BlockWithROBlobs
type BlockWithROBlobsSlice []BlockWithROSidecars
func (s BlockWithROBlobsSlice) ROBlocks() []ROBlock {
r := make([]ROBlock, len(s))

View File

@@ -66,16 +66,16 @@ func (dc *RODataColumn) Slot() primitives.Slot {
return dc.SignedBlockHeader.Header.Slot
}
// ParentRoot returns the parent root of the data column sidecar.
func (dc *RODataColumn) ParentRoot() [fieldparams.RootLength]byte {
return bytesutil.ToBytes32(dc.SignedBlockHeader.Header.ParentRoot)
}
// ProposerIndex returns the proposer index of the data column sidecar.
func (dc *RODataColumn) ProposerIndex() primitives.ValidatorIndex {
return dc.SignedBlockHeader.Header.ProposerIndex
}
// ParentRoot returns the parent root of the data column sidecar.
func (dc *RODataColumn) ParentRoot() [fieldparams.RootLength]byte {
return bytesutil.ToBytes32(dc.SignedBlockHeader.Header.ParentRoot)
}
// VerifiedRODataColumn represents an RODataColumn that has undergone full verification (eg block sig, inclusion proof, commitment check).
type VerifiedRODataColumn struct {
RODataColumn

View File

@@ -1,96 +0,0 @@
package blocks
import (
"github.com/pkg/errors"
)
// ROSidecar represents a read-only sidecar with its block root.
type ROSidecar struct {
blob *ROBlob
dataColumn *RODataColumn
}
var (
errBlobNeeded = errors.New("blob sidecar needed")
errDataColumnNeeded = errors.New("data column sidecar needed")
)
// NewSidecarFromBlobSidecar creates a new read-only (generic) sidecar from a read-only blob sidecar.
func NewSidecarFromBlobSidecar(blob ROBlob) ROSidecar {
return ROSidecar{blob: &blob}
}
// NewSidecarFromDataColumnSidecar creates a new read-only (generic) sidecar from a read-only data column sidecar.
func NewSidecarFromDataColumnSidecar(dataColumn RODataColumn) ROSidecar {
return ROSidecar{dataColumn: &dataColumn}
}
// NewSidecarsFromBlobSidecars creates a new slice of read-only (generic) sidecars from a slice of read-only blobs sidecars.
func NewSidecarsFromBlobSidecars(blobSidecars []ROBlob) []ROSidecar {
sidecars := make([]ROSidecar, 0, len(blobSidecars))
for _, blob := range blobSidecars {
blobSidecar := ROSidecar{blob: &blob} // #nosec G601
sidecars = append(sidecars, blobSidecar)
}
return sidecars
}
// NewSidecarsFromDataColumnSidecars creates a new slice of read-only (generic) sidecars from a slice of read-only data column sidecars.
func NewSidecarsFromDataColumnSidecars(dataColumnSidecars []RODataColumn) []ROSidecar {
sidecars := make([]ROSidecar, 0, len(dataColumnSidecars))
for _, dataColumn := range dataColumnSidecars {
dataColumnSidecar := ROSidecar{dataColumn: &dataColumn} // #nosec G601
sidecars = append(sidecars, dataColumnSidecar)
}
return sidecars
}
// Blob returns the blob sidecar.
func (sc *ROSidecar) Blob() (ROBlob, error) {
if sc.blob == nil {
return ROBlob{}, errBlobNeeded
}
return *sc.blob, nil
}
// DataColumn returns the data column sidecar.
func (sc *ROSidecar) DataColumn() (RODataColumn, error) {
if sc.dataColumn == nil {
return RODataColumn{}, errDataColumnNeeded
}
return *sc.dataColumn, nil
}
// BlobSidecarsFromSidecars creates a new slice of read-only blobs sidecars from a slice of read-only (generic) sidecars.
func BlobSidecarsFromSidecars(sidecars []ROSidecar) ([]ROBlob, error) {
blobSidecars := make([]ROBlob, 0, len(sidecars))
for _, sidecar := range sidecars {
blob, err := sidecar.Blob()
if err != nil {
return nil, errors.Wrap(err, "blob")
}
blobSidecars = append(blobSidecars, blob)
}
return blobSidecars, nil
}
// DataColumnSidecarsFromSidecars creates a new slice of read-only data column sidecars from a slice of read-only (generic) sidecars.
func DataColumnSidecarsFromSidecars(sidecars []ROSidecar) ([]RODataColumn, error) {
dataColumnSidecars := make([]RODataColumn, 0, len(sidecars))
for _, sidecar := range sidecars {
dataColumn, err := sidecar.DataColumn()
if err != nil {
return nil, errors.Wrap(err, "data column")
}
dataColumnSidecars = append(dataColumnSidecars, dataColumn)
}
return dataColumnSidecars, nil
}

View File

@@ -1,109 +0,0 @@
package blocks
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestNewSidecarFromBlobSidecar(t *testing.T) {
blob := ROBlob{}
sidecar := NewSidecarFromBlobSidecar(blob)
// Check that the blob is set
retrievedBlob, err := sidecar.Blob()
require.NoError(t, err)
require.Equal(t, blob, retrievedBlob)
// Check that data column is not set
_, err = sidecar.DataColumn()
require.ErrorIs(t, err, errDataColumnNeeded)
}
func TestNewSidecarFromDataColumnSidecar(t *testing.T) {
dataColumn := RODataColumn{}
sidecar := NewSidecarFromDataColumnSidecar(dataColumn)
// Check that the data column is set
retrievedDataColumn, err := sidecar.DataColumn()
require.NoError(t, err)
require.Equal(t, dataColumn, retrievedDataColumn)
// Check that blob is not set
_, err = sidecar.Blob()
require.ErrorIs(t, err, errBlobNeeded)
}
func TestNewSidecarsFromBlobSidecars(t *testing.T) {
blobSidecars := []ROBlob{{}, {}}
sidecars := NewSidecarsFromBlobSidecars(blobSidecars)
require.Equal(t, len(blobSidecars), len(sidecars))
for i, sidecar := range sidecars {
retrievedBlob, err := sidecar.Blob()
require.NoError(t, err)
require.Equal(t, blobSidecars[i], retrievedBlob)
}
}
func TestNewSidecarsFromDataColumnSidecars(t *testing.T) {
dataColumnSidecars := []RODataColumn{{}, {}}
sidecars := NewSidecarsFromDataColumnSidecars(dataColumnSidecars)
require.Equal(t, len(dataColumnSidecars), len(sidecars))
for i, sidecar := range sidecars {
retrievedDataColumn, err := sidecar.DataColumn()
require.NoError(t, err)
require.Equal(t, dataColumnSidecars[i], retrievedDataColumn)
}
}
func TestBlobSidecarsFromSidecars(t *testing.T) {
// Create sidecars with blobs
blobSidecars := []ROBlob{{}, {}}
sidecars := NewSidecarsFromBlobSidecars(blobSidecars)
// Convert back to blob sidecars
retrievedBlobSidecars, err := BlobSidecarsFromSidecars(sidecars)
require.NoError(t, err)
require.Equal(t, len(blobSidecars), len(retrievedBlobSidecars))
for i, blob := range retrievedBlobSidecars {
require.Equal(t, blobSidecars[i], blob)
}
// Test with a mix of sidecar types
mixedSidecars := []ROSidecar{
NewSidecarFromBlobSidecar(ROBlob{}),
NewSidecarFromDataColumnSidecar(RODataColumn{}),
}
_, err = BlobSidecarsFromSidecars(mixedSidecars)
require.Error(t, err)
}
func TestDataColumnSidecarsFromSidecars(t *testing.T) {
// Create sidecars with data columns
dataColumnSidecars := []RODataColumn{{}, {}}
sidecars := NewSidecarsFromDataColumnSidecars(dataColumnSidecars)
// Convert back to data column sidecars
retrievedDataColumnSidecars, err := DataColumnSidecarsFromSidecars(sidecars)
require.NoError(t, err)
require.Equal(t, len(dataColumnSidecars), len(retrievedDataColumnSidecars))
for i, dataColumn := range retrievedDataColumnSidecars {
require.Equal(t, dataColumnSidecars[i], dataColumn)
}
// Test with a mix of sidecar types
mixedSidecars := []ROSidecar{
NewSidecarFromDataColumnSidecar(RODataColumn{}),
NewSidecarFromBlobSidecar(ROBlob{}),
}
_, err = DataColumnSidecarsFromSidecars(mixedSidecars)
require.Error(t, err)
}