Validate beacon block in pending queue (#7847)

This commit is contained in:
terence tsao
2020-11-17 13:50:51 -08:00
committed by GitHub
parent 1a72733c53
commit 925fba0570
3 changed files with 56 additions and 39 deletions

View File

@@ -125,12 +125,21 @@ func (s *Service) processPendingBlocks(ctx context.Context) error {
span.End()
continue
}
if err := s.validateBeaconBlock(ctx, b, blkRoot); err != nil {
log.Debugf("Could not validate block from slot %d: %v", b.Block.Slot, err)
s.setBadBlock(ctx, blkRoot)
traceutil.AnnotateError(span, err)
}
if err := s.chain.ReceiveBlock(ctx, b, blkRoot); err != nil {
log.Debugf("Could not process block from slot %d: %v", b.Block.Slot, err)
s.setBadBlock(ctx, blkRoot)
traceutil.AnnotateError(span, err)
}
s.setSeenBlockIndexSlot(b.Block.Slot, b.Block.ProposerIndex)
// Broadcasting the block again once a node is able to process it.
if err := s.p2p.Broadcast(ctx, b); err != nil {
log.WithError(err).Debug("Failed to broadcast block")

View File

@@ -28,7 +28,7 @@ import (
// \- b3
// Test b1 was missing then received and we can process b0 -> b1 -> b2
func TestRegularSyncBeaconBlockSubscriber_ProcessPendingBlocks1(t *testing.T) {
db, _ := dbtest.SetupDB(t)
db, stateSummaryCache := dbtest.SetupDB(t)
p1 := p2ptest.NewTestP2P(t)
r := &Service{
@@ -41,6 +41,7 @@ func TestRegularSyncBeaconBlockSubscriber_ProcessPendingBlocks1(t *testing.T) {
},
slotToPendingBlocks: make(map[uint64][]*ethpb.SignedBeaconBlock),
seenPendingBlocks: make(map[[32]byte]bool),
stateSummaryCache: stateSummaryCache,
}
err := r.initCaches()
require.NoError(t, err)
@@ -134,7 +135,7 @@ func TestRegularSync_InsertDuplicateBlocks(t *testing.T) {
// \- b3 - b4
// Test b2 and b3 were missed, after receiving them we can process 2 chains.
func TestRegularSyncBeaconBlockSubscriber_ProcessPendingBlocks_2Chains(t *testing.T) {
db, _ := dbtest.SetupDB(t)
db, stateSummaryCache := dbtest.SetupDB(t)
p1 := p2ptest.NewTestP2P(t)
p2 := p2ptest.NewTestP2P(t)
p1.Connect(p2)
@@ -166,6 +167,7 @@ func TestRegularSyncBeaconBlockSubscriber_ProcessPendingBlocks_2Chains(t *testin
},
slotToPendingBlocks: make(map[uint64][]*ethpb.SignedBeaconBlock),
seenPendingBlocks: make(map[[32]byte]bool),
stateSummaryCache: stateSummaryCache,
}
err := r.initCaches()
require.NoError(t, err)

View File

@@ -2,6 +2,7 @@ package sync
import (
"context"
"errors"
"time"
"github.com/libp2p/go-libp2p-core/peer"
@@ -118,43 +119,8 @@ func (s *Service) validateBeaconBlockPubSub(ctx context.Context, pid peer.ID, ms
return pubsub.ValidationIgnore
}
if err := s.chain.VerifyBlkDescendant(ctx, bytesutil.ToBytes32(blk.Block.ParentRoot)); err != nil {
log.WithError(err).Warn("Rejecting block")
s.setBadBlock(ctx, blockRoot)
return pubsub.ValidationReject
}
hasStateSummaryDB := s.db.HasStateSummary(ctx, bytesutil.ToBytes32(blk.Block.ParentRoot))
hasStateSummaryCache := s.stateSummaryCache.Has(bytesutil.ToBytes32(blk.Block.ParentRoot))
if !hasStateSummaryDB && !hasStateSummaryCache {
log.WithError(err).WithField("blockSlot", blk.Block.Slot).Warn("No access to parent state")
return pubsub.ValidationIgnore
}
parentState, err := s.stateGen.StateByRoot(ctx, bytesutil.ToBytes32(blk.Block.ParentRoot))
if err != nil {
log.WithError(err).WithField("blockSlot", blk.Block.Slot).Warn("Could not get parent state")
return pubsub.ValidationIgnore
}
if err := blocks.VerifyBlockSignature(parentState, blk); err != nil {
log.WithError(err).WithField("blockSlot", blk.Block.Slot).Warn("Could not verify block signature")
s.setBadBlock(ctx, blockRoot)
return pubsub.ValidationReject
}
parentState, err = state.ProcessSlots(ctx, parentState, blk.Block.Slot)
if err != nil {
log.Errorf("Could not advance slot to calculate proposer index: %v", err)
return pubsub.ValidationIgnore
}
idx, err := helpers.BeaconProposerIndex(parentState)
if err != nil {
log.WithError(err).WithField("blockSlot", blk.Block.Slot).Warn("Could not get proposer index using parent state")
return pubsub.ValidationIgnore
}
if blk.Block.ProposerIndex != idx {
log.WithError(err).WithField("blockSlot", blk.Block.Slot).Warn("Incorrect proposer index")
s.setBadBlock(ctx, blockRoot)
if err := s.validateBeaconBlock(ctx, blk, blockRoot); err != nil {
log.WithError(err).WithField("blockSlot", blk.Block.Slot).Warn("Could not validate beacon block")
return pubsub.ValidationReject
}
@@ -162,6 +128,46 @@ func (s *Service) validateBeaconBlockPubSub(ctx context.Context, pid peer.ID, ms
return pubsub.ValidationAccept
}
func (s *Service) validateBeaconBlock(ctx context.Context, blk *ethpb.SignedBeaconBlock, blockRoot [32]byte) error {
ctx, span := trace.StartSpan(ctx, "sync.validateBeaconBlock")
defer span.End()
if err := s.chain.VerifyBlkDescendant(ctx, bytesutil.ToBytes32(blk.Block.ParentRoot)); err != nil {
s.setBadBlock(ctx, blockRoot)
return err
}
hasStateSummaryDB := s.db.HasStateSummary(ctx, bytesutil.ToBytes32(blk.Block.ParentRoot))
hasStateSummaryCache := s.stateSummaryCache.Has(bytesutil.ToBytes32(blk.Block.ParentRoot))
if !hasStateSummaryDB && !hasStateSummaryCache {
return errors.New("no access to parent state")
}
parentState, err := s.stateGen.StateByRoot(ctx, bytesutil.ToBytes32(blk.Block.ParentRoot))
if err != nil {
return err
}
if err := blocks.VerifyBlockSignature(parentState, blk); err != nil {
s.setBadBlock(ctx, blockRoot)
return err
}
parentState, err = state.ProcessSlots(ctx, parentState, blk.Block.Slot)
if err != nil {
return err
}
idx, err := helpers.BeaconProposerIndex(parentState)
if err != nil {
return err
}
if blk.Block.ProposerIndex != idx {
s.setBadBlock(ctx, blockRoot)
return errors.New("incorrect proposer index")
}
return nil
}
// Returns true if the block is not the first block proposed for the proposer for the slot.
func (s *Service) hasSeenBlockIndexSlot(slot, proposerIdx uint64) bool {
s.seenBlockLock.RLock()