mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-06 22:23:56 -05:00
**What type of PR is this?** Other **What does this PR do? Why is it needed?** This pull request removes `NUMBER_OF_COLUMNS` and `MAX_CELLS_IN_EXTENDED_MATRIX` configuration. **Other notes for review** Please read commit by commit, with commit messages. **Acknowledgements** - [x] I have read [CONTRIBUTING.md](https://github.com/prysmaticlabs/prysm/blob/develop/CONTRIBUTING.md). - [x] I have included a uniquely named [changelog fragment file](https://github.com/prysmaticlabs/prysm/blob/develop/CONTRIBUTING.md#maintaining-changelogmd). - [x] I have added a description to this PR with sufficient context for reviewers to understand this PR.
401 lines
12 KiB
Go
401 lines
12 KiB
Go
package peerdas_test
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/blockchain/kzg"
|
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/peerdas"
|
|
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
|
|
"github.com/OffchainLabs/prysm/v7/config/params"
|
|
"github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
|
|
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
|
|
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
|
"github.com/OffchainLabs/prysm/v7/testing/require"
|
|
"github.com/OffchainLabs/prysm/v7/testing/util"
|
|
"github.com/ethereum/go-ethereum/p2p/enr"
|
|
)
|
|
|
|
func TestVerifyDataColumnSidecar(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
index uint64
|
|
blobCount int
|
|
commitmentCount int
|
|
proofCount int
|
|
maxBlobsPerBlock uint64
|
|
expectedError error
|
|
}{
|
|
{name: "index too large", index: 1_000_000, expectedError: peerdas.ErrIndexTooLarge},
|
|
{name: "no commitments", expectedError: peerdas.ErrNoKzgCommitments},
|
|
{name: "too many commitments", blobCount: 10, commitmentCount: 10, proofCount: 10, maxBlobsPerBlock: 2, expectedError: peerdas.ErrTooManyCommitments},
|
|
{name: "commitments size mismatch", commitmentCount: 1, maxBlobsPerBlock: 1, expectedError: peerdas.ErrMismatchLength},
|
|
{name: "proofs size mismatch", blobCount: 1, commitmentCount: 1, maxBlobsPerBlock: 1, expectedError: peerdas.ErrMismatchLength},
|
|
{name: "nominal", blobCount: 1, commitmentCount: 1, proofCount: 1, maxBlobsPerBlock: 1, expectedError: nil},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
params.SetupTestConfigCleanup(t)
|
|
cfg := params.BeaconConfig()
|
|
cfg.FuluForkEpoch = 0
|
|
cfg.BlobSchedule = []params.BlobScheduleEntry{{Epoch: 0, MaxBlobsPerBlock: tc.maxBlobsPerBlock}}
|
|
params.OverrideBeaconConfig(cfg)
|
|
|
|
column := make([][]byte, tc.blobCount)
|
|
kzgCommitments := make([][]byte, tc.commitmentCount)
|
|
kzgProof := make([][]byte, tc.proofCount)
|
|
|
|
roSidecar := createTestSidecar(t, tc.index, column, kzgCommitments, kzgProof)
|
|
err := peerdas.VerifyDataColumnSidecar(roSidecar)
|
|
|
|
if tc.expectedError != nil {
|
|
require.ErrorIs(t, err, tc.expectedError)
|
|
return
|
|
}
|
|
|
|
require.NoError(t, err)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestVerifyDataColumnSidecarKZGProofs(t *testing.T) {
|
|
const (
|
|
blobCount = 6
|
|
seed = 0
|
|
)
|
|
err := kzg.Start()
|
|
require.NoError(t, err)
|
|
|
|
t.Run("size mismatch", func(t *testing.T) {
|
|
sidecars := generateRandomSidecars(t, seed, blobCount)
|
|
sidecars[0].Column[0] = sidecars[0].Column[0][:len(sidecars[0].Column[0])-1] // Remove one byte to create size mismatch
|
|
|
|
err := peerdas.VerifyDataColumnsSidecarKZGProofs(sidecars)
|
|
require.ErrorIs(t, err, peerdas.ErrMismatchLength)
|
|
})
|
|
|
|
t.Run("invalid proof", func(t *testing.T) {
|
|
sidecars := generateRandomSidecars(t, seed, blobCount)
|
|
sidecars[0].Column[0][0]++ // It is OK to overflow
|
|
|
|
err := peerdas.VerifyDataColumnsSidecarKZGProofs(sidecars)
|
|
require.ErrorIs(t, err, peerdas.ErrInvalidKZGProof)
|
|
})
|
|
|
|
t.Run("nominal", func(t *testing.T) {
|
|
sidecars := generateRandomSidecars(t, seed, blobCount)
|
|
err := peerdas.VerifyDataColumnsSidecarKZGProofs(sidecars)
|
|
require.NoError(t, err)
|
|
})
|
|
}
|
|
|
|
func Test_VerifyKZGInclusionProofColumn(t *testing.T) {
|
|
const (
|
|
blobCount = 3
|
|
columnIndex = 0
|
|
)
|
|
|
|
// Generate random KZG commitments `blobCount` blobs.
|
|
kzgCommitments := make([][]byte, blobCount)
|
|
|
|
for i := range blobCount {
|
|
kzgCommitments[i] = make([]byte, 48)
|
|
_, err := rand.Read(kzgCommitments[i])
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
pbBody := ðpb.BeaconBlockBodyDeneb{
|
|
RandaoReveal: make([]byte, 96),
|
|
Eth1Data: ðpb.Eth1Data{
|
|
DepositRoot: make([]byte, fieldparams.RootLength),
|
|
BlockHash: make([]byte, fieldparams.RootLength),
|
|
},
|
|
Graffiti: make([]byte, 32),
|
|
SyncAggregate: ðpb.SyncAggregate{
|
|
SyncCommitteeBits: make([]byte, fieldparams.SyncAggregateSyncCommitteeBytesLength),
|
|
SyncCommitteeSignature: make([]byte, fieldparams.BLSSignatureLength),
|
|
},
|
|
ExecutionPayload: &enginev1.ExecutionPayloadDeneb{
|
|
ParentHash: make([]byte, fieldparams.RootLength),
|
|
FeeRecipient: make([]byte, 20),
|
|
StateRoot: make([]byte, fieldparams.RootLength),
|
|
ReceiptsRoot: make([]byte, fieldparams.RootLength),
|
|
LogsBloom: make([]byte, 256),
|
|
PrevRandao: make([]byte, fieldparams.RootLength),
|
|
BaseFeePerGas: make([]byte, fieldparams.RootLength),
|
|
BlockHash: make([]byte, fieldparams.RootLength),
|
|
Transactions: make([][]byte, 0),
|
|
ExtraData: make([]byte, 0),
|
|
},
|
|
BlobKzgCommitments: kzgCommitments,
|
|
}
|
|
|
|
root, err := pbBody.HashTreeRoot()
|
|
require.NoError(t, err)
|
|
|
|
body, err := blocks.NewBeaconBlockBody(pbBody)
|
|
require.NoError(t, err)
|
|
|
|
kzgCommitmentsInclusionProof, err := blocks.MerkleProofKZGCommitments(body)
|
|
require.NoError(t, err)
|
|
|
|
testCases := []struct {
|
|
name string
|
|
expectedError error
|
|
dataColumnSidecar *ethpb.DataColumnSidecar
|
|
}{
|
|
{
|
|
name: "nilSignedBlockHeader",
|
|
expectedError: peerdas.ErrNilBlockHeader,
|
|
dataColumnSidecar: ðpb.DataColumnSidecar{},
|
|
},
|
|
{
|
|
name: "nilHeader",
|
|
expectedError: peerdas.ErrNilBlockHeader,
|
|
dataColumnSidecar: ðpb.DataColumnSidecar{
|
|
SignedBlockHeader: ðpb.SignedBeaconBlockHeader{},
|
|
},
|
|
},
|
|
{
|
|
name: "invalidBodyRoot",
|
|
expectedError: peerdas.ErrBadRootLength,
|
|
dataColumnSidecar: ðpb.DataColumnSidecar{
|
|
SignedBlockHeader: ðpb.SignedBeaconBlockHeader{
|
|
Header: ðpb.BeaconBlockHeader{},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "unverifiedMerkleProof",
|
|
expectedError: peerdas.ErrInvalidInclusionProof,
|
|
dataColumnSidecar: ðpb.DataColumnSidecar{
|
|
SignedBlockHeader: ðpb.SignedBeaconBlockHeader{
|
|
Header: ðpb.BeaconBlockHeader{
|
|
BodyRoot: make([]byte, 32),
|
|
},
|
|
},
|
|
KzgCommitments: kzgCommitments,
|
|
},
|
|
},
|
|
{
|
|
name: "nominal",
|
|
expectedError: nil,
|
|
dataColumnSidecar: ðpb.DataColumnSidecar{
|
|
KzgCommitments: kzgCommitments,
|
|
SignedBlockHeader: ðpb.SignedBeaconBlockHeader{
|
|
Header: ðpb.BeaconBlockHeader{
|
|
BodyRoot: root[:],
|
|
},
|
|
},
|
|
KzgCommitmentsInclusionProof: kzgCommitmentsInclusionProof,
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
roDataColumn := blocks.RODataColumn{DataColumnSidecar: tc.dataColumnSidecar}
|
|
err = peerdas.VerifyDataColumnSidecarInclusionProof(roDataColumn)
|
|
if tc.expectedError == nil {
|
|
require.NoError(t, err)
|
|
return
|
|
}
|
|
|
|
require.ErrorIs(t, tc.expectedError, err)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestComputeSubnetForDataColumnSidecar(t *testing.T) {
|
|
params.SetupTestConfigCleanup(t)
|
|
config := params.BeaconConfig()
|
|
config.DataColumnSidecarSubnetCount = 128
|
|
params.OverrideBeaconConfig(config)
|
|
|
|
require.Equal(t, uint64(0), peerdas.ComputeSubnetForDataColumnSidecar(0))
|
|
require.Equal(t, uint64(1), peerdas.ComputeSubnetForDataColumnSidecar(1))
|
|
require.Equal(t, uint64(0), peerdas.ComputeSubnetForDataColumnSidecar(128))
|
|
require.Equal(t, uint64(1), peerdas.ComputeSubnetForDataColumnSidecar(129))
|
|
}
|
|
|
|
func TestDataColumnSubnets(t *testing.T) {
|
|
params.SetupTestConfigCleanup(t)
|
|
config := params.BeaconConfig()
|
|
config.DataColumnSidecarSubnetCount = 128
|
|
params.OverrideBeaconConfig(config)
|
|
|
|
input := map[uint64]bool{0: true, 1: true, 128: true, 129: true, 131: true}
|
|
expected := map[uint64]bool{0: true, 1: true, 3: true}
|
|
actual := peerdas.DataColumnSubnets(input)
|
|
|
|
require.Equal(t, len(expected), len(actual))
|
|
for k, v := range expected {
|
|
require.Equal(t, v, actual[k])
|
|
}
|
|
}
|
|
|
|
func TestCustodyGroupCountFromRecord(t *testing.T) {
|
|
t.Run("nil record", func(t *testing.T) {
|
|
_, err := peerdas.CustodyGroupCountFromRecord(nil)
|
|
require.ErrorIs(t, err, peerdas.ErrRecordNil)
|
|
})
|
|
|
|
t.Run("no cgc", func(t *testing.T) {
|
|
_, err := peerdas.CustodyGroupCountFromRecord(&enr.Record{})
|
|
require.ErrorIs(t, err, peerdas.ErrCannotLoadCustodyGroupCount)
|
|
})
|
|
|
|
t.Run("nominal", func(t *testing.T) {
|
|
const expected uint64 = 7
|
|
|
|
record := &enr.Record{}
|
|
record.Set(peerdas.Cgc(expected))
|
|
|
|
actual, err := peerdas.CustodyGroupCountFromRecord(record)
|
|
require.NoError(t, err)
|
|
require.Equal(t, expected, actual)
|
|
})
|
|
}
|
|
|
|
func BenchmarkVerifyDataColumnSidecarKZGProofs_SameCommitments_NoBatch(b *testing.B) {
|
|
const blobCount = 12
|
|
err := kzg.Start()
|
|
require.NoError(b, err)
|
|
|
|
b.StopTimer()
|
|
b.ResetTimer()
|
|
for i := range int64(b.N) {
|
|
// Generate new random sidecars to ensure the KZG backend does not cache anything.
|
|
sidecars := generateRandomSidecars(b, i, blobCount)
|
|
|
|
for _, sidecar := range sidecars {
|
|
sidecars := []blocks.RODataColumn{sidecar}
|
|
b.StartTimer()
|
|
err := peerdas.VerifyDataColumnsSidecarKZGProofs(sidecars)
|
|
b.StopTimer()
|
|
require.NoError(b, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkVerifyDataColumnSidecarKZGProofs_DiffCommitments_Batch(b *testing.B) {
|
|
const (
|
|
blobCount = 12
|
|
numberOfColumns = fieldparams.NumberOfColumns
|
|
)
|
|
|
|
err := kzg.Start()
|
|
require.NoError(b, err)
|
|
|
|
columnsCounts := []int64{1, 2, 4, 8, 16, 32, 64, 128}
|
|
|
|
for i, columnsCount := range columnsCounts {
|
|
b.Run(fmt.Sprintf("columnsCount_%d", columnsCount), func(b *testing.B) {
|
|
b.StopTimer()
|
|
b.ResetTimer()
|
|
|
|
for j := range int64(b.N) {
|
|
allSidecars := make([]blocks.RODataColumn, 0, numberOfColumns)
|
|
for k := int64(0); k < numberOfColumns; k += columnsCount {
|
|
// Use different seeds to generate different blobs/commitments
|
|
seed := int64(b.N*i) + numberOfColumns*j + blobCount*k
|
|
sidecars := generateRandomSidecars(b, seed, blobCount)
|
|
|
|
// Pick sidecars.
|
|
allSidecars = append(allSidecars, sidecars[k:k+columnsCount]...)
|
|
}
|
|
|
|
b.StartTimer()
|
|
err := peerdas.VerifyDataColumnsSidecarKZGProofs(allSidecars)
|
|
b.StopTimer()
|
|
require.NoError(b, err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func BenchmarkVerifyDataColumnSidecarKZGProofs_DiffCommitments_Batch4(b *testing.B) {
|
|
const (
|
|
blobCount = 12
|
|
|
|
// columnsCount*batchCount = 128
|
|
columnsCount = 4
|
|
batchCount = 32
|
|
)
|
|
|
|
err := kzg.Start()
|
|
require.NoError(b, err)
|
|
|
|
b.StopTimer()
|
|
b.ResetTimer()
|
|
|
|
for i := range int64(b.N) {
|
|
allSidecars := make([][]blocks.RODataColumn, 0, batchCount)
|
|
for j := range int64(batchCount) {
|
|
// Use different seeds to generate different blobs/commitments
|
|
sidecars := generateRandomSidecars(b, int64(batchCount)*i+j*blobCount, blobCount)
|
|
allSidecars = append(allSidecars, sidecars)
|
|
}
|
|
|
|
for _, sidecars := range allSidecars {
|
|
b.StartTimer()
|
|
err := peerdas.VerifyDataColumnsSidecarKZGProofs(sidecars)
|
|
b.StopTimer()
|
|
require.NoError(b, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func createTestSidecar(t *testing.T, index uint64, column, kzgCommitments, kzgProofs [][]byte) blocks.RODataColumn {
|
|
pbSignedBeaconBlock := util.NewBeaconBlockDeneb()
|
|
signedBeaconBlock, err := blocks.NewSignedBeaconBlock(pbSignedBeaconBlock)
|
|
require.NoError(t, err)
|
|
|
|
signedBlockHeader, err := signedBeaconBlock.Header()
|
|
require.NoError(t, err)
|
|
|
|
sidecar := ðpb.DataColumnSidecar{
|
|
Index: index,
|
|
Column: column,
|
|
KzgCommitments: kzgCommitments,
|
|
KzgProofs: kzgProofs,
|
|
SignedBlockHeader: signedBlockHeader,
|
|
}
|
|
|
|
roSidecar, err := blocks.NewRODataColumn(sidecar)
|
|
require.NoError(t, err)
|
|
|
|
return roSidecar
|
|
}
|
|
|
|
func generateRandomSidecars(t testing.TB, seed, blobCount int64) []blocks.RODataColumn {
|
|
dbBlock := util.NewBeaconBlockDeneb()
|
|
|
|
commitments := make([][]byte, 0, blobCount)
|
|
blobs := make([]kzg.Blob, 0, blobCount)
|
|
|
|
for i := range blobCount {
|
|
subSeed := seed + i
|
|
blob := getRandBlob(subSeed)
|
|
commitment, err := generateCommitment(&blob)
|
|
require.NoError(t, err)
|
|
|
|
commitments = append(commitments, commitment[:])
|
|
blobs = append(blobs, blob)
|
|
}
|
|
|
|
dbBlock.Block.Body.BlobKzgCommitments = commitments
|
|
sBlock, err := blocks.NewSignedBeaconBlock(dbBlock)
|
|
require.NoError(t, err)
|
|
|
|
cellsPerBlob, proofsPerBlob := util.GenerateCellsAndProofs(t, blobs)
|
|
rob, err := blocks.NewROBlock(sBlock)
|
|
require.NoError(t, err)
|
|
sidecars, err := peerdas.DataColumnSidecars(cellsPerBlob, proofsPerBlob, peerdas.PopulateFromBlock(rob))
|
|
require.NoError(t, err)
|
|
|
|
return sidecars
|
|
}
|