-
Notifications
You must be signed in to change notification settings - Fork 1.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
Ignore some untimely attestations #12387
Conversation
f81436a
to
3dc041f
Compare
return nil, errors.Wrap(err, "could not compute epoch start") | ||
} | ||
cachedState = transition.NextSlotState(c.Root, slot) | ||
if cachedState != 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.
cachedState, err := s.checkpointStateCache.StateByCheckpoint(c) has a check
!cachedState.IsNil() on line 33. is this cachedState different as we don't need that IsNil check?
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 think it's safe to add !cachedState.IsNil() check here
// If the attestation is recent and canonical we can use the head state to compute the shuffling. | ||
headEpoch := slots.ToEpoch(s.HeadSlot()) | ||
if c.Epoch == headEpoch { | ||
targetSlot, err := s.cfg.ForkChoiceStore.Slot([32]byte(c.Root)) |
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 there be a check for cfg or ForkChoice initialized
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 think so, this is in the blockchain package and forkchoice starts up before in the node.
{ | ||
name: "no pre state for attestations's target block", | ||
a: util.HydrateAttestation(ðpb.Attestation{Data: ðpb.AttestationData{Target: ðpb.Checkpoint{Root: BlkWithOutStateRoot[:]}}}), | ||
wantedErr: "could not get pre state for epoch 0", | ||
}, |
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.
Note I removed this test. This becomes an impossible scenario with the addition of getting head state read-only
@@ -152,20 +151,6 @@ func (s *Service) validateAggregatedAtt(ctx context.Context, signed *ethpb.Signe | |||
return pubsub.ValidationIgnore, err | |||
} | |||
|
|||
attSlot := signed.Message.Aggregate.Data.Slot |
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 change is quite irrelevant but it's worth noting to the audience:
Processing slots is unnecessary here
ss, err := slots.EpochStart(target.Epoch) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if err := slots.ValidateClock(ss, uint64(s.genesisTime.Unix())); err != nil { | ||
return nil, err | ||
} | ||
s.cfg.ForkChoiceStore.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.
Should this be outside of getAttPreState instead of inside?
getAttPreState is used in OnAttestation which don't have the same locks.
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.
OnAttestation path is called only from UpdateHead
that grabs the lock.
2e6a9d5
to
8dd8373
Compare
…ysm into ignore_old_attestations
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.
Lgtm
* Ignore some untimely attestations * correct child slot check * consider tips as viable for checkpoints * deal with canonical blocks * forkchoice unit tests * blockchain readonly beacon state * Ignore some untimely attestations * correct child slot check * consider tips as viable for checkpoints * deal with canonical blocks * forkchoice unit tests * blockchain readonly beacon state * Fix AttestationTargetState mock * Fix ineffectual assignment lint * Fix blockchain tests * Fix build * Add Nil check * add comment on lock --------- Co-authored-by: terence tsao <terence@prysmaticlabs.com> Co-authored-by: Preston Van Loon <pvanloon@offchainlabs.com>
@@ -380,6 +381,14 @@ func (s *Service) InForkchoice(root [32]byte) bool { | |||
return s.cfg.ForkChoiceStore.HasNode(root) | |||
} | |||
|
|||
// IsViableForkCheckpoint returns whether the given checkpoint is a checkpoint in any | |||
// chain known to forkchoice | |||
func (s *Service) IsViableForCheckpoint(cp *forkchoicetypes.Checkpoint) (bool, 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.
I am not seeing that this function is called from anywhere
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 just to ensure s.cfg.ForkChoiceStore.RLock()
is grabbed if it this accessor is used in the future? I did check that the locks are acquired correctly in the other call path for s.cfg.ForkChoiceStore.IsViableForCheckpoint(cp)
. The only other call path I see is UpdateHead
->processAttestations
->receiveAttestationNoPubsub
->OnAttestation
->getAttPreState
)
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.
the lock is acquired in UpdateHead
FYI
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.
+1. I think it can be removed
@@ -380,6 +381,14 @@ func (s *Service) InForkchoice(root [32]byte) bool { | |||
return s.cfg.ForkChoiceStore.HasNode(root) | |||
} | |||
|
|||
// IsViableForkCheckpoint returns whether the given checkpoint is a checkpoint in any | |||
// chain known to forkchoice | |||
func (s *Service) IsViableForCheckpoint(cp *forkchoicetypes.Checkpoint) (bool, 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.
Is this just to ensure s.cfg.ForkChoiceStore.RLock()
is grabbed if it this accessor is used in the future? I did check that the locks are acquired correctly in the other call path for s.cfg.ForkChoiceStore.IsViableForCheckpoint(cp)
. The only other call path I see is UpdateHead
->processAttestations
->receiveAttestationNoPubsub
->OnAttestation
->getAttPreState
)
@@ -380,6 +381,14 @@ func (s *Service) InForkchoice(root [32]byte) bool { | |||
return s.cfg.ForkChoiceStore.HasNode(root) | |||
} | |||
|
|||
// IsViableForkCheckpoint returns whether the given checkpoint is a checkpoint in any | |||
// chain known to forkchoice | |||
func (s *Service) IsViableForCheckpoint(cp *forkchoicetypes.Checkpoint) (bool, 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.
the lock is acquired in UpdateHead
FYI
if node.slot > epochStart { | ||
return false, 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.
I might remove this space for OCD unless it is to separate these conditionals into groups but def not a big deal
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.
Hi David yeah this function was just mostly for future reference that locking of forlchoice is tricky within the Blockchain package but any external user has to use the service one that is self locking
When we receive an attestation for an old target, a node needs to regenerate the beacon state at that time in order to validate the attestation. Performing several of these replays at the same time is what stresses the nodes' CPUs and bloats memory usage. A node has a cache of seen attestation targets designed to address this situation. With the increase in validator sizes and the number of this untimely attestation, this cache quickly filled and forced us to replay several times in the same state. This PR implements a heuristic such that when a node receives many unviable checkpoint attestations, a node will simply ignore them if the target of the attestation is known to be old and not have been a checkpoint in any chain known to our node
This PR also made a change to validate aggregated p2p pipeline to not process slots for state used to verify selection proof and signature