func New(
	ctx context.Context,
	network *types.NetworkIdentifier,
	fetcher *fetcher.Fetcher,
	blockStorage *modules.BlockStorage,
	counterStorage *modules.CounterStorage,
	logger Logger,
	cancel context.CancelFunc,
	workers []modules.BlockWorker,
	options ...Option,
) *StatefulSyncer {
	s := &StatefulSyncer{
		network:        network,
		fetcher:        fetcher,
		cancel:         cancel,
		blockStorage:   blockStorage,
		counterStorage: counterStorage,
		workers:        workers,
		logger:         logger,
		cacheSize:         syncer.DefaultCacheSize,
		maxConcurrency:    syncer.DefaultMaxConcurrency,
		pastBlockLimit:    syncer.DefaultPastBlockLimit,
		adjustmentWindow:  syncer.DefaultAdjustmentWindow,
		pruneSleepTime:    DefaultPruneSleepTime,
		seenSemaphoreSize: int64(runtime.NumCPU()),
	}
	for _, opt := range options {
		opt(s)
	}
	s.seenSemaphore = semaphore.NewWeighted(s.seenSemaphoreSize)
	return s
}
New returns a new *StatefulSyncer.
package statefulsyncer
import (
	"context"
	"errors"
	"fmt"
	"log"
	"runtime"
	"time"
	"golang.org/x/sync/semaphore"
	"github.com/coinbase/rosetta-sdk-go/fetcher"
	storageErrs "github.com/coinbase/rosetta-sdk-go/storage/errors"
	"github.com/coinbase/rosetta-sdk-go/storage/modules"
	"github.com/coinbase/rosetta-sdk-go/syncer"
	"github.com/coinbase/rosetta-sdk-go/types"
	"github.com/coinbase/rosetta-sdk-go/utils"
)
var _ syncer.Handler = (*StatefulSyncer)(nil)
var _ syncer.Helper = (*StatefulSyncer)(nil)
const (
	DefaultPruneSleepTime = 10 * time.Minute
	pruneBuffer = 2
	semaphoreWeight = int64(1)
)
type StatefulSyncer struct {
	network        *types.NetworkIdentifier
	fetcher        *fetcher.Fetcher
	cancel         context.CancelFunc
	blockStorage   *modules.BlockStorage
	counterStorage *modules.CounterStorage
	logger         Logger
	workers        []modules.BlockWorker
	cacheSize        int
	maxConcurrency   int64
	pastBlockLimit   int
	adjustmentWindow int64
	pruneSleepTime   time.Duration
	seenSemaphore     *semaphore.Weighted
	seenSemaphoreSize int64
}
type Logger interface {
	AddBlockStream(context.Context, *types.Block) error
	RemoveBlockStream(context.Context, *types.BlockIdentifier) error
}
type PruneHelper interface {
	PruneableIndex(ctx context.Context, headIndex int64) (int64, error)
}