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.

257 lines
7.0 KiB

10 years ago
11 years ago
11 years ago
11 years ago
10 years ago
10 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
10 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
10 years ago
  1. package node
  2. import (
  3. "math/rand"
  4. "net"
  5. "net/http"
  6. "os"
  7. "strconv"
  8. bc "github.com/tendermint/tendermint/blockchain"
  9. . "github.com/tendermint/tendermint/common"
  10. "github.com/tendermint/tendermint/config"
  11. "github.com/tendermint/tendermint/consensus"
  12. dbm "github.com/tendermint/tendermint/db"
  13. "github.com/tendermint/tendermint/events"
  14. mempl "github.com/tendermint/tendermint/mempool"
  15. "github.com/tendermint/tendermint/p2p"
  16. "github.com/tendermint/tendermint/rpc"
  17. "github.com/tendermint/tendermint/rpc/core"
  18. sm "github.com/tendermint/tendermint/state"
  19. "github.com/tendermint/tendermint/types"
  20. )
  21. type Node struct {
  22. sw *p2p.Switch
  23. evsw *events.EventSwitch
  24. book *p2p.AddrBook
  25. blockStore *bc.BlockStore
  26. pexReactor *p2p.PEXReactor
  27. bcReactor *bc.BlockchainReactor
  28. mempoolReactor *mempl.MempoolReactor
  29. consensusState *consensus.ConsensusState
  30. consensusReactor *consensus.ConsensusReactor
  31. privValidator *sm.PrivValidator
  32. }
  33. func NewNode() *Node {
  34. // Get BlockStore
  35. blockStoreDB := dbm.GetDB("blockstore")
  36. blockStore := bc.NewBlockStore(blockStoreDB)
  37. // Get State
  38. stateDB := dbm.GetDB("state")
  39. state := sm.LoadState(stateDB)
  40. if state == nil {
  41. state = sm.MakeGenesisStateFromFile(stateDB, config.App().GetString("GenesisFile"))
  42. state.Save()
  43. }
  44. // Get PrivValidator
  45. var privValidator *sm.PrivValidator
  46. privValidatorFile := config.App().GetString("PrivValidatorFile")
  47. if _, err := os.Stat(privValidatorFile); err == nil {
  48. privValidator = sm.LoadPrivValidator(privValidatorFile)
  49. log.Info("Loaded PrivValidator",
  50. "file", privValidatorFile, "privValidator", privValidator)
  51. } else {
  52. privValidator = sm.GenPrivValidator()
  53. privValidator.SetFile(privValidatorFile)
  54. privValidator.Save()
  55. log.Info("Generated PrivValidator", "file", privValidatorFile)
  56. }
  57. eventSwitch := new(events.EventSwitch)
  58. eventSwitch.Start()
  59. // Get PEXReactor
  60. book := p2p.NewAddrBook(config.App().GetString("AddrBookFile"))
  61. pexReactor := p2p.NewPEXReactor(book)
  62. // Get BlockchainReactor
  63. bcReactor := bc.NewBlockchainReactor(state, blockStore, config.App().GetBool("FastSync"))
  64. // Get MempoolReactor
  65. mempool := mempl.NewMempool(state.Copy())
  66. mempoolReactor := mempl.NewMempoolReactor(mempool)
  67. // Get ConsensusReactor
  68. consensusState := consensus.NewConsensusState(state, blockStore, mempoolReactor)
  69. consensusReactor := consensus.NewConsensusReactor(consensusState, blockStore)
  70. if privValidator != nil {
  71. consensusReactor.SetPrivValidator(privValidator)
  72. }
  73. // so the consensus reactor won't do anything until we're synced
  74. if config.App().GetBool("FastSync") {
  75. consensusReactor.SetSyncing(true)
  76. }
  77. sw := p2p.NewSwitch()
  78. sw.AddReactor("PEX", pexReactor)
  79. sw.AddReactor("MEMPOOL", mempoolReactor)
  80. sw.AddReactor("BLOCKCHAIN", bcReactor)
  81. sw.AddReactor("CONSENSUS", consensusReactor)
  82. // add the event switch to all services
  83. // they should all satisfy events.Eventable
  84. SetFireable(eventSwitch, pexReactor, bcReactor, mempoolReactor, consensusReactor)
  85. return &Node{
  86. sw: sw,
  87. evsw: eventSwitch,
  88. book: book,
  89. blockStore: blockStore,
  90. pexReactor: pexReactor,
  91. bcReactor: bcReactor,
  92. mempoolReactor: mempoolReactor,
  93. consensusState: consensusState,
  94. consensusReactor: consensusReactor,
  95. privValidator: privValidator,
  96. }
  97. }
  98. // Call Start() after adding the listeners.
  99. func (n *Node) Start() {
  100. log.Info("Starting Node")
  101. n.book.Start()
  102. nodeInfo := makeNodeInfo(n.sw)
  103. n.sw.SetNodeInfo(nodeInfo)
  104. n.sw.Start()
  105. }
  106. func (n *Node) Stop() {
  107. log.Info("Stopping Node")
  108. // TODO: gracefully disconnect from peers.
  109. n.sw.Stop()
  110. n.book.Stop()
  111. }
  112. // Add the event switch to reactors, mempool, etc.
  113. func SetFireable(evsw *events.EventSwitch, eventables ...events.Eventable) {
  114. for _, e := range eventables {
  115. e.SetFireable(evsw)
  116. }
  117. }
  118. // Add a Listener to accept inbound peer connections.
  119. // Add listeners before starting the Node.
  120. // The first listener is the primary listener (in NodeInfo)
  121. func (n *Node) AddListener(l p2p.Listener) {
  122. log.Info(Fmt("Added %v", l))
  123. n.sw.AddListener(l)
  124. n.book.AddOurAddress(l.ExternalAddress())
  125. }
  126. func (n *Node) DialSeed() {
  127. // if the single seed node is available, use only it
  128. prioritySeed := config.App().GetString("SeedNode")
  129. if prioritySeed != "" {
  130. addr := p2p.NewNetAddressString(prioritySeed)
  131. n.dialSeed(addr)
  132. return
  133. }
  134. // permute the list, dial half of them
  135. seeds := config.App().GetStringSlice("SeedNodes")
  136. perm := rand.Perm(len(seeds))
  137. // TODO: we shouldn't necessarily connect to all of them every time ...
  138. for i := 0; i < len(perm); i++ {
  139. j := perm[i]
  140. addr := p2p.NewNetAddressString(seeds[j])
  141. n.dialSeed(addr)
  142. }
  143. }
  144. func (n *Node) dialSeed(addr *p2p.NetAddress) {
  145. peer, err := n.sw.DialPeerWithAddress(addr)
  146. if err != nil {
  147. log.Error("Error dialing seed", "error", err)
  148. //n.book.MarkAttempt(addr)
  149. return
  150. } else {
  151. log.Info("Connected to seed", "peer", peer)
  152. n.book.AddAddress(addr, addr)
  153. }
  154. }
  155. func (n *Node) StartRPC() {
  156. core.SetBlockStore(n.blockStore)
  157. core.SetConsensusState(n.consensusState)
  158. core.SetMempoolReactor(n.mempoolReactor)
  159. core.SetSwitch(n.sw)
  160. listenAddr := config.App().GetString("RPC.HTTP.ListenAddr")
  161. mux := http.NewServeMux()
  162. rpc.RegisterEventsHandler(mux, n.evsw)
  163. rpc.RegisterRPCFuncs(mux, core.Routes)
  164. rpc.StartHTTPServer(listenAddr, mux)
  165. }
  166. func (n *Node) Switch() *p2p.Switch {
  167. return n.sw
  168. }
  169. func (n *Node) ConsensusState() *consensus.ConsensusState {
  170. return n.consensusState
  171. }
  172. func (n *Node) MempoolReactor() *mempl.MempoolReactor {
  173. return n.mempoolReactor
  174. }
  175. func (n *Node) EventSwitch() *events.EventSwitch {
  176. return n.evsw
  177. }
  178. func makeNodeInfo(sw *p2p.Switch) *types.NodeInfo {
  179. nodeInfo := &types.NodeInfo{
  180. Moniker: config.App().GetString("Moniker"),
  181. Network: config.App().GetString("Network"),
  182. Version: "0.0.1",
  183. }
  184. if !sw.IsListening() {
  185. return nodeInfo
  186. }
  187. p2pListener := sw.Listeners()[0]
  188. p2pHost := p2pListener.ExternalAddress().IP.String()
  189. p2pPort := p2pListener.ExternalAddress().Port
  190. rpcListenAddr := config.App().GetString("RPC.HTTP.ListenAddr")
  191. _, rpcPortStr, _ := net.SplitHostPort(rpcListenAddr)
  192. rpcPort, err := strconv.Atoi(rpcPortStr)
  193. if err != nil {
  194. panic(Fmt("Expected numeric RPC.HTTP.ListenAddr port but got %v", rpcPortStr))
  195. }
  196. // We assume that the rpcListener has the same ExternalAddress.
  197. // This is probably true because both P2P and RPC listeners use UPnP.
  198. nodeInfo.Host = p2pHost
  199. nodeInfo.P2PPort = p2pPort
  200. nodeInfo.RPCPort = uint16(rpcPort)
  201. return nodeInfo
  202. }
  203. //------------------------------------------------------------------------------
  204. func RunNode() {
  205. // Create & start node
  206. n := NewNode()
  207. l := p2p.NewDefaultListener("tcp", config.App().GetString("ListenAddr"), false)
  208. n.AddListener(l)
  209. n.Start()
  210. // If seedNode is provided by config, dial out.
  211. if config.App().GetString("SeedNode") != "" || len(config.App().GetStringSlice("SeedNodes")) != 0 {
  212. n.DialSeed()
  213. }
  214. // Run the RPC server.
  215. if config.App().GetString("RPC.HTTP.ListenAddr") != "" {
  216. n.StartRPC()
  217. }
  218. // Sleep forever and then...
  219. TrapSignal(func() {
  220. n.Stop()
  221. })
  222. }