mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2024-12-23 03:51:29 +00:00
5a66807989
* First take at updating everything to v5 * Patch gRPC gateway to use prysm v5 Fix patch * Update go ssz --------- Co-authored-by: Preston Van Loon <pvanloon@offchainlabs.com>
198 lines
4.6 KiB
Go
198 lines
4.6 KiB
Go
package backfill
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"time"
|
|
|
|
"github.com/libp2p/go-libp2p/core/peer"
|
|
"github.com/pkg/errors"
|
|
"github.com/prysmaticlabs/prysm/v5/beacon-chain/das"
|
|
"github.com/prysmaticlabs/prysm/v5/beacon-chain/sync"
|
|
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
|
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
|
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// ErrChainBroken indicates a backfill batch can't be imported to the db because it is not known to be the ancestor
|
|
// of the canonical chain.
|
|
var ErrChainBroken = errors.New("batch is not the ancestor of a known finalized root")
|
|
|
|
type batchState int
|
|
|
|
func (s batchState) String() string {
|
|
switch s {
|
|
case batchNil:
|
|
return "nil"
|
|
case batchInit:
|
|
return "init"
|
|
case batchSequenced:
|
|
return "sequenced"
|
|
case batchErrRetryable:
|
|
return "error_retryable"
|
|
case batchImportable:
|
|
return "importable"
|
|
case batchImportComplete:
|
|
return "import_complete"
|
|
case batchEndSequence:
|
|
return "end_sequence"
|
|
case batchBlobSync:
|
|
return "blob_sync"
|
|
default:
|
|
return "unknown"
|
|
}
|
|
}
|
|
|
|
const (
|
|
batchNil batchState = iota
|
|
batchInit
|
|
batchSequenced
|
|
batchErrRetryable
|
|
batchBlobSync
|
|
batchImportable
|
|
batchImportComplete
|
|
batchEndSequence
|
|
)
|
|
|
|
type batchId string
|
|
|
|
type batch struct {
|
|
firstScheduled time.Time
|
|
scheduled time.Time
|
|
seq int // sequence identifier, ie how many times has the sequence() method served this batch
|
|
retries int
|
|
begin primitives.Slot
|
|
end primitives.Slot // half-open interval, [begin, end), ie >= start, < end.
|
|
results verifiedROBlocks
|
|
err error
|
|
state batchState
|
|
busy peer.ID
|
|
blockPid peer.ID
|
|
blobPid peer.ID
|
|
bs *blobSync
|
|
}
|
|
|
|
func (b batch) logFields() log.Fields {
|
|
return map[string]interface{}{
|
|
"batch_id": b.id(),
|
|
"state": b.state.String(),
|
|
"scheduled": b.scheduled.String(),
|
|
"seq": b.seq,
|
|
"retries": b.retries,
|
|
"begin": b.begin,
|
|
"end": b.end,
|
|
"busyPid": b.busy,
|
|
"blockPid": b.blockPid,
|
|
"blobPid": b.blobPid,
|
|
}
|
|
}
|
|
|
|
func (b batch) replaces(r batch) bool {
|
|
if r.state == batchImportComplete {
|
|
return false
|
|
}
|
|
if b.begin != r.begin {
|
|
return false
|
|
}
|
|
if b.end != r.end {
|
|
return false
|
|
}
|
|
return b.seq >= r.seq
|
|
}
|
|
|
|
func (b batch) id() batchId {
|
|
return batchId(fmt.Sprintf("%d:%d", b.begin, b.end))
|
|
}
|
|
|
|
func (b batch) ensureParent(expected [32]byte) error {
|
|
tail := b.results[len(b.results)-1]
|
|
if tail.Root() != expected {
|
|
return errors.Wrapf(ErrChainBroken, "last parent_root=%#x, tail root=%#x", expected, tail.Root())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (b batch) blockRequest() *eth.BeaconBlocksByRangeRequest {
|
|
return ð.BeaconBlocksByRangeRequest{
|
|
StartSlot: b.begin,
|
|
Count: uint64(b.end - b.begin),
|
|
Step: 1,
|
|
}
|
|
}
|
|
|
|
func (b batch) blobRequest() *eth.BlobSidecarsByRangeRequest {
|
|
return ð.BlobSidecarsByRangeRequest{
|
|
StartSlot: b.begin,
|
|
Count: uint64(b.end - b.begin),
|
|
}
|
|
}
|
|
|
|
func (b batch) withResults(results verifiedROBlocks, bs *blobSync) batch {
|
|
b.results = results
|
|
b.bs = bs
|
|
if bs.blobsNeeded() > 0 {
|
|
return b.withState(batchBlobSync)
|
|
}
|
|
return b.withState(batchImportable)
|
|
}
|
|
|
|
func (b batch) postBlobSync() batch {
|
|
if b.blobsNeeded() > 0 {
|
|
log.WithFields(b.logFields()).WithField("blobs_missing", b.blobsNeeded()).Error("batch still missing blobs after downloading from peer")
|
|
b.bs = nil
|
|
b.results = []blocks.ROBlock{}
|
|
return b.withState(batchErrRetryable)
|
|
}
|
|
return b.withState(batchImportable)
|
|
}
|
|
|
|
func (b batch) withState(s batchState) batch {
|
|
if s == batchSequenced {
|
|
b.scheduled = time.Now()
|
|
switch b.state {
|
|
case batchErrRetryable:
|
|
b.retries += 1
|
|
log.WithFields(b.logFields()).Info("sequencing batch for retry")
|
|
case batchInit, batchNil:
|
|
b.firstScheduled = b.scheduled
|
|
}
|
|
}
|
|
if s == batchImportComplete {
|
|
backfillBatchTimeRoundtrip.Observe(float64(time.Since(b.firstScheduled).Milliseconds()))
|
|
log.WithFields(b.logFields()).Debug("Backfill batch imported.")
|
|
}
|
|
b.state = s
|
|
b.seq += 1
|
|
return b
|
|
}
|
|
|
|
func (b batch) withPeer(p peer.ID) batch {
|
|
b.blockPid = p
|
|
backfillBatchTimeWaiting.Observe(float64(time.Since(b.scheduled).Milliseconds()))
|
|
return b
|
|
}
|
|
|
|
func (b batch) withRetryableError(err error) batch {
|
|
b.err = err
|
|
return b.withState(batchErrRetryable)
|
|
}
|
|
|
|
func (b batch) blobsNeeded() int {
|
|
return b.bs.blobsNeeded()
|
|
}
|
|
|
|
func (b batch) blobResponseValidator() sync.BlobResponseValidation {
|
|
return b.bs.validateNext
|
|
}
|
|
|
|
func (b batch) availabilityStore() das.AvailabilityStore {
|
|
return b.bs.store
|
|
}
|
|
|
|
func sortBatchDesc(bb []batch) {
|
|
sort.Slice(bb, func(i, j int) bool {
|
|
return bb[j].end < bb[i].end
|
|
})
|
|
}
|