Files
prysm/beacon-chain/sync/data_columns_reconstruct.go
Manu NALEPA 2773bdef89 Remove NUMBER_OF_COLUMNS and MAX_CELLS_IN_EXTENDED_MATRIX configuration. (#16073)
**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.
2025-11-29 09:30:54 +00:00

132 lines
4.6 KiB
Go

package sync
import (
"context"
"fmt"
"sync"
"time"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/helpers"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/peerdas"
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
"github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
"github.com/OffchainLabs/prysm/v7/time/slots"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
// processDataColumnSidecarsFromReconstruction, after a random delay, attempts to reconstruct,
// broadcast and receive missing data column sidecars for the given block root.
// https:github.com/ethereum/consensus-specs/blob/master/specs/fulu/das-core.md#reconstruction-and-cross-seeding
func (s *Service) processDataColumnSidecarsFromReconstruction(ctx context.Context, sidecar blocks.VerifiedRODataColumn) error {
key := fmt.Sprintf("%#x", sidecar.BlockRoot())
if _, err, _ := s.reconstructionSingleFlight.Do(key, func() (any, error) {
var wg sync.WaitGroup
root := sidecar.BlockRoot()
slot := sidecar.Slot()
proposerIndex := sidecar.ProposerIndex()
// Return early if reconstruction is not needed.
if !s.shouldReconstruct(root) {
return nil, nil
}
// Compute the slot start time.
slotStartTime, err := slots.StartTime(s.cfg.clock.GenesisTime(), slot)
if err != nil {
return nil, errors.Wrap(err, "failed to calculate slot start time")
}
// Randomly choose value before starting reconstruction.
timeIntoSlot := s.computeRandomDelay(slotStartTime)
broadcastTime := slotStartTime.Add(timeIntoSlot)
waitingTime := time.Until(broadcastTime)
wg.Add(1)
time.AfterFunc(waitingTime, func() {
defer wg.Done()
// Return early if the context was canceled during the waiting time.
if err := ctx.Err(); err != nil {
return
}
// Return early if reconstruction is not needed anymore.
if !s.shouldReconstruct(root) {
return
}
// Load all the stored data column sidecars for this root.
verifiedSidecars, err := s.cfg.dataColumnStorage.Get(root, nil)
if err != nil {
log.WithError(err).Error("Failed to get data column sidecars")
return
}
// Reconstruct all the data column sidecars.
startTime := time.Now()
reconstructedSidecars, err := peerdas.ReconstructDataColumnSidecars(verifiedSidecars)
if err != nil {
log.WithError(err).Error("Failed to reconstruct data column sidecars")
return
}
duration := time.Since(startTime)
dataColumnReconstructionHistogram.Observe(float64(duration.Milliseconds()))
dataColumnReconstructionCounter.Add(float64(len(reconstructedSidecars) - len(verifiedSidecars)))
// Retrieve indices of data column sidecars to sample.
columnIndicesToSample, err := s.columnIndicesToSample()
if err != nil {
log.WithError(err).Error("Failed to get column indices to sample")
return
}
unseenIndices, err := s.broadcastAndReceiveUnseenDataColumnSidecars(ctx, slot, proposerIndex, columnIndicesToSample, reconstructedSidecars)
if err != nil {
log.WithError(err).Error("Failed to broadcast and receive unseen data column sidecars")
return
}
if len(unseenIndices) > 0 {
log.WithFields(logrus.Fields{
"root": fmt.Sprintf("%#x", root),
"slot": slot,
"proposerIndex": proposerIndex,
"count": len(unseenIndices),
"indices": helpers.SortedPrettySliceFromMap(unseenIndices),
"duration": duration,
}).Debug("Reconstructed data column sidecars")
}
})
wg.Wait()
return nil, nil
}); err != nil {
return err
}
return nil
}
// shouldReconstruct returns true if we should attempt to reconstruct the data columns for the given block root.
func (s *Service) shouldReconstruct(root [fieldparams.RootLength]byte) bool {
// Get the columns we store.
storedDataColumns := s.cfg.dataColumnStorage.Summary(root)
storedColumnsCount := storedDataColumns.Count()
// Reconstruct only if we have at least the minimum number of columns to reconstruct, but not all the columns.
// (If we have not enough columns, reconstruction is impossible. If we have all the columns, reconstruction is unnecessary.)
return storedColumnsCount >= peerdas.MinimumColumnCountToReconstruct() && storedColumnsCount != fieldparams.NumberOfColumns
}
// computeRandomDelay computes a random delay duration to wait before reconstructing data column sidecars.
func (s *Service) computeRandomDelay(slotStartTime time.Time) time.Duration {
const maxReconstructionDelaySec = 2.
randFloat := s.reconstructionRandGen.Float64()
timeIntoSlot := time.Duration(maxReconstructionDelaySec * randFloat * float64(time.Second))
return timeIntoSlot
}