func (n *nodeImpl) Mempool() mempool.Mempool {
	return n.mempool
}
Mempool returns the Node's mempool.
package node
import (
	"context"
	"errors"
	"fmt"
	"net"
	"net/http"
	"strconv"
	"time"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/rs/cors"
	abciclient "github.com/tendermint/tendermint/abci/client"
	abci "github.com/tendermint/tendermint/abci/types"
	"github.com/tendermint/tendermint/config"
	"github.com/tendermint/tendermint/crypto"
	"github.com/tendermint/tendermint/internal/consensus"
	"github.com/tendermint/tendermint/internal/mempool"
	"github.com/tendermint/tendermint/internal/p2p"
	"github.com/tendermint/tendermint/internal/proxy"
	rpccore "github.com/tendermint/tendermint/internal/rpc/core"
	sm "github.com/tendermint/tendermint/internal/state"
	"github.com/tendermint/tendermint/internal/state/indexer"
	"github.com/tendermint/tendermint/internal/statesync"
	"github.com/tendermint/tendermint/internal/store"
	"github.com/tendermint/tendermint/libs/log"
	tmnet "github.com/tendermint/tendermint/libs/net"
	tmpubsub "github.com/tendermint/tendermint/libs/pubsub"
	"github.com/tendermint/tendermint/libs/service"
	"github.com/tendermint/tendermint/libs/strings"
	tmtime "github.com/tendermint/tendermint/libs/time"
	"github.com/tendermint/tendermint/privval"
	tmgrpc "github.com/tendermint/tendermint/privval/grpc"
	rpcserver "github.com/tendermint/tendermint/rpc/jsonrpc/server"
	"github.com/tendermint/tendermint/types"
	_ "net/http/pprof"  
	_ "github.com/lib/pq"  
)
type nodeImpl struct {
	service.BaseService
	config        *config.Config
	genesisDoc    *types.GenesisDoc    
	privValidator types.PrivValidator  
	transport   *p2p.MConnTransport
	peerManager *p2p.PeerManager
	router      *p2p.Router
	nodeInfo    types.NodeInfo
	nodeKey     types.NodeKey  
	isListening bool
	eventBus         *types.EventBus  
	eventSinks       []indexer.EventSink
	stateStore       sm.Store
	blockStore       *store.BlockStore  
	bcReactor        service.Service    
	mempoolReactor   service.Service    
	mempool          mempool.Mempool
	stateSync        bool                
	stateSyncReactor *statesync.Reactor  
	consensusReactor *consensus.Reactor  
	pexReactor       service.Service     
	evidenceReactor  service.Service
	rpcListeners     []net.Listener  
	shutdownOps      closer
	indexerService   service.Service
	rpcEnv           *rpccore.Environment
	prometheusSrv    *http.Server
}
func newDefaultNode(cfg *config.Config, logger log.Logger) (service.Service, error) {
	nodeKey, err := types.LoadOrGenNodeKey(cfg.NodeKeyFile())
	if err != nil {
		return nil, fmt.Errorf("failed to load or gen node key %s: %w", cfg.NodeKeyFile(), err)
	}
	if cfg.Mode == config.ModeSeed {
		return makeSeedNode(cfg,
			config.DefaultDBProvider,
			nodeKey,
			defaultGenesisDocProviderFunc(cfg),
			logger,
		)
	}
	var pval *privval.FilePV
	if cfg.Mode == config.ModeValidator {
		pval, err = privval.LoadOrGenFilePV(cfg.PrivValidator.KeyFile(), cfg.PrivValidator.StateFile())
		if err != nil {
			return nil, err
		}
	} else {
		pval = nil
	}
	appClient, _ := proxy.DefaultClientCreator(cfg.ProxyApp, cfg.ABCI, cfg.DBDir())
	return makeNode(cfg,
		pval,
		nodeKey,
		appClient,
		defaultGenesisDocProviderFunc(cfg),
		config.DefaultDBProvider,
		logger,
	)
}
func makeNode(cfg *config.Config,
	privValidator types.PrivValidator,
	nodeKey types.NodeKey,
	clientCreator abciclient.Creator,
	genesisDocProvider genesisDocProvider,
	dbProvider config.DBProvider,
	logger log.Logger,
) (service.Service, error) {
	closers := []closer{}
	blockStore, stateDB, dbCloser, err := initDBs(cfg, dbProvider)
	if err != nil {
		return nil, combineCloseError(err, dbCloser)
	}
	closers = append(closers, dbCloser)
	stateStore := sm.NewStore(stateDB)
	genDoc, err := genesisDocProvider()
	if err != nil {
		return nil, combineCloseError(err, makeCloser(closers))
	}
	err = genDoc.ValidateAndComplete()
	if err != nil {
		return nil, combineCloseError(
			fmt.Errorf("error in genesis doc: %w", err),
			makeCloser(closers))
	}
	state, err := loadStateFromDBOrGenesisDocProvider(stateStore, genDoc)
	if err != nil {
		return nil, combineCloseError(err, makeCloser(closers))
	}
	nodeMetrics := defaultMetricsProvider(cfg.Instrumentation)(genDoc.ChainID)
	proxyApp, err := createAndStartProxyAppConns(clientCreator, logger, nodeMetrics.proxy)
	if err != nil {
		return nil, combineCloseError(err, makeCloser(closers))
	}
	eventBus, err := createAndStartEventBus(logger)
	if err != nil {
		return nil, combineCloseError(err, makeCloser(closers))
	}
	indexerService, eventSinks, err := createAndStartIndexerService(cfg, dbProvider, eventBus, logger, genDoc.ChainID)
	if err != nil {
		return nil, combineCloseError(err, makeCloser(closers))
	}
	if cfg.PrivValidator.ListenAddr != "" {
		protocol, _ := tmnet.ProtocolAndAddress(cfg.PrivValidator.ListenAddr)
		switch protocol {
		case "grpc":
			privValidator, err = createAndStartPrivValidatorGRPCClient(cfg, genDoc.ChainID, logger)
			if err != nil {
				return nil, combineCloseError(
					fmt.Errorf("error with private validator grpc client: %w", err),
					makeCloser(closers))
			}
		default:
			privValidator, err = createAndStartPrivValidatorSocketClient(cfg.PrivValidator.ListenAddr, genDoc.ChainID, logger)
			if err != nil {
				return nil, combineCloseError(
					fmt.Errorf("error with private validator socket client: %w", err),
					makeCloser(closers))
			}
		}
	}
	var pubKey crypto.PubKey
	if cfg.Mode == config.ModeValidator {
		pubKey, err = privValidator.GetPubKey(context.TODO())
		if err != nil {
			return nil, combineCloseError(fmt.Errorf("can't get pubkey: %w", err),
				makeCloser(closers))
		}
		if pubKey == nil {
			return nil, combineCloseError(
				errors.New("could not retrieve public key from private validator"),
				makeCloser(closers))
		}
	}
	stateSync := cfg.StateSync.Enable && !onlyValidatorIsUs(state, pubKey)
	if stateSync && state.LastBlockHeight > 0 {
		logger.Info("Found local state with non-zero height, skipping state sync")
		stateSync = false
	}
	consensusLogger := logger.With("module", "consensus")
	if !stateSync {
		if err := doHandshake(stateStore, state, blockStore, genDoc, eventBus, proxyApp, consensusLogger); err != nil {
			return nil, combineCloseError(err, makeCloser(closers))
		}
		state, err = stateStore.Load()
		if err != nil {
			return nil, combineCloseError(
				fmt.Errorf("cannot load state: %w", err),
				makeCloser(closers))
		}
	}
	blockSync := cfg.BlockSync.Enable && !onlyValidatorIsUs(state, pubKey)
	logNodeStartupInfo(state, pubKey, logger, consensusLogger, cfg.Mode)
	nodeInfo, err := makeNodeInfo(cfg, nodeKey, eventSinks, genDoc, state)
	if err != nil {
		return nil, combineCloseError(err, makeCloser(closers))
	}
	p2pLogger := logger.With("module", "p2p")
	transport := createTransport(p2pLogger, cfg)
	peerManager, peerCloser, err := createPeerManager(cfg, dbProvider, nodeKey.ID)
	closers = append(closers, peerCloser)
	if err != nil {
		return nil, combineCloseError(
			fmt.Errorf("failed to create peer manager: %w", err),
			makeCloser(closers))
	}
	router, err := createRouter(p2pLogger, nodeMetrics.p2p, nodeInfo, nodeKey.PrivKey,
		peerManager, transport, getRouterConfig(cfg, proxyApp))
	if err != nil {
		return nil, combineCloseError(
			fmt.Errorf("failed to create router: %w", err),
			makeCloser(closers))
	}
	mpReactor, mp, err := createMempoolReactor(
		cfg, proxyApp, state, nodeMetrics.mempool, peerManager, router, logger,
	)
	if err != nil {
		return nil, combineCloseError(err, makeCloser(closers))
	}
	evReactor, evPool, err := createEvidenceReactor(
		cfg, dbProvider, stateDB, blockStore, peerManager, router, logger,
	)
	if err != nil {
		return nil, combineCloseError(err, makeCloser(closers))
	}
	blockExec := sm.NewBlockExecutor(
		stateStore,
		logger.With("module", "state"),
		proxyApp.Consensus(),
		mp,
		evPool,
		blockStore,
		sm.BlockExecutorWithMetrics(nodeMetrics.state),
	)
	csReactor, csState, err := createConsensusReactor(
		cfg, state, blockExec, blockStore, mp, evPool,
		privValidator, nodeMetrics.consensus, stateSync || blockSync, eventBus,
		peerManager, router, consensusLogger,
	)
	if err != nil {
		return nil, combineCloseError(err, makeCloser(closers))
	}
	bcReactor, err := createBlockchainReactor(
		logger, state, blockExec, blockStore, csReactor,
		peerManager, router, blockSync && !stateSync, nodeMetrics.consensus,
	)
	if err != nil {
		return nil, combineCloseError(
			fmt.Errorf("could not create blockchain reactor: %w", err),
			makeCloser(closers))
	}
	if stateSync {
		nodeMetrics.consensus.StateSyncing.Set(1)
	} else if blockSync {
		nodeMetrics.consensus.BlockSyncing.Set(1)
	}
	ssLogger := logger.With("module", "statesync")
	ssChDesc := statesync.GetChannelDescriptors()
	channels := make(map[p2p.ChannelID]*p2p.Channel, len(ssChDesc))
	for idx := range ssChDesc {
		chd := ssChDesc[idx]
		ch, err := router.OpenChannel(chd)
		if err != nil {
			return nil, err
		}
		channels[ch.ID] = ch
	}
	peerUpdates := peerManager.Subscribe()
	stateSyncReactor := statesync.NewReactor(
		genDoc.ChainID,
		genDoc.InitialHeight,
		*cfg.StateSync,
		ssLogger,
		proxyApp.Snapshot(),
		proxyApp.Query(),
		channels[statesync.SnapshotChannel],
		channels[statesync.ChunkChannel],
		channels[statesync.LightBlockChannel],
		channels[statesync.ParamsChannel],
		peerUpdates,
		stateStore,
		blockStore,
		cfg.StateSync.TempDir,
		nodeMetrics.statesync,
	)
	var pexReactor service.Service
	pexReactor, err = createPEXReactor(logger, peerManager, router)
	if err != nil {
		return nil, combineCloseError(err, makeCloser(closers))
	}
	if cfg.RPC.PprofListenAddress != "" {
		go func() {
			logger.Info("Starting pprof server", "laddr", cfg.RPC.PprofListenAddress)
			logger.Error("pprof server error", "err", http.ListenAndServe(cfg.RPC.PprofListenAddress, nil))
		}()
	}
	node := &nodeImpl{
		config:        cfg,
		genesisDoc:    genDoc,
		privValidator: privValidator,
		transport:   transport,
		peerManager: peerManager,
		router:      router,
		nodeInfo:    nodeInfo,
		nodeKey:     nodeKey,
		stateStore:       stateStore,
		blockStore:       blockStore,
		bcReactor:        bcReactor,
		mempoolReactor:   mpReactor,
		mempool:          mp,
		consensusReactor: csReactor,
		stateSyncReactor: stateSyncReactor,
		stateSync:        stateSync,
		pexReactor:       pexReactor,
		evidenceReactor:  evReactor,
		indexerService:   indexerService,
		eventBus:         eventBus,
		eventSinks:       eventSinks,
		shutdownOps: makeCloser(closers),
		rpcEnv: &rpccore.Environment{
			ProxyAppQuery:   proxyApp.Query(),
			ProxyAppMempool: proxyApp.Mempool(),
			StateStore:     stateStore,
			BlockStore:     blockStore,
			EvidencePool:   evPool,
			ConsensusState: csState,
			ConsensusReactor: csReactor,
			BlockSyncReactor: bcReactor.(consensus.BlockSyncReactor),
			PeerManager: peerManager,
			GenDoc:     genDoc,
			EventSinks: eventSinks,
			EventBus:   eventBus,
			Mempool:    mp,
			Logger:     logger.With("module", "rpc"),
			Config:     *cfg.RPC,
		},
	}
	node.rpcEnv.P2PTransport = node
	node.BaseService = *service.NewBaseService(logger, "Node", node)
	return node, nil
}
func makeSeedNode(cfg *config.Config,
	dbProvider config.DBProvider,
	nodeKey types.NodeKey,
	genesisDocProvider genesisDocProvider,
	logger log.Logger,
) (service.Service, error) {
	genDoc, err := genesisDocProvider()
	if err != nil {
		return nil, err
	}
	state, err := sm.MakeGenesisState(genDoc)
	if err != nil {
		return nil, err
	}
	nodeInfo, err := makeSeedNodeInfo(cfg, nodeKey, genDoc, state)
	if err != nil {
		return nil, err
	}
	p2pMetrics := p2p.PrometheusMetrics(cfg.Instrumentation.Namespace, "chain_id", genDoc.ChainID)
	p2pLogger := logger.With("module", "p2p")
	transport := createTransport(p2pLogger, cfg)
	peerManager, closer, err := createPeerManager(cfg, dbProvider, nodeKey.ID)
	if err != nil {
		return nil, combineCloseError(
			fmt.Errorf("failed to create peer manager: %w", err),
			closer)
	}
	router, err := createRouter(p2pLogger, p2pMetrics, nodeInfo, nodeKey.PrivKey,
		peerManager, transport, getRouterConfig(cfg, nil))
	if err != nil {
		return nil, combineCloseError(
			fmt.Errorf("failed to create router: %w", err),
			closer)
	}
	var pexReactor service.Service
	pexReactor, err = createPEXReactor(logger, peerManager, router)
	if err != nil {
		return nil, combineCloseError(err, closer)
	}
	if cfg.RPC.PprofListenAddress != "" {
		go func() {
			logger.Info("Starting pprof server", "laddr", cfg.RPC.PprofListenAddress)
			logger.Error("pprof server error", "err", http.ListenAndServe(cfg.RPC.PprofListenAddress, nil))
		}()
	}
	node := &nodeImpl{
		config:     cfg,
		genesisDoc: genDoc,
		transport:   transport,
		nodeInfo:    nodeInfo,
		nodeKey:     nodeKey,
		peerManager: peerManager,
		router:      router,
		shutdownOps: closer,
		pexReactor: pexReactor,
	}
	node.BaseService = *service.NewBaseService(logger, "SeedNode", node)
	return node, nil
}
func (n *nodeImpl) OnStart() error {
	now := tmtime.Now()
	genTime := n.genesisDoc.GenesisTime
	if genTime.After(now) {
		n.Logger.Info("Genesis time is in the future. Sleeping until then...", "genTime", genTime)
		time.Sleep(genTime.Sub(now))
	}
	if n.config.RPC.ListenAddress != "" && n.config.Mode != config.ModeSeed {
		listeners, err := n.startRPC()
		if err != nil {
			return err
		}
		n.rpcListeners = listeners
	}
	if n.config.Instrumentation.Prometheus &&
		n.config.Instrumentation.PrometheusListenAddr != "" {
		n.prometheusSrv = n.startPrometheusServer(n.config.Instrumentation.PrometheusListenAddr)
	}
	ep, err := p2p.NewEndpoint(n.nodeKey.ID.AddressString(n.config.P2P.ListenAddress))
	if err != nil {
		return err
	}
	if err := n.transport.Listen(ep); err != nil {
		return err
	}
	n.isListening = true
	if err = n.router.Start(); err != nil {
		return err
	}
	if n.config.Mode != config.ModeSeed {
		if n.config.BlockSync.Enable {
			if err := n.bcReactor.Start(); err != nil {
				return err
			}
		}
		if err := n.consensusReactor.Start(); err != nil {
			return err
		}
		if err := n.stateSyncReactor.Start(); err != nil {
			return err
		}
		if err := n.mempoolReactor.Start(); err != nil {
			return err
		}
		if err := n.evidenceReactor.Start(); err != nil {
			return err
		}
	}
	if err := n.pexReactor.Start(); err != nil {
		return err
	}
	if n.stateSync {
		bcR, ok := n.bcReactor.(consensus.BlockSyncReactor)
		if !ok {
			return fmt.Errorf("this blockchain reactor does not support switching from state sync")
		}
		state, err := sm.MakeGenesisState(n.genesisDoc)
		if err != nil {
			return fmt.Errorf("unable to derive state: %w", err)
		}
		d := types.EventDataStateSyncStatus{Complete: false, Height: state.InitialHeight}
		if err := n.eventBus.PublishEventStateSyncStatus(d); err != nil {
			n.eventBus.Logger.Error("failed to emit the statesync start event", "err", err)
		}
		go func() {
			n.Logger.Info("starting state sync")
			state, err := n.stateSyncReactor.Sync(context.TODO())
			if err != nil {
				n.Logger.Error("state sync failed; shutting down this node", "err", err)
				if err := n.Stop(); err != nil {
					n.Logger.Error("failed to shut down node", "err", err)
				}
				return
			}
			n.consensusReactor.SetStateSyncingMetrics(0)
			d := types.EventDataStateSyncStatus{Complete: true, Height: state.LastBlockHeight}
			if err := n.eventBus.PublishEventStateSyncStatus(d); err != nil {
				n.eventBus.Logger.Error("failed to emit the statesync start event", "err", err)
			}
			if n.config.BlockSync.Enable {
				n.consensusReactor.SetBlockSyncingMetrics(1)
				if err := bcR.SwitchToBlockSync(state); err != nil {
					n.Logger.Error("failed to switch to block sync", "err", err)
					return
				}
				d := types.EventDataBlockSyncStatus{Complete: false, Height: state.LastBlockHeight}
				if err := n.eventBus.PublishEventBlockSyncStatus(d); err != nil {
					n.eventBus.Logger.Error("failed to emit the block sync starting event", "err", err)
				}
			} else {
				n.consensusReactor.SwitchToConsensus(state, true)
			}
		}()
	}
	return nil
}
func (n *nodeImpl) OnStop() {
	n.Logger.Info("Stopping Node")
	if n.eventBus != nil {
		if err := n.eventBus.Stop(); err != nil {
			n.Logger.Error("Error closing eventBus", "err", err)
		}
	}
	if n.indexerService != nil {
		if err := n.indexerService.Stop(); err != nil {
			n.Logger.Error("Error closing indexerService", "err", err)
		}
	}
	for _, es := range n.eventSinks {
		if err := es.Stop(); err != nil {
			n.Logger.Error("failed to stop event sink", "err", err)
		}
	}
	if n.config.Mode != config.ModeSeed {
		if n.config.BlockSync.Enable {
			if err := n.bcReactor.Stop(); err != nil {
				n.Logger.Error("failed to stop the blockchain reactor", "err", err)
			}
		}
		if err := n.consensusReactor.Stop(); err != nil {
			n.Logger.Error("failed to stop the consensus reactor", "err", err)
		}
		if err := n.stateSyncReactor.Stop(); err != nil {
			n.Logger.Error("failed to stop the state sync reactor", "err", err)
		}
		if err := n.mempoolReactor.Stop(); err != nil {
			n.Logger.Error("failed to stop the mempool reactor", "err", err)
		}
		if err := n.evidenceReactor.Stop(); err != nil {
			n.Logger.Error("failed to stop the evidence reactor", "err", err)
		}
	}
	if err := n.pexReactor.Stop(); err != nil {
		n.Logger.Error("failed to stop the PEX v2 reactor", "err", err)
	}
	if err := n.router.Stop(); err != nil {
		n.Logger.Error("failed to stop router", "err", err)
	}
	if err := n.transport.Close(); err != nil {
		n.Logger.Error("Error closing transport", "err", err)
	}
	n.isListening = false
	for _, l := range n.rpcListeners {
		n.Logger.Info("Closing rpc listener", "listener", l)
		if err := l.Close(); err != nil {
			n.Logger.Error("Error closing listener", "listener", l, "err", err)
		}
	}
	if pvsc, ok := n.privValidator.(service.Service); ok {
		if err := pvsc.Stop(); err != nil {
			n.Logger.Error("Error closing private validator", "err", err)
		}
	}
	if n.prometheusSrv != nil {
		if err := n.prometheusSrv.Shutdown(context.Background()); err != nil {
			n.Logger.Error("Prometheus HTTP server Shutdown", "err", err)
		}
	}
	if err := n.shutdownOps(); err != nil {
		n.Logger.Error("problem shutting down additional services", "err", err)
	}
}
func (n *nodeImpl) startRPC() ([]net.Listener, error) {
	if n.config.Mode == config.ModeValidator {
		pubKey, err := n.privValidator.GetPubKey(context.TODO())
		if pubKey == nil || err != nil {
			return nil, fmt.Errorf("can't get pubkey: %w", err)
		}
		n.rpcEnv.PubKey = pubKey
	}
	if err := n.rpcEnv.InitGenesisChunks(); err != nil {
		return nil, err
	}
	listenAddrs := strings.SplitAndTrimEmpty(n.config.RPC.ListenAddress, ",", " ")
	routes := n.rpcEnv.GetRoutes()
	if n.config.RPC.Unsafe {
		n.rpcEnv.AddUnsafe(routes)
	}
	cfg := rpcserver.DefaultConfig()
	cfg.MaxBodyBytes = n.config.RPC.MaxBodyBytes
	cfg.MaxHeaderBytes = n.config.RPC.MaxHeaderBytes
	cfg.MaxOpenConnections = n.config.RPC.MaxOpenConnections
	if cfg.WriteTimeout <= n.config.RPC.TimeoutBroadcastTxCommit {
		cfg.WriteTimeout = n.config.RPC.TimeoutBroadcastTxCommit + 1*time.Second
	}
	listeners := make([]net.Listener, len(listenAddrs))
	for i, listenAddr := range listenAddrs {
		mux := http.NewServeMux()
		rpcLogger := n.Logger.With("module", "rpc-server")
		wmLogger := rpcLogger.With("protocol", "websocket")
		wm := rpcserver.NewWebsocketManager(routes,
			rpcserver.OnDisconnect(func(remoteAddr string) {
				err := n.eventBus.UnsubscribeAll(context.Background(), remoteAddr)
				if err != nil && err != tmpubsub.ErrSubscriptionNotFound {
					wmLogger.Error("Failed to unsubscribe addr from events", "addr", remoteAddr, "err", err)
				}
			}),
			rpcserver.ReadLimit(cfg.MaxBodyBytes),
		)
		wm.SetLogger(wmLogger)
		mux.HandleFunc("/websocket", wm.WebsocketHandler)
		rpcserver.RegisterRPCFuncs(mux, routes, rpcLogger)
		listener, err := rpcserver.Listen(
			listenAddr,
			cfg.MaxOpenConnections,
		)
		if err != nil {
			return nil, err
		}
		var rootHandler http.Handler = mux
		if n.config.RPC.IsCorsEnabled() {
			corsMiddleware := cors.New(cors.Options{
				AllowedOrigins: n.config.RPC.CORSAllowedOrigins,
				AllowedMethods: n.config.RPC.CORSAllowedMethods,
				AllowedHeaders: n.config.RPC.CORSAllowedHeaders,
			})
			rootHandler = corsMiddleware.Handler(mux)
		}
		if n.config.RPC.IsTLSEnabled() {
			go func() {
				if err := rpcserver.ServeTLS(
					listener,
					rootHandler,
					n.config.RPC.CertFile(),
					n.config.RPC.KeyFile(),
					rpcLogger,
					cfg,
				); err != nil {
					n.Logger.Error("Error serving server with TLS", "err", err)
				}
			}()
		} else {
			go func() {
				if err := rpcserver.Serve(
					listener,
					rootHandler,
					rpcLogger,
					cfg,
				); err != nil {
					n.Logger.Error("Error serving server", "err", err)
				}
			}()
		}
		listeners[i] = listener
	}
	return listeners, nil
}
func (n *nodeImpl) startPrometheusServer(addr string) *http.Server {
	srv := &http.Server{
		Addr: addr,
		Handler: promhttp.InstrumentMetricHandler(
			prometheus.DefaultRegisterer, promhttp.HandlerFor(
				prometheus.DefaultGatherer,
				promhttp.HandlerOpts{MaxRequestsInFlight: n.config.Instrumentation.MaxOpenConnections},
			),
		),
	}
	go func() {
		if err := srv.ListenAndServe(); err != http.ErrServerClosed {
			n.Logger.Error("Prometheus HTTP server ListenAndServe", "err", err)
		}
	}()
	return srv
}
func (n *nodeImpl) ConsensusReactor() *consensus.Reactor {
	return n.consensusReactor
}