|
|
@ -10,12 +10,10 @@ import ( |
|
|
|
"strconv" |
|
|
|
"time" |
|
|
|
|
|
|
|
_ "github.com/lib/pq" // provide the psql db driver
|
|
|
|
"github.com/prometheus/client_golang/prometheus" |
|
|
|
"github.com/prometheus/client_golang/prometheus/promhttp" |
|
|
|
"github.com/rs/cors" |
|
|
|
dbm "github.com/tendermint/tm-db" |
|
|
|
|
|
|
|
_ "github.com/lib/pq" // provide the psql db driver
|
|
|
|
abci "github.com/tendermint/tendermint/abci/types" |
|
|
|
cfg "github.com/tendermint/tendermint/config" |
|
|
|
cs "github.com/tendermint/tendermint/consensus" |
|
|
@ -43,11 +41,12 @@ import ( |
|
|
|
"github.com/tendermint/tendermint/store" |
|
|
|
"github.com/tendermint/tendermint/types" |
|
|
|
tmtime "github.com/tendermint/tendermint/types/time" |
|
|
|
dbm "github.com/tendermint/tm-db" |
|
|
|
) |
|
|
|
|
|
|
|
// Node is the highest level interface to a full Tendermint node.
|
|
|
|
// nodeImpl is the highest level interface to a full Tendermint node.
|
|
|
|
// It includes all configuration information and running services.
|
|
|
|
type Node struct { |
|
|
|
type nodeImpl struct { |
|
|
|
service.BaseService |
|
|
|
|
|
|
|
// config
|
|
|
@ -89,19 +88,19 @@ type Node struct { |
|
|
|
prometheusSrv *http.Server |
|
|
|
} |
|
|
|
|
|
|
|
// DefaultNewNode returns a Tendermint node with default settings for the
|
|
|
|
// newDefaultNode returns a Tendermint node with default settings for the
|
|
|
|
// PrivValidator, ClientCreator, GenesisDoc, and DBProvider.
|
|
|
|
// It implements NodeProvider.
|
|
|
|
func DefaultNewNode(config *cfg.Config, logger log.Logger) (*Node, error) { |
|
|
|
func newDefaultNode(config *cfg.Config, logger log.Logger) (service.Service, error) { |
|
|
|
nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile()) |
|
|
|
if err != nil { |
|
|
|
return nil, fmt.Errorf("failed to load or gen node key %s: %w", config.NodeKeyFile(), err) |
|
|
|
} |
|
|
|
if config.Mode == cfg.ModeSeed { |
|
|
|
return NewSeedNode(config, |
|
|
|
DefaultDBProvider, |
|
|
|
return makeSeedNode(config, |
|
|
|
cfg.DefaultDBProvider, |
|
|
|
nodeKey, |
|
|
|
DefaultGenesisDocProviderFunc(config), |
|
|
|
defaultGenesisDocProviderFunc(config), |
|
|
|
logger, |
|
|
|
) |
|
|
|
} |
|
|
@ -117,27 +116,24 @@ func DefaultNewNode(config *cfg.Config, logger log.Logger) (*Node, error) { |
|
|
|
} |
|
|
|
|
|
|
|
appClient, _ := proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir()) |
|
|
|
return NewNode(config, |
|
|
|
return makeNode(config, |
|
|
|
pval, |
|
|
|
nodeKey, |
|
|
|
appClient, |
|
|
|
DefaultGenesisDocProviderFunc(config), |
|
|
|
DefaultDBProvider, |
|
|
|
DefaultMetricsProvider(config.Instrumentation), |
|
|
|
defaultGenesisDocProviderFunc(config), |
|
|
|
cfg.DefaultDBProvider, |
|
|
|
logger, |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
// NewNode returns a new, ready to go, Tendermint Node.
|
|
|
|
func NewNode(config *cfg.Config, |
|
|
|
// makeNode returns a new, ready to go, Tendermint Node.
|
|
|
|
func makeNode(config *cfg.Config, |
|
|
|
privValidator types.PrivValidator, |
|
|
|
nodeKey p2p.NodeKey, |
|
|
|
clientCreator proxy.ClientCreator, |
|
|
|
genesisDocProvider GenesisDocProvider, |
|
|
|
dbProvider DBProvider, |
|
|
|
metricsProvider MetricsProvider, |
|
|
|
logger log.Logger, |
|
|
|
options ...Option) (*Node, error) { |
|
|
|
genesisDocProvider genesisDocProvider, |
|
|
|
dbProvider cfg.DBProvider, |
|
|
|
logger log.Logger) (service.Service, error) { |
|
|
|
|
|
|
|
blockStore, stateDB, err := initDBs(config, dbProvider) |
|
|
|
if err != nil { |
|
|
@ -146,7 +142,7 @@ func NewNode(config *cfg.Config, |
|
|
|
|
|
|
|
stateStore := sm.NewStore(stateDB) |
|
|
|
|
|
|
|
state, genDoc, err := LoadStateFromDBOrGenesisDocProvider(stateDB, genesisDocProvider) |
|
|
|
state, genDoc, err := loadStateFromDBOrGenesisDocProvider(stateDB, genesisDocProvider) |
|
|
|
if err != nil { |
|
|
|
return nil, err |
|
|
|
} |
|
|
@ -245,7 +241,7 @@ func NewNode(config *cfg.Config, |
|
|
|
return nil, fmt.Errorf("failed to create peer manager: %w", err) |
|
|
|
} |
|
|
|
|
|
|
|
csMetrics, p2pMetrics, memplMetrics, smMetrics := metricsProvider(genDoc.ChainID) |
|
|
|
csMetrics, p2pMetrics, memplMetrics, smMetrics := defaultMetricsProvider(config.Instrumentation)(genDoc.ChainID) |
|
|
|
|
|
|
|
router, err := createRouter(p2pLogger, p2pMetrics, nodeInfo, nodeKey.PrivKey, |
|
|
|
peerManager, transport, getRouterConfig(config, proxyApp)) |
|
|
@ -412,7 +408,7 @@ func NewNode(config *cfg.Config, |
|
|
|
}() |
|
|
|
} |
|
|
|
|
|
|
|
node := &Node{ |
|
|
|
node := &nodeImpl{ |
|
|
|
config: config, |
|
|
|
genesisDoc: genDoc, |
|
|
|
privValidator: privValidator, |
|
|
@ -446,20 +442,16 @@ func NewNode(config *cfg.Config, |
|
|
|
} |
|
|
|
node.BaseService = *service.NewBaseService(logger, "Node", node) |
|
|
|
|
|
|
|
for _, option := range options { |
|
|
|
option(node) |
|
|
|
} |
|
|
|
|
|
|
|
return node, nil |
|
|
|
} |
|
|
|
|
|
|
|
// NewSeedNode returns a new seed node, containing only p2p, pex reactor
|
|
|
|
func NewSeedNode(config *cfg.Config, |
|
|
|
dbProvider DBProvider, |
|
|
|
// makeSeedNode returns a new seed node, containing only p2p, pex reactor
|
|
|
|
func makeSeedNode(config *cfg.Config, |
|
|
|
dbProvider cfg.DBProvider, |
|
|
|
nodeKey p2p.NodeKey, |
|
|
|
genesisDocProvider GenesisDocProvider, |
|
|
|
genesisDocProvider genesisDocProvider, |
|
|
|
logger log.Logger, |
|
|
|
options ...Option) (*Node, error) { |
|
|
|
) (service.Service, error) { |
|
|
|
|
|
|
|
genDoc, err := genesisDocProvider() |
|
|
|
if err != nil { |
|
|
@ -538,7 +530,7 @@ func NewSeedNode(config *cfg.Config, |
|
|
|
}() |
|
|
|
} |
|
|
|
|
|
|
|
node := &Node{ |
|
|
|
node := &nodeImpl{ |
|
|
|
config: config, |
|
|
|
genesisDoc: genDoc, |
|
|
|
|
|
|
@ -555,58 +547,17 @@ func NewSeedNode(config *cfg.Config, |
|
|
|
} |
|
|
|
node.BaseService = *service.NewBaseService(logger, "SeedNode", node) |
|
|
|
|
|
|
|
for _, option := range options { |
|
|
|
option(node) |
|
|
|
} |
|
|
|
|
|
|
|
return node, nil |
|
|
|
} |
|
|
|
|
|
|
|
// Option sets a parameter for the node.
|
|
|
|
type Option func(*Node) |
|
|
|
|
|
|
|
// Temporary interface for switching to fast sync, we should get rid of v0.
|
|
|
|
// See: https://github.com/tendermint/tendermint/issues/4595
|
|
|
|
type fastSyncReactor interface { |
|
|
|
SwitchToFastSync(sm.State) error |
|
|
|
} |
|
|
|
|
|
|
|
// CustomReactors allows you to add custom reactors (name -> p2p.Reactor) to
|
|
|
|
// the node's Switch.
|
|
|
|
//
|
|
|
|
// WARNING: using any name from the below list of the existing reactors will
|
|
|
|
// result in replacing it with the custom one.
|
|
|
|
//
|
|
|
|
// - MEMPOOL
|
|
|
|
// - BLOCKCHAIN
|
|
|
|
// - CONSENSUS
|
|
|
|
// - EVIDENCE
|
|
|
|
// - PEX
|
|
|
|
// - STATESYNC
|
|
|
|
func CustomReactors(reactors map[string]p2p.Reactor) Option { |
|
|
|
return func(n *Node) { |
|
|
|
for name, reactor := range reactors { |
|
|
|
if existingReactor := n.sw.Reactor(name); existingReactor != nil { |
|
|
|
n.sw.Logger.Info("Replacing existing reactor with a custom one", |
|
|
|
"name", name, "existing", existingReactor, "custom", reactor) |
|
|
|
n.sw.RemoveReactor(name, existingReactor) |
|
|
|
} |
|
|
|
n.sw.AddReactor(name, reactor) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// StateProvider overrides the state provider used by state sync to retrieve trusted app hashes and
|
|
|
|
// build a State object for bootstrapping the node.
|
|
|
|
// WARNING: this interface is considered unstable and subject to change.
|
|
|
|
func StateProvider(stateProvider statesync.StateProvider) Option { |
|
|
|
return func(n *Node) { |
|
|
|
n.stateSyncProvider = stateProvider |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// OnStart starts the Node. It implements service.Service.
|
|
|
|
func (n *Node) OnStart() error { |
|
|
|
func (n *nodeImpl) OnStart() error { |
|
|
|
now := tmtime.Now() |
|
|
|
genTime := n.genesisDoc.GenesisTime |
|
|
|
if genTime.After(now) { |
|
|
@ -712,7 +663,7 @@ func (n *Node) OnStart() error { |
|
|
|
} |
|
|
|
|
|
|
|
// OnStop stops the Node. It implements service.Service.
|
|
|
|
func (n *Node) OnStop() { |
|
|
|
func (n *nodeImpl) OnStop() { |
|
|
|
|
|
|
|
n.Logger.Info("Stopping Node") |
|
|
|
|
|
|
@ -799,7 +750,7 @@ func (n *Node) OnStop() { |
|
|
|
} |
|
|
|
|
|
|
|
// ConfigureRPC makes sure RPC has all the objects it needs to operate.
|
|
|
|
func (n *Node) ConfigureRPC() (*rpccore.Environment, error) { |
|
|
|
func (n *nodeImpl) ConfigureRPC() (*rpccore.Environment, error) { |
|
|
|
rpcCoreEnv := rpccore.Environment{ |
|
|
|
ProxyAppQuery: n.proxyApp.Query(), |
|
|
|
ProxyAppMempool: n.proxyApp.Mempool(), |
|
|
@ -835,7 +786,7 @@ func (n *Node) ConfigureRPC() (*rpccore.Environment, error) { |
|
|
|
return &rpcCoreEnv, nil |
|
|
|
} |
|
|
|
|
|
|
|
func (n *Node) startRPC() ([]net.Listener, error) { |
|
|
|
func (n *nodeImpl) startRPC() ([]net.Listener, error) { |
|
|
|
env, err := n.ConfigureRPC() |
|
|
|
if err != nil { |
|
|
|
return nil, err |
|
|
@ -956,7 +907,7 @@ func (n *Node) startRPC() ([]net.Listener, error) { |
|
|
|
|
|
|
|
// startPrometheusServer starts a Prometheus HTTP server, listening for metrics
|
|
|
|
// collectors on addr.
|
|
|
|
func (n *Node) startPrometheusServer(addr string) *http.Server { |
|
|
|
func (n *nodeImpl) startPrometheusServer(addr string) *http.Server { |
|
|
|
srv := &http.Server{ |
|
|
|
Addr: addr, |
|
|
|
Handler: promhttp.InstrumentMetricHandler( |
|
|
@ -976,90 +927,90 @@ func (n *Node) startPrometheusServer(addr string) *http.Server { |
|
|
|
} |
|
|
|
|
|
|
|
// Switch returns the Node's Switch.
|
|
|
|
func (n *Node) Switch() *p2p.Switch { |
|
|
|
func (n *nodeImpl) Switch() *p2p.Switch { |
|
|
|
return n.sw |
|
|
|
} |
|
|
|
|
|
|
|
// BlockStore returns the Node's BlockStore.
|
|
|
|
func (n *Node) BlockStore() *store.BlockStore { |
|
|
|
func (n *nodeImpl) BlockStore() *store.BlockStore { |
|
|
|
return n.blockStore |
|
|
|
} |
|
|
|
|
|
|
|
// ConsensusState returns the Node's ConsensusState.
|
|
|
|
func (n *Node) ConsensusState() *cs.State { |
|
|
|
func (n *nodeImpl) ConsensusState() *cs.State { |
|
|
|
return n.consensusState |
|
|
|
} |
|
|
|
|
|
|
|
// ConsensusReactor returns the Node's ConsensusReactor.
|
|
|
|
func (n *Node) ConsensusReactor() *cs.Reactor { |
|
|
|
func (n *nodeImpl) ConsensusReactor() *cs.Reactor { |
|
|
|
return n.consensusReactor |
|
|
|
} |
|
|
|
|
|
|
|
// MempoolReactor returns the Node's mempool reactor.
|
|
|
|
func (n *Node) MempoolReactor() service.Service { |
|
|
|
func (n *nodeImpl) MempoolReactor() service.Service { |
|
|
|
return n.mempoolReactor |
|
|
|
} |
|
|
|
|
|
|
|
// Mempool returns the Node's mempool.
|
|
|
|
func (n *Node) Mempool() mempool.Mempool { |
|
|
|
func (n *nodeImpl) Mempool() mempool.Mempool { |
|
|
|
return n.mempool |
|
|
|
} |
|
|
|
|
|
|
|
// PEXReactor returns the Node's PEXReactor. It returns nil if PEX is disabled.
|
|
|
|
func (n *Node) PEXReactor() *pex.Reactor { |
|
|
|
func (n *nodeImpl) PEXReactor() *pex.Reactor { |
|
|
|
return n.pexReactor |
|
|
|
} |
|
|
|
|
|
|
|
// EvidencePool returns the Node's EvidencePool.
|
|
|
|
func (n *Node) EvidencePool() *evidence.Pool { |
|
|
|
func (n *nodeImpl) EvidencePool() *evidence.Pool { |
|
|
|
return n.evidencePool |
|
|
|
} |
|
|
|
|
|
|
|
// EventBus returns the Node's EventBus.
|
|
|
|
func (n *Node) EventBus() *types.EventBus { |
|
|
|
func (n *nodeImpl) EventBus() *types.EventBus { |
|
|
|
return n.eventBus |
|
|
|
} |
|
|
|
|
|
|
|
// PrivValidator returns the Node's PrivValidator.
|
|
|
|
// XXX: for convenience only!
|
|
|
|
func (n *Node) PrivValidator() types.PrivValidator { |
|
|
|
func (n *nodeImpl) PrivValidator() types.PrivValidator { |
|
|
|
return n.privValidator |
|
|
|
} |
|
|
|
|
|
|
|
// GenesisDoc returns the Node's GenesisDoc.
|
|
|
|
func (n *Node) GenesisDoc() *types.GenesisDoc { |
|
|
|
func (n *nodeImpl) GenesisDoc() *types.GenesisDoc { |
|
|
|
return n.genesisDoc |
|
|
|
} |
|
|
|
|
|
|
|
// ProxyApp returns the Node's AppConns, representing its connections to the ABCI application.
|
|
|
|
func (n *Node) ProxyApp() proxy.AppConns { |
|
|
|
func (n *nodeImpl) ProxyApp() proxy.AppConns { |
|
|
|
return n.proxyApp |
|
|
|
} |
|
|
|
|
|
|
|
// Config returns the Node's config.
|
|
|
|
func (n *Node) Config() *cfg.Config { |
|
|
|
func (n *nodeImpl) Config() *cfg.Config { |
|
|
|
return n.config |
|
|
|
} |
|
|
|
|
|
|
|
// EventSinks returns the Node's event indexing sinks.
|
|
|
|
func (n *Node) EventSinks() []indexer.EventSink { |
|
|
|
func (n *nodeImpl) EventSinks() []indexer.EventSink { |
|
|
|
return n.eventSinks |
|
|
|
} |
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
func (n *Node) Listeners() []string { |
|
|
|
func (n *nodeImpl) Listeners() []string { |
|
|
|
return []string{ |
|
|
|
fmt.Sprintf("Listener(@%v)", n.config.P2P.ExternalAddress), |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func (n *Node) IsListening() bool { |
|
|
|
func (n *nodeImpl) IsListening() bool { |
|
|
|
return n.isListening |
|
|
|
} |
|
|
|
|
|
|
|
// NodeInfo returns the Node's Info from the Switch.
|
|
|
|
func (n *Node) NodeInfo() p2p.NodeInfo { |
|
|
|
func (n *nodeImpl) NodeInfo() p2p.NodeInfo { |
|
|
|
return n.nodeInfo |
|
|
|
} |
|
|
|
|
|
|
@ -1119,44 +1070,25 @@ func startStateSync(ssR *statesync.Reactor, bcR fastSyncReactor, conR *cs.Reacto |
|
|
|
return nil |
|
|
|
} |
|
|
|
|
|
|
|
// DBContext specifies config information for loading a new DB.
|
|
|
|
type DBContext struct { |
|
|
|
ID string |
|
|
|
Config *cfg.Config |
|
|
|
} |
|
|
|
|
|
|
|
// DBProvider takes a DBContext and returns an instantiated DB.
|
|
|
|
type DBProvider func(*DBContext) (dbm.DB, error) |
|
|
|
|
|
|
|
// DefaultDBProvider returns a database using the DBBackend and DBDir
|
|
|
|
// specified in the ctx.Config.
|
|
|
|
func DefaultDBProvider(ctx *DBContext) (dbm.DB, error) { |
|
|
|
dbType := dbm.BackendType(ctx.Config.DBBackend) |
|
|
|
return dbm.NewDB(ctx.ID, dbType, ctx.Config.DBDir()) |
|
|
|
} |
|
|
|
|
|
|
|
// GenesisDocProvider returns a GenesisDoc.
|
|
|
|
// genesisDocProvider returns a GenesisDoc.
|
|
|
|
// It allows the GenesisDoc to be pulled from sources other than the
|
|
|
|
// filesystem, for instance from a distributed key-value store cluster.
|
|
|
|
type GenesisDocProvider func() (*types.GenesisDoc, error) |
|
|
|
type genesisDocProvider func() (*types.GenesisDoc, error) |
|
|
|
|
|
|
|
// DefaultGenesisDocProviderFunc returns a GenesisDocProvider that loads
|
|
|
|
// defaultGenesisDocProviderFunc returns a GenesisDocProvider that loads
|
|
|
|
// the GenesisDoc from the config.GenesisFile() on the filesystem.
|
|
|
|
func DefaultGenesisDocProviderFunc(config *cfg.Config) GenesisDocProvider { |
|
|
|
func defaultGenesisDocProviderFunc(config *cfg.Config) genesisDocProvider { |
|
|
|
return func() (*types.GenesisDoc, error) { |
|
|
|
return types.GenesisDocFromFile(config.GenesisFile()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Provider takes a config and a logger and returns a ready to go Node.
|
|
|
|
type Provider func(*cfg.Config, log.Logger) (*Node, error) |
|
|
|
|
|
|
|
// MetricsProvider returns a consensus, p2p and mempool Metrics.
|
|
|
|
type MetricsProvider func(chainID string) (*cs.Metrics, *p2p.Metrics, *mempool.Metrics, *sm.Metrics) |
|
|
|
// metricsProvider returns a consensus, p2p and mempool Metrics.
|
|
|
|
type metricsProvider func(chainID string) (*cs.Metrics, *p2p.Metrics, *mempool.Metrics, *sm.Metrics) |
|
|
|
|
|
|
|
// DefaultMetricsProvider returns Metrics build using Prometheus client library
|
|
|
|
// defaultMetricsProvider returns Metrics build using Prometheus client library
|
|
|
|
// if Prometheus is enabled. Otherwise, it returns no-op Metrics.
|
|
|
|
func DefaultMetricsProvider(config *cfg.InstrumentationConfig) MetricsProvider { |
|
|
|
func defaultMetricsProvider(config *cfg.InstrumentationConfig) metricsProvider { |
|
|
|
return func(chainID string) (*cs.Metrics, *p2p.Metrics, *mempool.Metrics, *sm.Metrics) { |
|
|
|
if config.Prometheus { |
|
|
|
return cs.PrometheusMetrics(config.Namespace, "chain_id", chainID), |
|
|
@ -1174,12 +1106,12 @@ var ( |
|
|
|
genesisDocKey = []byte("genesisDoc") |
|
|
|
) |
|
|
|
|
|
|
|
// LoadStateFromDBOrGenesisDocProvider attempts to load the state from the
|
|
|
|
// loadStateFromDBOrGenesisDocProvider attempts to load the state from the
|
|
|
|
// database, or creates one using the given genesisDocProvider. On success this also
|
|
|
|
// returns the genesis doc loaded through the given provider.
|
|
|
|
func LoadStateFromDBOrGenesisDocProvider( |
|
|
|
func loadStateFromDBOrGenesisDocProvider( |
|
|
|
stateDB dbm.DB, |
|
|
|
genesisDocProvider GenesisDocProvider, |
|
|
|
genesisDocProvider genesisDocProvider, |
|
|
|
) (sm.State, *types.GenesisDoc, error) { |
|
|
|
// Get genesis doc
|
|
|
|
genDoc, err := loadGenesisDoc(stateDB) |
|
|
|