func (app *App) LoadOrCreateEdSigner() (*signing.EdSigner, error) {
	filename := filepath.Join(app.Config.SMESHING.Opts.DataDir, edKeyFileName)
	log.Info("Looking for identity file at `%v`", filename)
	data, err := ioutil.ReadFile(filename)
	if err != nil {
		if !os.IsNotExist(err) {
			return nil, fmt.Errorf("failed to read identity file: %w", err)
		}
		log.Info("Identity file not found. Creating new identity...")
		edSgn := signing.NewEdSigner()
		err := os.MkdirAll(filepath.Dir(filename), filesystem.OwnerReadWriteExec)
		if err != nil {
			return nil, fmt.Errorf("failed to create directory for identity file: %w", err)
		}
		err = ioutil.WriteFile(filename, edSgn.ToBuffer(), filesystem.OwnerReadWrite)
		if err != nil {
			return nil, fmt.Errorf("failed to write identity file: %w", err)
		}
		log.With().Info("created new identity", edSgn.PublicKey())
		return edSgn, nil
	}
	edSgn, err := signing.NewEdSignerFromBuffer(data)
	if err != nil {
		return nil, fmt.Errorf("failed to construct identity from data file: %w", err)
	}
	log.Info("Loaded existing identity; public key: %v", edSgn.PublicKey())
	return edSgn, nil
}
LoadOrCreateEdSigner either loads a previously created ed identity for the node or creates a new one if not exists.
package node
import (
	"context"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"os/signal"
	"path/filepath"
	"runtime"
	"strconv"
	"time"
	"github.com/mitchellh/mapstructure"
	"github.com/pyroscope-io/pyroscope/pkg/agent/profiler"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"github.com/spacemeshos/go-spacemesh/activation"
	"github.com/spacemeshos/go-spacemesh/api/grpcserver"
	"github.com/spacemeshos/go-spacemesh/blocks"
	cmdp "github.com/spacemeshos/go-spacemesh/cmd"
	"github.com/spacemeshos/go-spacemesh/cmd/mapstructureutil"
	"github.com/spacemeshos/go-spacemesh/common/types"
	"github.com/spacemeshos/go-spacemesh/common/util"
	cfg "github.com/spacemeshos/go-spacemesh/config"
	"github.com/spacemeshos/go-spacemesh/database"
	"github.com/spacemeshos/go-spacemesh/events"
	"github.com/spacemeshos/go-spacemesh/fetch"
	"github.com/spacemeshos/go-spacemesh/filesystem"
	"github.com/spacemeshos/go-spacemesh/hare"
	"github.com/spacemeshos/go-spacemesh/hare/eligibility"
	"github.com/spacemeshos/go-spacemesh/layerfetcher"
	"github.com/spacemeshos/go-spacemesh/layerpatrol"
	"github.com/spacemeshos/go-spacemesh/log"
	"github.com/spacemeshos/go-spacemesh/mempool"
	"github.com/spacemeshos/go-spacemesh/mesh"
	"github.com/spacemeshos/go-spacemesh/metrics"
	"github.com/spacemeshos/go-spacemesh/miner"
	"github.com/spacemeshos/go-spacemesh/p2p"
	"github.com/spacemeshos/go-spacemesh/p2p/pubsub"
	"github.com/spacemeshos/go-spacemesh/pendingtxs"
	"github.com/spacemeshos/go-spacemesh/signing"
	"github.com/spacemeshos/go-spacemesh/svm"
	"github.com/spacemeshos/go-spacemesh/svm/state"
	"github.com/spacemeshos/go-spacemesh/syncer"
	"github.com/spacemeshos/go-spacemesh/system"
	"github.com/spacemeshos/go-spacemesh/timesync"
	timeCfg "github.com/spacemeshos/go-spacemesh/timesync/config"
	"github.com/spacemeshos/go-spacemesh/timesync/peersync"
	"github.com/spacemeshos/go-spacemesh/tortoise"
	"github.com/spacemeshos/go-spacemesh/tortoisebeacon"
	"github.com/spacemeshos/go-spacemesh/tortoisebeacon/weakcoin"
	"github.com/spacemeshos/go-spacemesh/turbohare"
)
const edKeyFileName = "key.bin"
const (
	AppLogger            = "app"
	P2PLogger            = "p2p"
	PostLogger           = "post"
	StateDbLogger        = "stateDbStore"
	StateLogger          = "state"
	AtxDbStoreLogger     = "atxDbStore"
	TBeaconDbStoreLogger = "tbDbStore"
	TBeaconLogger        = "tBeacon"
	WeakCoinLogger       = "weakCoin"
	PoetDbStoreLogger    = "poetDbStore"
	StoreLogger          = "store"
	PoetDbLogger         = "poetDb"
	MeshDBLogger         = "meshDb"
	TrtlLogger           = "trtl"
	AtxDbLogger          = "atxDb"
	BlkEligibilityLogger = "blkElgValidator"
	MeshLogger           = "mesh"
	SyncLogger           = "sync"
	BlockOracle          = "blockOracle"
	HareBeaconLogger     = "hareBeacon"
	HareOracleLogger     = "hareOracle"
	HareLogger           = "hare"
	BlockBuilderLogger   = "blockBuilder"
	BlockListenerLogger  = "blockListener"
	PoetListenerLogger   = "poetListener"
	NipostBuilderLogger  = "nipostBuilder"
	AtxBuilderLogger     = "atxBuilder"
	GossipListener       = "gossipListener"
	Fetcher              = "fetcher"
	LayerFetcher         = "layerFetcher"
	TimeSyncLogger       = "timesync"
	SVMLogger            = "SVM"
)
var Cmd = &cobra.Command{
	Use:   "node",
	Short: "start node",
	Run: func(cmd *cobra.Command, args []string) {
		conf, err := LoadConfigFromFile()
		if err != nil {
			log.With().Error("can't load config file", log.Err(err))
			return
		}
		if err := cmdp.EnsureCLIFlags(cmd, conf); err != nil {
			log.With().Error("can't ensure that cli flags match config value types", log.Err(err))
			return
		}
		if conf.TestMode {
			log.JSONLog(true)
		}
		app := New(
			WithConfig(conf),
			WithLog(log.RegisterHooks(
				log.NewWithLevel("", zap.NewAtomicLevelAt(zapcore.DebugLevel)),
				events.EventHook())),
		)
		starter := func() error {
			if err := app.Initialize(); err != nil {
				log.With().Error("Failed to initialize node.", log.Err(err))
				return fmt.Errorf("init node: %w", err)
			}
			if err := app.Start(); err != nil {
				log.With().Error("Failed to start the node. See logs for details.", log.Err(err))
				return fmt.Errorf("start node: %w", err)
			}
			return nil
		}
		err = starter()
		app.Cleanup()
		if err != nil {
			os.Exit(1)
		}
	},
}
var VersionCmd = &cobra.Command{
	Use:   "version",
	Short: "Show version info",
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Print(cmdp.Version)
		if cmdp.Commit != "" {
			fmt.Printf("+%s", cmdp.Commit)
		}
		fmt.Println()
	},
}
func init() {
	cmdp.AddCommands(Cmd)
	Cmd.AddCommand(VersionCmd)
}
type Service interface {
	Start(ctx context.Context) error
	Close()
}
type HareService interface {
	Service
	GetResult(types.LayerID) ([]types.BlockID, error)
}
type TortoiseBeaconService interface {
	Service
	GetBeacon(id types.EpochID) ([]byte, error)
	HandleSerializedProposalMessage(context.Context, p2p.Peer, []byte) pubsub.ValidationResult
	HandleSerializedFirstVotingMessage(context.Context, p2p.Peer, []byte) pubsub.ValidationResult
	HandleSerializedFollowingVotingMessage(context.Context, p2p.Peer, []byte) pubsub.ValidationResult
}
type TickProvider interface {
	Subscribe() timesync.LayerTimer
	Unsubscribe(timesync.LayerTimer)
	GetCurrentLayer() types.LayerID
	StartNotifying()
	GetGenesisTime() time.Time
	LayerToTime(types.LayerID) time.Time
	Close()
	AwaitLayer(types.LayerID) chan struct{}
}
func LoadConfigFromFile() (*cfg.Config, error) {
	fileLocation := viper.GetString("config")
	vip := viper.New()
	if err := cfg.LoadConfig(fileLocation, vip); err != nil {
		log.Error(fmt.Sprintf("couldn't load config file at location: %s switching to defaults \n error: %v.",
			fileLocation, err))
	}
	conf := cfg.DefaultConfig()
	hook := mapstructure.ComposeDecodeHookFunc(
		mapstructure.StringToTimeDurationHookFunc(),
		mapstructure.StringToSliceHookFunc(","),
		mapstructureutil.BigRatDecodeFunc(),
	)
	if err := vip.Unmarshal(&conf, viper.DecodeHook(hook)); err != nil {
		log.With().Error("Failed to parse config", log.Err(err))
		return nil, fmt.Errorf("unmarshal viper: %w", err)
	}
	return &conf, nil
}
type Option func(app *App)
func WithLog(logger log.Log) Option {
	return func(app *App) {
		app.log = logger
	}
}
func WithConfig(conf *cfg.Config) Option {
	return func(app *App) {
		app.Config = conf
	}
}
func New(opts ...Option) *App {
	defaultConfig := cfg.DefaultConfig()
	app := &App{
		Config:  &defaultConfig,
		log:     log.NewNop(),
		loggers: make(map[string]*zap.AtomicLevel),
		term:    make(chan struct{}),
		started: make(chan struct{}),
	}
	for _, opt := range opts {
		opt(app)
	}
	lvl := zap.NewAtomicLevelAt(zap.InfoLevel)
	log.SetupGlobal(app.log.SetLevel(&lvl))
	return app
}
type App struct {
	*cobra.Command
	nodeID         types.NodeID
	Config         *cfg.Config
	grpcAPIService *grpcserver.Server
	jsonAPIService *grpcserver.JSONHTTPServer
	gatewaySvc     *grpcserver.GatewayService
	globalstateSvc *grpcserver.GlobalStateService
	txService      *grpcserver.TransactionService
	syncer         *syncer.Syncer
	blockListener  *blocks.BlockHandler
	state          *state.TransactionProcessor
	blockProducer  *miner.BlockBuilder
	oracle         *blocks.Oracle
	txProcessor    *state.TransactionProcessor
	mesh           *mesh.Mesh
	clock          TickProvider
	hare           HareService
	postSetupMgr   *activation.PostSetupManager
	atxBuilder     *activation.Builder
	atxDb          *activation.DB
	poetListener   *activation.PoetListener
	edSgn          *signing.EdSigner
	tortoiseBeacon TortoiseBeaconService
	closers        []interface{ Close() }
	log            log.Log
	txPool         *mempool.TxMempool
	svm            *svm.SVM
	layerFetch     *layerfetcher.Logic
	ptimesync      *peersync.Sync
	host *p2p.Host
	loggers map[string]*zap.AtomicLevel
	term    chan struct{}  
	started chan struct{}  
}
func (app *App) introduction() {
	log.Info("Welcome to Spacemesh. Spacemesh full node is starting...")
}
func (app *App) Initialize() (err error) {
	timeCfg.TimeConfigValues = app.Config.TIME
	err = filesystem.ExistOrCreate(app.Config.DataDir())
	if err != nil {
		return fmt.Errorf("ensure folders exist: %w", err)
	}
	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, os.Interrupt)
	go func() {
		for range signalChan {
			app.log.Info("Received an interrupt, stopping services...\n")
			cmdp.Cancel()
		}
	}()
	app.setupLogging()
	app.introduction()
	drift, err := timesync.CheckSystemClockDrift()
	if err != nil {
		return fmt.Errorf("check system clock drift: %w", err)
	}
	log.Info("System clock synchronized with ntp. drift: %s", drift)
	return nil
}
func (app *App) setupLogging() {
	log.Info("%s", app.getAppInfo())
	msg := "initializing event reporter"
	if app.Config.PublishEventsURL != "" {
		msg += fmt.Sprintf(" with pubsub URL: %s", app.Config.PublishEventsURL)
	}
	log.Info(msg)
	if err := events.InitializeEventReporter(app.Config.PublishEventsURL); err != nil {
		log.With().Error("unable to initialize event reporter", log.Err(err))
	}
}
func (app *App) getAppInfo() string {
	return fmt.Sprintf("App version: %s. Git: %s - %s . Go Version: %s. OS: %s-%s ",
		cmdp.Version, cmdp.Branch, cmdp.Commit, runtime.Version(), runtime.GOOS, runtime.GOARCH)
}
func (app *App) Cleanup() {
	log.Info("app cleanup starting...")
	app.stopServices()
	log.Info("app cleanup completed")
}
func (app *App) addLogger(name string, logger log.Log) log.Log {
	lvl := zap.NewAtomicLevel()
	config := app.Config.LOGGING
	level, ok := map[string]string{
		AppLogger:            config.AppLoggerLevel,
		P2PLogger:            config.P2PLoggerLevel,
		PostLogger:           config.PostLoggerLevel,
		StateDbLogger:        config.StateDbLoggerLevel,
		StateLogger:          config.StateLoggerLevel,
		AtxDbStoreLogger:     config.AtxDbStoreLoggerLevel,
		TBeaconLogger:        config.TBeaconLoggerLevel,
		WeakCoinLogger:       config.WeakCoinLoggerLevel,
		PoetDbStoreLogger:    config.PoetDbStoreLoggerLevel,
		StoreLogger:          config.StoreLoggerLevel,
		PoetDbLogger:         config.PoetDbLoggerLevel,
		MeshDBLogger:         config.MeshDBLoggerLevel,
		TrtlLogger:           config.TrtlLoggerLevel,
		AtxDbLogger:          config.AtxDbLoggerLevel,
		BlkEligibilityLogger: config.BlkEligibilityLoggerLevel,
		MeshLogger:           config.MeshLoggerLevel,
		SyncLogger:           config.SyncLoggerLevel,
		BlockOracle:          config.BlockOracleLevel,
		HareOracleLogger:     config.HareOracleLoggerLevel,
		HareBeaconLogger:     config.HareBeaconLoggerLevel,
		HareLogger:           config.HareLoggerLevel,
		BlockBuilderLogger:   config.BlockBuilderLoggerLevel,
		BlockListenerLogger:  config.BlockListenerLoggerLevel,
		PoetListenerLogger:   config.PoetListenerLoggerLevel,
		NipostBuilderLogger:  config.NipostBuilderLoggerLevel,
		AtxBuilderLogger:     config.AtxBuilderLoggerLevel,
		TimeSyncLogger:       config.TimeSyncLoggerLevel,
	}[name]
	if ok {
		if err := lvl.UnmarshalText([]byte(level)); err != nil {
			app.log.Error("cannot parse logging for %v error %v", name, err)
			lvl.SetLevel(log.Level())
		}
	} else {
		lvl.SetLevel(log.Level())
	}
	if logger.Check(lvl.Level()) {
		app.loggers[name] = &lvl
		logger = logger.SetLevel(&lvl)
	}
	return logger.WithName(name).WithFields(log.String("module", name))
}
func (app *App) SetLogLevel(name, loglevel string) error {
	lvl, ok := app.loggers[name]
	if !ok {
		return fmt.Errorf("cannot find logger %v", name)
	}
	if err := lvl.UnmarshalText([]byte(loglevel)); err != nil {
		return fmt.Errorf("unmarshal text: %w", err)
	}
	return nil
}
func (app *App) initServices(ctx context.Context,
	nodeID types.NodeID,
	dbStorepath string,
	sgn *signing.EdSigner,
	isFixedOracle bool,
	rolacle hare.Rolacle,
	layerSize uint32,
	poetClient activation.PoetProvingServiceClient,
	vrfSigner signing.Signer,
	layersPerEpoch uint32, clock TickProvider) error {
	app.nodeID = nodeID
	lg := app.log.Named(nodeID.ShortString()).WithFields(nodeID)
	types.SetLayersPerEpoch(app.Config.LayersPerEpoch)
	app.log = app.addLogger(AppLogger, lg)
	db, err := database.NewLDBDatabase(filepath.Join(dbStorepath, "state"), 0, 0, app.addLogger(StateDbLogger, lg))
	if err != nil {
		return fmt.Errorf("create state DB: %w", err)
	}
	app.closers = append(app.closers, db)
	atxdbstore, err := database.NewLDBDatabase(filepath.Join(dbStorepath, "atx"), 0, 0, app.addLogger(AtxDbStoreLogger, lg))
	if err != nil {
		return fmt.Errorf("create ATX DB: %w", err)
	}
	app.closers = append(app.closers, atxdbstore)
	tBeaconDBStore, err := database.NewLDBDatabase(filepath.Join(dbStorepath, "tbeacon"), 0, 0, app.addLogger(TBeaconDbStoreLogger, lg))
	if err != nil {
		return fmt.Errorf("create tortoise beacon DB: %w", err)
	}
	app.closers = append(app.closers, tBeaconDBStore)
	poetDbStore, err := database.NewLDBDatabase(filepath.Join(dbStorepath, "poet"), 0, 0, app.addLogger(PoetDbStoreLogger, lg))
	if err != nil {
		return fmt.Errorf("create PoET DB: %w", err)
	}
	app.closers = append(app.closers, poetDbStore)
	iddbstore, err := database.NewLDBDatabase(filepath.Join(dbStorepath, "ids"), 0, 0, app.addLogger(StateDbLogger, lg))
	if err != nil {
		return fmt.Errorf("create IDs DB: %w", err)
	}
	app.closers = append(app.closers, iddbstore)
	store, err := database.NewLDBDatabase(filepath.Join(dbStorepath, "store"), 0, 0, app.addLogger(StoreLogger, lg))
	if err != nil {
		return fmt.Errorf("create store DB: %w", err)
	}
	app.closers = append(app.closers, store)
	idStore := activation.NewIdentityStore(iddbstore)
	poetDb := activation.NewPoetDb(poetDbStore, app.addLogger(PoetDbLogger, lg))
	validator := activation.NewValidator(poetDb, app.Config.POST)
	mdb, err := mesh.NewPersistentMeshDB(filepath.Join(dbStorepath, "mesh"), app.Config.BlockCacheSize, app.addLogger(MeshDBLogger, lg))
	if err != nil {
		return fmt.Errorf("create mesh DB: %w", err)
	}
	app.txPool = mempool.NewTxMemPool()
	meshAndPoolProjector := pendingtxs.NewMeshAndPoolProjector(mdb, app.txPool)
	appliedTxs, err := database.NewLDBDatabase(filepath.Join(dbStorepath, "appliedTxs"), 0, 0, lg.WithName("appliedTxs"))
	if err != nil {
		return fmt.Errorf("create applied txs DB: %w", err)
	}
	app.closers = append(app.closers, appliedTxs)
	processor := state.NewTransactionProcessor(db, appliedTxs, meshAndPoolProjector, app.txPool, lg.WithName("state"))
	goldenATXID := types.ATXID(types.HexToHash32(app.Config.GoldenATXID))
	if goldenATXID == *types.EmptyATXID {
		return errors.New("invalid golden atx id")
	}
	fetcherWrapped := &layerFetcher{}
	atxDB := activation.NewDB(atxdbstore, fetcherWrapped, idStore, mdb, layersPerEpoch, goldenATXID, validator, app.addLogger(AtxDbLogger, lg))
	edVerifier := signing.NewEDVerifier()
	vrfVerifier := signing.VRFVerifier{}
	wc := weakcoin.New(app.host,
		vrfSigner, vrfVerifier,
		weakcoin.WithLog(app.addLogger(WeakCoinLogger, lg)),
		weakcoin.WithMaxRound(app.Config.TortoiseBeacon.RoundsNumber),
	)
	tBeacon := tortoisebeacon.New(
		app.Config.TortoiseBeacon,
		nodeID,
		app.host,
		atxDB,
		sgn,
		edVerifier,
		vrfSigner,
		vrfVerifier,
		wc,
		tBeaconDBStore,
		clock,
		app.addLogger(TBeaconLogger, lg))
	var msh *mesh.Mesh
	var trtl *tortoise.ThreadSafeVerifyingTortoise
	trtlStateDB, err := database.NewLDBDatabase(filepath.Join(dbStorepath, "turtle"), 0, 0, app.addLogger(StateDbLogger, lg))
	if err != nil {
		return fmt.Errorf("create turtle DB: %w", err)
	}
	app.closers = append(app.closers, trtlStateDB)
	trtlCfg := tortoise.Config{
		LayerSize:       layerSize,
		Database:        trtlStateDB,
		MeshDatabase:    mdb,
		ATXDB:           atxDB,
		Clock:           clock,
		Hdist:           app.Config.Hdist,
		Zdist:           app.Config.Zdist,
		ConfidenceParam: app.Config.ConfidenceParam,
		WindowSize:      app.Config.WindowSize,
		GlobalThreshold: app.Config.GlobalThreshold,
		LocalThreshold:  app.Config.LocalThreshold,
		Log:             app.addLogger(TrtlLogger, lg),
		RerunInterval:   time.Minute * time.Duration(app.Config.TortoiseRerunInterval),
	}
	trtl = tortoise.NewVerifyingTortoise(ctx, trtlCfg)
	svm := svm.New(processor, app.addLogger(SVMLogger, lg))
	if mdb.PersistentData() {
		msh = mesh.NewRecoveredMesh(ctx, mdb, atxDB, app.Config.REWARD, trtl, app.txPool, svm, app.addLogger(MeshLogger, lg))
		go msh.CacheWarmUp(app.Config.LayerAvgSize)
	} else {
		msh = mesh.NewMesh(mdb, atxDB, app.Config.REWARD, trtl, app.txPool, svm, app.addLogger(MeshLogger, lg))
		if err := svm.SetupGenesis(app.Config.Genesis); err != nil {
			return fmt.Errorf("setup genesis: %w", err)
		}
	}
	eValidator := blocks.NewBlockEligibilityValidator(layerSize, layersPerEpoch, atxDB, tBeacon,
		signing.VRFVerify, msh, app.addLogger(BlkEligibilityLogger, lg))
	if app.Config.AtxsPerBlock > miner.AtxsPerBlockLimit {  
		return fmt.Errorf("number of atxs per block required is bigger than the limit. atxs_per_block: %d. limit: %d",
			app.Config.AtxsPerBlock, miner.AtxsPerBlockLimit,
		)
	}
	if app.Config.HareEligibility.EpochOffset >= app.Config.BaseConfig.LayersPerEpoch {
		return fmt.Errorf("epoch offset cannot be greater than or equal to the number of layers per epoch. epoch_offset: %d. layers_per_epoch: %d",
			app.Config.HareEligibility.EpochOffset, app.Config.BaseConfig.LayersPerEpoch)
	}
	bCfg := blocks.Config{
		Depth:       app.Config.Hdist,
		GoldenATXID: goldenATXID,
	}
	blockListener := blocks.NewBlockHandler(bCfg, fetcherWrapped, msh, eValidator, app.addLogger(BlockListenerLogger, lg))
	remoteFetchService := fetch.NewFetch(ctx, app.Config.FETCH, app.host, app.addLogger(Fetcher, lg))
	layerFetch := layerfetcher.NewLogic(ctx, app.Config.LAYERS, blockListener, atxDB, poetDb, atxDB, processor, app.host, remoteFetchService, msh, app.addLogger(LayerFetcher, lg))
	layerFetch.AddDBs(mdb.Blocks(), atxdbstore, mdb.Transactions(), poetDbStore)
	fetcherWrapped.Fetcher = layerFetch
	patrol := layerpatrol.New()
	syncerConf := syncer.Configuration{
		SyncInterval: time.Duration(app.Config.SyncInterval) * time.Second,
		AlwaysListen: app.Config.AlwaysListen,
	}
	newSyncer := syncer.NewSyncer(ctx, syncerConf, clock, msh, layerFetch, patrol, app.addLogger(SyncLogger, lg))
	tBeacon.SetSyncState(newSyncer)
	blockOracle := blocks.NewMinerBlockOracle(layerSize, layersPerEpoch, atxDB, tBeacon, vrfSigner, nodeID, newSyncer.ListenToGossip, app.addLogger(BlockOracle, lg))
	var hOracle hare.Rolacle
	if isFixedOracle {
		hOracle = rolacle
	} else {
		beacon := eligibility.NewBeacon(tBeacon, app.addLogger(HareBeaconLogger, lg))
		hOracle = eligibility.New(beacon, atxDB, mdb, signing.VRFVerify, vrfSigner, app.Config.LayersPerEpoch, app.Config.HareEligibility, app.addLogger(HareOracleLogger, lg))
	}
	rabbit := app.HareFactory(ctx, mdb, sgn, nodeID, patrol, newSyncer, msh, tBeacon, hOracle, idStore, clock, lg)
	stateAndMeshProjector := pendingtxs.NewStateAndMeshProjector(processor, msh)
	minerCfg := miner.Config{
		DBPath:         filepath.Join(dbStorepath, "builder"),
		MinerID:        nodeID,
		AtxsPerBlock:   app.Config.AtxsPerBlock,
		LayersPerEpoch: layersPerEpoch,
		TxsPerBlock:    app.Config.TxsPerBlock,
	}
	blockProducer := miner.NewBlockBuilder(
		minerCfg,
		sgn,
		app.host,
		clock.Subscribe(),
		msh,
		trtl,
		blockOracle,
		tBeacon,
		newSyncer,
		stateAndMeshProjector,
		app.txPool,
		app.addLogger(BlockBuilderLogger, lg))
	poetListener := activation.NewPoetListener(poetDb, app.addLogger(PoetListenerLogger, lg))
	postSetupMgr, err := activation.NewPostSetupManager(util.Hex2Bytes(nodeID.Key), app.Config.POST, app.addLogger(PostLogger, lg))
	if err != nil {
		app.log.Panic("failed to create post setup manager: %v", err)
	}
	nipostBuilder := activation.NewNIPostBuilder(util.Hex2Bytes(nodeID.Key), postSetupMgr, poetClient, poetDb, store, app.addLogger(NipostBuilderLogger, lg))
	coinbaseAddr := types.HexToAddress(app.Config.SMESHING.CoinbaseAccount)
	if app.Config.SMESHING.Start {
		if coinbaseAddr.Big().Uint64() == 0 {
			app.log.Panic("invalid coinbase account")
		}
	}
	builderConfig := activation.Config{
		CoinbaseAccount: coinbaseAddr,
		GoldenATXID:     goldenATXID,
		LayersPerEpoch:  layersPerEpoch,
	}
	atxBuilder := activation.NewBuilder(builderConfig, nodeID, sgn,
		atxDB, app.host, msh, layersPerEpoch, nipostBuilder,
		postSetupMgr, clock, newSyncer, store, app.addLogger("atxBuilder", lg),
		activation.WithContext(ctx),
	)
	syncHandler := func(_ context.Context, _ p2p.Peer, _ []byte) pubsub.ValidationResult {
		if newSyncer.ListenToGossip() {
			return pubsub.ValidationAccept
		}
		return pubsub.ValidationIgnore
	}
	app.host.Register(weakcoin.GossipProtocol, pubsub.ChainGossipHandler(syncHandler, wc.HandleProposal))
	app.host.Register(tortoisebeacon.TBProposalProtocol,
		pubsub.ChainGossipHandler(syncHandler, tBeacon.HandleSerializedProposalMessage))
	app.host.Register(tortoisebeacon.TBFirstVotingProtocol,
		pubsub.ChainGossipHandler(syncHandler, tBeacon.HandleSerializedFirstVotingMessage))
	app.host.Register(tortoisebeacon.TBFollowingVotingProtocol,
		pubsub.ChainGossipHandler(syncHandler, tBeacon.HandleSerializedFollowingVotingMessage))
	app.host.Register(blocks.NewBlockProtocol, pubsub.ChainGossipHandler(syncHandler, blockListener.HandleBlock))
	app.host.Register(activation.AtxProtocol, pubsub.ChainGossipHandler(syncHandler, atxDB.HandleGossipAtx))
	app.host.Register(state.IncomingTxProtocol, pubsub.ChainGossipHandler(syncHandler, processor.HandleTxGossipData))
	app.host.Register(activation.PoetProofProtocol, poetListener.HandlePoetProofMessage)
	app.blockProducer = blockProducer
	app.blockListener = blockListener
	app.mesh = msh
	app.syncer = newSyncer
	app.clock = clock
	app.state = processor
	app.hare = rabbit
	app.poetListener = poetListener
	app.atxBuilder = atxBuilder
	app.postSetupMgr = postSetupMgr
	app.oracle = blockOracle
	app.txProcessor = processor
	app.atxDb = atxDB
	app.layerFetch = layerFetch
	app.tortoiseBeacon = tBeacon
	app.svm = svm
	if !app.Config.TIME.Peersync.Disable {
		app.ptimesync = peersync.New(
			app.host,
			app.host,
			peersync.WithLog(app.addLogger(TimeSyncLogger, lg)),
			peersync.WithConfig(app.Config.TIME.Peersync),
		)
	}
	return nil
}
func (app *App) checkTimeDrifts() {
	checkTimeSync := time.NewTicker(app.Config.TIME.RefreshNtpInterval)
	defer checkTimeSync.Stop()  
	for {
		select {
		case <-app.term:
			return
		case <-checkTimeSync.C:
			_, err := timesync.CheckSystemClockDrift()
			if err != nil {
				app.log.With().Error("unable to synchronize system time", log.Err(err))
				cmdp.Cancel()
				return
			}
		}
	}
}
func (app *App) HareFactory(
	ctx context.Context,
	mdb *mesh.DB,
	sgn hare.Signer,
	nodeID types.NodeID,
	patrol *layerpatrol.LayerPatrol,
	syncer *syncer.Syncer,
	msh *mesh.Mesh,
	beacons blocks.BeaconGetter,
	hOracle hare.Rolacle,
	idStore *activation.IdentityStore,
	clock TickProvider,
	lg log.Log,
) HareService {
	if app.Config.HARE.SuperHare {
		hr := turbohare.New(ctx, app.Config.HARE, msh, clock.Subscribe(), app.addLogger(HareLogger, lg))
		mdb.InputVectorBackupFunc = hr.GetResult
		return hr
	}
	ha := hare.New(
		app.Config.HARE,
		app.host.ID(),
		app.host,
		sgn,
		nodeID,
		syncer.IsSynced,
		msh,
		beacons,
		hOracle,
		patrol,
		uint16(app.Config.LayersPerEpoch),
		idStore,
		hOracle,
		clock,
		app.addLogger(HareLogger, lg))
	return ha
}
func (app *App) startServices(ctx context.Context) error {
	app.layerFetch.Start()
	go app.startSyncer(ctx)
	if err := app.tortoiseBeacon.Start(ctx); err != nil {
		return fmt.Errorf("cannot start tortoise beacon: %w", err)
	}
	if err := app.hare.Start(ctx); err != nil {
		return fmt.Errorf("cannot start hare: %w", err)
	}
	if err := app.blockProducer.Start(ctx); err != nil {
		return fmt.Errorf("cannot start block producer: %w", err)
	}
	if app.Config.SMESHING.Start {
		coinbaseAddr := types.HexToAddress(app.Config.SMESHING.CoinbaseAccount)
		go func() {
			if err := app.atxBuilder.StartSmeshing(coinbaseAddr, app.Config.SMESHING.Opts); err != nil {
				log.Panic("failed to start smeshing: %v", err)
			}
		}()
	} else {
		log.Info("smeshing not started, waiting to be triggered via smesher api")
	}
	app.clock.StartNotifying()
	if app.ptimesync != nil {
		app.ptimesync.Start()
	}
	go app.checkTimeDrifts()
	return nil
}
func (app *App) startAPIServices(ctx context.Context) {
	apiConf := &app.Config.API
	layerDuration := app.Config.LayerDurationSec
	services := []grpcserver.ServiceAPI{}
	registerService := func(svc grpcserver.ServiceAPI) {
		if app.grpcAPIService == nil {
			app.grpcAPIService = grpcserver.NewServerWithInterface(apiConf.GrpcServerPort, apiConf.GrpcServerInterface)
		}
		services = append(services, svc)
		svc.RegisterService(app.grpcAPIService)
	}
	if apiConf.StartDebugService {
		registerService(grpcserver.NewDebugService(app.mesh))
	}
	if apiConf.StartGatewayService {
		registerService(grpcserver.NewGatewayService(app.host))
	}
	if apiConf.StartGlobalStateService {
		registerService(grpcserver.NewGlobalStateService(app.mesh, app.txPool))
	}
	if apiConf.StartMeshService {
		registerService(grpcserver.NewMeshService(app.mesh, app.clock, app.Config.LayersPerEpoch, app.Config.P2P.NetworkID, layerDuration, app.Config.LayerAvgSize, app.Config.TxsPerBlock))
	}
	if apiConf.StartNodeService {
		nodeService := grpcserver.NewNodeService(app.host, app.mesh, app.clock, app.syncer, app.atxBuilder)
		registerService(nodeService)
		app.closers = append(app.closers, nodeService)
	}
	if apiConf.StartSmesherService {
		registerService(grpcserver.NewSmesherService(app.postSetupMgr, app.atxBuilder))
	}
	if apiConf.StartTransactionService {
		registerService(grpcserver.NewTransactionService(app.host, app.mesh, app.txPool, app.syncer))
	}
	if app.grpcAPIService != nil {
		app.grpcAPIService.Start()
	}
	if apiConf.StartJSONServer {
		if app.grpcAPIService == nil {
			log.Panic("one or more new grpc services must be enabled with new json gateway server")
		}
		app.jsonAPIService = grpcserver.NewJSONHTTPServer(apiConf.JSONServerPort)
		app.jsonAPIService.StartService(ctx, services...)
	}
}
func (app *App) stopServices() {
	close(app.term)
	if app.jsonAPIService != nil {
		log.Info("stopping json gateway service")
		if err := app.jsonAPIService.Close(); err != nil {
			log.With().Error("error stopping json gateway server", log.Err(err))
		}
	}
	if app.grpcAPIService != nil {
		log.Info("stopping grpc service")
		_ = app.grpcAPIService.Close()
	}
	if app.blockProducer != nil {
		app.log.Info("closing block producer")
		if err := app.blockProducer.Close(); err != nil {
			log.With().Error("cannot stop block producer", log.Err(err))
		}
	}
	if app.clock != nil {
		app.log.Info("closing clock")
		app.clock.Close()
	}
	if app.tortoiseBeacon != nil {
		app.log.Info("stopping tortoise beacon")
		app.tortoiseBeacon.Close()
	}
	if app.atxBuilder != nil {
		app.log.Info("closing atx builder")
		_ = app.atxBuilder.StopSmeshing(false)
	}
	if app.hare != nil {
		app.log.Info("closing hare")
		app.hare.Close()
	}
	if app.layerFetch != nil {
		app.log.Info("closing layerFetch")
		app.layerFetch.Close()
	}
	if app.syncer != nil {
		app.log.Info("closing sync")
		app.syncer.Close()
	}
	if app.mesh != nil {
		app.log.Info("closing mesh")
		app.mesh.Close()
	}
	if app.ptimesync != nil {
		app.ptimesync.Stop()
		app.log.Debug("peer timesync stopped")
	}
	if app.host != nil {
		if err := app.host.Stop(); err != nil {
			app.log.With().Warning("p2p host exited with error", log.Err(err))
		}
	}
	events.CloseEventReporter()
	events.CloseEventPubSub()
	for _, closer := range app.closers {
		if closer != nil {
			closer.Close()
		}
	}
}