You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1556 lines
47 KiB

p2p: implement new Transport interface (#5791) This implements a new `Transport` interface and related types for the P2P refactor in #5670. Previously, `conn.MConnection` was very tightly coupled to the `Peer` implementation -- in order to allow alternative non-multiplexed transports (e.g. QUIC), MConnection has now been moved below the `Transport` interface, as `MConnTransport`, and decoupled from the peer. Since the `p2p` package is not covered by our Go API stability, this is not considered a breaking change, and not listed in the changelog. The initial approach was to implement the new interface in its final form (which also involved possible protocol changes, see https://github.com/tendermint/spec/pull/227). However, it turned out that this would require a large amount of changes to existing P2P code because of the previous tight coupling between `Peer` and `MConnection` and the reliance on subtleties in the MConnection behavior. Instead, I have broadened the `Transport` interface to expose much of the existing MConnection interface, preserved much of the existing MConnection logic and behavior in the transport implementation, and tried to make as few changes to the rest of the P2P stack as possible. We will instead reduce this interface gradually as we refactor other parts of the P2P stack. The low-level transport code and protocol (e.g. MConnection, SecretConnection and so on) has not been significantly changed, and refactoring this is not a priority until we come up with a plan for QUIC adoption, as we may end up discarding the MConnection code entirely. There are no tests of the new `MConnTransport`, as this code is likely to evolve as we proceed with the P2P refactor, but tests should be added before a final release. The E2E tests are sufficient for basic validation in the meanwhile.
4 years ago
p2p: implement new Transport interface (#5791) This implements a new `Transport` interface and related types for the P2P refactor in #5670. Previously, `conn.MConnection` was very tightly coupled to the `Peer` implementation -- in order to allow alternative non-multiplexed transports (e.g. QUIC), MConnection has now been moved below the `Transport` interface, as `MConnTransport`, and decoupled from the peer. Since the `p2p` package is not covered by our Go API stability, this is not considered a breaking change, and not listed in the changelog. The initial approach was to implement the new interface in its final form (which also involved possible protocol changes, see https://github.com/tendermint/spec/pull/227). However, it turned out that this would require a large amount of changes to existing P2P code because of the previous tight coupling between `Peer` and `MConnection` and the reliance on subtleties in the MConnection behavior. Instead, I have broadened the `Transport` interface to expose much of the existing MConnection interface, preserved much of the existing MConnection logic and behavior in the transport implementation, and tried to make as few changes to the rest of the P2P stack as possible. We will instead reduce this interface gradually as we refactor other parts of the P2P stack. The low-level transport code and protocol (e.g. MConnection, SecretConnection and so on) has not been significantly changed, and refactoring this is not a priority until we come up with a plan for QUIC adoption, as we may end up discarding the MConnection code entirely. There are no tests of the new `MConnTransport`, as this code is likely to evolve as we proceed with the P2P refactor, but tests should be added before a final release. The E2E tests are sufficient for basic validation in the meanwhile.
4 years ago
p2p: implement new Transport interface (#5791) This implements a new `Transport` interface and related types for the P2P refactor in #5670. Previously, `conn.MConnection` was very tightly coupled to the `Peer` implementation -- in order to allow alternative non-multiplexed transports (e.g. QUIC), MConnection has now been moved below the `Transport` interface, as `MConnTransport`, and decoupled from the peer. Since the `p2p` package is not covered by our Go API stability, this is not considered a breaking change, and not listed in the changelog. The initial approach was to implement the new interface in its final form (which also involved possible protocol changes, see https://github.com/tendermint/spec/pull/227). However, it turned out that this would require a large amount of changes to existing P2P code because of the previous tight coupling between `Peer` and `MConnection` and the reliance on subtleties in the MConnection behavior. Instead, I have broadened the `Transport` interface to expose much of the existing MConnection interface, preserved much of the existing MConnection logic and behavior in the transport implementation, and tried to make as few changes to the rest of the P2P stack as possible. We will instead reduce this interface gradually as we refactor other parts of the P2P stack. The low-level transport code and protocol (e.g. MConnection, SecretConnection and so on) has not been significantly changed, and refactoring this is not a priority until we come up with a plan for QUIC adoption, as we may end up discarding the MConnection code entirely. There are no tests of the new `MConnTransport`, as this code is likely to evolve as we proceed with the P2P refactor, but tests should be added before a final release. The E2E tests are sufficient for basic validation in the meanwhile.
4 years ago
p2p: implement new Transport interface (#5791) This implements a new `Transport` interface and related types for the P2P refactor in #5670. Previously, `conn.MConnection` was very tightly coupled to the `Peer` implementation -- in order to allow alternative non-multiplexed transports (e.g. QUIC), MConnection has now been moved below the `Transport` interface, as `MConnTransport`, and decoupled from the peer. Since the `p2p` package is not covered by our Go API stability, this is not considered a breaking change, and not listed in the changelog. The initial approach was to implement the new interface in its final form (which also involved possible protocol changes, see https://github.com/tendermint/spec/pull/227). However, it turned out that this would require a large amount of changes to existing P2P code because of the previous tight coupling between `Peer` and `MConnection` and the reliance on subtleties in the MConnection behavior. Instead, I have broadened the `Transport` interface to expose much of the existing MConnection interface, preserved much of the existing MConnection logic and behavior in the transport implementation, and tried to make as few changes to the rest of the P2P stack as possible. We will instead reduce this interface gradually as we refactor other parts of the P2P stack. The low-level transport code and protocol (e.g. MConnection, SecretConnection and so on) has not been significantly changed, and refactoring this is not a priority until we come up with a plan for QUIC adoption, as we may end up discarding the MConnection code entirely. There are no tests of the new `MConnTransport`, as this code is likely to evolve as we proceed with the P2P refactor, but tests should be added before a final release. The E2E tests are sufficient for basic validation in the meanwhile.
4 years ago
p2p: implement new Transport interface (#5791) This implements a new `Transport` interface and related types for the P2P refactor in #5670. Previously, `conn.MConnection` was very tightly coupled to the `Peer` implementation -- in order to allow alternative non-multiplexed transports (e.g. QUIC), MConnection has now been moved below the `Transport` interface, as `MConnTransport`, and decoupled from the peer. Since the `p2p` package is not covered by our Go API stability, this is not considered a breaking change, and not listed in the changelog. The initial approach was to implement the new interface in its final form (which also involved possible protocol changes, see https://github.com/tendermint/spec/pull/227). However, it turned out that this would require a large amount of changes to existing P2P code because of the previous tight coupling between `Peer` and `MConnection` and the reliance on subtleties in the MConnection behavior. Instead, I have broadened the `Transport` interface to expose much of the existing MConnection interface, preserved much of the existing MConnection logic and behavior in the transport implementation, and tried to make as few changes to the rest of the P2P stack as possible. We will instead reduce this interface gradually as we refactor other parts of the P2P stack. The low-level transport code and protocol (e.g. MConnection, SecretConnection and so on) has not been significantly changed, and refactoring this is not a priority until we come up with a plan for QUIC adoption, as we may end up discarding the MConnection code entirely. There are no tests of the new `MConnTransport`, as this code is likely to evolve as we proceed with the P2P refactor, but tests should be added before a final release. The E2E tests are sufficient for basic validation in the meanwhile.
4 years ago
p2p: implement new Transport interface (#5791) This implements a new `Transport` interface and related types for the P2P refactor in #5670. Previously, `conn.MConnection` was very tightly coupled to the `Peer` implementation -- in order to allow alternative non-multiplexed transports (e.g. QUIC), MConnection has now been moved below the `Transport` interface, as `MConnTransport`, and decoupled from the peer. Since the `p2p` package is not covered by our Go API stability, this is not considered a breaking change, and not listed in the changelog. The initial approach was to implement the new interface in its final form (which also involved possible protocol changes, see https://github.com/tendermint/spec/pull/227). However, it turned out that this would require a large amount of changes to existing P2P code because of the previous tight coupling between `Peer` and `MConnection` and the reliance on subtleties in the MConnection behavior. Instead, I have broadened the `Transport` interface to expose much of the existing MConnection interface, preserved much of the existing MConnection logic and behavior in the transport implementation, and tried to make as few changes to the rest of the P2P stack as possible. We will instead reduce this interface gradually as we refactor other parts of the P2P stack. The low-level transport code and protocol (e.g. MConnection, SecretConnection and so on) has not been significantly changed, and refactoring this is not a priority until we come up with a plan for QUIC adoption, as we may end up discarding the MConnection code entirely. There are no tests of the new `MConnTransport`, as this code is likely to evolve as we proceed with the P2P refactor, but tests should be added before a final release. The E2E tests are sufficient for basic validation in the meanwhile.
4 years ago
p2p: implement new Transport interface (#5791) This implements a new `Transport` interface and related types for the P2P refactor in #5670. Previously, `conn.MConnection` was very tightly coupled to the `Peer` implementation -- in order to allow alternative non-multiplexed transports (e.g. QUIC), MConnection has now been moved below the `Transport` interface, as `MConnTransport`, and decoupled from the peer. Since the `p2p` package is not covered by our Go API stability, this is not considered a breaking change, and not listed in the changelog. The initial approach was to implement the new interface in its final form (which also involved possible protocol changes, see https://github.com/tendermint/spec/pull/227). However, it turned out that this would require a large amount of changes to existing P2P code because of the previous tight coupling between `Peer` and `MConnection` and the reliance on subtleties in the MConnection behavior. Instead, I have broadened the `Transport` interface to expose much of the existing MConnection interface, preserved much of the existing MConnection logic and behavior in the transport implementation, and tried to make as few changes to the rest of the P2P stack as possible. We will instead reduce this interface gradually as we refactor other parts of the P2P stack. The low-level transport code and protocol (e.g. MConnection, SecretConnection and so on) has not been significantly changed, and refactoring this is not a priority until we come up with a plan for QUIC adoption, as we may end up discarding the MConnection code entirely. There are no tests of the new `MConnTransport`, as this code is likely to evolve as we proceed with the P2P refactor, but tests should be added before a final release. The E2E tests are sufficient for basic validation in the meanwhile.
4 years ago
p2p: implement new Transport interface (#5791) This implements a new `Transport` interface and related types for the P2P refactor in #5670. Previously, `conn.MConnection` was very tightly coupled to the `Peer` implementation -- in order to allow alternative non-multiplexed transports (e.g. QUIC), MConnection has now been moved below the `Transport` interface, as `MConnTransport`, and decoupled from the peer. Since the `p2p` package is not covered by our Go API stability, this is not considered a breaking change, and not listed in the changelog. The initial approach was to implement the new interface in its final form (which also involved possible protocol changes, see https://github.com/tendermint/spec/pull/227). However, it turned out that this would require a large amount of changes to existing P2P code because of the previous tight coupling between `Peer` and `MConnection` and the reliance on subtleties in the MConnection behavior. Instead, I have broadened the `Transport` interface to expose much of the existing MConnection interface, preserved much of the existing MConnection logic and behavior in the transport implementation, and tried to make as few changes to the rest of the P2P stack as possible. We will instead reduce this interface gradually as we refactor other parts of the P2P stack. The low-level transport code and protocol (e.g. MConnection, SecretConnection and so on) has not been significantly changed, and refactoring this is not a priority until we come up with a plan for QUIC adoption, as we may end up discarding the MConnection code entirely. There are no tests of the new `MConnTransport`, as this code is likely to evolve as we proceed with the P2P refactor, but tests should be added before a final release. The E2E tests are sufficient for basic validation in the meanwhile.
4 years ago
p2p: implement new Transport interface (#5791) This implements a new `Transport` interface and related types for the P2P refactor in #5670. Previously, `conn.MConnection` was very tightly coupled to the `Peer` implementation -- in order to allow alternative non-multiplexed transports (e.g. QUIC), MConnection has now been moved below the `Transport` interface, as `MConnTransport`, and decoupled from the peer. Since the `p2p` package is not covered by our Go API stability, this is not considered a breaking change, and not listed in the changelog. The initial approach was to implement the new interface in its final form (which also involved possible protocol changes, see https://github.com/tendermint/spec/pull/227). However, it turned out that this would require a large amount of changes to existing P2P code because of the previous tight coupling between `Peer` and `MConnection` and the reliance on subtleties in the MConnection behavior. Instead, I have broadened the `Transport` interface to expose much of the existing MConnection interface, preserved much of the existing MConnection logic and behavior in the transport implementation, and tried to make as few changes to the rest of the P2P stack as possible. We will instead reduce this interface gradually as we refactor other parts of the P2P stack. The low-level transport code and protocol (e.g. MConnection, SecretConnection and so on) has not been significantly changed, and refactoring this is not a priority until we come up with a plan for QUIC adoption, as we may end up discarding the MConnection code entirely. There are no tests of the new `MConnTransport`, as this code is likely to evolve as we proceed with the P2P refactor, but tests should be added before a final release. The E2E tests are sufficient for basic validation in the meanwhile.
4 years ago
p2p: implement new Transport interface (#5791) This implements a new `Transport` interface and related types for the P2P refactor in #5670. Previously, `conn.MConnection` was very tightly coupled to the `Peer` implementation -- in order to allow alternative non-multiplexed transports (e.g. QUIC), MConnection has now been moved below the `Transport` interface, as `MConnTransport`, and decoupled from the peer. Since the `p2p` package is not covered by our Go API stability, this is not considered a breaking change, and not listed in the changelog. The initial approach was to implement the new interface in its final form (which also involved possible protocol changes, see https://github.com/tendermint/spec/pull/227). However, it turned out that this would require a large amount of changes to existing P2P code because of the previous tight coupling between `Peer` and `MConnection` and the reliance on subtleties in the MConnection behavior. Instead, I have broadened the `Transport` interface to expose much of the existing MConnection interface, preserved much of the existing MConnection logic and behavior in the transport implementation, and tried to make as few changes to the rest of the P2P stack as possible. We will instead reduce this interface gradually as we refactor other parts of the P2P stack. The low-level transport code and protocol (e.g. MConnection, SecretConnection and so on) has not been significantly changed, and refactoring this is not a priority until we come up with a plan for QUIC adoption, as we may end up discarding the MConnection code entirely. There are no tests of the new `MConnTransport`, as this code is likely to evolve as we proceed with the P2P refactor, but tests should be added before a final release. The E2E tests are sufficient for basic validation in the meanwhile.
4 years ago
p2p: implement new Transport interface (#5791) This implements a new `Transport` interface and related types for the P2P refactor in #5670. Previously, `conn.MConnection` was very tightly coupled to the `Peer` implementation -- in order to allow alternative non-multiplexed transports (e.g. QUIC), MConnection has now been moved below the `Transport` interface, as `MConnTransport`, and decoupled from the peer. Since the `p2p` package is not covered by our Go API stability, this is not considered a breaking change, and not listed in the changelog. The initial approach was to implement the new interface in its final form (which also involved possible protocol changes, see https://github.com/tendermint/spec/pull/227). However, it turned out that this would require a large amount of changes to existing P2P code because of the previous tight coupling between `Peer` and `MConnection` and the reliance on subtleties in the MConnection behavior. Instead, I have broadened the `Transport` interface to expose much of the existing MConnection interface, preserved much of the existing MConnection logic and behavior in the transport implementation, and tried to make as few changes to the rest of the P2P stack as possible. We will instead reduce this interface gradually as we refactor other parts of the P2P stack. The low-level transport code and protocol (e.g. MConnection, SecretConnection and so on) has not been significantly changed, and refactoring this is not a priority until we come up with a plan for QUIC adoption, as we may end up discarding the MConnection code entirely. There are no tests of the new `MConnTransport`, as this code is likely to evolve as we proceed with the P2P refactor, but tests should be added before a final release. The E2E tests are sufficient for basic validation in the meanwhile.
4 years ago
  1. package node
  2. import (
  3. "bytes"
  4. "context"
  5. "errors"
  6. "fmt"
  7. "net"
  8. "net/http"
  9. _ "net/http/pprof" // nolint: gosec // securely exposed on separate, optional port
  10. "strconv"
  11. "strings"
  12. "time"
  13. "github.com/prometheus/client_golang/prometheus"
  14. "github.com/prometheus/client_golang/prometheus/promhttp"
  15. "github.com/rs/cors"
  16. dbm "github.com/tendermint/tm-db"
  17. abci "github.com/tendermint/tendermint/abci/types"
  18. bcv0 "github.com/tendermint/tendermint/blockchain/v0"
  19. bcv2 "github.com/tendermint/tendermint/blockchain/v2"
  20. cfg "github.com/tendermint/tendermint/config"
  21. "github.com/tendermint/tendermint/consensus"
  22. "github.com/tendermint/tendermint/crypto"
  23. "github.com/tendermint/tendermint/evidence"
  24. tmjson "github.com/tendermint/tendermint/libs/json"
  25. "github.com/tendermint/tendermint/libs/log"
  26. tmpubsub "github.com/tendermint/tendermint/libs/pubsub"
  27. "github.com/tendermint/tendermint/libs/service"
  28. "github.com/tendermint/tendermint/light"
  29. mempl "github.com/tendermint/tendermint/mempool"
  30. "github.com/tendermint/tendermint/p2p"
  31. "github.com/tendermint/tendermint/p2p/pex"
  32. "github.com/tendermint/tendermint/privval"
  33. "github.com/tendermint/tendermint/proxy"
  34. rpccore "github.com/tendermint/tendermint/rpc/core"
  35. grpccore "github.com/tendermint/tendermint/rpc/grpc"
  36. rpcserver "github.com/tendermint/tendermint/rpc/jsonrpc/server"
  37. sm "github.com/tendermint/tendermint/state"
  38. "github.com/tendermint/tendermint/state/txindex"
  39. "github.com/tendermint/tendermint/state/txindex/kv"
  40. "github.com/tendermint/tendermint/state/txindex/null"
  41. "github.com/tendermint/tendermint/statesync"
  42. "github.com/tendermint/tendermint/store"
  43. cs "github.com/tendermint/tendermint/test/maverick/consensus"
  44. "github.com/tendermint/tendermint/types"
  45. tmtime "github.com/tendermint/tendermint/types/time"
  46. "github.com/tendermint/tendermint/version"
  47. )
  48. //------------------------------------------------------------------------------
  49. // ParseMisbehaviors is a util function that converts a comma separated string into
  50. // a map of misbehaviors to be executed by the maverick node
  51. func ParseMisbehaviors(str string) (map[int64]cs.Misbehavior, error) {
  52. // check if string is empty in which case we run a normal node
  53. var misbehaviors = make(map[int64]cs.Misbehavior)
  54. if str == "" {
  55. return misbehaviors, nil
  56. }
  57. strs := strings.Split(str, ",")
  58. if len(strs)%2 != 0 {
  59. return misbehaviors, errors.New("missing either height or misbehavior name in the misbehavior flag")
  60. }
  61. OUTER_LOOP:
  62. for i := 0; i < len(strs); i += 2 {
  63. height, err := strconv.ParseInt(strs[i+1], 10, 64)
  64. if err != nil {
  65. return misbehaviors, fmt.Errorf("failed to parse misbehavior height: %w", err)
  66. }
  67. for key, misbehavior := range cs.MisbehaviorList {
  68. if key == strs[i] {
  69. misbehaviors[height] = misbehavior
  70. continue OUTER_LOOP
  71. }
  72. }
  73. return misbehaviors, fmt.Errorf("received unknown misbehavior: %s. Did you forget to add it?", strs[i])
  74. }
  75. return misbehaviors, nil
  76. }
  77. // DBContext specifies config information for loading a new DB.
  78. type DBContext struct {
  79. ID string
  80. Config *cfg.Config
  81. }
  82. // DBProvider takes a DBContext and returns an instantiated DB.
  83. type DBProvider func(*DBContext) (dbm.DB, error)
  84. // DefaultDBProvider returns a database using the DBBackend and DBDir
  85. // specified in the ctx.Config.
  86. func DefaultDBProvider(ctx *DBContext) (dbm.DB, error) {
  87. dbType := dbm.BackendType(ctx.Config.DBBackend)
  88. return dbm.NewDB(ctx.ID, dbType, ctx.Config.DBDir())
  89. }
  90. // GenesisDocProvider returns a GenesisDoc.
  91. // It allows the GenesisDoc to be pulled from sources other than the
  92. // filesystem, for instance from a distributed key-value store cluster.
  93. type GenesisDocProvider func() (*types.GenesisDoc, error)
  94. // DefaultGenesisDocProviderFunc returns a GenesisDocProvider that loads
  95. // the GenesisDoc from the config.GenesisFile() on the filesystem.
  96. func DefaultGenesisDocProviderFunc(config *cfg.Config) GenesisDocProvider {
  97. return func() (*types.GenesisDoc, error) {
  98. return types.GenesisDocFromFile(config.GenesisFile())
  99. }
  100. }
  101. // Provider takes a config and a logger and returns a ready to go Node.
  102. type Provider func(*cfg.Config, log.Logger) (*Node, error)
  103. // DefaultNewNode returns a Tendermint node with default settings for the
  104. // PrivValidator, ClientCreator, GenesisDoc, and DBProvider.
  105. // It implements NodeProvider.
  106. func DefaultNewNode(config *cfg.Config, logger log.Logger, misbehaviors map[int64]cs.Misbehavior) (*Node, error) {
  107. nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
  108. if err != nil {
  109. return nil, fmt.Errorf("failed to load or gen node key %s, err: %w", config.NodeKeyFile(), err)
  110. }
  111. return NewNode(config,
  112. LoadOrGenFilePV(config.PrivValidatorKeyFile(), config.PrivValidatorStateFile()),
  113. nodeKey,
  114. proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir()),
  115. DefaultGenesisDocProviderFunc(config),
  116. DefaultDBProvider,
  117. DefaultMetricsProvider(config.Instrumentation),
  118. logger,
  119. misbehaviors,
  120. )
  121. }
  122. // MetricsProvider returns a consensus, p2p and mempool Metrics.
  123. type MetricsProvider func(chainID string) (*cs.Metrics, *p2p.Metrics, *mempl.Metrics, *sm.Metrics)
  124. // DefaultMetricsProvider returns Metrics build using Prometheus client library
  125. // if Prometheus is enabled. Otherwise, it returns no-op Metrics.
  126. func DefaultMetricsProvider(config *cfg.InstrumentationConfig) MetricsProvider {
  127. return func(chainID string) (*cs.Metrics, *p2p.Metrics, *mempl.Metrics, *sm.Metrics) {
  128. if config.Prometheus {
  129. return cs.PrometheusMetrics(config.Namespace, "chain_id", chainID),
  130. p2p.PrometheusMetrics(config.Namespace, "chain_id", chainID),
  131. mempl.PrometheusMetrics(config.Namespace, "chain_id", chainID),
  132. sm.PrometheusMetrics(config.Namespace, "chain_id", chainID)
  133. }
  134. return cs.NopMetrics(), p2p.NopMetrics(), mempl.NopMetrics(), sm.NopMetrics()
  135. }
  136. }
  137. // Option sets a parameter for the node.
  138. type Option func(*Node)
  139. // Temporary interface for switching to fast sync, we should get rid of v0.
  140. // See: https://github.com/tendermint/tendermint/issues/4595
  141. type fastSyncReactor interface {
  142. SwitchToFastSync(sm.State) error
  143. }
  144. // CustomReactors allows you to add custom reactors (name -> p2p.Reactor) to
  145. // the node's Switch.
  146. //
  147. // WARNING: using any name from the below list of the existing reactors will
  148. // result in replacing it with the custom one.
  149. //
  150. // - MEMPOOL
  151. // - BLOCKCHAIN
  152. // - CONSENSUS
  153. // - EVIDENCE
  154. // - PEX
  155. // - STATESYNC
  156. func CustomReactors(reactors map[string]p2p.Reactor) Option {
  157. return func(n *Node) {
  158. for name, reactor := range reactors {
  159. if existingReactor := n.sw.Reactor(name); existingReactor != nil {
  160. n.sw.Logger.Info("Replacing existing reactor with a custom one",
  161. "name", name, "existing", existingReactor, "custom", reactor)
  162. n.sw.RemoveReactor(name, existingReactor)
  163. }
  164. n.sw.AddReactor(name, reactor)
  165. }
  166. }
  167. }
  168. func CustomReactorsAsConstructors(reactors map[string]func(n *Node) p2p.Reactor) Option {
  169. return func(n *Node) {
  170. for name, customReactor := range reactors {
  171. if existingReactor := n.sw.Reactor(name); existingReactor != nil {
  172. n.sw.Logger.Info("Replacing existing reactor with a custom one",
  173. "name", name)
  174. n.sw.RemoveReactor(name, existingReactor)
  175. }
  176. n.sw.AddReactor(name, customReactor(n))
  177. }
  178. }
  179. }
  180. // StateProvider overrides the state provider used by state sync to retrieve trusted app hashes and
  181. // build a State object for bootstrapping the node.
  182. // WARNING: this interface is considered unstable and subject to change.
  183. func StateProvider(stateProvider statesync.StateProvider) Option {
  184. return func(n *Node) {
  185. n.stateSyncProvider = stateProvider
  186. }
  187. }
  188. //------------------------------------------------------------------------------
  189. // Node is the highest level interface to a full Tendermint node.
  190. // It includes all configuration information and running services.
  191. type Node struct {
  192. service.BaseService
  193. // config
  194. config *cfg.Config
  195. genesisDoc *types.GenesisDoc // initial validator set
  196. privValidator types.PrivValidator // local node's validator key
  197. // network
  198. transport *p2p.MConnTransport
  199. sw *p2p.Switch // p2p connections
  200. addrBook pex.AddrBook // known peers
  201. nodeInfo p2p.NodeInfo
  202. nodeKey p2p.NodeKey // our node privkey
  203. isListening bool
  204. // services
  205. eventBus *types.EventBus // pub/sub for services
  206. stateStore sm.Store
  207. blockStore *store.BlockStore // store the blockchain to disk
  208. bcReactor service.Service // for fast-syncing
  209. mempoolReactor *mempl.Reactor // for gossipping transactions
  210. mempool mempl.Mempool
  211. stateSync bool // whether the node should state sync on startup
  212. stateSyncReactor *statesync.Reactor // for hosting and restoring state sync snapshots
  213. stateSyncProvider statesync.StateProvider // provides state data for bootstrapping a node
  214. stateSyncGenesis sm.State // provides the genesis state for state sync
  215. consensusState *cs.State // latest consensus state
  216. consensusReactor *cs.Reactor // for participating in the consensus
  217. pexReactor *pex.Reactor // for exchanging peer addresses
  218. evidenceReactor *evidence.Reactor
  219. evidencePool *evidence.Pool // tracking evidence
  220. proxyApp proxy.AppConns // connection to the application
  221. rpcListeners []net.Listener // rpc servers
  222. txIndexer txindex.TxIndexer
  223. indexerService *txindex.IndexerService
  224. prometheusSrv *http.Server
  225. }
  226. func initDBs(config *cfg.Config, dbProvider DBProvider) (blockStore *store.BlockStore, stateDB dbm.DB, err error) {
  227. var blockStoreDB dbm.DB
  228. blockStoreDB, err = dbProvider(&DBContext{"blockstore", config})
  229. if err != nil {
  230. return
  231. }
  232. blockStore = store.NewBlockStore(blockStoreDB)
  233. stateDB, err = dbProvider(&DBContext{"state", config})
  234. if err != nil {
  235. return
  236. }
  237. return
  238. }
  239. func createAndStartProxyAppConns(clientCreator proxy.ClientCreator, logger log.Logger) (proxy.AppConns, error) {
  240. proxyApp := proxy.NewAppConns(clientCreator)
  241. proxyApp.SetLogger(logger.With("module", "proxy"))
  242. if err := proxyApp.Start(); err != nil {
  243. return nil, fmt.Errorf("error starting proxy app connections: %v", err)
  244. }
  245. return proxyApp, nil
  246. }
  247. func createAndStartEventBus(logger log.Logger) (*types.EventBus, error) {
  248. eventBus := types.NewEventBus()
  249. eventBus.SetLogger(logger.With("module", "events"))
  250. if err := eventBus.Start(); err != nil {
  251. return nil, err
  252. }
  253. return eventBus, nil
  254. }
  255. func createAndStartIndexerService(config *cfg.Config, dbProvider DBProvider,
  256. eventBus *types.EventBus, logger log.Logger) (*txindex.IndexerService, txindex.TxIndexer, error) {
  257. var txIndexer txindex.TxIndexer
  258. switch config.TxIndex.Indexer {
  259. case "kv":
  260. store, err := dbProvider(&DBContext{"tx_index", config})
  261. if err != nil {
  262. return nil, nil, err
  263. }
  264. txIndexer = kv.NewTxIndex(store)
  265. default:
  266. txIndexer = &null.TxIndex{}
  267. }
  268. indexerService := txindex.NewIndexerService(txIndexer, eventBus)
  269. indexerService.SetLogger(logger.With("module", "txindex"))
  270. if err := indexerService.Start(); err != nil {
  271. return nil, nil, err
  272. }
  273. return indexerService, txIndexer, nil
  274. }
  275. func doHandshake(
  276. stateStore sm.Store,
  277. state sm.State,
  278. blockStore sm.BlockStore,
  279. genDoc *types.GenesisDoc,
  280. eventBus types.BlockEventPublisher,
  281. proxyApp proxy.AppConns,
  282. consensusLogger log.Logger) error {
  283. handshaker := cs.NewHandshaker(stateStore, state, blockStore, genDoc)
  284. handshaker.SetLogger(consensusLogger)
  285. handshaker.SetEventBus(eventBus)
  286. if err := handshaker.Handshake(proxyApp); err != nil {
  287. return fmt.Errorf("error during handshake: %v", err)
  288. }
  289. return nil
  290. }
  291. func logNodeStartupInfo(state sm.State, pubKey crypto.PubKey, logger, consensusLogger log.Logger) {
  292. // Log the version info.
  293. logger.Info("Version info",
  294. "software", version.TMCoreSemVer,
  295. "block", version.BlockProtocol,
  296. "p2p", version.P2PProtocol,
  297. )
  298. // If the state and software differ in block version, at least log it.
  299. if state.Version.Consensus.Block != version.BlockProtocol {
  300. logger.Info("Software and state have different block protocols",
  301. "software", version.BlockProtocol,
  302. "state", state.Version.Consensus.Block,
  303. )
  304. }
  305. addr := pubKey.Address()
  306. // Log whether this node is a validator or an observer
  307. if state.Validators.HasAddress(addr) {
  308. consensusLogger.Info("This node is a validator", "addr", addr, "pubKey", pubKey)
  309. } else {
  310. consensusLogger.Info("This node is not a validator", "addr", addr, "pubKey", pubKey)
  311. }
  312. }
  313. func onlyValidatorIsUs(state sm.State, pubKey crypto.PubKey) bool {
  314. if state.Validators.Size() > 1 {
  315. return false
  316. }
  317. addr, _ := state.Validators.GetByIndex(0)
  318. return bytes.Equal(pubKey.Address(), addr)
  319. }
  320. func createMempoolReactor(
  321. config *cfg.Config,
  322. proxyApp proxy.AppConns,
  323. state sm.State,
  324. memplMetrics *mempl.Metrics,
  325. peerMgr *p2p.PeerManager,
  326. logger log.Logger,
  327. ) (*p2p.ReactorShim, *mempl.Reactor, *mempl.CListMempool) {
  328. logger = logger.With("module", "mempool")
  329. mempool := mempl.NewCListMempool(
  330. config.Mempool,
  331. proxyApp.Mempool(),
  332. state.LastBlockHeight,
  333. mempl.WithMetrics(memplMetrics),
  334. mempl.WithPreCheck(sm.TxPreCheck(state)),
  335. mempl.WithPostCheck(sm.TxPostCheck(state)),
  336. )
  337. mempool.SetLogger(logger)
  338. reactorShim := p2p.NewReactorShim(logger, "MempoolShim", mempl.GetChannelShims(config.Mempool))
  339. reactor := mempl.NewReactor(
  340. logger,
  341. config.Mempool,
  342. peerMgr,
  343. mempool,
  344. reactorShim.GetChannel(mempl.MempoolChannel),
  345. reactorShim.PeerUpdates,
  346. )
  347. if config.Consensus.WaitForTxs() {
  348. mempool.EnableTxsAvailable()
  349. }
  350. return reactorShim, reactor, mempool
  351. }
  352. func createEvidenceReactor(
  353. config *cfg.Config,
  354. dbProvider DBProvider,
  355. stateDB dbm.DB,
  356. blockStore *store.BlockStore,
  357. logger log.Logger,
  358. ) (*p2p.ReactorShim, *evidence.Reactor, *evidence.Pool, error) {
  359. evidenceDB, err := dbProvider(&DBContext{"evidence", config})
  360. if err != nil {
  361. return nil, nil, nil, err
  362. }
  363. logger = logger.With("module", "evidence")
  364. evidencePool, err := evidence.NewPool(logger, evidenceDB, sm.NewStore(stateDB), blockStore)
  365. if err != nil {
  366. return nil, nil, nil, err
  367. }
  368. evidenceReactorShim := p2p.NewReactorShim(logger, "EvidenceShim", evidence.ChannelShims)
  369. evidenceReactor := evidence.NewReactor(
  370. logger,
  371. evidenceReactorShim.GetChannel(evidence.EvidenceChannel),
  372. evidenceReactorShim.PeerUpdates,
  373. evidencePool,
  374. )
  375. return evidenceReactorShim, evidenceReactor, evidencePool, nil
  376. }
  377. func createBlockchainReactor(
  378. logger log.Logger,
  379. config *cfg.Config,
  380. state sm.State,
  381. blockExec *sm.BlockExecutor,
  382. blockStore *store.BlockStore,
  383. csReactor *cs.Reactor,
  384. fastSync bool,
  385. ) (*p2p.ReactorShim, service.Service, error) {
  386. logger = logger.With("module", "blockchain")
  387. switch config.FastSync.Version {
  388. case "v0":
  389. reactorShim := p2p.NewReactorShim(logger, "BlockchainShim", bcv0.ChannelShims)
  390. reactor, err := bcv0.NewReactor(
  391. logger, state.Copy(), blockExec, blockStore, csReactor,
  392. reactorShim.GetChannel(bcv0.BlockchainChannel), reactorShim.PeerUpdates, fastSync,
  393. )
  394. if err != nil {
  395. return nil, nil, err
  396. }
  397. return reactorShim, reactor, nil
  398. case "v2":
  399. reactor := bcv2.NewBlockchainReactor(state.Copy(), blockExec, blockStore, fastSync)
  400. reactor.SetLogger(logger)
  401. return nil, reactor, nil
  402. default:
  403. return nil, nil, fmt.Errorf("unknown fastsync version %s", config.FastSync.Version)
  404. }
  405. }
  406. func createConsensusReactor(config *cfg.Config,
  407. state sm.State,
  408. blockExec *sm.BlockExecutor,
  409. blockStore sm.BlockStore,
  410. mempool *mempl.CListMempool,
  411. evidencePool *evidence.Pool,
  412. privValidator types.PrivValidator,
  413. csMetrics *cs.Metrics,
  414. waitSync bool,
  415. eventBus *types.EventBus,
  416. consensusLogger log.Logger,
  417. misbehaviors map[int64]cs.Misbehavior) (*cs.Reactor, *cs.State) {
  418. consensusState := cs.NewState(
  419. config.Consensus,
  420. state.Copy(),
  421. blockExec,
  422. blockStore,
  423. mempool,
  424. evidencePool,
  425. misbehaviors,
  426. cs.StateMetrics(csMetrics),
  427. )
  428. consensusState.SetLogger(consensusLogger)
  429. if privValidator != nil {
  430. consensusState.SetPrivValidator(privValidator)
  431. }
  432. consensusReactor := cs.NewReactor(consensusState, waitSync, cs.ReactorMetrics(csMetrics))
  433. consensusReactor.SetLogger(consensusLogger)
  434. // services which will be publishing and/or subscribing for messages (events)
  435. // consensusReactor will set it on consensusState and blockExecutor
  436. consensusReactor.SetEventBus(eventBus)
  437. return consensusReactor, consensusState
  438. }
  439. func createTransport(
  440. logger log.Logger,
  441. config *cfg.Config,
  442. nodeInfo p2p.NodeInfo,
  443. nodeKey p2p.NodeKey,
  444. proxyApp proxy.AppConns,
  445. ) (
  446. *p2p.MConnTransport,
  447. []p2p.PeerFilterFunc,
  448. ) {
  449. var (
  450. connFilters = []p2p.ConnFilterFunc{}
  451. peerFilters = []p2p.PeerFilterFunc{}
  452. )
  453. if !config.P2P.AllowDuplicateIP {
  454. connFilters = append(connFilters, p2p.ConnDuplicateIPFilter)
  455. }
  456. // Filter peers by addr or pubkey with an ABCI query.
  457. // If the query return code is OK, add peer.
  458. if config.FilterPeers {
  459. connFilters = append(
  460. connFilters,
  461. // ABCI query for address filtering.
  462. func(_ p2p.ConnSet, c net.Conn, _ []net.IP) error {
  463. res, err := proxyApp.Query().QuerySync(context.Background(), abci.RequestQuery{
  464. Path: fmt.Sprintf("/p2p/filter/addr/%s", c.RemoteAddr().String()),
  465. })
  466. if err != nil {
  467. return err
  468. }
  469. if res.IsErr() {
  470. return fmt.Errorf("error querying abci app: %v", res)
  471. }
  472. return nil
  473. },
  474. )
  475. peerFilters = append(
  476. peerFilters,
  477. // ABCI query for ID filtering.
  478. func(_ p2p.IPeerSet, p p2p.Peer) error {
  479. res, err := proxyApp.Query().QuerySync(context.Background(), abci.RequestQuery{
  480. Path: fmt.Sprintf("/p2p/filter/id/%s", p.ID()),
  481. })
  482. if err != nil {
  483. return err
  484. }
  485. if res.IsErr() {
  486. return fmt.Errorf("error querying abci app: %v", res)
  487. }
  488. return nil
  489. },
  490. )
  491. }
  492. transport := p2p.NewMConnTransport(
  493. logger, nodeInfo, nodeKey.PrivKey, p2p.MConnConfig(config.P2P),
  494. p2p.MConnTransportConnFilters(connFilters...),
  495. p2p.MConnTransportMaxIncomingConnections(config.P2P.MaxNumInboundPeers+
  496. len(splitAndTrimEmpty(config.P2P.UnconditionalPeerIDs, ",", " "))),
  497. )
  498. return transport, peerFilters
  499. }
  500. func createSwitch(config *cfg.Config,
  501. transport p2p.Transport,
  502. p2pMetrics *p2p.Metrics,
  503. peerFilters []p2p.PeerFilterFunc,
  504. mempoolReactor *p2p.ReactorShim,
  505. bcReactor p2p.Reactor,
  506. stateSyncReactor *p2p.ReactorShim,
  507. consensusReactor *cs.Reactor,
  508. evidenceReactor *p2p.ReactorShim,
  509. nodeInfo p2p.NodeInfo,
  510. nodeKey p2p.NodeKey,
  511. p2pLogger log.Logger) *p2p.Switch {
  512. sw := p2p.NewSwitch(
  513. config.P2P,
  514. transport,
  515. p2p.WithMetrics(p2pMetrics),
  516. p2p.SwitchPeerFilters(peerFilters...),
  517. )
  518. sw.SetLogger(p2pLogger)
  519. sw.AddReactor("MEMPOOL", mempoolReactor)
  520. sw.AddReactor("BLOCKCHAIN", bcReactor)
  521. sw.AddReactor("CONSENSUS", consensusReactor)
  522. sw.AddReactor("EVIDENCE", evidenceReactor)
  523. sw.AddReactor("STATESYNC", stateSyncReactor)
  524. sw.SetNodeInfo(nodeInfo)
  525. sw.SetNodeKey(nodeKey)
  526. p2pLogger.Info("P2P Node ID", "ID", nodeKey.ID, "file", config.NodeKeyFile())
  527. return sw
  528. }
  529. func createAddrBookAndSetOnSwitch(config *cfg.Config, sw *p2p.Switch,
  530. p2pLogger log.Logger, nodeKey p2p.NodeKey) (pex.AddrBook, error) {
  531. addrBook := pex.NewAddrBook(config.P2P.AddrBookFile(), config.P2P.AddrBookStrict)
  532. addrBook.SetLogger(p2pLogger.With("book", config.P2P.AddrBookFile()))
  533. // Add ourselves to addrbook to prevent dialing ourselves
  534. if config.P2P.ExternalAddress != "" {
  535. addr, err := p2p.NewNetAddressString(p2p.IDAddressString(nodeKey.ID, config.P2P.ExternalAddress))
  536. if err != nil {
  537. return nil, fmt.Errorf("p2p.external_address is incorrect: %w", err)
  538. }
  539. addrBook.AddOurAddress(addr)
  540. }
  541. if config.P2P.ListenAddress != "" {
  542. addr, err := p2p.NewNetAddressString(p2p.IDAddressString(nodeKey.ID, config.P2P.ListenAddress))
  543. if err != nil {
  544. return nil, fmt.Errorf("p2p.laddr is incorrect: %w", err)
  545. }
  546. addrBook.AddOurAddress(addr)
  547. }
  548. sw.SetAddrBook(addrBook)
  549. return addrBook, nil
  550. }
  551. func createPEXReactorAndAddToSwitch(addrBook pex.AddrBook, config *cfg.Config,
  552. sw *p2p.Switch, logger log.Logger) *pex.Reactor {
  553. // TODO persistent peers ? so we can have their DNS addrs saved
  554. pexReactor := pex.NewReactor(addrBook,
  555. &pex.ReactorConfig{
  556. Seeds: splitAndTrimEmpty(config.P2P.Seeds, ",", " "),
  557. SeedMode: config.P2P.SeedMode,
  558. // See consensus/reactor.go: blocksToContributeToBecomeGoodPeer 10000
  559. // blocks assuming 10s blocks ~ 28 hours.
  560. // TODO (melekes): make it dynamic based on the actual block latencies
  561. // from the live network.
  562. // https://github.com/tendermint/tendermint/issues/3523
  563. SeedDisconnectWaitPeriod: 28 * time.Hour,
  564. PersistentPeersMaxDialPeriod: config.P2P.PersistentPeersMaxDialPeriod,
  565. })
  566. pexReactor.SetLogger(logger.With("module", "pex"))
  567. sw.AddReactor("PEX", pexReactor)
  568. return pexReactor
  569. }
  570. // startStateSync starts an asynchronous state sync process, then switches to fast sync mode.
  571. func startStateSync(ssR *statesync.Reactor, bcR fastSyncReactor, conR *cs.Reactor,
  572. stateProvider statesync.StateProvider, config *cfg.StateSyncConfig, fastSync bool,
  573. stateStore sm.Store, blockStore *store.BlockStore, state sm.State) error {
  574. ssR.Logger.Info("Starting state sync")
  575. if stateProvider == nil {
  576. var err error
  577. ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  578. defer cancel()
  579. stateProvider, err = statesync.NewLightClientStateProvider(
  580. ctx,
  581. state.ChainID, state.Version, state.InitialHeight,
  582. config.RPCServers, light.TrustOptions{
  583. Period: config.TrustPeriod,
  584. Height: config.TrustHeight,
  585. Hash: config.TrustHashBytes(),
  586. }, ssR.Logger.With("module", "light"))
  587. if err != nil {
  588. return fmt.Errorf("failed to set up light client state provider: %w", err)
  589. }
  590. }
  591. go func() {
  592. state, commit, err := ssR.Sync(stateProvider, config.DiscoveryTime)
  593. if err != nil {
  594. ssR.Logger.Error("State sync failed", "err", err)
  595. return
  596. }
  597. err = stateStore.Bootstrap(state)
  598. if err != nil {
  599. ssR.Logger.Error("Failed to bootstrap node with new state", "err", err)
  600. return
  601. }
  602. err = blockStore.SaveSeenCommit(state.LastBlockHeight, commit)
  603. if err != nil {
  604. ssR.Logger.Error("Failed to store last seen commit", "err", err)
  605. return
  606. }
  607. if fastSync {
  608. // FIXME Very ugly to have these metrics bleed through here.
  609. conR.Metrics.StateSyncing.Set(0)
  610. conR.Metrics.FastSyncing.Set(1)
  611. err = bcR.SwitchToFastSync(state)
  612. if err != nil {
  613. ssR.Logger.Error("Failed to switch to fast sync", "err", err)
  614. return
  615. }
  616. } else {
  617. conR.SwitchToConsensus(state, true)
  618. }
  619. }()
  620. return nil
  621. }
  622. // NewNode returns a new, ready to go, Tendermint Node.
  623. func NewNode(config *cfg.Config,
  624. privValidator types.PrivValidator,
  625. nodeKey p2p.NodeKey,
  626. clientCreator proxy.ClientCreator,
  627. genesisDocProvider GenesisDocProvider,
  628. dbProvider DBProvider,
  629. metricsProvider MetricsProvider,
  630. logger log.Logger,
  631. misbehaviors map[int64]cs.Misbehavior,
  632. options ...Option) (*Node, error) {
  633. blockStore, stateDB, err := initDBs(config, dbProvider)
  634. if err != nil {
  635. return nil, err
  636. }
  637. stateStore := sm.NewStore(stateDB)
  638. state, genDoc, err := LoadStateFromDBOrGenesisDocProvider(stateDB, genesisDocProvider)
  639. if err != nil {
  640. return nil, err
  641. }
  642. // Create the proxyApp and establish connections to the ABCI app (consensus, mempool, query).
  643. proxyApp, err := createAndStartProxyAppConns(clientCreator, logger)
  644. if err != nil {
  645. return nil, err
  646. }
  647. // EventBus and IndexerService must be started before the handshake because
  648. // we might need to index the txs of the replayed block as this might not have happened
  649. // when the node stopped last time (i.e. the node stopped after it saved the block
  650. // but before it indexed the txs, or, endblocker panicked)
  651. eventBus, err := createAndStartEventBus(logger)
  652. if err != nil {
  653. return nil, err
  654. }
  655. // Transaction indexing
  656. indexerService, txIndexer, err := createAndStartIndexerService(config, dbProvider, eventBus, logger)
  657. if err != nil {
  658. return nil, err
  659. }
  660. // If an address is provided, listen on the socket for a connection from an
  661. // external signing process.
  662. if config.PrivValidatorListenAddr != "" {
  663. // FIXME: we should start services inside OnStart
  664. privValidator, err = createAndStartPrivValidatorSocketClient(config.PrivValidatorListenAddr, genDoc.ChainID, logger)
  665. if err != nil {
  666. return nil, fmt.Errorf("error with private validator socket client: %w", err)
  667. }
  668. }
  669. pubKey, err := privValidator.GetPubKey()
  670. if err != nil {
  671. return nil, fmt.Errorf("can't get pubkey: %w", err)
  672. }
  673. // Determine whether we should do state and/or fast sync.
  674. // We don't fast-sync when the only validator is us.
  675. fastSync := config.FastSyncMode && !onlyValidatorIsUs(state, pubKey)
  676. stateSync := config.StateSync.Enable && !onlyValidatorIsUs(state, pubKey)
  677. if stateSync && state.LastBlockHeight > 0 {
  678. logger.Info("Found local state with non-zero height, skipping state sync")
  679. stateSync = false
  680. }
  681. // Create the handshaker, which calls RequestInfo, sets the AppVersion on the state,
  682. // and replays any blocks as necessary to sync tendermint with the app.
  683. consensusLogger := logger.With("module", "consensus")
  684. if !stateSync {
  685. if err := doHandshake(stateStore, state, blockStore, genDoc, eventBus, proxyApp, consensusLogger); err != nil {
  686. return nil, err
  687. }
  688. // Reload the state. It will have the Version.Consensus.App set by the
  689. // Handshake, and may have other modifications as well (ie. depending on
  690. // what happened during block replay).
  691. state, err = stateStore.Load()
  692. if err != nil {
  693. return nil, fmt.Errorf("cannot load state: %w", err)
  694. }
  695. }
  696. logNodeStartupInfo(state, pubKey, logger, consensusLogger)
  697. // TODO: Fetch and provide real options and do proper p2p bootstrapping.
  698. // TODO: Use a persistent peer database.
  699. peerMgr, err := p2p.NewPeerManager(dbm.NewMemDB(), p2p.PeerManagerOptions{})
  700. if err != nil {
  701. return nil, err
  702. }
  703. csMetrics, p2pMetrics, memplMetrics, smMetrics := metricsProvider(genDoc.ChainID)
  704. mpReactorShim, mpReactor, mempool := createMempoolReactor(config, proxyApp, state, memplMetrics, peerMgr, logger)
  705. evReactorShim, evReactor, evPool, err := createEvidenceReactor(config, dbProvider, stateDB, blockStore, logger)
  706. if err != nil {
  707. return nil, err
  708. }
  709. // make block executor for consensus and blockchain reactors to execute blocks
  710. blockExec := sm.NewBlockExecutor(
  711. stateStore,
  712. logger.With("module", "state"),
  713. proxyApp.Consensus(),
  714. mempool,
  715. evPool,
  716. sm.BlockExecutorWithMetrics(smMetrics),
  717. )
  718. logger.Info("Setting up maverick consensus reactor", "Misbehaviors", misbehaviors)
  719. csReactor, csState := createConsensusReactor(
  720. config, state, blockExec, blockStore, mempool, evPool,
  721. privValidator, csMetrics, stateSync || fastSync, eventBus, consensusLogger, misbehaviors,
  722. )
  723. // Create the blockchain reactor. Note, we do not start fast sync if we're
  724. // doing a state sync first.
  725. bcReactorShim, bcReactor, err := createBlockchainReactor(
  726. logger, config, state, blockExec, blockStore, csReactor, fastSync && !stateSync,
  727. )
  728. if err != nil {
  729. return nil, fmt.Errorf("could not create blockchain reactor: %w", err)
  730. }
  731. // TODO: Remove this once the switch is removed.
  732. var bcReactorForSwitch p2p.Reactor
  733. if bcReactorShim != nil {
  734. bcReactorForSwitch = bcReactorShim
  735. } else {
  736. bcReactorForSwitch = bcReactor.(p2p.Reactor)
  737. }
  738. // Make ConsensusReactor. Don't enable fully if doing a state sync and/or fast sync first.
  739. // FIXME We need to update metrics here, since other reactors don't have access to them.
  740. if stateSync {
  741. csMetrics.StateSyncing.Set(1)
  742. } else if fastSync {
  743. csMetrics.FastSyncing.Set(1)
  744. }
  745. // Set up state sync reactor, and schedule a sync if requested.
  746. // FIXME The way we do phased startups (e.g. replay -> fast sync -> consensus) is very messy,
  747. // we should clean this whole thing up. See:
  748. // https://github.com/tendermint/tendermint/issues/4644
  749. stateSyncReactorShim := p2p.NewReactorShim(logger.With("module", "statesync"), "StateSyncShim", statesync.ChannelShims)
  750. stateSyncReactor := statesync.NewReactor(
  751. stateSyncReactorShim.Logger,
  752. proxyApp.Snapshot(),
  753. proxyApp.Query(),
  754. stateSyncReactorShim.GetChannel(statesync.SnapshotChannel),
  755. stateSyncReactorShim.GetChannel(statesync.ChunkChannel),
  756. stateSyncReactorShim.PeerUpdates,
  757. config.StateSync.TempDir,
  758. )
  759. nodeInfo, err := makeNodeInfo(config, nodeKey, txIndexer, genDoc, state)
  760. if err != nil {
  761. return nil, err
  762. }
  763. // Setup Transport and Switch.
  764. p2pLogger := logger.With("module", "p2p")
  765. transport, peerFilters := createTransport(p2pLogger, config, nodeInfo, nodeKey, proxyApp)
  766. sw := createSwitch(
  767. config, transport, p2pMetrics, peerFilters, mpReactorShim, bcReactorForSwitch,
  768. stateSyncReactorShim, csReactor, evReactorShim, nodeInfo, nodeKey, p2pLogger,
  769. )
  770. err = sw.AddPersistentPeers(splitAndTrimEmpty(config.P2P.PersistentPeers, ",", " "))
  771. if err != nil {
  772. return nil, fmt.Errorf("could not add peers from persistent-peers field: %w", err)
  773. }
  774. err = sw.AddUnconditionalPeerIDs(splitAndTrimEmpty(config.P2P.UnconditionalPeerIDs, ",", " "))
  775. if err != nil {
  776. return nil, fmt.Errorf("could not add peer ids from unconditional_peer_ids field: %w", err)
  777. }
  778. addrBook, err := createAddrBookAndSetOnSwitch(config, sw, p2pLogger, nodeKey)
  779. if err != nil {
  780. return nil, fmt.Errorf("could not create addrbook: %w", err)
  781. }
  782. // Optionally, start the pex reactor
  783. //
  784. // TODO:
  785. //
  786. // We need to set Seeds and PersistentPeers on the switch,
  787. // since it needs to be able to use these (and their DNS names)
  788. // even if the PEX is off. We can include the DNS name in the NetAddress,
  789. // but it would still be nice to have a clear list of the current "PersistentPeers"
  790. // somewhere that we can return with net_info.
  791. //
  792. // If PEX is on, it should handle dialing the seeds. Otherwise the switch does it.
  793. // Note we currently use the addrBook regardless at least for AddOurAddress
  794. var pexReactor *pex.Reactor
  795. if config.P2P.PexReactor {
  796. pexReactor = createPEXReactorAndAddToSwitch(addrBook, config, sw, logger)
  797. }
  798. if config.RPC.PprofListenAddress != "" {
  799. go func() {
  800. logger.Info("Starting pprof server", "laddr", config.RPC.PprofListenAddress)
  801. logger.Error("pprof server error", "err", http.ListenAndServe(config.RPC.PprofListenAddress, nil))
  802. }()
  803. }
  804. node := &Node{
  805. config: config,
  806. genesisDoc: genDoc,
  807. privValidator: privValidator,
  808. transport: transport,
  809. sw: sw,
  810. addrBook: addrBook,
  811. nodeInfo: nodeInfo,
  812. nodeKey: nodeKey,
  813. stateStore: stateStore,
  814. blockStore: blockStore,
  815. bcReactor: bcReactor,
  816. mempoolReactor: mpReactor,
  817. mempool: mempool,
  818. consensusState: csState,
  819. consensusReactor: csReactor,
  820. stateSyncReactor: stateSyncReactor,
  821. stateSync: stateSync,
  822. stateSyncGenesis: state, // Shouldn't be necessary, but need a way to pass the genesis state
  823. pexReactor: pexReactor,
  824. evidenceReactor: evReactor,
  825. evidencePool: evPool,
  826. proxyApp: proxyApp,
  827. txIndexer: txIndexer,
  828. indexerService: indexerService,
  829. eventBus: eventBus,
  830. }
  831. node.BaseService = *service.NewBaseService(logger, "Node", node)
  832. for _, option := range options {
  833. option(node)
  834. }
  835. return node, nil
  836. }
  837. // OnStart starts the Node. It implements service.Service.
  838. func (n *Node) OnStart() error {
  839. now := tmtime.Now()
  840. genTime := n.genesisDoc.GenesisTime
  841. if genTime.After(now) {
  842. n.Logger.Info("Genesis time is in the future. Sleeping until then...", "genTime", genTime)
  843. time.Sleep(genTime.Sub(now))
  844. }
  845. // Add private IDs to addrbook to block those peers being added
  846. n.addrBook.AddPrivateIDs(splitAndTrimEmpty(n.config.P2P.PrivatePeerIDs, ",", " "))
  847. // Start the RPC server before the P2P server
  848. // so we can eg. receive txs for the first block
  849. if n.config.RPC.ListenAddress != "" {
  850. listeners, err := n.startRPC()
  851. if err != nil {
  852. return err
  853. }
  854. n.rpcListeners = listeners
  855. }
  856. if n.config.Instrumentation.Prometheus &&
  857. n.config.Instrumentation.PrometheusListenAddr != "" {
  858. n.prometheusSrv = n.startPrometheusServer(n.config.Instrumentation.PrometheusListenAddr)
  859. }
  860. // Start the mempool.
  861. if n.config.Mempool.WalEnabled() {
  862. err := n.mempool.InitWAL()
  863. if err != nil {
  864. return fmt.Errorf("init mempool WAL: %w", err)
  865. }
  866. }
  867. // Start the switch (the P2P server).
  868. err := n.sw.Start()
  869. if err != nil {
  870. return err
  871. }
  872. // Start the transport.
  873. addr, err := p2p.NewNetAddressString(p2p.IDAddressString(n.nodeKey.ID, n.config.P2P.ListenAddress))
  874. if err != nil {
  875. return err
  876. }
  877. if err := n.transport.Listen(addr.Endpoint()); err != nil {
  878. return err
  879. }
  880. n.isListening = true
  881. if n.config.FastSync.Version == "v0" {
  882. // Start the real blockchain reactor separately since the switch uses the shim.
  883. if err := n.bcReactor.Start(); err != nil {
  884. return err
  885. }
  886. }
  887. // Start the real state sync reactor separately since the switch uses the shim.
  888. if err := n.stateSyncReactor.Start(); err != nil {
  889. return err
  890. }
  891. // Start the real mempool reactor separately since the switch uses the shim.
  892. if err := n.mempoolReactor.Start(); err != nil {
  893. return err
  894. }
  895. // Start the real evidence reactor separately since the switch uses the shim.
  896. if err := n.evidenceReactor.Start(); err != nil {
  897. return err
  898. }
  899. // Always connect to persistent peers
  900. err = n.sw.DialPeersAsync(splitAndTrimEmpty(n.config.P2P.PersistentPeers, ",", " "))
  901. if err != nil {
  902. return fmt.Errorf("could not dial peers from persistent-peers field: %w", err)
  903. }
  904. // Run state sync
  905. if n.stateSync {
  906. bcR, ok := n.bcReactor.(fastSyncReactor)
  907. if !ok {
  908. return fmt.Errorf("this blockchain reactor does not support switching from state sync")
  909. }
  910. err := startStateSync(n.stateSyncReactor, bcR, n.consensusReactor, n.stateSyncProvider,
  911. n.config.StateSync, n.config.FastSyncMode, n.stateStore, n.blockStore, n.stateSyncGenesis)
  912. if err != nil {
  913. return fmt.Errorf("failed to start state sync: %w", err)
  914. }
  915. }
  916. return nil
  917. }
  918. // OnStop stops the Node. It implements service.Service.
  919. func (n *Node) OnStop() {
  920. n.BaseService.OnStop()
  921. n.Logger.Info("Stopping Node")
  922. // first stop the non-reactor services
  923. if err := n.eventBus.Stop(); err != nil {
  924. n.Logger.Error("Error closing eventBus", "err", err)
  925. }
  926. if err := n.indexerService.Stop(); err != nil {
  927. n.Logger.Error("Error closing indexerService", "err", err)
  928. }
  929. // now stop the reactors
  930. if err := n.sw.Stop(); err != nil {
  931. n.Logger.Error("Error closing switch", "err", err)
  932. }
  933. if n.config.FastSync.Version == "v0" {
  934. // Stop the real blockchain reactor separately since the switch uses the shim.
  935. if err := n.bcReactor.Stop(); err != nil {
  936. n.Logger.Error("failed to stop the blockchain reactor", "err", err)
  937. }
  938. }
  939. // Stop the real state sync reactor separately since the switch uses the shim.
  940. if err := n.stateSyncReactor.Stop(); err != nil {
  941. n.Logger.Error("failed to stop the state sync reactor", "err", err)
  942. }
  943. // Stop the real mempool reactor separately since the switch uses the shim.
  944. if err := n.mempoolReactor.Stop(); err != nil {
  945. n.Logger.Error("failed to stop the mempool reactor", "err", err)
  946. }
  947. // Stop the real evidence reactor separately since the switch uses the shim.
  948. if err := n.evidenceReactor.Stop(); err != nil {
  949. n.Logger.Error("failed to stop the evidence reactor", "err", err)
  950. }
  951. // stop mempool WAL
  952. if n.config.Mempool.WalEnabled() {
  953. n.mempool.CloseWAL()
  954. }
  955. if err := n.transport.Close(); err != nil {
  956. n.Logger.Error("Error closing transport", "err", err)
  957. }
  958. n.isListening = false
  959. // finally stop the listeners / external services
  960. for _, l := range n.rpcListeners {
  961. n.Logger.Info("Closing rpc listener", "listener", l)
  962. if err := l.Close(); err != nil {
  963. n.Logger.Error("Error closing listener", "listener", l, "err", err)
  964. }
  965. }
  966. if pvsc, ok := n.privValidator.(service.Service); ok {
  967. if err := pvsc.Stop(); err != nil {
  968. n.Logger.Error("Error closing private validator", "err", err)
  969. }
  970. }
  971. if n.prometheusSrv != nil {
  972. if err := n.prometheusSrv.Shutdown(context.Background()); err != nil {
  973. // Error from closing listeners, or context timeout:
  974. n.Logger.Error("Prometheus HTTP server Shutdown", "err", err)
  975. }
  976. }
  977. }
  978. // ConfigureRPC makes sure RPC has all the objects it needs to operate.
  979. func (n *Node) ConfigureRPC() error {
  980. pubKey, err := n.privValidator.GetPubKey()
  981. if err != nil {
  982. return fmt.Errorf("can't get pubkey: %w", err)
  983. }
  984. rpccore.SetEnvironment(&rpccore.Environment{
  985. ProxyAppQuery: n.proxyApp.Query(),
  986. ProxyAppMempool: n.proxyApp.Mempool(),
  987. StateStore: n.stateStore,
  988. BlockStore: n.blockStore,
  989. EvidencePool: n.evidencePool,
  990. ConsensusState: n.consensusState,
  991. P2PPeers: n.sw,
  992. P2PTransport: n,
  993. PubKey: pubKey,
  994. GenDoc: n.genesisDoc,
  995. TxIndexer: n.txIndexer,
  996. ConsensusReactor: &consensus.Reactor{},
  997. EventBus: n.eventBus,
  998. Mempool: n.mempool,
  999. Logger: n.Logger.With("module", "rpc"),
  1000. Config: *n.config.RPC,
  1001. })
  1002. return nil
  1003. }
  1004. func (n *Node) startRPC() ([]net.Listener, error) {
  1005. err := n.ConfigureRPC()
  1006. if err != nil {
  1007. return nil, err
  1008. }
  1009. listenAddrs := splitAndTrimEmpty(n.config.RPC.ListenAddress, ",", " ")
  1010. if n.config.RPC.Unsafe {
  1011. rpccore.AddUnsafeRoutes()
  1012. }
  1013. config := rpcserver.DefaultConfig()
  1014. config.MaxBodyBytes = n.config.RPC.MaxBodyBytes
  1015. config.MaxHeaderBytes = n.config.RPC.MaxHeaderBytes
  1016. config.MaxOpenConnections = n.config.RPC.MaxOpenConnections
  1017. // If necessary adjust global WriteTimeout to ensure it's greater than
  1018. // TimeoutBroadcastTxCommit.
  1019. // See https://github.com/tendermint/tendermint/issues/3435
  1020. if config.WriteTimeout <= n.config.RPC.TimeoutBroadcastTxCommit {
  1021. config.WriteTimeout = n.config.RPC.TimeoutBroadcastTxCommit + 1*time.Second
  1022. }
  1023. // we may expose the rpc over both a unix and tcp socket
  1024. listeners := make([]net.Listener, len(listenAddrs))
  1025. for i, listenAddr := range listenAddrs {
  1026. mux := http.NewServeMux()
  1027. rpcLogger := n.Logger.With("module", "rpc-server")
  1028. wmLogger := rpcLogger.With("protocol", "websocket")
  1029. wm := rpcserver.NewWebsocketManager(rpccore.Routes,
  1030. rpcserver.OnDisconnect(func(remoteAddr string) {
  1031. err := n.eventBus.UnsubscribeAll(context.Background(), remoteAddr)
  1032. if err != nil && err != tmpubsub.ErrSubscriptionNotFound {
  1033. wmLogger.Error("Failed to unsubscribe addr from events", "addr", remoteAddr, "err", err)
  1034. }
  1035. }),
  1036. rpcserver.ReadLimit(config.MaxBodyBytes),
  1037. )
  1038. wm.SetLogger(wmLogger)
  1039. mux.HandleFunc("/websocket", wm.WebsocketHandler)
  1040. rpcserver.RegisterRPCFuncs(mux, rpccore.Routes, rpcLogger)
  1041. listener, err := rpcserver.Listen(
  1042. listenAddr,
  1043. config,
  1044. )
  1045. if err != nil {
  1046. return nil, err
  1047. }
  1048. var rootHandler http.Handler = mux
  1049. if n.config.RPC.IsCorsEnabled() {
  1050. corsMiddleware := cors.New(cors.Options{
  1051. AllowedOrigins: n.config.RPC.CORSAllowedOrigins,
  1052. AllowedMethods: n.config.RPC.CORSAllowedMethods,
  1053. AllowedHeaders: n.config.RPC.CORSAllowedHeaders,
  1054. })
  1055. rootHandler = corsMiddleware.Handler(mux)
  1056. }
  1057. if n.config.RPC.IsTLSEnabled() {
  1058. go func() {
  1059. if err := rpcserver.ServeTLS(
  1060. listener,
  1061. rootHandler,
  1062. n.config.RPC.CertFile(),
  1063. n.config.RPC.KeyFile(),
  1064. rpcLogger,
  1065. config,
  1066. ); err != nil {
  1067. n.Logger.Error("Error serving server with TLS", "err", err)
  1068. }
  1069. }()
  1070. } else {
  1071. go func() {
  1072. if err := rpcserver.Serve(
  1073. listener,
  1074. rootHandler,
  1075. rpcLogger,
  1076. config,
  1077. ); err != nil {
  1078. n.Logger.Error("Error serving server", "err", err)
  1079. }
  1080. }()
  1081. }
  1082. listeners[i] = listener
  1083. }
  1084. // we expose a simplified api over grpc for convenience to app devs
  1085. grpcListenAddr := n.config.RPC.GRPCListenAddress
  1086. if grpcListenAddr != "" {
  1087. config := rpcserver.DefaultConfig()
  1088. config.MaxBodyBytes = n.config.RPC.MaxBodyBytes
  1089. config.MaxHeaderBytes = n.config.RPC.MaxHeaderBytes
  1090. // NOTE: GRPCMaxOpenConnections is used, not MaxOpenConnections
  1091. config.MaxOpenConnections = n.config.RPC.GRPCMaxOpenConnections
  1092. // If necessary adjust global WriteTimeout to ensure it's greater than
  1093. // TimeoutBroadcastTxCommit.
  1094. // See https://github.com/tendermint/tendermint/issues/3435
  1095. if config.WriteTimeout <= n.config.RPC.TimeoutBroadcastTxCommit {
  1096. config.WriteTimeout = n.config.RPC.TimeoutBroadcastTxCommit + 1*time.Second
  1097. }
  1098. listener, err := rpcserver.Listen(grpcListenAddr, config)
  1099. if err != nil {
  1100. return nil, err
  1101. }
  1102. go func() {
  1103. if err := grpccore.StartGRPCServer(listener); err != nil {
  1104. n.Logger.Error("Error starting gRPC server", "err", err)
  1105. }
  1106. }()
  1107. listeners = append(listeners, listener)
  1108. }
  1109. return listeners, nil
  1110. }
  1111. // startPrometheusServer starts a Prometheus HTTP server, listening for metrics
  1112. // collectors on addr.
  1113. func (n *Node) startPrometheusServer(addr string) *http.Server {
  1114. srv := &http.Server{
  1115. Addr: addr,
  1116. Handler: promhttp.InstrumentMetricHandler(
  1117. prometheus.DefaultRegisterer, promhttp.HandlerFor(
  1118. prometheus.DefaultGatherer,
  1119. promhttp.HandlerOpts{MaxRequestsInFlight: n.config.Instrumentation.MaxOpenConnections},
  1120. ),
  1121. ),
  1122. }
  1123. go func() {
  1124. if err := srv.ListenAndServe(); err != http.ErrServerClosed {
  1125. // Error starting or closing listener:
  1126. n.Logger.Error("Prometheus HTTP server ListenAndServe", "err", err)
  1127. }
  1128. }()
  1129. return srv
  1130. }
  1131. // Switch returns the Node's Switch.
  1132. func (n *Node) Switch() *p2p.Switch {
  1133. return n.sw
  1134. }
  1135. // BlockStore returns the Node's BlockStore.
  1136. func (n *Node) BlockStore() *store.BlockStore {
  1137. return n.blockStore
  1138. }
  1139. // ConsensusState returns the Node's ConsensusState.
  1140. func (n *Node) ConsensusState() *cs.State {
  1141. return n.consensusState
  1142. }
  1143. // ConsensusReactor returns the Node's ConsensusReactor.
  1144. func (n *Node) ConsensusReactor() *cs.Reactor {
  1145. return n.consensusReactor
  1146. }
  1147. // MempoolReactor returns the Node's mempool reactor.
  1148. func (n *Node) MempoolReactor() *mempl.Reactor {
  1149. return n.mempoolReactor
  1150. }
  1151. // Mempool returns the Node's mempool.
  1152. func (n *Node) Mempool() mempl.Mempool {
  1153. return n.mempool
  1154. }
  1155. // PEXReactor returns the Node's PEXReactor. It returns nil if PEX is disabled.
  1156. func (n *Node) PEXReactor() *pex.Reactor {
  1157. return n.pexReactor
  1158. }
  1159. // EvidencePool returns the Node's EvidencePool.
  1160. func (n *Node) EvidencePool() *evidence.Pool {
  1161. return n.evidencePool
  1162. }
  1163. // EventBus returns the Node's EventBus.
  1164. func (n *Node) EventBus() *types.EventBus {
  1165. return n.eventBus
  1166. }
  1167. // PrivValidator returns the Node's PrivValidator.
  1168. // XXX: for convenience only!
  1169. func (n *Node) PrivValidator() types.PrivValidator {
  1170. return n.privValidator
  1171. }
  1172. // GenesisDoc returns the Node's GenesisDoc.
  1173. func (n *Node) GenesisDoc() *types.GenesisDoc {
  1174. return n.genesisDoc
  1175. }
  1176. // ProxyApp returns the Node's AppConns, representing its connections to the ABCI application.
  1177. func (n *Node) ProxyApp() proxy.AppConns {
  1178. return n.proxyApp
  1179. }
  1180. // Config returns the Node's config.
  1181. func (n *Node) Config() *cfg.Config {
  1182. return n.config
  1183. }
  1184. //------------------------------------------------------------------------------
  1185. func (n *Node) Listeners() []string {
  1186. return []string{
  1187. fmt.Sprintf("Listener(@%v)", n.config.P2P.ExternalAddress),
  1188. }
  1189. }
  1190. func (n *Node) IsListening() bool {
  1191. return n.isListening
  1192. }
  1193. // NodeInfo returns the Node's Info from the Switch.
  1194. func (n *Node) NodeInfo() p2p.NodeInfo {
  1195. return n.nodeInfo
  1196. }
  1197. func makeNodeInfo(
  1198. config *cfg.Config,
  1199. nodeKey p2p.NodeKey,
  1200. txIndexer txindex.TxIndexer,
  1201. genDoc *types.GenesisDoc,
  1202. state sm.State,
  1203. ) (p2p.NodeInfo, error) {
  1204. txIndexerStatus := "on"
  1205. if _, ok := txIndexer.(*null.TxIndex); ok {
  1206. txIndexerStatus = "off"
  1207. }
  1208. var bcChannel byte
  1209. switch config.FastSync.Version {
  1210. case "v0":
  1211. bcChannel = byte(bcv0.BlockchainChannel)
  1212. case "v2":
  1213. bcChannel = bcv2.BlockchainChannel
  1214. default:
  1215. return p2p.NodeInfo{}, fmt.Errorf("unknown fastsync version %s", config.FastSync.Version)
  1216. }
  1217. nodeInfo := p2p.NodeInfo{
  1218. ProtocolVersion: p2p.NewProtocolVersion(
  1219. version.P2PProtocol, // global
  1220. state.Version.Consensus.Block,
  1221. state.Version.Consensus.App,
  1222. ),
  1223. NodeID: nodeKey.ID,
  1224. Network: genDoc.ChainID,
  1225. Version: version.TMCoreSemVer,
  1226. Channels: []byte{
  1227. bcChannel,
  1228. cs.StateChannel,
  1229. cs.DataChannel,
  1230. cs.VoteChannel,
  1231. cs.VoteSetBitsChannel,
  1232. byte(mempl.MempoolChannel),
  1233. byte(evidence.EvidenceChannel),
  1234. byte(statesync.SnapshotChannel),
  1235. byte(statesync.ChunkChannel),
  1236. },
  1237. Moniker: config.Moniker,
  1238. Other: p2p.NodeInfoOther{
  1239. TxIndex: txIndexerStatus,
  1240. RPCAddress: config.RPC.ListenAddress,
  1241. },
  1242. }
  1243. if config.P2P.PexReactor {
  1244. nodeInfo.Channels = append(nodeInfo.Channels, pex.PexChannel)
  1245. }
  1246. lAddr := config.P2P.ExternalAddress
  1247. if lAddr == "" {
  1248. lAddr = config.P2P.ListenAddress
  1249. }
  1250. nodeInfo.ListenAddr = lAddr
  1251. err := nodeInfo.Validate()
  1252. return nodeInfo, err
  1253. }
  1254. //------------------------------------------------------------------------------
  1255. var (
  1256. genesisDocKey = []byte("genesisDoc")
  1257. )
  1258. // LoadStateFromDBOrGenesisDocProvider attempts to load the state from the
  1259. // database, or creates one using the given genesisDocProvider and persists the
  1260. // result to the database. On success this also returns the genesis doc loaded
  1261. // through the given provider.
  1262. func LoadStateFromDBOrGenesisDocProvider(
  1263. stateDB dbm.DB,
  1264. genesisDocProvider GenesisDocProvider,
  1265. ) (sm.State, *types.GenesisDoc, error) {
  1266. // Get genesis doc
  1267. genDoc, err := loadGenesisDoc(stateDB)
  1268. if err != nil {
  1269. genDoc, err = genesisDocProvider()
  1270. if err != nil {
  1271. return sm.State{}, nil, err
  1272. }
  1273. // save genesis doc to prevent a certain class of user errors (e.g. when it
  1274. // was changed, accidentally or not). Also good for audit trail.
  1275. saveGenesisDoc(stateDB, genDoc)
  1276. }
  1277. stateStore := sm.NewStore(stateDB)
  1278. state, err := stateStore.LoadFromDBOrGenesisDoc(genDoc)
  1279. if err != nil {
  1280. return sm.State{}, nil, err
  1281. }
  1282. return state, genDoc, nil
  1283. }
  1284. // panics if failed to unmarshal bytes
  1285. func loadGenesisDoc(db dbm.DB) (*types.GenesisDoc, error) {
  1286. b, err := db.Get(genesisDocKey)
  1287. if err != nil {
  1288. panic(err)
  1289. }
  1290. if len(b) == 0 {
  1291. return nil, errors.New("genesis doc not found")
  1292. }
  1293. var genDoc *types.GenesisDoc
  1294. err = tmjson.Unmarshal(b, &genDoc)
  1295. if err != nil {
  1296. panic(fmt.Sprintf("Failed to load genesis doc due to unmarshaling error: %v (bytes: %X)", err, b))
  1297. }
  1298. return genDoc, nil
  1299. }
  1300. // panics if failed to marshal the given genesis document
  1301. func saveGenesisDoc(db dbm.DB, genDoc *types.GenesisDoc) {
  1302. b, err := tmjson.Marshal(genDoc)
  1303. if err != nil {
  1304. panic(fmt.Sprintf("Failed to save genesis doc due to marshaling error: %v", err))
  1305. }
  1306. if err := db.SetSync(genesisDocKey, b); err != nil {
  1307. panic(fmt.Sprintf("Failed to save genesis doc: %v", err))
  1308. }
  1309. }
  1310. func createAndStartPrivValidatorSocketClient(
  1311. listenAddr,
  1312. chainID string,
  1313. logger log.Logger,
  1314. ) (types.PrivValidator, error) {
  1315. pve, err := privval.NewSignerListener(listenAddr, logger)
  1316. if err != nil {
  1317. return nil, fmt.Errorf("failed to start private validator: %w", err)
  1318. }
  1319. pvsc, err := privval.NewSignerClient(pve, chainID)
  1320. if err != nil {
  1321. return nil, fmt.Errorf("failed to start private validator: %w", err)
  1322. }
  1323. // try to get a pubkey from private validate first time
  1324. _, err = pvsc.GetPubKey()
  1325. if err != nil {
  1326. return nil, fmt.Errorf("can't get pubkey: %w", err)
  1327. }
  1328. const (
  1329. retries = 50 // 50 * 100ms = 5s total
  1330. timeout = 100 * time.Millisecond
  1331. )
  1332. pvscWithRetries := privval.NewRetrySignerClient(pvsc, retries, timeout)
  1333. return pvscWithRetries, nil
  1334. }
  1335. // splitAndTrimEmpty slices s into all subslices separated by sep and returns a
  1336. // slice of the string s with all leading and trailing Unicode code points
  1337. // contained in cutset removed. If sep is empty, SplitAndTrim splits after each
  1338. // UTF-8 sequence. First part is equivalent to strings.SplitN with a count of
  1339. // -1. also filter out empty strings, only return non-empty strings.
  1340. func splitAndTrimEmpty(s, sep, cutset string) []string {
  1341. if s == "" {
  1342. return []string{}
  1343. }
  1344. spl := strings.Split(s, sep)
  1345. nonEmptyStrings := make([]string, 0, len(spl))
  1346. for i := 0; i < len(spl); i++ {
  1347. element := strings.Trim(spl[i], cutset)
  1348. if element != "" {
  1349. nonEmptyStrings = append(nonEmptyStrings, element)
  1350. }
  1351. }
  1352. return nonEmptyStrings
  1353. }