-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Use a cache of one entry to build attestation #13300
Conversation
minDelay = float64(10) // 10 nanoseconds | ||
maxDelay = float64(100000000) // 0.1 second | ||
delayFactor = 1.1 | ||
const maxSize = 4 |
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 was from the previous cache I think
cache *cache.FIFO | ||
lock sync.RWMutex | ||
inProgress map[string]bool | ||
a *ethpb.AttestationData |
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.
why would you keep the full attestation data with the given committee index ?
attestationCacheHit.Inc() | ||
return ethpb.CopyAttestationData(item.(*attestationReqResWrapper).res), nil | ||
return ethpb.CopyAttestationData(c.a), nil |
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 will return the wrong committee index for some validators.
beacon-chain/rpc/core/validator.go
Outdated
isCurrentOrPastSlot := s.HeadFetcher.HeadSlot() == req.Slot || currentUnixTime >= timeThreshold | ||
|
||
if isCurrentOrPastSlot { | ||
err := s.AttestationCache.Put(ctx, res) |
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.
If someone requests an attestation for the previous slot you will overwrite the cache, why is this? Say you hold 1000 keys, and one of them for some reason (for example is run on a different VC on a different network and that one lags) requests for the previous slot. If you overwrite the cache then you'll fail on any of the other 1000 keys. I think we shouldn't even serve these attestations.
Also notice that there is another bug here: Suppose that the requested slot is from 5 slots ago, the first branch of || will be false but the second will be true. The attestation here will be for the wrong headBlock!
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.
I've updated the design to ensure RPC only serves current slot attestation, it should address most of the concerns. Let's wait a few days and gather more feedback from the team
TargetCheckpoint *ethpb.Checkpoint | ||
SourceCheckpoint *ethpb.Checkpoint |
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.
Why are these pointers?
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.
I don't want to copy the whole protobuf object; there are many irrelevant fields.
Instead of Checkpoint, I'll switch to the root and epoch
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.
You can use forkchoicetypes.Checkpoint
for this
// ErrAlreadyInProgress appears when attempting to mark a cache as in progress while it is | ||
// already in progress. The client should handle this error and wait for the in progress | ||
// data to resolve via Get. | ||
ErrAlreadyInProgress = errors.New("already in progress") |
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.
Is this still used? ah perhaps in another cache?
96549ca
to
23fa758
Compare
beacon-chain/rpc/core/validator.go
Outdated
targetRoot = headRoot | ||
} | ||
justifiedCheckpoint := s.FinalizedFetcher.CurrentJustifiedCheckpt() | ||
if err = s.AttestationCache.Put(ctx, &cache.AttestationConsensusData{ |
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.
Could possibly be contention here with 100+ routines trying to put this in the cache if this beacon node hosts many validators.
37518b2
to
30afc71
Compare
beacon-chain/rpc/core/validator.go
Outdated
if err != nil { | ||
return nil, &RpcError{Reason: Internal, Err: errors.Errorf("could not retrieve head state: %v", err)} | ||
return nil, &RpcError{Reason: Internal, Err: errors.Errorf("could not retrieve data from attestation cache: %v", err)} |
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.
If there is an error, we need to unlock the attestation cache, otherwise it remains permanently locked.
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 function never errors, we should change the signature.
a8a6ebb
to
8512108
Compare
attestationCacheMiss.Inc() | ||
return nil, nil | ||
// Get retrieves cached attestation data, recording a cache hit or miss. This method is lock free. | ||
func (c *AttestationCache) Get(ctx context.Context) (*AttestationConsensusData, error) { |
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.
Why the error signature here?
lock sync.RWMutex | ||
inProgress map[string]bool | ||
a *AttestationConsensusData | ||
lock sync.RWMutex |
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.
no need to have this named, see also below.
} | ||
return reqToKey(w.req) | ||
// Unlock unlocks the cache for writing. | ||
func (c *AttestationCache) Unlock() { |
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 not needed if you not name the lock
func reqToKey(req *ethpb.AttestationDataRequest) (string, error) { | ||
return fmt.Sprintf("%d", req.Slot), nil | ||
// RLock locks the cache for reading. | ||
func (c *AttestationCache) RLock() { |
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 not needed if you don' t name the lock.
beacon-chain/rpc/core/validator.go
Outdated
return res, nil | ||
} | ||
return nil, &RpcError{Reason: Internal, Err: errors.Errorf("could not mark attestation as in-progress: %v", err)} | ||
if req.Slot != s.GenesisTimeFetcher.CurrentSlot() { |
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.
Please move this before the call to ValidateAttestationTime
that does a bunch of silly computations.
beacon-chain/rpc/core/validator.go
Outdated
if err != nil { | ||
return nil, &RpcError{Reason: Internal, Err: errors.Errorf("could not retrieve head state: %v", err)} | ||
return nil, &RpcError{Reason: Internal, Err: errors.Errorf("could not retrieve data from attestation cache: %v", err)} |
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 function never errors, we should change the signature.
575aacf
to
e6e73fe
Compare
e6e73fe
to
466ca55
Compare
Co-authored-by: Potuz <potuz@prysmaticlabs.com>
Alternate Implementation to #13286 and #13256
This proposal introduces a modified caching strategy for single attestation entries, implementing stricter controls on the RPC behavior.