func (listener *listener) syncBlockRange(start, end *big.Int) error {
	for curr := new(big.Int).Set(start); curr.Cmp(end) <= 0; curr.Add(curr, utils.Big1) {
		h, err := listener.cc.Eth.HeaderByNumber(listener.ctx, curr)
		if err != nil {
			return err
		}
		if err = listener.writeHeader(h); err != nil {
			return err
		}
	}
	return nil
}
syncBlockRange will fetch & write all blocks in range [start,end] inclusive
package monitor
import (
	"context"
	"math/big"
	"sync"
	"github.com/celo-org/celo-blockchain/core/types"
	"github.com/celo-org/celo-blockchain/log"
	"github.com/celo-org/celo-blockchain/rpc"
	"github.com/celo-org/kliento/client"
	"github.com/celo-org/rosetta/internal/utils"
)
type listener struct {
	ctx     context.Context
	headers chan<- *types.Header
	cc      *client.CeloClient
	logger  log.Logger
}
const (
	maxAllowedGap = 50
)
func HeaderListener(ctx context.Context, headers chan<- *types.Header, cc *client.CeloClient, logger log.Logger, startBlock *big.Int) error {
	listener := &listener{
		logger:  logger.New("pipe", "header_listener"),
		ctx:     ctx,
		cc:      cc,
		headers: headers,
	}
	var nextBlock *big.Int = startBlock
	var err error
	for {
		nextBlock, err = listener.syncOldBlocks(nextBlock)
		if err != nil {
			return err
		}
		nextBlock, err = listener.syncNewBlocks(nextBlock)
		if err != nil {
			return err
		}
	}
}
func (listener *listener) syncOldBlocks(firstBlockToFetch *big.Int) (*big.Int, error) {
	maxGap := big.NewInt(maxAllowedGap)
	nextBlock := firstBlockToFetch
	lastBlockInRange, err := listener.lastNodeBlockNumber()
	if err != nil {
		return nil, err
	}
	for new(big.Int).Sub(lastBlockInRange, nextBlock).Cmp(maxGap) > 0 {
		listener.logger.Info("BatchFetchMode:Start", "start", nextBlock, "end", lastBlockInRange)
		if err = listener.syncBlockRange(nextBlock, lastBlockInRange); err != nil {
			return nil, err
		}
		listener.logger.Info("BatchFetchMode:Finish", "start", nextBlock, "end", lastBlockInRange)
		nextBlock = utils.Inc(lastBlockInRange)
		lastBlockInRange, err = listener.lastNodeBlockNumber()
		if err != nil {
			return nil, err
		}
	}
	return nextBlock, nil
}
func (listener *listener) syncNewBlocks(firstBlockToFetch *big.Int) (*big.Int, error) {
	subscriptionHeaders := make(chan *types.Header, 100)
	var closeOnce sync.Once
	defer closeOnce.Do(func() { close(subscriptionHeaders) })
	sub, err := listener.cc.Eth.SubscribeNewHead(listener.ctx, subscriptionHeaders)
	if err != nil {
		return nil, err
	}
	defer sub.Unsubscribe()
	nextHeader := func() (*types.Header, error) {
		select {
		case err := <-sub.Err():
			return nil, err
		case <-listener.ctx.Done():
			return nil, listener.ctx.Err()
		case h := <-subscriptionHeaders:
			return h, nil
		}
	}
	var lastWrittenBlock *big.Int
	write := func(h *types.Header) error {
		if err := listener.writeHeader(h); err != nil {
			return err
		}
		lastWrittenBlock = h.Number
		return nil
	}
	listener.logger.Info("SubscriptionFetchMode:Start", "start", firstBlockToFetch)
	defer func() {
		listener.logger.Info("SubscriptionFetchMode:Finish", "start", firstBlockToFetch, "end", lastWrittenBlock)
	}()
	firstSubscriptionBlock, err := nextHeader()
	if err != nil {
		return nil, err
	}
	if firstSubscriptionBlock.Number.Cmp(firstBlockToFetch) > 0 {
		endGapBlock := utils.Dec(firstSubscriptionBlock.Number)
		listener.logger.Info("Gap found: closing gap with header subscription", "from", firstBlockToFetch, "to", endGapBlock)
		if err = listener.syncBlockRange(firstBlockToFetch, endGapBlock); err != nil {
			return nil, err
		}
	}
	if err := write(firstSubscriptionBlock); err != nil {
		return nil, err
	}
	for {
		header, err := nextHeader()
		if err == rpc.ErrSubscriptionQueueOverflow {
			listener.logger.Warn("Header Subscription overflowed. Flushing remaining headers")
			closeOnce.Do(func() { close(subscriptionHeaders) })
			for h := range subscriptionHeaders {
				if nestedErr := write(h); nestedErr != nil {
					return nil, nestedErr
				}
			}
			return utils.Inc(lastWrittenBlock), nil
		}
		if err != nil {
			return nil, err
		}
		if err := write(header); err != nil {
			return nil, err
		}
	}
}