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.

305 lines
8.3 KiB

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