Skip to content

Commit ade35c4

Browse files
committed
Finish ReconstructDataColumnSidecars
1 parent 7189334 commit ade35c4

File tree

1 file changed

+123
-6
lines changed

1 file changed

+123
-6
lines changed

Diff for: beacon-chain/execution/engine_client.go

+123-6
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import (
1313
gethRPC "github.com/ethereum/go-ethereum/rpc"
1414
"github.com/holiman/uint256"
1515
"github.com/pkg/errors"
16+
"github.com/prysmaticlabs/prysm/v5/beacon-chain/blockchain/kzg"
17+
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/peerdas"
1618
"github.com/prysmaticlabs/prysm/v5/beacon-chain/execution/types"
1719
"github.com/prysmaticlabs/prysm/v5/beacon-chain/verification"
1820
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
@@ -44,11 +46,15 @@ var (
4446
GetPayloadMethodV3,
4547
GetPayloadBodiesByHashV1,
4648
GetPayloadBodiesByRangeV1,
49+
GetBlobsV1,
4750
}
4851
electraEngineEndpoints = []string{
4952
NewPayloadMethodV4,
5053
GetPayloadMethodV4,
5154
}
55+
fuluEngineEndpoints = []string{
56+
GetBlobsV2,
57+
}
5258
)
5359

5460
const (
@@ -85,6 +91,8 @@ const (
8591
ExchangeCapabilities = "engine_exchangeCapabilities"
8692
// GetBlobsV1 request string for JSON-RPC.
8793
GetBlobsV1 = "engine_getBlobsV1"
94+
// GetBlobsV2 request string for JSON-RPC.
95+
GetBlobsV2 = "engine_getBlobsV2"
8896
// Defines the seconds before timing out engine endpoints with non-block execution semantics.
8997
defaultEngineTimeout = time.Second
9098
)
@@ -108,6 +116,7 @@ type Reconstructor interface {
108116
ctx context.Context, blindedBlocks []interfaces.ReadOnlySignedBeaconBlock,
109117
) ([]interfaces.SignedBeaconBlock, error)
110118
ReconstructBlobSidecars(ctx context.Context, block interfaces.ReadOnlySignedBeaconBlock, blockRoot [32]byte, hi func(uint64) bool) ([]blocks.VerifiedROBlob, error)
119+
ReconstructDataColumnSidecars(ctx context.Context, block interfaces.ReadOnlySignedBeaconBlock, blockRoot [32]byte, hi func(uint64) bool) ([]blocks.VerifiedRODataColumn, error)
111120
}
112121

113122
// EngineCaller defines a client that can interact with an Ethereum
@@ -302,6 +311,9 @@ func (s *Service) ExchangeCapabilities(ctx context.Context) ([]string, error) {
302311
if params.ElectraEnabled() {
303312
supportedEngineEndpoints = append(supportedEngineEndpoints, electraEngineEndpoints...)
304313
}
314+
if params.FuluEnabled() {
315+
supportedEngineEndpoints = append(supportedEngineEndpoints, fuluEngineEndpoints...)
316+
}
305317
var result []string
306318
err := s.rpcClient.CallContext(ctx, &result, ExchangeCapabilities, supportedEngineEndpoints)
307319
if err != nil {
@@ -492,19 +504,38 @@ func (s *Service) HeaderByNumber(ctx context.Context, number *big.Int) (*types.H
492504
}
493505

494506
// GetBlobs returns the blob and proof from the execution engine for the given versioned hashes.
495-
func (s *Service) GetBlobs(ctx context.Context, versionedHashes []common.Hash) ([]*pb.BlobAndProof, error) {
507+
func (s *Service) GetBlobs(ctx context.Context, slot primitives.Slot, versionedHashes []common.Hash) (any, error) {
496508
ctx, span := trace.StartSpan(ctx, "powchain.engine-api-client.GetBlobs")
497509
defer span.End()
498-
// If the execution engine does not support `GetBlobsV1`, return early to prevent encountering an error later.
499-
if !s.capabilityCache.has(GetBlobsV1) {
510+
511+
method, proto := s.getPayloadMethodAndMessage(slot)
512+
// If the execution engine does not support the method, return early to prevent encountering an error later.
513+
if !s.capabilityCache.has(method) {
500514
return nil, nil
501515
}
502516

503-
result := make([]*pb.BlobAndProof, len(versionedHashes))
504-
err := s.rpcClient.CallContext(ctx, &result, GetBlobsV1, versionedHashes)
517+
var result any
518+
switch proto.(type) {
519+
case *pb.BlobAndProofV2:
520+
result = make([]*pb.BlobAndProofV2, len(versionedHashes))
521+
case *pb.BlobAndProof:
522+
result = make([]*pb.BlobAndProof, len(versionedHashes))
523+
default:
524+
return nil, errors.New("unsupported blob proof type")
525+
}
526+
527+
err := s.rpcClient.CallContext(ctx, &result, method, versionedHashes)
505528
return result, handleRPCError(err)
506529
}
507530

531+
func (s *Service) getPayloadMethodAndMessage(slot primitives.Slot) (string, proto.Message) {
532+
pe := slots.ToEpoch(slot)
533+
if pe >= params.BeaconConfig().FuluForkEpoch {
534+
return GetBlobsV2, &pb.BlobAndProofV2{}
535+
}
536+
return GetBlobsV1, &pb.BlobAndProof{}
537+
}
538+
508539
// ReconstructFullBlock takes in a blinded beacon block and reconstructs
509540
// a beacon block with a full execution payload via the engine API.
510541
func (s *Service) ReconstructFullBlock(
@@ -561,10 +592,14 @@ func (s *Service) ReconstructBlobSidecars(ctx context.Context, block interfaces.
561592
}
562593

563594
// Fetch blobs from EL
564-
blobs, err := s.GetBlobs(ctx, kzgHashes)
595+
result, err := s.GetBlobs(ctx, block.Block().Slot(), kzgHashes)
565596
if err != nil {
566597
return nil, errors.Wrap(err, "could not get blobs")
567598
}
599+
blobs, ok := result.([]*pb.BlobAndProof)
600+
if !ok {
601+
return nil, errors.New("invalid blob proof type")
602+
}
568603
if len(blobs) == 0 {
569604
return nil, nil
570605
}
@@ -615,6 +650,88 @@ func (s *Service) ReconstructBlobSidecars(ctx context.Context, block interfaces.
615650
return verifiedBlobs, nil
616651
}
617652

653+
// ReconstructDataColumnSidecars reconstructs the verified data column sidecars for a given beacon block.
654+
// It retrieves the KZG commitments from the block body, fetches the associated blobs and cell proofs,
655+
// and constructs the corresponding verified read-only data column sidecars.
656+
func (s *Service) ReconstructDataColumnSidecars(ctx context.Context, block interfaces.ReadOnlySignedBeaconBlock, blockRoot [32]byte) ([]blocks.VerifiedRODataColumn, error) {
657+
blockBody := block.Block().Body()
658+
kzgCommitments, err := blockBody.BlobKzgCommitments()
659+
if err != nil {
660+
return nil, errors.Wrap(err, "could not get blob KZG commitments")
661+
}
662+
663+
// Collect KZG hashes for all blobs
664+
var kzgHashes []common.Hash
665+
var kzgIndexes []int
666+
for i, commitment := range kzgCommitments {
667+
kzgHashes = append(kzgHashes, primitives.ConvertKzgCommitmentToVersionedHash(commitment))
668+
kzgIndexes = append(kzgIndexes, i)
669+
}
670+
671+
// Fetch all blobs from EL
672+
result, err := s.GetBlobs(ctx, block.Block().Slot(), kzgHashes)
673+
if err != nil {
674+
return nil, errors.Wrap(err, "could not get blobs")
675+
}
676+
677+
blobAndProofs, ok := result.([]*pb.BlobAndProofV2)
678+
if !ok {
679+
return nil, errors.New("invalid blob and proof type")
680+
}
681+
for _, blobAndCellProofs := range blobAndProofs {
682+
if blobAndCellProofs == nil {
683+
return nil, errors.Wrap(err, "unable to reconstruct data column sidecars, not enough blob data from EL")
684+
}
685+
}
686+
687+
var cellsAndProofs []kzg.CellsAndProofs
688+
for _, blobAndCellProofs := range blobAndProofs {
689+
blob := kzg.Blob(blobAndCellProofs.Blob)
690+
cells, err := kzg.ComputeCells(&blob)
691+
if err != nil {
692+
return nil, errors.Wrap(err, "could not compute cells")
693+
}
694+
695+
proofs := make([]kzg.Proof, len(blobAndCellProofs.CellProofs))
696+
for i, proof := range blobAndCellProofs.CellProofs {
697+
proofs[i] = kzg.Proof(proof)
698+
}
699+
cellsAndProofs = append(cellsAndProofs, kzg.CellsAndProofs{
700+
Cells: cells,
701+
Proofs: proofs,
702+
})
703+
}
704+
705+
header, err := block.Header()
706+
if err != nil {
707+
return nil, errors.Wrap(err, "could not get header")
708+
}
709+
710+
kzgCommitmentsInclusionProof, err := blocks.MerkleProofKZGCommitments(blockBody)
711+
if err != nil {
712+
return nil, errors.Wrap(err, "could not get Merkle proof for KZG commitments")
713+
}
714+
715+
dataColumnSidecars, err := peerdas.DataColumnSidecarsForReconstruct(kzgCommitments, header, kzgCommitmentsInclusionProof, cellsAndProofs)
716+
if err != nil {
717+
return nil, errors.Wrap(err, "could not reconstruct data column sidecars")
718+
}
719+
720+
verifiedRODataColumns := make([]blocks.VerifiedRODataColumn, len(dataColumnSidecars))
721+
for i, dataColumnSidecar := range dataColumnSidecars {
722+
roDataColumn, err := blocks.NewRODataColumnWithRoot(dataColumnSidecar, blockRoot)
723+
if err != nil {
724+
return nil, errors.Wrap(err, "new read-only data column with root")
725+
}
726+
727+
verifiedRODataColumns[i] = blocks.NewVerifiedRODataColumn(roDataColumn)
728+
}
729+
730+
log.WithField("root", fmt.Sprintf("%x", blockRoot)).Debug("Data columns reconstructed successfully")
731+
732+
return verifiedRODataColumns, nil
733+
}
734+
618735
func fullPayloadFromPayloadBody(
619736
header interfaces.ExecutionData, body *pb.ExecutionPayloadBody, bVersion int,
620737
) (interfaces.ExecutionData, error) {

0 commit comments

Comments
 (0)