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.

265 lines
7.0 KiB

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