Skip to content
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

Fix Range Request Responses #7531

Merged
merged 16 commits into from Oct 22, 2020
Merged

Fix Range Request Responses #7531

merged 16 commits into from Oct 22, 2020

Conversation

nisdas
Copy link
Member

@nisdas nisdas commented Oct 14, 2020

What type of PR is this?

Bug Fix

What does this PR do? Why is it needed?

We were responding to range request with invalid blocks which were non linear. This lead to lighthouse nodes to disconnect
from us. This PR adds a new method to filter all blocks to be sent and to ensure their linearity.

  • Add in a new filtration method to make sure blocks are valid.
  • Add regression test cases for this.

Which issues(s) does this PR fix?

Fixes #7464

Other notes for review

@nisdas nisdas requested a review from a team as a code owner October 14, 2020 17:31
@nisdas nisdas added Ready For Review A pull request ready for code review Sync Sync (regular, initial, checkpoint) related issues labels Oct 14, 2020
farazdagi
farazdagi previously approved these changes Oct 14, 2020
Copy link
Contributor

@farazdagi farazdagi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our implementation of beaconBlocksByRangeRPCHandler() and writeBlockRangeToStream() is a bit convoluted and hard to review (complexity isn't introduced in this PR, though), so not 100% sure I haven't missed anything - but imo, the PR is solid.

// Decrease allowed blocks capacity by the number of streamed blocks.
if startSlot <= endSlot {
s.rateLimiter.add(stream, int64(1+(endSlot-startSlot)/m.Step))
}
// Exit in the event we have a disjoint chain to
// return.
if err == errInvalidParent {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use errors.Is(err, errInvalidParent), so that we can wrap errors?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would seem best IMO

step, startSlot uint64) ([]*ethpb.SignedBeaconBlock, error) {

newBlks := make([]*ethpb.SignedBeaconBlock, 0, len(blks))

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

// Decrease allowed blocks capacity by the number of streamed blocks.
if startSlot <= endSlot {
s.rateLimiter.add(stream, int64(1+(endSlot-startSlot)/m.Step))
}
// Exit in the event we have a disjoint chain to
// return.
if err == errInvalidParent {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would seem best IMO

newBlks := make([]*ethpb.SignedBeaconBlock, 0, len(blks))

for i, b := range blks {
isRequestedSlotStep := (b.Block.Slot-startSlot)%step == 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we validate start slot <= b.Block.Slot ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all this validation is already done and taken care of in validateRangeRequest


for i, b := range blks {
isRequestedSlotStep := (b.Block.Slot-startSlot)%step == 0
isCanonical, err := s.chain.IsCanonical(ctx, roots[i])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This func will never return err, is that ok?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I think we might need to fix the api of that method then. It can be done in another PR

@@ -214,6 +217,37 @@ func (s *Service) validateRangeRequest(r *pb.BeaconBlocksByRangeRequest) error {
return nil
}

// filters all the provided blocks to ensure they are canonical
// and are strictly linear.
func (s *Service) filterBlocks(ctx context.Context, blks []*ethpb.SignedBeaconBlock, roots [][32]byte, prevRoot *[32]byte,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does prevRoot mean? is it like a starting head root?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a comment in the main request handler of what prevRoot is and why it is used.

// and are strictly linear.
func (s *Service) filterBlocks(ctx context.Context, blks []*ethpb.SignedBeaconBlock, roots [][32]byte, prevRoot *[32]byte,
step, startSlot uint64) ([]*ethpb.SignedBeaconBlock, error) {

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perhaps do a defensive check that blks and roots are the same length

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually already done in dedupBlocksAndRoots but I can add it in again too.

isLinear := *prevRoot == bytesutil.ToBytes32(b.Block.ParentRoot)
isSingular := step == 1
if isRequestedSlotStep && isCanonical {
// Exit early if our valid block is non linear.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we want to be nicer here and actually return the resorted blocks for linearity? or exit early is good enough

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do return the blocks if we find the next block is non-linear. In the caller of this function, it checks the error and if it is invalidParent we just exit early and return what we have so far.

@codecov
Copy link

codecov bot commented Oct 15, 2020

Codecov Report

Merging #7531 into master will increase coverage by 0.13%.
The diff coverage is n/a.

@@            Coverage Diff             @@
##           master    #7531      +/-   ##
==========================================
+ Coverage   61.62%   61.76%   +0.13%     
==========================================
  Files         422      423       +1     
  Lines       29688    29761      +73     
==========================================
+ Hits        18296    18381      +85     
+ Misses       8466     8452      -14     
- Partials     2926     2928       +2     

@rauljordan rauljordan merged commit ddbece5 into master Oct 22, 2020
@rauljordan rauljordan deleted the fixUpRoots branch October 22, 2020 14:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Ready For Review A pull request ready for code review Sync Sync (regular, initial, checkpoint) related issues
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Beacon Node Still Returns Out of Order Blocks From Range Requests
4 participants