Skip to content

Commit 57107e5

Browse files
authored
Cells proofs (#15152)
* Implement distributed block building. Credits: Francis * Add fixes.
1 parent 4727125 commit 57107e5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+398
-1111
lines changed

beacon-chain/core/blocks/payload.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -230,14 +230,17 @@ func verifyBlobCommitmentCount(slot primitives.Slot, body interfaces.ReadOnlyBea
230230
if body.Version() < version.Deneb {
231231
return nil
232232
}
233+
233234
kzgs, err := body.BlobKzgCommitments()
234235
if err != nil {
235236
return err
236237
}
237-
maxBlobsPerBlock := params.BeaconConfig().MaxBlobsPerBlock(slot)
238-
if len(kzgs) > maxBlobsPerBlock {
239-
return fmt.Errorf("too many kzg commitments in block: %d", len(kzgs))
238+
239+
commitmentCount, maxBlobsPerBlock := len(kzgs), params.BeaconConfig().MaxBlobsPerBlock(slot)
240+
if commitmentCount > maxBlobsPerBlock {
241+
return fmt.Errorf("too many kzg commitments in block: actual count %d - max allowed %d", commitmentCount, maxBlobsPerBlock)
240242
}
243+
241244
return nil
242245
}
243246

beacon-chain/core/blocks/payload_test.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -926,8 +926,10 @@ func TestVerifyBlobCommitmentCount(t *testing.T) {
926926
require.NoError(t, err)
927927
require.NoError(t, blocks.VerifyBlobCommitmentCount(rb.Slot(), rb.Body()))
928928

929-
b = &ethpb.BeaconBlockDeneb{Body: &ethpb.BeaconBlockBodyDeneb{BlobKzgCommitments: make([][]byte, params.BeaconConfig().MaxBlobsPerBlock(rb.Slot())+1)}}
929+
maxCommitmentsPerBlock := params.BeaconConfig().MaxBlobsPerBlock(rb.Slot())
930+
931+
b = &ethpb.BeaconBlockDeneb{Body: &ethpb.BeaconBlockBodyDeneb{BlobKzgCommitments: make([][]byte, maxCommitmentsPerBlock+1)}}
930932
rb, err = consensusblocks.NewBeaconBlock(b)
931933
require.NoError(t, err)
932-
require.ErrorContains(t, fmt.Sprintf("too many kzg commitments in block: %d", params.BeaconConfig().MaxBlobsPerBlock(rb.Slot())+1), blocks.VerifyBlobCommitmentCount(rb.Slot(), rb.Body()))
934+
require.ErrorContains(t, fmt.Sprintf("too many kzg commitments in block: actual count %d - max allowed %d", maxCommitmentsPerBlock+1, maxCommitmentsPerBlock), blocks.VerifyBlobCommitmentCount(rb.Slot(), rb.Body()))
933935
}

beacon-chain/core/fulu/upgrade.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ func UpgradeToFulu(beaconState state.BeaconState) (state.BeaconState, error) {
6969
if err != nil {
7070
return nil, err
7171
}
72+
depostiRequestsStartIndex, err := beaconState.DepositRequestsStartIndex()
73+
if err != nil {
74+
return nil, err
75+
}
7276
depositBalanceToConsume, err := beaconState.DepositBalanceToConsume()
7377
if err != nil {
7478
return nil, err
@@ -154,7 +158,7 @@ func UpgradeToFulu(beaconState state.BeaconState) (state.BeaconState, error) {
154158
NextWithdrawalValidatorIndex: vi,
155159
HistoricalSummaries: summaries,
156160

157-
DepositRequestsStartIndex: params.BeaconConfig().UnsetDepositRequestsStartIndex,
161+
DepositRequestsStartIndex: depostiRequestsStartIndex,
158162
DepositBalanceToConsume: depositBalanceToConsume,
159163
ExitBalanceToConsume: exitBalanceToConsume,
160164
EarliestExitEpoch: earliestExitEpoch,

beacon-chain/core/peerdas/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ go_library(
99
"p2p_interface.go",
1010
"peer_sampling.go",
1111
"reconstruction.go",
12+
"util.go",
1213
],
1314
importpath = "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/peerdas",
1415
visibility = ["//visibility:public"],
@@ -24,6 +25,7 @@ go_library(
2425
"//crypto/hash:go_default_library",
2526
"//encoding/bytesutil:go_default_library",
2627
"//proto/prysm/v1alpha1:go_default_library",
28+
"//runtime/version:go_default_library",
2729
"@com_github_ethereum_go_ethereum//p2p/enode:go_default_library",
2830
"@com_github_ethereum_go_ethereum//p2p/enr:go_default_library",
2931
"@com_github_hashicorp_golang_lru//:go_default_library",

beacon-chain/core/peerdas/das_core.go

Lines changed: 17 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package peerdas
22

33
import (
4-
"context"
54
"encoding/binary"
65
"math"
76
"slices"
@@ -20,7 +19,6 @@ import (
2019
"github.com/prysmaticlabs/prysm/v5/crypto/hash"
2120
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
2221
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
23-
"golang.org/x/sync/errgroup"
2422
)
2523

2624
var (
@@ -105,59 +103,36 @@ func ComputeColumnsForCustodyGroup(custodyGroup uint64) ([]uint64, error) {
105103
return columns, nil
106104
}
107105

108-
// DataColumnSidecars computes the data column sidecars from the signed block and blobs.
109-
// https://github.com/ethereum/consensus-specs/blob/dev/specs/fulu/das-core.md#get_data_column_sidecars
110-
func DataColumnSidecars(signedBlock interfaces.ReadOnlySignedBeaconBlock, blobs []kzg.Blob) ([]*ethpb.DataColumnSidecar, error) {
111-
startTime := time.Now()
112-
blobsCount := len(blobs)
113-
if blobsCount == 0 {
106+
// DataColumnSidecars computes the data column sidecars from the signed block, cells and cell proofs.
107+
// https://github.com/ethereum/consensus-specs/blob/v1.5.0-beta.3/specs/fulu/das-core.md#get_data_column_sidecars
108+
func DataColumnSidecars(signedBlock interfaces.ReadOnlySignedBeaconBlock, cellsAndProofs []kzg.CellsAndProofs) ([]*ethpb.DataColumnSidecar, error) {
109+
start := time.Now()
110+
if signedBlock == nil || len(cellsAndProofs) == 0 {
114111
return nil, nil
115112
}
116113

117-
// Get the signed block header.
118-
signedBlockHeader, err := signedBlock.Header()
119-
if err != nil {
120-
return nil, errors.Wrap(err, "signed block header")
121-
}
122-
123-
// Get the block body.
124114
block := signedBlock.Block()
125115
blockBody := block.Body()
126-
127-
// Get the blob KZG commitments.
128116
blobKzgCommitments, err := blockBody.BlobKzgCommitments()
129117
if err != nil {
130118
return nil, errors.Wrap(err, "blob KZG commitments")
131119
}
132120

133-
// Compute the KZG commitments inclusion proof.
134-
kzgCommitmentsInclusionProof, err := blocks.MerkleProofKZGCommitments(blockBody)
135-
if err != nil {
136-
return nil, errors.Wrap(err, "merkle proof ZKG commitments")
121+
if len(blobKzgCommitments) != len(cellsAndProofs) {
122+
return nil, errors.New("mismatch in the number of blob KZG commitments and cellsAndProofs")
137123
}
138124

139-
// Compute cells and proofs.
140-
cellsAndProofs := make([]kzg.CellsAndProofs, blobsCount)
141-
142-
eg, _ := errgroup.WithContext(context.Background())
143-
for i := range blobs {
144-
blobIndex := i
145-
eg.Go(func() error {
146-
blob := &blobs[blobIndex]
147-
blobCellsAndProofs, err := kzg.ComputeCellsAndKZGProofs(blob)
148-
if err != nil {
149-
return errors.Wrap(err, "compute cells and KZG proofs")
150-
}
151-
152-
cellsAndProofs[blobIndex] = blobCellsAndProofs
153-
return nil
154-
})
125+
signedBlockHeader, err := signedBlock.Header()
126+
if err != nil {
127+
return nil, errors.Wrap(err, "signed block header")
155128
}
156-
if err := eg.Wait(); err != nil {
157-
return nil, err
129+
130+
kzgCommitmentsInclusionProof, err := blocks.MerkleProofKZGCommitments(blockBody)
131+
if err != nil {
132+
return nil, errors.Wrap(err, "merkle proof ZKG commitments")
158133
}
159134

160-
// Get the column sidecars.
135+
blobsCount := len(cellsAndProofs)
161136
sidecars := make([]*ethpb.DataColumnSidecar, 0, fieldparams.NumberOfColumns)
162137
for columnIndex := uint64(0); columnIndex < fieldparams.NumberOfColumns; columnIndex++ {
163138
column := make([]kzg.Cell, 0, blobsCount)
@@ -196,7 +171,8 @@ func DataColumnSidecars(signedBlock interfaces.ReadOnlySignedBeaconBlock, blobs
196171

197172
sidecars = append(sidecars, sidecar)
198173
}
199-
dataColumnComputationTime.Observe(float64(time.Since(startTime).Milliseconds()))
174+
175+
dataColumnComputationTime.Observe(float64(time.Since(start).Milliseconds()))
200176
return sidecars, nil
201177
}
202178

beacon-chain/core/peerdas/das_core_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import (
1717

1818
func TestDataColumnSidecars(t *testing.T) {
1919
var expected []*ethpb.DataColumnSidecar = nil
20-
actual, err := peerdas.DataColumnSidecars(nil, []kzg.Blob{})
20+
actual, err := peerdas.DataColumnSidecars(nil, []kzg.CellsAndProofs{})
2121
require.NoError(t, err)
2222

2323
require.DeepSSZEqual(t, expected, actual)
@@ -139,7 +139,8 @@ func TestDataColumnsSidecarsBlobsRoundtrip(t *testing.T) {
139139
}
140140

141141
// Compute data columns sidecars from the signed beacon block and from the blobs.
142-
dataColumnsSidecar, err := peerdas.DataColumnSidecars(signedBeaconBlock, blobs)
142+
cellsAndProofs := util.GenerateCellsAndProofs(t, blobs)
143+
dataColumnsSidecar, err := peerdas.DataColumnSidecars(signedBeaconBlock, cellsAndProofs)
143144
require.NoError(t, err)
144145

145146
// Compute the blobs from the data columns sidecar.

beacon-chain/core/peerdas/p2p_interface_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ func TestVerifyDataColumnSidecarKZGProofs(t *testing.T) {
3131
dbBlock.Block.Body.BlobKzgCommitments = comms
3232
sBlock, err := blocks.NewSignedBeaconBlock(dbBlock)
3333
require.NoError(t, err)
34-
sCars, err := peerdas.DataColumnSidecars(sBlock, blobs)
34+
cellsAndProofs := util.GenerateCellsAndProofs(t, blobs)
35+
sCars, err := peerdas.DataColumnSidecars(sBlock, cellsAndProofs)
3536
require.NoError(t, err)
3637

3738
for i, sidecar := range sCars {

beacon-chain/core/peerdas/reconstruction_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ func TestReconstructionRoundTrip(t *testing.T) {
9595
require.NoError(t, err)
9696

9797
// Convert data columns sidecars from signed block and blobs.
98-
dataColumnSidecars, err := peerdas.DataColumnSidecars(signedBeaconBlock, blobs)
98+
cellsAndProofs := util.GenerateCellsAndProofs(t, blobs)
99+
dataColumnSidecars, err := peerdas.DataColumnSidecars(signedBeaconBlock, cellsAndProofs)
99100
require.NoError(t, err)
100101

101102
// Create verified RO data columns.

beacon-chain/core/peerdas/util.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package peerdas
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/prysmaticlabs/prysm/v5/beacon-chain/blockchain/kzg"
7+
"github.com/prysmaticlabs/prysm/v5/config/params"
8+
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
9+
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
10+
"github.com/prysmaticlabs/prysm/v5/runtime/version"
11+
)
12+
13+
// ConstructDataColumnSidecars constructs data column sidecars from a block, blobs and their cell proofs.
14+
// This is a convenience method as blob and cell proofs are common inputs.
15+
func ConstructDataColumnSidecars(block interfaces.SignedBeaconBlock, blobs [][]byte, cellProofs [][]byte) ([]*ethpb.DataColumnSidecar, error) {
16+
// Check if the block is at least a Fulu block.
17+
if block.Version() < version.Fulu {
18+
return nil, nil
19+
}
20+
21+
cellsAndProofs, err := constructCellsAndProofs(blobs, cellProofs)
22+
if err != nil {
23+
return nil, err
24+
}
25+
26+
return DataColumnSidecars(block, cellsAndProofs)
27+
}
28+
29+
func constructCellsAndProofs(blobs [][]byte, cellProofs [][]byte) ([]kzg.CellsAndProofs, error) {
30+
numColumns := int(params.BeaconConfig().NumberOfColumns)
31+
if len(blobs)*numColumns != len(cellProofs) {
32+
return nil, fmt.Errorf("number of blobs and cell proofs do not match: %d * %d != %d", len(blobs), numColumns, len(cellProofs))
33+
}
34+
35+
cellsAndProofs := make([]kzg.CellsAndProofs, 0, len(blobs))
36+
37+
for i, blob := range blobs {
38+
var b kzg.Blob
39+
copy(b[:], blob)
40+
cells, err := kzg.ComputeCells(&b)
41+
if err != nil {
42+
return nil, err
43+
}
44+
45+
var proofs []kzg.Proof
46+
for idx := i * numColumns; idx < (i+1)*numColumns; idx++ {
47+
proofs = append(proofs, kzg.Proof(cellProofs[idx]))
48+
}
49+
50+
cellsAndProofs = append(cellsAndProofs, kzg.CellsAndProofs{
51+
Cells: cells,
52+
Proofs: proofs,
53+
})
54+
}
55+
56+
return cellsAndProofs, nil
57+
}

beacon-chain/execution/engine_client.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ var (
5353
GetPayloadMethodV4,
5454
}
5555
fuluEngineEndpoints = []string{
56+
GetPayloadMethodV5,
5657
GetBlobsV2,
5758
}
5859
)
@@ -79,6 +80,8 @@ const (
7980
GetPayloadMethodV3 = "engine_getPayloadV3"
8081
// GetPayloadMethodV4 is the get payload method added for electra
8182
GetPayloadMethodV4 = "engine_getPayloadV4"
83+
// GetPayloadMethodV5 is the get payload method added for fulu
84+
GetPayloadMethodV5 = "engine_getPayloadV5"
8285
// BlockByHashMethod request string for JSON-RPC.
8386
BlockByHashMethod = "eth_getBlockByHash"
8487
// BlockByNumberMethod request string for JSON-RPC.
@@ -271,6 +274,9 @@ func (s *Service) ForkchoiceUpdated(
271274

272275
func getPayloadMethodAndMessage(slot primitives.Slot) (string, proto.Message) {
273276
pe := slots.ToEpoch(slot)
277+
if pe >= params.BeaconConfig().FuluForkEpoch {
278+
return GetPayloadMethodV5, &pb.ExecutionBundleElectra{}
279+
}
274280
if pe >= params.BeaconConfig().ElectraForkEpoch {
275281
return GetPayloadMethodV4, &pb.ExecutionBundleElectra{}
276282
}
@@ -303,7 +309,7 @@ func (s *Service) GetPayload(ctx context.Context, payloadId [8]byte, slot primit
303309
}
304310
res, err := blocks.NewGetPayloadResponse(result)
305311
if err != nil {
306-
return nil, err
312+
return nil, errors.Wrap(err, "new get payload response")
307313
}
308314
return res, nil
309315
}
@@ -663,26 +669,26 @@ func (s *Service) ReconstructDataColumnSidecars(ctx context.Context, block inter
663669
}
664670

665671
// Fetch all blobsAndCellsProofs from EL
666-
blobsAndCellsProofs, err := s.GetBlobsV2(ctx, kzgHashes)
672+
blobAndProofV2s, err := s.GetBlobsV2(ctx, kzgHashes)
667673
if err != nil {
668674
return nil, wrapWithBlockRoot(err, blockRoot, "get blobs V2")
669675
}
670676

671677
var cellsAndProofs []kzg.CellsAndProofs
672-
for _, blobAndCellProofs := range blobsAndCellsProofs {
673-
if blobAndCellProofs == nil {
678+
for _, blobAndProof := range blobAndProofV2s {
679+
if blobAndProof == nil {
674680
return nil, wrapWithBlockRoot(errors.New("unable to reconstruct data column sidecars, did not get all blobs from EL"), blockRoot, "")
675681
}
676682

677683
var blob kzg.Blob
678-
copy(blob[:], blobAndCellProofs.Blob)
684+
copy(blob[:], blobAndProof.Blob)
679685
cells, err := kzg.ComputeCells(&blob)
680686
if err != nil {
681687
return nil, wrapWithBlockRoot(err, blockRoot, "could not compute cells")
682688
}
683689

684-
proofs := make([]kzg.Proof, len(blobAndCellProofs.CellProofs))
685-
for i, proof := range blobAndCellProofs.CellProofs {
690+
proofs := make([]kzg.Proof, len(blobAndProof.KzgProofs))
691+
for i, proof := range blobAndProof.KzgProofs {
686692
proofs[i] = kzg.Proof(proof)
687693
}
688694
cellsAndProofs = append(cellsAndProofs, kzg.CellsAndProofs{

0 commit comments

Comments
 (0)