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.

317 lines
8.7 KiB

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