-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Pending aggregates: When multiple aggregated attestations only differing by the aggregator index are in the pending queue, only process one of them. #16153
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 9 commits
68a28bb
8ad1b9d
bd71128
86387d7
04a95d7
84830bf
3b8f5f0
b748c04
e94e7c1
9969761
d3a3279
e2db419
668918f
ed9dd00
84ce0f8
0ce9c60
4eb55cd
df3b0da
7dfaa90
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,9 +3,9 @@ package sync | |
| import ( | ||
| "bytes" | ||
| "context" | ||
| "encoding/hex" | ||
| "fmt" | ||
| "slices" | ||
| "time" | ||
|
|
||
| "github.com/OffchainLabs/prysm/v7/beacon-chain/blockchain" | ||
| "github.com/OffchainLabs/prysm/v7/beacon-chain/core/blocks" | ||
|
|
@@ -21,13 +21,12 @@ import ( | |
| "github.com/OffchainLabs/prysm/v7/monitoring/tracing/trace" | ||
| ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1" | ||
| "github.com/OffchainLabs/prysm/v7/runtime/version" | ||
| "github.com/OffchainLabs/prysm/v7/time" | ||
| "github.com/OffchainLabs/prysm/v7/time/slots" | ||
| pubsub "github.com/libp2p/go-libp2p-pubsub" | ||
| "github.com/sirupsen/logrus" | ||
| ) | ||
|
|
||
| var pendingAttsLimit = 32768 | ||
| const pendingAttsLimit = 32768 | ||
|
|
||
| // This method processes pending attestations as a "known" block as arrived. With validations, | ||
| // the valid attestations get saved into the operation mem pool, and the invalid attestations gets deleted | ||
|
|
@@ -50,16 +49,7 @@ func (s *Service) processPendingAttsForBlock(ctx context.Context, bRoot [32]byte | |
| attestations := s.blkRootToPendingAtts[bRoot] | ||
| s.pendingAttsLock.RUnlock() | ||
|
|
||
| if len(attestations) > 0 { | ||
| start := time.Now() | ||
| s.processAttestations(ctx, attestations) | ||
| duration := time.Since(start) | ||
| log.WithFields(logrus.Fields{ | ||
| "blockRoot": hex.EncodeToString(bytesutil.Trunc(bRoot[:])), | ||
| "pendingAttsCount": len(attestations), | ||
| "duration": duration, | ||
| }).Debug("Verified and saved pending attestations to pool") | ||
| } | ||
| s.processAttestations(ctx, attestations, bRoot) | ||
|
|
||
| randGen := rand.NewGenerator() | ||
| // Delete the missing block root key from pending attestation queue so a node will not request for the block again. | ||
|
|
@@ -79,26 +69,43 @@ func (s *Service) processPendingAttsForBlock(ctx context.Context, bRoot [32]byte | |
| return s.sendBatchRootRequest(ctx, pendingRoots, randGen) | ||
| } | ||
|
|
||
| func (s *Service) processAttestations(ctx context.Context, attestations []any) { | ||
| func (s *Service) processAttestations(ctx context.Context, attestations []any, blockRoot [32]byte) { | ||
| if len(attestations) == 0 { | ||
| return | ||
| } | ||
|
|
||
| startAggregate := time.Now() | ||
| atts := make([]ethpb.Att, 0, len(attestations)) | ||
| aggregateAttAndProofCount := 0 | ||
| for _, att := range attestations { | ||
| switch v := att.(type) { | ||
| case ethpb.Att: | ||
| atts = append(atts, v) | ||
| case ethpb.SignedAggregateAttAndProof: | ||
| s.processAggregate(ctx, v) | ||
| aggregateAttAndProofCount++ | ||
| default: | ||
| log.Warnf("Unexpected attestation type %T, skipping", v) | ||
| } | ||
| } | ||
| durationAggregateAttAndProof := time.Since(startAggregate) | ||
|
|
||
| startAtts := time.Now() | ||
| for _, bucket := range bucketAttestationsByData(atts) { | ||
| s.processAttestationBucket(ctx, bucket) | ||
| } | ||
|
|
||
| durationAtts := time.Since(startAtts) | ||
|
|
||
| log.WithFields(logrus.Fields{ | ||
| "blockRoot": fmt.Sprintf("%#x", blockRoot), | ||
| "pendingTotalCount": len(attestations), | ||
| "pendingAggregateAttAndProofCount": aggregateAttAndProofCount, | ||
| "pendingAttCount": len(atts), | ||
| "durationTotal": durationAggregateAttAndProof + durationAtts, | ||
| "durationAggregateAttAndProof": durationAggregateAttAndProof, | ||
| "durationAtts": durationAtts, | ||
| }).Debug("Verified and saved pending attestations to pool") | ||
| } | ||
|
|
||
| // attestationBucket groups attestations with the same AttestationData for batch processing. | ||
|
|
@@ -395,9 +402,6 @@ func pendingAggregatesAreEqual(a, b ethpb.SignedAggregateAttAndProof) bool { | |
| if a.Version() != b.Version() { | ||
| return false | ||
| } | ||
| if a.AggregateAttestationAndProof().GetAggregatorIndex() != b.AggregateAttestationAndProof().GetAggregatorIndex() { | ||
| return false | ||
| } | ||
|
Comment on lines
-398
to
-400
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to make sure that one of the aggregates is valid if and only iff all other aggregates are valid
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Moving to draft until your comment is solved.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With this PR, there is a flaw: Later, when processing the queue, we finally reject this aggregated attestation because it is not valid. 9969761 fixes is issue, by moving all verifications not needing the block (including the aggregator index) before inserting the aggregated attestation into the queue. As a bonus, it considerably reduces the process time when pulling aggregated attestations from the queue. |
||
| aAtt := a.AggregateAttestationAndProof().AggregateVal() | ||
| bAtt := b.AggregateAttestationAndProof().AggregateVal() | ||
| if aAtt.GetData().Slot != bAtt.GetData().Slot { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,7 +2,6 @@ package sync | |
|
|
||
| import ( | ||
| "context" | ||
| "encoding/hex" | ||
| "fmt" | ||
| "slices" | ||
| "sync" | ||
|
|
@@ -44,11 +43,13 @@ func (s *Service) processPendingBlocksQueue() { | |
| if !s.chainIsStarted() { | ||
| return | ||
| } | ||
|
|
||
| locker.Lock() | ||
| defer locker.Unlock() | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if this deadlock ever happened in the wild |
||
| if err := s.processPendingBlocks(s.ctx); err != nil { | ||
| log.WithError(err).Debug("Could not process pending blocks") | ||
| } | ||
| locker.Unlock() | ||
| }) | ||
| } | ||
|
|
||
|
|
@@ -91,6 +92,8 @@ func (s *Service) processPendingBlocks(ctx context.Context) error { | |
|
|
||
| // Process each block in the queue. | ||
| for _, b := range blocksInCache { | ||
| start := time.Now() | ||
|
|
||
| if err := blocks.BeaconBlockIsNil(b); err != nil { | ||
| continue | ||
| } | ||
|
|
@@ -156,8 +159,14 @@ func (s *Service) processPendingBlocks(ctx context.Context) error { | |
| if err := s.removeBlockFromQueue(b, blkRoot); err != nil { | ||
| return err | ||
| } | ||
| log.WithFields(logrus.Fields{"slot": slot, "blockRoot": hex.EncodeToString(bytesutil.Trunc(blkRoot[:]))}).Debug("Processed pending block and cleared it in cache") | ||
|
|
||
| log.WithFields(logrus.Fields{ | ||
| "slot": slot, | ||
| "root": fmt.Sprintf("%#x", blkRoot), | ||
| "duration": time.Since(start), | ||
| }).Debug("Processed pending block and cleared it in cache") | ||
| } | ||
|
|
||
| span.End() | ||
| } | ||
| return s.sendBatchRootRequest(ctx, parentRoots, randGen) | ||
|
|
@@ -379,6 +388,19 @@ func (s *Service) sendBatchRootRequest(ctx context.Context, roots [][32]byte, ra | |
| req = roots[:maxReqBlock] | ||
| } | ||
|
|
||
| if logrus.GetLevel() >= logrus.DebugLevel { | ||
| rootsStr := make([]string, 0, len(roots)) | ||
| for _, req := range roots { | ||
| rootsStr = append(rootsStr, fmt.Sprintf("%#x", req)) | ||
| } | ||
|
|
||
| log.WithFields(logrus.Fields{ | ||
| "peer": pid, | ||
| "count": len(req), | ||
| "roots": rootsStr, | ||
| }).Debug("Requesting blocks by root") | ||
| } | ||
|
|
||
| // Send the request to the peer. | ||
| if err := s.sendBeaconBlocksRequest(ctx, &req, pid); err != nil { | ||
| tracing.AnnotateError(span, err) | ||
|
|
@@ -438,8 +460,6 @@ func (s *Service) filterOutPendingAndSynced(roots [][fieldparams.RootLength]byte | |
| roots = append(roots[:i], roots[i+1:]...) | ||
| continue | ||
| } | ||
|
|
||
| log.WithField("blockRoot", fmt.Sprintf("%#x", r)).Debug("Requesting block by root") | ||
| } | ||
| return roots | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| ### Changed | ||
|
|
||
| - Pending aggregates: When multiple aggregated attestations only differing by the aggregator index are in the pending queue, only process one of them. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is unrelated with the PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's right. That's the reason why it's modified in a totally separated commit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we take it out of the PR?
id at least mention it in the github description, as reviewer, it was confusing to read at first