From f76684a05c9e179f8b5fcb528d90b74a1956b4b9 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Wed, 3 Jul 2019 17:17:59 +0400 Subject: [PATCH] node: allow registration of custom reactors while creating node (#3771) * change invocation of NewNode across * custom reactor name are prefixed with CUSTOM_ * upgate changelog pending * improve comments * node: refactor NewNode to use functional options --- CHANGELOG_PENDING.md | 4 ++++ node/node.go | 25 ++++++++++++++++++++++++- node/node_test.go | 34 +++++++++++++++++++++++++++++++++- p2p/mock/reactor.go | 23 +++++++++++++++++++++++ 4 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 p2p/mock/reactor.go diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index fa81d9bbb..5a747650e 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -26,6 +26,10 @@ program](https://hackerone.com/tendermint). * P2P Protocol ### FEATURES: +- [node] Refactor `NewNode` to use functional options to make it more flexible + and extensible in the future. +- [node] [\#3730](https://github.com/tendermint/tendermint/pull/3730) Add `CustomReactors` option to `NewNode` allowing caller to pass + custom reactors to run inside Tendermint node (@ParthDesai) ### IMPROVEMENTS: - [rpc] \#3700 Make possible to set absolute paths for TLS cert and key (@climber73) diff --git a/node/node.go b/node/node.go index c992e2424..9beb0669f 100644 --- a/node/node.go +++ b/node/node.go @@ -47,6 +47,10 @@ import ( "github.com/tendermint/tendermint/version" ) +// CustomReactorNamePrefix is a prefix for all custom reactors to prevent +// clashes with built-in reactors. +const CustomReactorNamePrefix = "CUSTOM_" + //------------------------------------------------------------------------------ // DBContext specifies config information for loading a new DB. @@ -136,6 +140,18 @@ func DefaultMetricsProvider(config *cfg.InstrumentationConfig) MetricsProvider { } } +// Option sets a parameter for the node. +type Option func(*Node) + +// CustomReactors allows you to add custom reactors to the node's Switch. +func CustomReactors(reactors map[string]p2p.Reactor) Option { + return func(n *Node) { + for name, reactor := range reactors { + n.sw.AddReactor(CustomReactorNamePrefix+name, reactor) + } + } +} + //------------------------------------------------------------------------------ // Node is the highest level interface to a full Tendermint node. @@ -433,6 +449,7 @@ func createSwitch(config *cfg.Config, sw.AddReactor("BLOCKCHAIN", bcReactor) sw.AddReactor("CONSENSUS", consensusReactor) sw.AddReactor("EVIDENCE", evidenceReactor) + sw.SetNodeInfo(nodeInfo) sw.SetNodeKey(nodeKey) @@ -495,7 +512,8 @@ func NewNode(config *cfg.Config, genesisDocProvider GenesisDocProvider, dbProvider DBProvider, metricsProvider MetricsProvider, - logger log.Logger) (*Node, error) { + logger log.Logger, + options ...Option) (*Node, error) { blockStore, stateDB, err := initDBs(config, dbProvider) if err != nil { @@ -661,6 +679,11 @@ func NewNode(config *cfg.Config, eventBus: eventBus, } node.BaseService = *cmn.NewBaseService(logger, "Node", node) + + for _, option := range options { + option(node) + } + return node, nil } diff --git a/node/node_test.go b/node/node_test.go index ce4e82c2d..841a04686 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -21,6 +21,7 @@ import ( "github.com/tendermint/tendermint/libs/log" mempl "github.com/tendermint/tendermint/mempool" "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" @@ -100,7 +101,10 @@ func TestNodeDelayedStart(t *testing.T) { n.GenesisDoc().GenesisTime = now.Add(2 * time.Second) require.NoError(t, err) - n.Start() + err = n.Start() + require.NoError(t, err) + defer n.Stop() + startTime := tmtime.Now() assert.Equal(t, true, startTime.After(n.GenesisDoc().GenesisTime)) } @@ -279,6 +283,34 @@ func TestCreateProposalBlock(t *testing.T) { assert.NoError(t, err) } +func TestNodeNewNodeCustomReactors(t *testing.T) { + config := cfg.ResetTestRoot("node_new_node_custom_reactors_test") + defer os.RemoveAll(config.RootDir) + + cr := p2pmock.NewReactor() + + nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile()) + require.NoError(t, err) + + n, err := NewNode(config, + privval.LoadOrGenFilePV(config.PrivValidatorKeyFile(), config.PrivValidatorStateFile()), + nodeKey, + proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir()), + DefaultGenesisDocProviderFunc(config), + DefaultDBProvider, + DefaultMetricsProvider(config.Instrumentation), + log.TestingLogger(), + CustomReactors(map[string]p2p.Reactor{"FOO": cr}), + ) + require.NoError(t, err) + + err = n.Start() + require.NoError(t, err) + defer n.Stop() + + assert.True(t, cr.IsRunning()) +} + func state(nVals int, height int64) (sm.State, dbm.DB) { vals := make([]types.GenesisValidator, nVals) for i := 0; i < nVals; i++ { diff --git a/p2p/mock/reactor.go b/p2p/mock/reactor.go new file mode 100644 index 000000000..cfce12bd1 --- /dev/null +++ b/p2p/mock/reactor.go @@ -0,0 +1,23 @@ +package mock + +import ( + "github.com/tendermint/tendermint/libs/log" + "github.com/tendermint/tendermint/p2p" + "github.com/tendermint/tendermint/p2p/conn" +) + +type Reactor struct { + p2p.BaseReactor +} + +func NewReactor() *Reactor { + r := &Reactor{} + r.BaseReactor = *p2p.NewBaseReactor("Reactor", r) + r.SetLogger(log.TestingLogger()) + return r +} + +func (r *Reactor) GetChannels() []*conn.ChannelDescriptor { return []*conn.ChannelDescriptor{} } +func (r *Reactor) AddPeer(peer p2p.Peer) {} +func (r *Reactor) RemovePeer(peer p2p.Peer, reason interface{}) {} +func (r *Reactor) Receive(chID byte, peer p2p.Peer, msgBytes []byte) {}