Browse Source

node: change package interface (#6540)

callum/config
Sam Kleinman 3 years ago
committed by GitHub
parent
commit
00c284d9d7
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 227 additions and 343 deletions
  1. +2
    -3
      cmd/tendermint/commands/run_node.go
  2. +2
    -2
      cmd/tendermint/main.go
  3. +26
    -0
      config/db.go
  4. +3
    -37
      node/doc.go
  5. +0
    -35
      node/id.go
  6. +59
    -127
      node/node.go
  7. +40
    -78
      node/node_test.go
  8. +67
    -0
      node/public.go
  9. +9
    -9
      node/setup.go
  10. +1
    -17
      rpc/test/helpers.go
  11. +18
    -35
      test/e2e/app/main.go

+ 2
- 3
cmd/tendermint/commands/run_node.go View File

@ -11,7 +11,6 @@ import (
cfg "github.com/tendermint/tendermint/config"
tmos "github.com/tendermint/tendermint/libs/os"
nm "github.com/tendermint/tendermint/node"
)
var (
@ -99,7 +98,7 @@ func AddNodeFlags(cmd *cobra.Command) {
// NewRunNodeCmd returns the command that allows the CLI to start a node.
// It can be used with a custom PrivValidator and in-process ABCI application.
func NewRunNodeCmd(nodeProvider nm.Provider) *cobra.Command {
func NewRunNodeCmd(nodeProvider cfg.ServiceProvider) *cobra.Command {
cmd := &cobra.Command{
Use: "start",
Aliases: []string{"node", "run"},
@ -118,7 +117,7 @@ func NewRunNodeCmd(nodeProvider nm.Provider) *cobra.Command {
return fmt.Errorf("failed to start node: %w", err)
}
logger.Info("Started node", "nodeInfo", n.NodeInfo())
logger.Info("started node", "node", n.String())
// Stop upon receiving SIGTERM or CTRL-C.
tmos.TrapSignal(logger, func() {


+ 2
- 2
cmd/tendermint/main.go View File

@ -38,8 +38,8 @@ func main() {
// * Supply a genesis doc file from another source
// * Provide their own DB implementation
// can copy this file and use something other than the
// DefaultNewNode function
nodeFunc := nm.DefaultNewNode
// node.NewDefault function
nodeFunc := nm.NewDefault
// Create & start node
rootCmd.AddCommand(cmd.NewRunNodeCmd(nodeFunc))


+ 26
- 0
config/db.go View File

@ -0,0 +1,26 @@
package config
import (
"github.com/tendermint/tendermint/libs/log"
"github.com/tendermint/tendermint/libs/service"
db "github.com/tendermint/tm-db"
)
// ServiceProvider takes a config and a logger and returns a ready to go Node.
type ServiceProvider func(*Config, log.Logger) (service.Service, error)
// DBContext specifies config information for loading a new DB.
type DBContext struct {
ID string
Config *Config
}
// DBProvider takes a DBContext and returns an instantiated DB.
type DBProvider func(*DBContext) (db.DB, error)
// DefaultDBProvider returns a database using the DBBackend and DBDir
// specified in the Config.
func DefaultDBProvider(ctx *DBContext) (db.DB, error) {
dbType := db.BackendType(ctx.Config.DBBackend)
return db.NewDB(ctx.ID, dbType, ctx.Config.DBDir())
}

+ 3
- 37
node/doc.go View File

@ -1,40 +1,6 @@
/*
Package node is the main entry point, where the Node struct, which
represents a full node, is defined.
Adding new p2p.Reactor(s)
To add a new p2p.Reactor, use the CustomReactors option:
node, err := NewNode(
config,
privVal,
nodeKey,
clientCreator,
genesisDocProvider,
dbProvider,
metricsProvider,
logger,
CustomReactors(map[string]p2p.Reactor{"CUSTOM": customReactor}),
)
Replacing existing p2p.Reactor(s)
To replace the built-in p2p.Reactor, use the CustomReactors option:
node, err := NewNode(
config,
privVal,
nodeKey,
clientCreator,
genesisDocProvider,
dbProvider,
metricsProvider,
logger,
CustomReactors(map[string]p2p.Reactor{"BLOCKCHAIN": customBlockchainReactor}),
)
The list of existing reactors can be found in CustomReactors documentation.
Package node is the main entry point, where the tendermint node
service is constructed and the implementation of that service is
defined.
*/
package node

+ 0
- 35
node/id.go View File

@ -1,35 +0,0 @@
package node
import (
"time"
"github.com/tendermint/tendermint/crypto"
)
type ID struct {
Name string
PubKey crypto.PubKey
}
type PrivNodeID struct {
ID
PrivKey crypto.PrivKey
}
type Greeting struct {
ID
Version string
ChainID string
Message string
Time time.Time
}
type SignedNodeGreeting struct {
Greeting
Signature []byte
}
func (pnid *PrivNodeID) SignGreeting() *SignedNodeGreeting {
// greeting := NodeGreeting{}
return nil
}

+ 59
- 127
node/node.go View File

@ -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)


+ 40
- 78
node/node_test.go View File

@ -27,7 +27,6 @@ import (
"github.com/tendermint/tendermint/mempool"
mempoolv0 "github.com/tendermint/tendermint/mempool/v0"
"github.com/tendermint/tendermint/p2p"
p2pmock "github.com/tendermint/tendermint/p2p/mock"
"github.com/tendermint/tendermint/privval"
"github.com/tendermint/tendermint/proxy"
sm "github.com/tendermint/tendermint/state"
@ -42,10 +41,12 @@ func TestNodeStartStop(t *testing.T) {
defer os.RemoveAll(config.RootDir)
// create & start node
n, err := DefaultNewNode(config, log.TestingLogger())
require.NoError(t, err)
err = n.Start()
ns, err := newDefaultNode(config, log.TestingLogger())
require.NoError(t, err)
require.NoError(t, ns.Start())
n, ok := ns.(*nodeImpl)
require.True(t, ok)
t.Logf("Started node %v", n.sw.NodeInfo())
@ -80,18 +81,26 @@ func TestNodeStartStop(t *testing.T) {
}
}
func getTestNode(t *testing.T, conf *cfg.Config, logger log.Logger) *nodeImpl {
t.Helper()
ns, err := newDefaultNode(conf, logger)
require.NoError(t, err)
n, ok := ns.(*nodeImpl)
require.True(t, ok)
return n
}
func TestNodeDelayedStart(t *testing.T) {
config := cfg.ResetTestRoot("node_delayed_start_test")
defer os.RemoveAll(config.RootDir)
now := tmtime.Now()
// create & start node
n, err := DefaultNewNode(config, log.TestingLogger())
n := getTestNode(t, config, log.TestingLogger())
n.GenesisDoc().GenesisTime = now.Add(2 * time.Second)
require.NoError(t, err)
err = n.Start()
require.NoError(t, err)
require.NoError(t, n.Start())
defer n.Stop() //nolint:errcheck // ignore for tests
startTime := tmtime.Now()
@ -102,9 +111,8 @@ func TestNodeSetAppVersion(t *testing.T) {
config := cfg.ResetTestRoot("node_app_version_test")
defer os.RemoveAll(config.RootDir)
// create & start node
n, err := DefaultNewNode(config, log.TestingLogger())
require.NoError(t, err)
// create node
n := getTestNode(t, config, log.TestingLogger())
// default config uses the kvstore app
var appVersion uint64 = kvstore.ProtocolVersion
@ -146,8 +154,7 @@ func TestNodeSetPrivValTCP(t *testing.T) {
}()
defer signerServer.Stop() //nolint:errcheck // ignore for tests
n, err := DefaultNewNode(config, log.TestingLogger())
require.NoError(t, err)
n := getTestNode(t, config, log.TestingLogger())
assert.IsType(t, &privval.RetrySignerClient{}, n.PrivValidator())
}
@ -159,7 +166,7 @@ func TestPrivValidatorListenAddrNoProtocol(t *testing.T) {
defer os.RemoveAll(config.RootDir)
config.PrivValidator.ListenAddr = addrNoPrefix
_, err := DefaultNewNode(config, log.TestingLogger())
_, err := newDefaultNode(config, log.TestingLogger())
assert.Error(t, err)
}
@ -189,9 +196,7 @@ func TestNodeSetPrivValIPC(t *testing.T) {
require.NoError(t, err)
}()
defer pvsc.Stop() //nolint:errcheck // ignore for tests
n, err := DefaultNewNode(config, log.TestingLogger())
require.NoError(t, err)
n := getTestNode(t, config, log.TestingLogger())
assert.IsType(t, &privval.RetrySignerClient{}, n.PrivValidator())
}
@ -470,43 +475,6 @@ func TestMaxProposalBlockSize(t *testing.T) {
}
func TestNodeNewNodeCustomReactors(t *testing.T) {
config := cfg.ResetTestRoot("node_new_node_custom_reactors_test")
defer os.RemoveAll(config.RootDir)
cr := p2pmock.NewReactor()
customBlockchainReactor := p2pmock.NewReactor()
nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
require.NoError(t, err)
pval, err := privval.LoadOrGenFilePV(config.PrivValidatorKeyFile(), config.PrivValidatorStateFile())
require.NoError(t, err)
appClient, closer := proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir())
t.Cleanup(func() { closer.Close() })
n, err := NewNode(config,
pval,
nodeKey,
appClient,
DefaultGenesisDocProviderFunc(config),
DefaultDBProvider,
DefaultMetricsProvider(config.Instrumentation),
log.TestingLogger(),
CustomReactors(map[string]p2p.Reactor{"FOO": cr, "BLOCKCHAIN": customBlockchainReactor}),
)
require.NoError(t, err)
err = n.Start()
require.NoError(t, err)
defer n.Stop() //nolint:errcheck // ignore for tests
assert.True(t, cr.IsRunning())
assert.Equal(t, cr, n.Switch().Reactor("FOO"))
assert.True(t, customBlockchainReactor.IsRunning())
assert.Equal(t, customBlockchainReactor, n.Switch().Reactor("BLOCKCHAIN"))
}
func TestNodeNewSeedNode(t *testing.T) {
config := cfg.ResetTestRoot("node_new_node_custom_reactors_test")
config.Mode = cfg.ModeSeed
@ -515,13 +483,15 @@ func TestNodeNewSeedNode(t *testing.T) {
nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
require.NoError(t, err)
n, err := NewSeedNode(config,
DefaultDBProvider,
ns, err := makeSeedNode(config,
cfg.DefaultDBProvider,
nodeKey,
DefaultGenesisDocProviderFunc(config),
defaultGenesisDocProviderFunc(config),
log.TestingLogger(),
)
require.NoError(t, err)
n, ok := ns.(*nodeImpl)
require.True(t, ok)
err = n.Start()
require.NoError(t, err)
@ -533,58 +503,51 @@ func TestNodeSetEventSink(t *testing.T) {
config := cfg.ResetTestRoot("node_app_version_test")
defer os.RemoveAll(config.RootDir)
// create & start node
n, err := DefaultNewNode(config, log.TestingLogger())
require.NoError(t, err)
n := getTestNode(t, config, log.TestingLogger())
assert.Equal(t, 1, len(n.eventSinks))
assert.Equal(t, indexer.KV, n.eventSinks[0].Type())
config.TxIndex.Indexer = []string{"null"}
n, err = DefaultNewNode(config, log.TestingLogger())
require.NoError(t, err)
n = getTestNode(t, config, log.TestingLogger())
assert.Equal(t, 1, len(n.eventSinks))
assert.Equal(t, indexer.NULL, n.eventSinks[0].Type())
config.TxIndex.Indexer = []string{"null", "kv"}
n, err = DefaultNewNode(config, log.TestingLogger())
require.NoError(t, err)
n = getTestNode(t, config, log.TestingLogger())
assert.Equal(t, 1, len(n.eventSinks))
assert.Equal(t, indexer.NULL, n.eventSinks[0].Type())
config.TxIndex.Indexer = []string{"kvv"}
n, err = DefaultNewNode(config, log.TestingLogger())
assert.Nil(t, n)
ns, err := newDefaultNode(config, log.TestingLogger())
assert.Nil(t, ns)
assert.Equal(t, errors.New("unsupported event sink type"), err)
config.TxIndex.Indexer = []string{}
n, err = DefaultNewNode(config, log.TestingLogger())
require.NoError(t, err)
n = getTestNode(t, config, log.TestingLogger())
assert.Equal(t, 1, len(n.eventSinks))
assert.Equal(t, indexer.NULL, n.eventSinks[0].Type())
config.TxIndex.Indexer = []string{"psql"}
n, err = DefaultNewNode(config, log.TestingLogger())
assert.Nil(t, n)
ns, err = newDefaultNode(config, log.TestingLogger())
assert.Nil(t, ns)
assert.Equal(t, errors.New("the psql connection settings cannot be empty"), err)
var psqlConn = "test"
config.TxIndex.Indexer = []string{"psql"}
config.TxIndex.PsqlConn = psqlConn
n, err = DefaultNewNode(config, log.TestingLogger())
require.NoError(t, err)
n = getTestNode(t, config, log.TestingLogger())
assert.Equal(t, 1, len(n.eventSinks))
assert.Equal(t, indexer.PSQL, n.eventSinks[0].Type())
n.OnStop()
config.TxIndex.Indexer = []string{"psql", "kv"}
config.TxIndex.PsqlConn = psqlConn
n, err = DefaultNewNode(config, log.TestingLogger())
require.NoError(t, err)
n = getTestNode(t, config, log.TestingLogger())
assert.Equal(t, 2, len(n.eventSinks))
// we use map to filter the duplicated sinks, so it's not guarantee the order when append sinks.
if n.eventSinks[0].Type() == indexer.KV {
@ -597,8 +560,7 @@ func TestNodeSetEventSink(t *testing.T) {
config.TxIndex.Indexer = []string{"kv", "psql"}
config.TxIndex.PsqlConn = psqlConn
n, err = DefaultNewNode(config, log.TestingLogger())
require.NoError(t, err)
n = getTestNode(t, config, log.TestingLogger())
assert.Equal(t, 2, len(n.eventSinks))
if n.eventSinks[0].Type() == indexer.KV {
assert.Equal(t, indexer.PSQL, n.eventSinks[1].Type())
@ -611,13 +573,13 @@ func TestNodeSetEventSink(t *testing.T) {
var e = errors.New("found duplicated sinks, please check the tx-index section in the config.toml")
config.TxIndex.Indexer = []string{"psql", "kv", "Kv"}
config.TxIndex.PsqlConn = psqlConn
_, err = DefaultNewNode(config, log.TestingLogger())
_, err = newDefaultNode(config, log.TestingLogger())
require.Error(t, err)
assert.Equal(t, e, err)
config.TxIndex.Indexer = []string{"Psql", "kV", "kv", "pSql"}
config.TxIndex.PsqlConn = psqlConn
_, err = DefaultNewNode(config, log.TestingLogger())
_, err = newDefaultNode(config, log.TestingLogger())
require.Error(t, err)
assert.Equal(t, e, err)
}


+ 67
- 0
node/public.go View File

@ -0,0 +1,67 @@
// Package node provides a high level wrapper around tendermint services.
package node
import (
"fmt"
"github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/libs/log"
"github.com/tendermint/tendermint/libs/service"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/privval"
"github.com/tendermint/tendermint/proxy"
"github.com/tendermint/tendermint/types"
)
// NewDefault constructs a tendermint node service for use in go
// process that host their own process-local tendermint node. This is
// equivalent to running tendermint in it's own process communicating
// to an external ABCI application.
func NewDefault(conf *config.Config, logger log.Logger) (service.Service, error) {
return newDefaultNode(conf, logger)
}
// New constructs a tendermint node. The ClientCreator makes it
// possible to construct an ABCI application that runs in the same
// process as the tendermint node. The final option is a pointer to a
// Genesis document: if the value is nil, the genesis document is read
// from the file specified in the config, and otherwise the node uses
// value of the final argument.
func New(conf *config.Config,
logger log.Logger,
cf proxy.ClientCreator,
gen *types.GenesisDoc,
) (service.Service, error) {
nodeKey, err := p2p.LoadOrGenNodeKey(conf.NodeKeyFile())
if err != nil {
return nil, fmt.Errorf("failed to load or gen node key %s: %w", conf.NodeKeyFile(), err)
}
var genProvider genesisDocProvider
switch gen {
case nil:
genProvider = defaultGenesisDocProviderFunc(conf)
default:
genProvider = func() (*types.GenesisDoc, error) { return gen, nil }
}
switch conf.Mode {
case config.ModeFull, config.ModeValidator:
pval, err := privval.LoadOrGenFilePV(conf.PrivValidatorKeyFile(), conf.PrivValidatorStateFile())
if err != nil {
return nil, err
}
return makeNode(conf,
pval,
nodeKey,
cf,
genProvider,
config.DefaultDBProvider,
logger)
case config.ModeSeed:
return makeSeedNode(conf, config.DefaultDBProvider, nodeKey, genProvider, logger)
default:
return nil, fmt.Errorf("%q is not a valid mode", conf.Mode)
}
}

+ 9
- 9
node/setup.go View File

@ -41,15 +41,15 @@ import (
"github.com/tendermint/tendermint/version"
)
func initDBs(config *cfg.Config, dbProvider DBProvider) (blockStore *store.BlockStore, stateDB dbm.DB, err error) {
func initDBs(config *cfg.Config, dbProvider cfg.DBProvider) (blockStore *store.BlockStore, stateDB dbm.DB, err error) {
var blockStoreDB dbm.DB
blockStoreDB, err = dbProvider(&DBContext{"blockstore", config})
blockStoreDB, err = dbProvider(&cfg.DBContext{ID: "blockstore", Config: config})
if err != nil {
return
}
blockStore = store.NewBlockStore(blockStoreDB)
stateDB, err = dbProvider(&DBContext{"state", config})
stateDB, err = dbProvider(&cfg.DBContext{ID: "state", Config: config})
return
}
@ -73,7 +73,7 @@ func createAndStartEventBus(logger log.Logger) (*types.EventBus, error) {
func createAndStartIndexerService(
config *cfg.Config,
dbProvider DBProvider,
dbProvider cfg.DBProvider,
eventBus *types.EventBus,
logger log.Logger,
chainID string,
@ -99,7 +99,7 @@ loop:
eventSinks = []indexer.EventSink{null.NewEventSink()}
break loop
case string(indexer.KV):
store, err := dbProvider(&DBContext{"tx_index", config})
store, err := dbProvider(&cfg.DBContext{ID: "tx_index", Config: config})
if err != nil {
return nil, nil, err
}
@ -278,14 +278,14 @@ func createMempoolReactor(
func createEvidenceReactor(
config *cfg.Config,
dbProvider DBProvider,
dbProvider cfg.DBProvider,
stateDB dbm.DB,
blockStore *store.BlockStore,
peerManager *p2p.PeerManager,
router *p2p.Router,
logger log.Logger,
) (*p2p.ReactorShim, *evidence.Reactor, *evidence.Pool, error) {
evidenceDB, err := dbProvider(&DBContext{"evidence", config})
evidenceDB, err := dbProvider(&cfg.DBContext{ID: "evidence", Config: config})
if err != nil {
return nil, nil, nil, err
}
@ -450,7 +450,7 @@ func createTransport(logger log.Logger, config *cfg.Config) *p2p.MConnTransport
func createPeerManager(
config *cfg.Config,
dbProvider DBProvider,
dbProvider cfg.DBProvider,
p2pLogger log.Logger,
nodeID p2p.NodeID,
) (*p2p.PeerManager, error) {
@ -513,7 +513,7 @@ func createPeerManager(
peers = append(peers, address)
}
peerDB, err := dbProvider(&DBContext{"peerstore", config})
peerDB, err := dbProvider(&cfg.DBContext{ID: "peerstore", Config: config})
if err != nil {
return nil, err
}


+ 1
- 17
rpc/test/helpers.go View File

@ -14,8 +14,6 @@ import (
tmnet "github.com/tendermint/tendermint/libs/net"
"github.com/tendermint/tendermint/libs/service"
nm "github.com/tendermint/tendermint/node"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/privval"
"github.com/tendermint/tendermint/proxy"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
core_grpc "github.com/tendermint/tendermint/rpc/grpc"
@ -118,22 +116,8 @@ func StartTendermint(ctx context.Context,
logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout))
logger = log.NewFilter(logger, log.AllowError())
}
pvKeyFile := conf.PrivValidatorKeyFile()
pvKeyStateFile := conf.PrivValidatorStateFile()
pv, err := privval.LoadOrGenFilePV(pvKeyFile, pvKeyStateFile)
if err != nil {
return nil, func(_ context.Context) error { return nil }, err
}
papp := proxy.NewLocalClientCreator(app)
nodeKey, err := p2p.LoadOrGenNodeKey(conf.NodeKeyFile())
if err != nil {
return nil, func(_ context.Context) error { return nil }, err
}
node, err := nm.NewNode(conf, pv, nodeKey, papp,
nm.DefaultGenesisDocProviderFunc(conf),
nm.DefaultDBProvider,
nm.DefaultMetricsProvider(conf.Instrumentation),
logger)
node, err := nm.New(conf, logger, papp, nil)
if err != nil {
return nil, func(_ context.Context) error { return nil }, err
}


+ 18
- 35
test/e2e/app/main.go View File

@ -124,23 +124,15 @@ func startNode(cfg *Config) error {
return err
}
tmcfg, nodeLogger, nodeKey, err := setupNode()
tmcfg, nodeLogger, err := setupNode()
if err != nil {
return fmt.Errorf("failed to setup config: %w", err)
}
pval, err := privval.LoadOrGenFilePV(tmcfg.PrivValidatorKeyFile(), tmcfg.PrivValidatorStateFile())
if err != nil {
return err
}
n, err := node.NewNode(tmcfg,
pval,
*nodeKey,
proxy.NewLocalClientCreator(app),
node.DefaultGenesisDocProviderFunc(tmcfg),
node.DefaultDBProvider,
node.DefaultMetricsProvider(tmcfg.Instrumentation),
n, err := node.New(tmcfg,
nodeLogger,
proxy.NewLocalClientCreator(app),
nil,
)
if err != nil {
return err
@ -149,18 +141,14 @@ func startNode(cfg *Config) error {
}
func startSeedNode(cfg *Config) error {
tmcfg, nodeLogger, nodeKey, err := setupNode()
tmcfg, nodeLogger, err := setupNode()
if err != nil {
return fmt.Errorf("failed to setup config: %w", err)
}
n, err := node.NewSeedNode(
tmcfg,
node.DefaultDBProvider,
*nodeKey,
node.DefaultGenesisDocProviderFunc(tmcfg),
nodeLogger,
)
tmcfg.Mode = config.ModeSeed
n, err := node.New(tmcfg, nodeLogger, nil, nil)
if err != nil {
return err
}
@ -168,13 +156,13 @@ func startSeedNode(cfg *Config) error {
}
func startLightNode(cfg *Config) error {
tmcfg, nodeLogger, _, err := setupNode()
tmcfg, nodeLogger, err := setupNode()
if err != nil {
return err
}
dbContext := &node.DBContext{ID: "light", Config: tmcfg}
lightDB, err := node.DefaultDBProvider(dbContext)
dbContext := &config.DBContext{ID: "light", Config: tmcfg}
lightDB, err := config.DefaultDBProvider(dbContext)
if err != nil {
return err
}
@ -272,31 +260,31 @@ func startSigner(cfg *Config) error {
return nil
}
func setupNode() (*config.Config, log.Logger, *p2p.NodeKey, error) {
func setupNode() (*config.Config, log.Logger, error) {
var tmcfg *config.Config
home := os.Getenv("TMHOME")
if home == "" {
return nil, nil, nil, errors.New("TMHOME not set")
return nil, nil, errors.New("TMHOME not set")
}
viper.AddConfigPath(filepath.Join(home, "config"))
viper.SetConfigName("config")
if err := viper.ReadInConfig(); err != nil {
return nil, nil, nil, err
return nil, nil, err
}
tmcfg = config.DefaultConfig()
if err := viper.Unmarshal(tmcfg); err != nil {
return nil, nil, nil, err
return nil, nil, err
}
tmcfg.SetRoot(home)
if err := tmcfg.ValidateBasic(); err != nil {
return nil, nil, nil, fmt.Errorf("error in config file: %w", err)
return nil, nil, fmt.Errorf("error in config file: %w", err)
}
if tmcfg.LogFormat == config.LogFormatJSON {
@ -305,17 +293,12 @@ func setupNode() (*config.Config, log.Logger, *p2p.NodeKey, error) {
nodeLogger, err := tmflags.ParseLogLevel(tmcfg.LogLevel, logger, config.DefaultLogLevel)
if err != nil {
return nil, nil, nil, err
return nil, nil, err
}
nodeLogger = nodeLogger.With("module", "main")
nodeKey, err := p2p.LoadOrGenNodeKey(tmcfg.NodeKeyFile())
if err != nil {
return nil, nil, nil, fmt.Errorf("failed to load or gen node key %s: %w", tmcfg.NodeKeyFile(), err)
}
return tmcfg, nodeLogger, &nodeKey, nil
return tmcfg, nodeLogger, nil
}
// rpcEndpoints takes a list of persistent peers and splits them into a list of rpc endpoints


Loading…
Cancel
Save