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.
257 lines
8.7 KiB
Go
257 lines
8.7 KiB
Go
package peerdas
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/blockchain/kzg"
|
|
beaconState "github.com/OffchainLabs/prysm/v7/beacon-chain/state"
|
|
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
|
|
"github.com/OffchainLabs/prysm/v7/config/params"
|
|
"github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
|
|
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
|
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
var (
|
|
ErrNilSignedBlockOrEmptyCellsAndProofs = errors.New("nil signed block or empty cells and proofs")
|
|
ErrSizeMismatch = errors.New("mismatch in the number of blob KZG commitments and cellsAndProofs")
|
|
ErrNotEnoughDataColumnSidecars = errors.New("not enough columns")
|
|
ErrDataColumnSidecarsNotSortedByIndex = errors.New("data column sidecars are not sorted by index")
|
|
)
|
|
|
|
var (
|
|
_ ConstructionPopulator = (*BlockReconstructionSource)(nil)
|
|
_ ConstructionPopulator = (*SidecarReconstructionSource)(nil)
|
|
)
|
|
|
|
const (
|
|
BlockType = "BeaconBlock"
|
|
SidecarType = "DataColumnSidecar"
|
|
)
|
|
|
|
type (
|
|
// ConstructionPopulator is an interface that can be satisfied by a type that can use data from a struct
|
|
// like a DataColumnSidecar or a BeaconBlock to set the fields in a data column sidecar that cannot
|
|
// be obtained from the engine api.
|
|
ConstructionPopulator interface {
|
|
Slot() primitives.Slot
|
|
Root() [fieldparams.RootLength]byte
|
|
ProposerIndex() primitives.ValidatorIndex
|
|
Commitments() ([][]byte, error)
|
|
Type() string
|
|
|
|
extract() (*blockInfo, error)
|
|
}
|
|
|
|
// BlockReconstructionSource is a ConstructionPopulator that uses a beacon block as the source of data
|
|
BlockReconstructionSource struct {
|
|
blocks.ROBlock
|
|
}
|
|
|
|
// DataColumnSidecar is a ConstructionPopulator that uses a data column sidecar as the source of data
|
|
SidecarReconstructionSource struct {
|
|
blocks.VerifiedRODataColumn
|
|
}
|
|
|
|
blockInfo struct {
|
|
signedBlockHeader *ethpb.SignedBeaconBlockHeader
|
|
kzgCommitments [][]byte
|
|
kzgInclusionProof [][]byte
|
|
}
|
|
)
|
|
|
|
// PopulateFromBlock creates a BlockReconstructionSource from a beacon block
|
|
func PopulateFromBlock(block blocks.ROBlock) *BlockReconstructionSource {
|
|
return &BlockReconstructionSource{ROBlock: block}
|
|
}
|
|
|
|
// PopulateFromSidecar creates a SidecarReconstructionSource from a data column sidecar
|
|
func PopulateFromSidecar(sidecar blocks.VerifiedRODataColumn) *SidecarReconstructionSource {
|
|
return &SidecarReconstructionSource{VerifiedRODataColumn: sidecar}
|
|
}
|
|
|
|
// ValidatorsCustodyRequirement returns the number of custody groups regarding the validator indices attached to the beacon node.
|
|
// https://github.com/ethereum/consensus-specs/blob/master/specs/fulu/validator.md#validator-custody
|
|
func ValidatorsCustodyRequirement(state beaconState.ReadOnlyBeaconState, validatorsIndex map[primitives.ValidatorIndex]bool) (uint64, error) {
|
|
totalNodeBalance := uint64(0)
|
|
for index := range validatorsIndex {
|
|
validator, err := state.ValidatorAtIndexReadOnly(index)
|
|
if err != nil {
|
|
return 0, errors.Wrapf(err, "validator at index %v", index)
|
|
}
|
|
|
|
totalNodeBalance += validator.EffectiveBalance()
|
|
}
|
|
|
|
cfg := params.BeaconConfig()
|
|
numberOfCustodyGroups := cfg.NumberOfCustodyGroups
|
|
validatorCustodyRequirement := cfg.ValidatorCustodyRequirement
|
|
balancePerAdditionalCustodyGroup := cfg.BalancePerAdditionalCustodyGroup
|
|
|
|
count := totalNodeBalance / balancePerAdditionalCustodyGroup
|
|
return min(max(count, validatorCustodyRequirement), numberOfCustodyGroups), nil
|
|
}
|
|
|
|
// DataColumnSidecars given ConstructionPopulator and the cells/proofs associated with each blob in the
|
|
// block, assembles sidecars which can be distributed to peers.
|
|
// cellsPerBlob and proofsPerBlob are parallel slices where each index represents a blob sidecar.
|
|
// This is an adapted version of
|
|
// https://github.com/ethereum/consensus-specs/blob/master/specs/fulu/validator.md#get_data_column_sidecars,
|
|
// which is designed to be used both when constructing sidecars from a block and from a sidecar, replacing
|
|
// https://github.com/ethereum/consensus-specs/blob/master/specs/fulu/validator.md#get_data_column_sidecars_from_block and
|
|
// https://github.com/ethereum/consensus-specs/blob/master/specs/fulu/validator.md#get_data_column_sidecars_from_column_sidecar
|
|
func DataColumnSidecars(cellsPerBlob [][]kzg.Cell, proofsPerBlob [][]kzg.Proof, src ConstructionPopulator) ([]blocks.RODataColumn, error) {
|
|
const numberOfColumns = uint64(fieldparams.NumberOfColumns)
|
|
|
|
if len(cellsPerBlob) == 0 {
|
|
return nil, nil
|
|
}
|
|
start := time.Now()
|
|
cells, proofs, err := rotateRowsToCols(cellsPerBlob, proofsPerBlob, numberOfColumns)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "rotate cells and proofs")
|
|
}
|
|
info, err := src.extract()
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "extract block info")
|
|
}
|
|
|
|
roSidecars := make([]blocks.RODataColumn, 0, numberOfColumns)
|
|
for idx := range numberOfColumns {
|
|
sidecar := ðpb.DataColumnSidecar{
|
|
Index: idx,
|
|
Column: cells[idx],
|
|
KzgCommitments: info.kzgCommitments,
|
|
KzgProofs: proofs[idx],
|
|
SignedBlockHeader: info.signedBlockHeader,
|
|
KzgCommitmentsInclusionProof: info.kzgInclusionProof,
|
|
}
|
|
|
|
if len(sidecar.KzgCommitments) != len(sidecar.Column) || len(sidecar.KzgCommitments) != len(sidecar.KzgProofs) {
|
|
return nil, ErrSizeMismatch
|
|
}
|
|
|
|
roSidecar, err := blocks.NewRODataColumnWithRoot(sidecar, src.Root())
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "new ro data column")
|
|
}
|
|
roSidecars = append(roSidecars, roSidecar)
|
|
}
|
|
|
|
dataColumnComputationTime.Observe(float64(time.Since(start).Milliseconds()))
|
|
return roSidecars, nil
|
|
}
|
|
|
|
// Slot returns the slot of the source
|
|
func (s *BlockReconstructionSource) Slot() primitives.Slot {
|
|
return s.Block().Slot()
|
|
}
|
|
|
|
// ProposerIndex returns the proposer index of the source
|
|
func (s *BlockReconstructionSource) ProposerIndex() primitives.ValidatorIndex {
|
|
return s.Block().ProposerIndex()
|
|
}
|
|
|
|
// Commitments returns the blob KZG commitments of the source
|
|
func (s *BlockReconstructionSource) Commitments() ([][]byte, error) {
|
|
c, err := s.Block().Body().BlobKzgCommitments()
|
|
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "blob KZG commitments")
|
|
}
|
|
|
|
return c, nil
|
|
}
|
|
|
|
// Type returns the type of the source
|
|
func (s *BlockReconstructionSource) Type() string {
|
|
return BlockType
|
|
}
|
|
|
|
// extract extracts the block information from the source
|
|
func (b *BlockReconstructionSource) extract() (*blockInfo, error) {
|
|
block := b.Block()
|
|
|
|
header, err := b.Header()
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "header")
|
|
}
|
|
|
|
commitments, err := block.Body().BlobKzgCommitments()
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "commitments")
|
|
}
|
|
|
|
inclusionProof, err := blocks.MerkleProofKZGCommitments(block.Body())
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "merkle proof kzg commitments")
|
|
}
|
|
|
|
info := &blockInfo{
|
|
signedBlockHeader: header,
|
|
kzgCommitments: commitments,
|
|
kzgInclusionProof: inclusionProof,
|
|
}
|
|
|
|
return info, nil
|
|
}
|
|
|
|
// rotateRowsToCols takes a 2D slice of cells and proofs, where the x is rows (blobs) and y is columns,
|
|
// and returns a 2D slice where x is columns and y is rows.
|
|
func rotateRowsToCols(cellsPerBlob [][]kzg.Cell, proofsPerBlob [][]kzg.Proof, numCols uint64) ([][][]byte, [][][]byte, error) {
|
|
if len(cellsPerBlob) == 0 {
|
|
return nil, nil, nil
|
|
}
|
|
if len(cellsPerBlob) != len(proofsPerBlob) {
|
|
return nil, nil, errors.New("cells and proofs length mismatch")
|
|
}
|
|
cellCols := make([][][]byte, numCols)
|
|
proofCols := make([][][]byte, numCols)
|
|
for i := range cellsPerBlob {
|
|
cells := cellsPerBlob[i]
|
|
proofs := proofsPerBlob[i]
|
|
if uint64(len(cells)) != numCols {
|
|
return nil, nil, errors.Wrap(ErrNotEnoughDataColumnSidecars, "not enough cells")
|
|
}
|
|
if len(cells) != len(proofs) {
|
|
return nil, nil, errors.Wrap(ErrNotEnoughDataColumnSidecars, "not enough proofs")
|
|
}
|
|
for j := range numCols {
|
|
if i == 0 {
|
|
cellCols[j] = make([][]byte, len(cellsPerBlob))
|
|
proofCols[j] = make([][]byte, len(cellsPerBlob))
|
|
}
|
|
cellCols[j][i] = cells[j][:]
|
|
proofCols[j][i] = proofs[j][:]
|
|
}
|
|
}
|
|
return cellCols, proofCols, nil
|
|
}
|
|
|
|
// Root returns the block root of the source
|
|
func (s *SidecarReconstructionSource) Root() [fieldparams.RootLength]byte {
|
|
return s.BlockRoot()
|
|
}
|
|
|
|
// Commmitments returns the blob KZG commitments of the source
|
|
func (s *SidecarReconstructionSource) Commitments() ([][]byte, error) {
|
|
return s.KzgCommitments, nil
|
|
}
|
|
|
|
// Type returns the type of the source
|
|
func (s *SidecarReconstructionSource) Type() string {
|
|
return SidecarType
|
|
}
|
|
|
|
// extract extracts the block information from the source
|
|
func (s *SidecarReconstructionSource) extract() (*blockInfo, error) {
|
|
info := &blockInfo{
|
|
signedBlockHeader: s.SignedBlockHeader,
|
|
kzgCommitments: s.KzgCommitments,
|
|
kzgInclusionProof: s.KzgCommitmentsInclusionProof,
|
|
}
|
|
|
|
return info, nil
|
|
}
|