Files
prysm/beacon-chain/sync/pending_blocks_queue.go
terence tsao cf2ad1f21c Parent blocks fetching/processing (#3459)
* first version of the watchtower api

* Initial prototype of sync parent fetching/processing

* Another map to track seen block root

* Fixed fmt

* Ready to live test

* Ready to live test

* Seperate pending block queue into its own

* first version

* delete watchtower

* move to message loop

* roughtime

* one time

* fix test

* Started testing but peer list empty

* Comment

* Loggins

* Stuck at decoding non proto type

* Revert

* First take, need feedback

* Run time panics at hello

* Revert

* use reflect properly

* Fixed subscriber

* instantiate helper

* More reverts

* Revert back tests

* Cont when EOF

* Working

* Clean hello tracker on peer disconnection

* Clean hello tracker on peer disconnection

* Move to validation

* Propoer locking

* Propoer locking

* Fmt

* Nishant's feedbacke

* More feedback

* All tests passing

* fix build

* remove log

* gaz

* Added the todo
2019-09-20 10:08:32 -07:00

106 lines
2.7 KiB
Go

package sync
import (
"context"
"encoding/hex"
"sort"
"time"
peer "github.com/libp2p/go-libp2p-peer"
"github.com/prysmaticlabs/go-ssz"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/sirupsen/logrus"
)
var processPendingBlocksPeriod = time.Duration(params.BeaconConfig().SecondsPerSlot/3) * time.Second
// processes pending blocks queue on every processPendingBlocksPeriod
func (r *RegularSync) processPendingBlocksQueue() {
ticker := time.NewTicker(processPendingBlocksPeriod)
for {
ctx := context.TODO()
select {
case <-ticker.C:
r.processPendingBlocks(ctx)
case <-r.ctx.Done():
log.Debug("p2p context is closed, exiting routine")
break
}
}
}
// processes the block tree inside the queue
func (r *RegularSync) processPendingBlocks(ctx context.Context) error {
pids := r.peerIDs()
slots := r.sortedPendingSlots()
for _, s := range slots {
r.pendingQueueLock.RLock()
b := r.slotToPendingBlocks[uint64(s)]
inPendingQueue := r.seenPendingBlocks[bytesutil.ToBytes32(b.ParentRoot)]
r.pendingQueueLock.RUnlock()
inDB := r.db.HasBlock(ctx, bytesutil.ToBytes32(b.ParentRoot))
hasPeer := len(pids) != 0
// Only request for missing parent block if it's not in DB, not in pending cache
// and has peer in the peer list.
if !inPendingQueue && !inDB && hasPeer {
log.WithFields(logrus.Fields{
"currentSlot": b.Slot,
"parentRoot": hex.EncodeToString(b.ParentRoot),
}).Info("Requesting parent block")
req := [][32]byte{bytesutil.ToBytes32(b.ParentRoot)}
// TODO(3450): Use round robin sync API to rotate peers for sending recent block request
if err := r.sendRecentBeaconBlocksRequest(ctx, req, pids[0]); err != nil {
log.Errorf("Could not send recent block request: %v", err)
}
continue
}
if !inDB {
continue
}
if err := r.chain.ReceiveBlockNoPubsub(ctx, b); err != nil {
log.Errorf("Could not process block from slot %d: %v", b.Slot, err)
}
r.pendingQueueLock.Lock()
delete(r.slotToPendingBlocks, uint64(s))
blkRoot, err := ssz.SigningRoot(b)
if err != nil {
return err
}
delete(r.seenPendingBlocks, blkRoot)
r.pendingQueueLock.Unlock()
log.Infof("Processed ancestor block %d and cleared pending block cache", s)
}
return nil
}
func (r *RegularSync) peerIDs() []peer.ID {
hellos := r.PeerStatuses()
pids := make([]peer.ID, 0, len(hellos))
for pid := range hellos {
pids = append(pids, pid)
}
return pids
}
func (r *RegularSync) sortedPendingSlots() []int {
r.pendingQueueLock.RLock()
defer r.pendingQueueLock.RUnlock()
slots := make([]int, 0, len(r.slotToPendingBlocks))
for s := range r.slotToPendingBlocks {
slots = append(slots, int(s))
}
sort.Ints(slots)
return slots
}