mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-08 23:18:15 -05:00
* Ran gopls modernize to fix everything go run golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@latest -fix -test ./... * Override rules_go provided dependency for golang.org/x/tools to v0.38.0. To update this, checked out rules_go, then ran `bazel run //go/tools/releaser -- upgrade-dep -mirror=false org_golang_x_tools` and copied the patches. * Fix buildtag violations and ignore buildtag violations in external * Introduce modernize analyzer package. * Add modernize "any" analyzer. * Fix violations of any analyzer * Add modernize "appendclipped" analyzer. * Fix violations of appendclipped * Add modernize "bloop" analyzer. * Add modernize "fmtappendf" analyzer. * Add modernize "forvar" analyzer. * Add modernize "mapsloop" analyzer. * Add modernize "minmax" analyzer. * Fix violations of minmax analyzer * Add modernize "omitzero" analyzer. * Add modernize "rangeint" analyzer. * Fix violations of rangeint. * Add modernize "reflecttypefor" analyzer. * Fix violations of reflecttypefor analyzer. * Add modernize "slicescontains" analyzer. * Add modernize "slicessort" analyzer. * Add modernize "slicesdelete" analyzer. This is disabled by default for now. See https://go.dev/issue/73686. * Add modernize "stringscutprefix" analyzer. * Add modernize "stringsbuilder" analyzer. * Fix violations of stringsbuilder analyzer. * Add modernize "stringsseq" analyzer. * Add modernize "testingcontext" analyzer. * Add modernize "waitgroup" analyzer. * Changelog fragment * gofmt * gazelle * Add modernize "newexpr" analyzer. * Disable newexpr until go1.26 * Add more details in WORKSPACE on how to update the override * @nalepae feedback on min() * gofmt * Fix violations of forvar
160 lines
5.5 KiB
Go
160 lines
5.5 KiB
Go
package sync
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sort"
|
|
"time"
|
|
|
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/db"
|
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/p2p"
|
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/p2p/types"
|
|
"github.com/OffchainLabs/prysm/v7/cmd/beacon-chain/flags"
|
|
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
|
|
"github.com/OffchainLabs/prysm/v7/config/params"
|
|
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
|
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
|
|
"github.com/OffchainLabs/prysm/v7/monitoring/tracing"
|
|
"github.com/OffchainLabs/prysm/v7/monitoring/tracing/trace"
|
|
"github.com/OffchainLabs/prysm/v7/time/slots"
|
|
libp2pcore "github.com/libp2p/go-libp2p/core"
|
|
"github.com/pkg/errors"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// blobSidecarByRootRPCHandler handles the /eth2/beacon_chain/req/blob_sidecars_by_root/1/ RPC request.
|
|
// spec: https://github.com/ethereum/consensus-specs/blob/a7e45db9ac2b60a33e144444969ad3ac0aae3d4c/specs/deneb/p2p-interface.md#blobsidecarsbyroot-v1
|
|
func (s *Service) blobSidecarByRootRPCHandler(ctx context.Context, msg any, stream libp2pcore.Stream) error {
|
|
ctx, span := trace.StartSpan(ctx, "sync.blobSidecarByRootRPCHandler")
|
|
defer span.End()
|
|
ctx, cancel := context.WithTimeout(ctx, ttfbTimeout)
|
|
defer cancel()
|
|
SetRPCStreamDeadlines(stream)
|
|
log := log.WithField("handler", p2p.BlobSidecarsByRootName[1:]) // slice the leading slash off the name var
|
|
ref, ok := msg.(*types.BlobSidecarsByRootReq)
|
|
if !ok {
|
|
return errors.New("message is not type BlobSidecarsByRootReq")
|
|
}
|
|
|
|
blobIdents := *ref
|
|
|
|
if err := s.rateLimiter.validateRequest(stream, uint64(len(blobIdents))); err != nil {
|
|
return errors.Wrap(err, "rate limiter validate request")
|
|
}
|
|
|
|
cs := s.cfg.clock.CurrentSlot()
|
|
remotePeer := stream.Conn().RemotePeer()
|
|
if err := validateBlobByRootRequest(blobIdents, cs); err != nil {
|
|
s.downscorePeer(remotePeer, "blobSidecarsByRootRpcHandlerValidationError")
|
|
s.writeErrorResponseToStream(responseCodeInvalidRequest, err.Error(), stream)
|
|
return err
|
|
}
|
|
|
|
// Sort the identifiers so that requests for the same blob root will be adjacent, minimizing db lookups.
|
|
sort.Sort(blobIdents)
|
|
|
|
batchSize := flags.Get().BlobBatchLimit
|
|
var ticker *time.Ticker
|
|
if len(blobIdents) > batchSize {
|
|
ticker = time.NewTicker(blobRpcThrottleInterval)
|
|
}
|
|
|
|
// Compute the oldest slot we'll allow a peer to request, based on the current slot.
|
|
minReqSlot, err := BlobRPCMinValidSlot(cs)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "unexpected error computing min valid blob request slot, current_slot=%d", cs)
|
|
}
|
|
|
|
// Extract all needed roots.
|
|
roots := make([][fieldparams.RootLength]byte, 0, len(blobIdents))
|
|
for _, ident := range blobIdents {
|
|
root := bytesutil.ToBytes32(ident.BlockRoot)
|
|
roots = append(roots, root)
|
|
}
|
|
|
|
// Filter all available roots in block storage.
|
|
availableRoots := s.cfg.beaconDB.AvailableBlocks(ctx, roots)
|
|
|
|
// Serve each requested blob sidecar.
|
|
for i := range blobIdents {
|
|
if err := ctx.Err(); err != nil {
|
|
closeStream(stream, log)
|
|
return err
|
|
}
|
|
|
|
// Throttle request processing to no more than batchSize/sec.
|
|
if i != 0 && i%batchSize == 0 && ticker != nil {
|
|
<-ticker.C
|
|
}
|
|
s.rateLimiter.add(stream, 1)
|
|
|
|
root, idx := bytesutil.ToBytes32(blobIdents[i].BlockRoot), blobIdents[i].Index
|
|
|
|
// Do not serve a blob sidecar if the corresponding block is not available.
|
|
if !availableRoots[root] {
|
|
log.Trace("Peer requested blob sidecar by root but corresponding block not found in db")
|
|
continue
|
|
}
|
|
|
|
sc, err := s.cfg.blobStorage.Get(root, idx)
|
|
if err != nil {
|
|
log := log.WithFields(logrus.Fields{
|
|
"root": fmt.Sprintf("%#x", root),
|
|
"index": idx,
|
|
"peer": remotePeer.String(),
|
|
})
|
|
|
|
if db.IsNotFound(err) {
|
|
log.Trace("Peer requested blob sidecar by root not found in db")
|
|
continue
|
|
}
|
|
|
|
log.Error("Unexpected DB error retrieving blob sidecar from storage")
|
|
s.writeErrorResponseToStream(responseCodeServerError, types.ErrGeneric.Error(), stream)
|
|
|
|
return errors.Wrap(err, "get blob sidecar by root")
|
|
}
|
|
|
|
// If any root in the request content references a block earlier than minimum_request_epoch,
|
|
// peers MAY respond with error code 3: ResourceUnavailable or not include the blob in the response.
|
|
// note: we are deviating from the spec to allow requests for blobs that are before minimum_request_epoch,
|
|
// up to the beginning of the retention period.
|
|
if sc.Slot() < minReqSlot {
|
|
s.writeErrorResponseToStream(responseCodeResourceUnavailable, types.ErrBlobLTMinRequest.Error(), stream)
|
|
log.WithError(types.ErrBlobLTMinRequest).
|
|
Debugf("Requested blob for block %#x before minimum_request_epoch", blobIdents[i].BlockRoot)
|
|
return types.ErrBlobLTMinRequest
|
|
}
|
|
|
|
SetStreamWriteDeadline(stream, defaultWriteDuration)
|
|
if chunkErr := WriteBlobSidecarChunk(stream, s.cfg.clock, s.cfg.p2p.Encoding(), sc); chunkErr != nil {
|
|
log.WithError(chunkErr).Debug("Could not send a chunked response")
|
|
s.writeErrorResponseToStream(responseCodeServerError, types.ErrGeneric.Error(), stream)
|
|
tracing.AnnotateError(span, chunkErr)
|
|
return chunkErr
|
|
}
|
|
}
|
|
closeStream(stream, log)
|
|
return nil
|
|
}
|
|
|
|
func validateBlobByRootRequest(blobIdents types.BlobSidecarsByRootReq, slot primitives.Slot) error {
|
|
cfg := params.BeaconConfig()
|
|
epoch := slots.ToEpoch(slot)
|
|
blobIdentCount := uint64(len(blobIdents))
|
|
|
|
if epoch >= cfg.ElectraForkEpoch {
|
|
if blobIdentCount > cfg.MaxRequestBlobSidecarsElectra {
|
|
return types.ErrMaxBlobReqExceeded
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
if blobIdentCount > cfg.MaxRequestBlobSidecars {
|
|
return types.ErrMaxBlobReqExceeded
|
|
}
|
|
|
|
return nil
|
|
}
|