mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2024-12-25 21:07:18 +00:00
Tidy-up of BestFinalized (#4505)
* Tidy up BestFinalized * Ensure no more than maxPeers returned * Merge branch 'master' into bestfinalized * Merge branch 'master' into bestfinalized * Merge branch 'master' into bestfinalized * Merge branch 'master' into bestfinalized * Remove swap file * Provide potential PIDs array with capacity * Add test for trimming and ordering in BestFinalized * Merge branch 'master' into bestfinalized
This commit is contained in:
parent
888e8925ee
commit
3d24a85121
@ -21,6 +21,7 @@ package peers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -319,41 +320,56 @@ func (p *Status) Decay() {
|
|||||||
|
|
||||||
// BestFinalized returns the highest finalized epoch equal to or higher than ours that is agreed upon by the majority of peers.
|
// BestFinalized returns the highest finalized epoch equal to or higher than ours that is agreed upon by the majority of peers.
|
||||||
// This method may not return the absolute highest finalized, but the finalized epoch in which most peers can serve blocks.
|
// This method may not return the absolute highest finalized, but the finalized epoch in which most peers can serve blocks.
|
||||||
// Ideally, all peers would be reporting the same finalized epoch.
|
// Ideally, all peers would be reporting the same finalized epoch but some may be behind due to their own latency, or because of
|
||||||
// Returns the best finalized root, epoch number, and list of peers that agree.
|
// 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) ([]byte, uint64, []peer.ID) {
|
||||||
|
connected := p.Connected()
|
||||||
finalized := make(map[[32]byte]uint64)
|
finalized := make(map[[32]byte]uint64)
|
||||||
rootToEpoch := make(map[[32]byte]uint64)
|
rootToEpoch := make(map[[32]byte]uint64)
|
||||||
for _, pid := range p.Connected() {
|
pidEpochs := make(map[peer.ID]uint64)
|
||||||
|
potentialPIDs := make([]peer.ID, 0, len(connected))
|
||||||
|
for _, pid := range connected {
|
||||||
peerChainState, err := p.ChainState(pid)
|
peerChainState, err := p.ChainState(pid)
|
||||||
if err == nil && peerChainState != nil && peerChainState.FinalizedEpoch >= ourFinalizedEpoch {
|
if err == nil && peerChainState != nil && peerChainState.FinalizedEpoch >= ourFinalizedEpoch {
|
||||||
r := bytesutil.ToBytes32(peerChainState.FinalizedRoot)
|
root := bytesutil.ToBytes32(peerChainState.FinalizedRoot)
|
||||||
finalized[r]++
|
finalized[root]++
|
||||||
rootToEpoch[r] = peerChainState.FinalizedEpoch
|
rootToEpoch[root] = peerChainState.FinalizedEpoch
|
||||||
|
pidEpochs[pid] = peerChainState.FinalizedEpoch
|
||||||
|
potentialPIDs = append(potentialPIDs, pid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var mostVotedFinalizedRoot [32]byte
|
// Select the target epoch, which is the epoch most peers agree upon.
|
||||||
|
var targetRoot [32]byte
|
||||||
var mostVotes uint64
|
var mostVotes uint64
|
||||||
for root, count := range finalized {
|
for root, count := range finalized {
|
||||||
if count > mostVotes {
|
if count > mostVotes {
|
||||||
mostVotes = count
|
mostVotes = count
|
||||||
mostVotedFinalizedRoot = root
|
targetRoot = root
|
||||||
|
}
|
||||||
|
}
|
||||||
|
targetEpoch := rootToEpoch[targetRoot]
|
||||||
|
|
||||||
|
// Sort PIDs by finalized epoch, in decreasing order.
|
||||||
|
sort.Slice(potentialPIDs, func(i, j int) bool {
|
||||||
|
return pidEpochs[potentialPIDs[i]] > pidEpochs[potentialPIDs[j]]
|
||||||
|
})
|
||||||
|
|
||||||
|
// Trim potential peers to those on or after target epoch.
|
||||||
|
for i, pid := range potentialPIDs {
|
||||||
|
if pidEpochs[pid] < targetEpoch {
|
||||||
|
potentialPIDs = potentialPIDs[:i]
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var pids []peer.ID
|
// Trim potential peers to at most maxPeers.
|
||||||
for _, pid := range p.Connected() {
|
if len(potentialPIDs) > maxPeers {
|
||||||
peerChainState, err := p.ChainState(pid)
|
potentialPIDs = potentialPIDs[:maxPeers]
|
||||||
if err == nil && peerChainState != nil && peerChainState.FinalizedEpoch >= rootToEpoch[mostVotedFinalizedRoot] {
|
|
||||||
pids = append(pids, pid)
|
|
||||||
if len(pids) >= maxPeers {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return mostVotedFinalizedRoot[:], rootToEpoch[mostVotedFinalizedRoot], pids
|
return targetRoot[:], targetEpoch, potentialPIDs
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetch is a helper function that fetches a peer status, possibly creating it.
|
// fetch is a helper function that fetches a peer status, possibly creating it.
|
||||||
|
@ -335,6 +335,58 @@ func TestDecay(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTrimmedOrderedPeers(t *testing.T) {
|
||||||
|
p := peers.NewStatus(1)
|
||||||
|
|
||||||
|
expectedTarget := uint64(2)
|
||||||
|
maxPeers := 3
|
||||||
|
|
||||||
|
// Peer 1
|
||||||
|
pid1 := addPeer(t, p, peers.PeerConnected)
|
||||||
|
p.SetChainState(pid1, &pb.Status{
|
||||||
|
FinalizedEpoch: 3,
|
||||||
|
})
|
||||||
|
// Peer 2
|
||||||
|
pid2 := addPeer(t, p, peers.PeerConnected)
|
||||||
|
p.SetChainState(pid2, &pb.Status{
|
||||||
|
FinalizedEpoch: 4,
|
||||||
|
})
|
||||||
|
// Peer 3
|
||||||
|
pid3 := addPeer(t, p, peers.PeerConnected)
|
||||||
|
p.SetChainState(pid3, &pb.Status{
|
||||||
|
FinalizedEpoch: 5,
|
||||||
|
})
|
||||||
|
// Peer 4
|
||||||
|
pid4 := addPeer(t, p, peers.PeerConnected)
|
||||||
|
p.SetChainState(pid4, &pb.Status{
|
||||||
|
FinalizedEpoch: 2,
|
||||||
|
})
|
||||||
|
// Peer 5
|
||||||
|
pid5 := addPeer(t, p, peers.PeerConnected)
|
||||||
|
p.SetChainState(pid5, &pb.Status{
|
||||||
|
FinalizedEpoch: 2,
|
||||||
|
})
|
||||||
|
|
||||||
|
_, target, pids := p.BestFinalized(maxPeers, 0)
|
||||||
|
if target != expectedTarget {
|
||||||
|
t.Errorf("Incorrect target epoch retrieved; wanted %v but got %v", expectedTarget, target)
|
||||||
|
}
|
||||||
|
if len(pids) != maxPeers {
|
||||||
|
t.Errorf("Incorrect number of peers retrieved; wanted %v but got %v", maxPeers, len(pids))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expect the returned list to be ordered by finalized epoch and trimmed to max peers.
|
||||||
|
if pids[0] != pid3 {
|
||||||
|
t.Errorf("Incorrect first peer; wanted %v but got %v", pid3, pids[0])
|
||||||
|
}
|
||||||
|
if pids[1] != pid2 {
|
||||||
|
t.Errorf("Incorrect second peer; wanted %v but got %v", pid2, pids[1])
|
||||||
|
}
|
||||||
|
if pids[2] != pid1 {
|
||||||
|
t.Errorf("Incorrect third peer; wanted %v but got %v", pid1, pids[2])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestBestPeer(t *testing.T) {
|
func TestBestPeer(t *testing.T) {
|
||||||
maxBadResponses := 2
|
maxBadResponses := 2
|
||||||
expectedFinEpoch := uint64(4)
|
expectedFinEpoch := uint64(4)
|
||||||
|
Loading…
Reference in New Issue
Block a user