status-go/geth/node/syncpoll.go

82 lines
1.9 KiB
Go

package node
import (
"context"
"errors"
"time"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/les"
"github.com/status-im/status-go/geth/log"
)
// errors
var (
ErrStartAborted = errors.New("node synchronization timeout before starting")
ErrSyncAborted = errors.New("node synchronization timeout before completion")
)
// SyncPoll provides a structure that allows us to check the status of
// ethereum node synchronization.
type SyncPoll struct {
downloader *downloader.Downloader
}
// NewSyncPoll returns a new instance of SyncPoll.
func NewSyncPoll(leth *les.LightEthereum) *SyncPoll {
return &SyncPoll{
downloader: leth.Downloader(),
}
}
// Poll checks for the status of blockchain synchronization and returns an error
// if the blockchain failed to start synchronizing or fails to complete, within
// the time provided by the passed in context.
func (n *SyncPoll) Poll(ctx context.Context) error {
if err := n.pollSyncStart(ctx); err != nil {
return err
}
if err := n.waitSyncCompleted(ctx); err != nil {
return err
}
return nil
}
func (n *SyncPoll) pollSyncStart(ctx context.Context) error {
for {
select {
case <-ctx.Done():
return ErrStartAborted
case <-time.After(100 * time.Millisecond):
if n.downloader.Synchronising() {
log.Info("Block synchronization progress just started")
return nil
}
}
}
}
func (n *SyncPoll) waitSyncCompleted(ctx context.Context) error {
for {
select {
case <-ctx.Done():
return ErrSyncAborted
case <-time.After(100 * time.Millisecond):
progress := n.downloader.Progress()
// If information on highest block has not being retrieved then wait.
if progress.HighestBlock <= 0 && progress.StartingBlock <= 0 {
time.Sleep(300 * time.Millisecond)
continue
}
if progress.CurrentBlock >= progress.HighestBlock {
log.Info("Block synchronization just finished")
return nil
}
}
}
}