Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions beacon-chain/blockchain/chain_info.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package blockchain

import (
"bytes"
"context"
"time"

Expand Down Expand Up @@ -299,13 +300,14 @@ func (s *Service) ForkChoicer() forkchoice.ForkChoicer {

// IsOptimistic returns true if the current head is optimistic.
func (s *Service) IsOptimistic(ctx context.Context) (bool, error) {
s.headLock.RLock()
defer s.headLock.RUnlock()
if slots.ToEpoch(s.CurrentSlot()) < params.BeaconConfig().BellatrixForkEpoch {
return false, nil
}
s.headLock.RLock()
headRoot := s.head.root
s.headLock.RUnlock()

return s.IsOptimisticForRoot(ctx, s.head.root)
return s.IsOptimisticForRoot(ctx, headRoot)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

IsOptimisticForRoot now requires a lock.

}

// IsFinalized returns true if the input root is finalized.
Expand All @@ -332,7 +334,17 @@ func (s *Service) IsOptimisticForRoot(ctx context.Context, root [32]byte) (bool,
return false, err
}
if ss == nil {
return false, errInvalidNilSummary
// if the requested root is the headroot we should treat the
// node as optimistic. This can happen if we pruned INVALID
// nodes and no viable head is available.
headRoot, err := s.HeadRoot(ctx)
Copy link
Contributor

Choose a reason for hiding this comment

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

how does this work, we have a head for which there is no state summary/block in the db ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, and even worse, it can be different than forkchoice's

if err != nil {
return true, err
}
if bytes.Equal(headRoot, root[:]) {
return true, nil
}
return true, errInvalidNilSummary
}

validatedCheckpoint, err := s.cfg.BeaconDB.LastValidatedCheckpoint(ctx)
Expand Down
8 changes: 6 additions & 2 deletions beacon-chain/blockchain/execution_engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,12 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *notifyForkcho

r, err := s.cfg.ForkChoiceStore.Head(ctx, s.justifiedBalances.balances)
if err != nil {
log.WithError(err).Error("Could not get head root")
return nil, nil
log.WithFields(logrus.Fields{
"slot": headBlk.Slot(),
"blockRoot": fmt.Sprintf("%#x", bytesutil.Trunc(headRoot[:])),
"invalidCount": len(invalidRoots),
}).Warn("Pruned invalid blocks, could not update head root")
return nil, invalidBlock{error: ErrInvalidPayload, root: arg.headRoot, invalidAncestorRoots: invalidRoots}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this will log here the pruned blocks, this is a code smell for a few reasons:

  1. It repeats the log below, it can be done by having two different log messages the only difference between this one and the one below in the regular pruning on invalid blocks is that the one below contains the new head root (that we failed to compute here). I didn't care much about the repetition because this code should not really happen in runtime unless some pretty extreme situation.
  2. This is a fairly sensitive change. On the one hand it fixes a bad bug: we were returning nil, allowing onBlock to succeed without any error when our head was INVALID! on the other hand it changes the return path of a recursive function, care must be taken by reviewers in all possible paths here.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Here's what is bothering me a little bit. We are returning nil for every err != nil under ErrInvalidPayloadStatus. Should we change most of them to invalidBlock{error: ErrInvalidPayload, root: arg.headRoot, invalidAncestorRoots: invalidRoots}? Ok to do this in another PR

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It bothers me too, but we used to return errors on everything and it was bad rendering the node locked with minor things. I feel this situation shouldn't happen often so it's kinda safe to put it here, I haven't thought deeply on the other errors here.

Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a reason we only add the invalid block error here ?

invalidBlock{error: ErrInvalidPayload, root: arg.headRoot, invalidAncestorRoots: invalidRoots}

In this whole conditional branch, this is the only location where we return the error.

}
b, err := s.getBlock(ctx, r)
if err != nil {
Expand Down
Loading