erigon-pulse/cl/phase1/network/backward_beacon_downloader.go
a cda14447ad
[caplin] pkg refactor (#7507)
Co-authored-by: Giulio <giulio.rebuffo@gmail.com>
2023-05-13 23:44:07 +02:00

119 lines
3.5 KiB
Go

package network
import (
"sync"
libcommon "github.com/ledgerwatch/erigon-lib/common"
"github.com/ledgerwatch/log/v3"
"golang.org/x/net/context"
"github.com/ledgerwatch/erigon/cl/cltypes"
"github.com/ledgerwatch/erigon/cl/rpc"
)
// Whether the reverse downloader arrived at expected height or condition.
type OnNewBlock func(blk *cltypes.SignedBeaconBlock) (finished bool, err error)
type BackwardBeaconDownloader struct {
ctx context.Context
slotToDownload uint64
expectedRoot libcommon.Hash
rpc *rpc.BeaconRpcP2P
onNewBlock OnNewBlock
finished bool
mu sync.Mutex
}
func NewBackwardBeaconDownloader(ctx context.Context, rpc *rpc.BeaconRpcP2P) *BackwardBeaconDownloader {
return &BackwardBeaconDownloader{
ctx: ctx,
rpc: rpc,
}
}
// SetSlotToDownload sets slot to download.
func (b *BackwardBeaconDownloader) SetSlotToDownload(slot uint64) {
b.mu.Lock()
defer b.mu.Unlock()
b.slotToDownload = slot
}
// SetExpectedRoot sets the expected root we expect to download.
func (b *BackwardBeaconDownloader) SetExpectedRoot(root libcommon.Hash) {
b.mu.Lock()
defer b.mu.Unlock()
b.expectedRoot = root
}
// SetShouldStopAtFn sets the stop condition.
func (b *BackwardBeaconDownloader) SetOnNewBlock(onNewBlock OnNewBlock) {
b.mu.Lock()
defer b.mu.Unlock()
b.onNewBlock = onNewBlock
}
// HighestProcessedRoot returns the highest processed block root so far.
func (b *BackwardBeaconDownloader) Finished() bool {
b.mu.Lock()
defer b.mu.Unlock()
return b.finished
}
// Progress current progress.
func (b *BackwardBeaconDownloader) Progress() uint64 {
// Skip if it is not downloading or limit was reached
b.mu.Lock()
defer b.mu.Unlock()
return b.slotToDownload
}
// Peers returns the current number of peers connected to the BackwardBeaconDownloader.
func (b *BackwardBeaconDownloader) Peers() (uint64, error) {
return b.rpc.Peers()
}
// RequestMore downloads a range of blocks in a backward manner.
// The function sends a request for a range of blocks starting from a given slot and ending count blocks before it.
// It then processes the response by iterating over the blocks in reverse order and calling a provided callback function onNewBlock on each block.
// If the callback returns an error or signals that the download should be finished, the function will exit.
// If the block's root hash does not match the expected root hash, it will be rejected and the function will continue to the next block.
func (b *BackwardBeaconDownloader) RequestMore() {
count := uint64(64)
start := b.slotToDownload - count + 1
// Overflow? round to 0.
if start > b.slotToDownload {
start = 0
}
responses, _, err := b.rpc.SendBeaconBlocksByRangeReq(start, count)
if err != nil {
return
}
// Import new blocks, order is forward so reverse the whole packet
for i := len(responses) - 1; i >= 0; i-- {
if b.finished {
return
}
segment := responses[i]
// is this new block root equal to the expected root?
blockRoot, err := segment.Block.HashSSZ()
if err != nil {
log.Debug("Could not compute block root while processing packet", "err", err)
continue
}
// No? Reject.
if blockRoot != b.expectedRoot {
continue
}
// Yes? then go for the callback.
b.finished, err = b.onNewBlock(segment)
if err != nil {
log.Warn("Found error while processing packet", "err", err)
continue
}
// set expected root to the segment parent root
b.expectedRoot = segment.Block.ParentRoot
b.slotToDownload = segment.Block.Slot - 1 // update slot (might be inexact but whatever)
}
}