QSP-45 Add Check for No Connected Peers BestFinalized (#6402)

* no error returned
* no target root
* fix build
* Merge refs/heads/master into best-finalized
This commit is contained in:
Raul Jordan 2020-06-26 11:35:12 -05:00 committed by GitHub
parent 252f758baa
commit ab89053597
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 20 additions and 30 deletions

View File

@ -9,7 +9,6 @@ go_library(
deps = [
"//beacon-chain/core/helpers:go_default_library",
"//proto/beacon/p2p/v1:go_default_library",
"//shared/bytesutil:go_default_library",
"//shared/roughtime:go_default_library",
"@com_github_ethereum_go_ethereum//p2p/enr:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",

View File

@ -34,7 +34,6 @@ import (
"github.com/prysmaticlabs/go-bitfield"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/roughtime"
)
@ -427,33 +426,29 @@ func (p *Status) Decay() {
// Ideally, all peers would be reporting the same finalized epoch but some may be behind due to their own latency, or because of
// their finalized epoch at the time we queried them.
// Returns the best finalized root, epoch number, and list of peers that are at or beyond that epoch.
func (p *Status) BestFinalized(maxPeers int, ourFinalizedEpoch uint64) ([]byte, uint64, []peer.ID) {
func (p *Status) BestFinalized(maxPeers int, ourFinalizedEpoch uint64) (uint64, []peer.ID) {
connected := p.Connected()
finalized := make(map[[32]byte]uint64)
rootToEpoch := make(map[[32]byte]uint64)
finalizedEpochVotes := make(map[uint64]uint64)
pidEpoch := make(map[peer.ID]uint64)
potentialPIDs := make([]peer.ID, 0, len(connected))
for _, pid := range connected {
peerChainState, err := p.ChainState(pid)
if err == nil && peerChainState != nil && peerChainState.FinalizedEpoch >= ourFinalizedEpoch {
root := bytesutil.ToBytes32(peerChainState.FinalizedRoot)
finalized[root]++
rootToEpoch[root] = peerChainState.FinalizedEpoch
finalizedEpochVotes[peerChainState.FinalizedEpoch]++
pidEpoch[pid] = peerChainState.FinalizedEpoch
potentialPIDs = append(potentialPIDs, pid)
}
}
// Select the target epoch, which is the epoch most peers agree upon.
var targetRoot [32]byte
var targetEpoch uint64
var mostVotes uint64
for root, count := range finalized {
for epoch, count := range finalizedEpochVotes {
if count > mostVotes {
mostVotes = count
targetRoot = root
targetEpoch = epoch
}
}
targetEpoch := rootToEpoch[targetRoot]
// Sort PIDs by finalized epoch, in decreasing order.
sort.Slice(potentialPIDs, func(i, j int) bool {
@ -473,7 +468,7 @@ func (p *Status) BestFinalized(maxPeers int, ourFinalizedEpoch uint64) ([]byte,
potentialPIDs = potentialPIDs[:maxPeers]
}
return targetRoot[:], targetEpoch, potentialPIDs
return targetEpoch, potentialPIDs
}
// fetch is a helper function that fetches a peer status, possibly creating it.

View File

@ -1,7 +1,6 @@
package peers_test
import (
"bytes"
"crypto/rand"
"fmt"
"reflect"
@ -12,6 +11,7 @@ import (
peer "github.com/libp2p/go-libp2p-peer"
ma "github.com/multiformats/go-multiaddr"
"github.com/prysmaticlabs/go-bitfield"
"github.com/prysmaticlabs/prysm/beacon-chain/p2p/peers"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/params"
@ -561,7 +561,7 @@ func TestTrimmedOrderedPeers(t *testing.T) {
FinalizedRoot: mockroot2[:],
})
_, target, pids := p.BestFinalized(maxPeers, 0)
target, pids := p.BestFinalized(maxPeers, 0)
if target != expectedTarget {
t.Errorf("Incorrect target epoch retrieved; wanted %v but got %v", expectedTarget, target)
}
@ -624,10 +624,7 @@ func TestBestPeer(t *testing.T) {
FinalizedEpoch: 3,
FinalizedRoot: junkRoot[:],
})
retRoot, retEpoch, _ := p.BestFinalized(15, 0)
if !bytes.Equal(retRoot, expectedRoot[:]) {
t.Errorf("Incorrect Finalized Root retrieved; wanted %v but got %v", expectedRoot, retRoot)
}
retEpoch, _ := p.BestFinalized(15, 0)
if retEpoch != expectedFinEpoch {
t.Errorf("Incorrect Finalized epoch retrieved; wanted %v but got %v", expectedFinEpoch, retEpoch)
}
@ -646,7 +643,7 @@ func TestBestFinalized_returnsMaxValue(t *testing.T) {
})
}
_, _, pids := p.BestFinalized(maxPeers, 0)
_, pids := p.BestFinalized(maxPeers, 0)
if len(pids) != maxPeers {
t.Fatalf("returned wrong number of peers, wanted %d, got %d", maxPeers, len(pids))
}

View File

@ -233,8 +233,7 @@ func (f *blocksFetcher) handleRequest(ctx context.Context, start, count uint64)
}
headEpoch := helpers.SlotToEpoch(f.headFetcher.HeadSlot())
_, finalizedEpoch, peers := f.p2p.Peers().BestFinalized(params.BeaconConfig().MaxPeersToSync, headEpoch)
finalizedEpoch, peers := f.p2p.Peers().BestFinalized(params.BeaconConfig().MaxPeersToSync, headEpoch)
if len(peers) == 0 {
response.err = errNoPeersAvailable
return response
@ -401,7 +400,7 @@ func (f *blocksFetcher) waitForMinimumPeers(ctx context.Context) ([]peer.ID, err
return nil, ctx.Err()
}
headEpoch := helpers.SlotToEpoch(f.headFetcher.HeadSlot())
_, _, peers := f.p2p.Peers().BestFinalized(params.BeaconConfig().MaxPeersToSync, headEpoch)
_, peers := f.p2p.Peers().BestFinalized(params.BeaconConfig().MaxPeersToSync, headEpoch)
if len(peers) >= required {
return peers, nil
}
@ -459,7 +458,7 @@ func (f *blocksFetcher) nonSkippedSlotAfter(ctx context.Context, slot uint64) (u
defer span.End()
headEpoch := helpers.SlotToEpoch(f.headFetcher.HeadSlot())
_, epoch, peers := f.p2p.Peers().BestFinalized(params.BeaconConfig().MaxPeersToSync, headEpoch)
epoch, peers := f.p2p.Peers().BestFinalized(params.BeaconConfig().MaxPeersToSync, headEpoch)
var err error
peers, err = f.filterPeers(peers, peersPercentagePerRequest)
if err != nil {
@ -541,6 +540,6 @@ func (f *blocksFetcher) nonSkippedSlotAfter(ctx context.Context, slot uint64) (u
// bestFinalizedSlot returns the highest finalized slot of the majority of connected peers.
func (f *blocksFetcher) bestFinalizedSlot() uint64 {
headEpoch := helpers.SlotToEpoch(f.headFetcher.HeadSlot())
_, finalizedEpoch, _ := f.p2p.Peers().BestFinalized(params.BeaconConfig().MaxPeersToSync, headEpoch)
finalizedEpoch, _ := f.p2p.Peers().BestFinalized(params.BeaconConfig().MaxPeersToSync, headEpoch)
return helpers.StartSlot(finalizedEpoch)
}

View File

@ -503,7 +503,7 @@ func TestBlocksFetcher_requestBeaconBlocksByRange(t *testing.T) {
p2p: p2p,
})
_, _, peers := p2p.Peers().BestFinalized(params.BeaconConfig().MaxPeersToSync, helpers.SlotToEpoch(mc.HeadSlot()))
_, peers := p2p.Peers().BestFinalized(params.BeaconConfig().MaxPeersToSync, helpers.SlotToEpoch(mc.HeadSlot()))
req := &p2ppb.BeaconBlocksByRangeRequest{
StartSlot: 1,
Step: 1,

View File

@ -84,11 +84,11 @@ func (s *Service) roundRobinSync(genesis time.Time) error {
p2p: s.p2p,
headFetcher: s.chain,
})
_, _, pids := s.p2p.Peers().BestFinalized(1 /* maxPeers */, s.highestFinalizedEpoch())
_, pids := s.p2p.Peers().BestFinalized(1 /* maxPeers */, s.highestFinalizedEpoch())
for len(pids) == 0 {
log.Info("Waiting for a suitable peer before syncing to the head of the chain")
time.Sleep(refreshTime)
_, _, pids = s.p2p.Peers().BestFinalized(1 /* maxPeers */, s.highestFinalizedEpoch())
_, pids = s.p2p.Peers().BestFinalized(1 /* maxPeers */, s.highestFinalizedEpoch())
}
best := pids[0]

View File

@ -214,7 +214,7 @@ func (s *Service) waitForMinimumPeers() {
required = flags.Get().MinimumSyncPeers
}
for {
_, _, peers := s.p2p.Peers().BestFinalized(params.BeaconConfig().MaxPeersToSync, s.chain.FinalizedCheckpt().Epoch)
_, peers := s.p2p.Peers().BestFinalized(params.BeaconConfig().MaxPeersToSync, s.chain.FinalizedCheckpt().Epoch)
if len(peers) >= required {
break
}

View File

@ -71,7 +71,7 @@ func (s *Service) resyncIfBehind() {
runutil.RunEvery(s.ctx, interval, func() {
if s.shouldReSync() {
syncedEpoch := helpers.SlotToEpoch(s.chain.HeadSlot())
_, highestEpoch, _ := s.p2p.Peers().BestFinalized(params.BeaconConfig().MaxPeersToSync, syncedEpoch)
highestEpoch, _ := s.p2p.Peers().BestFinalized(params.BeaconConfig().MaxPeersToSync, syncedEpoch)
if helpers.StartSlot(highestEpoch) > s.chain.HeadSlot() {
log.WithFields(logrus.Fields{
"currentEpoch": helpers.SlotToEpoch(s.chain.CurrentSlot()),