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.

244 lines
6.8 KiB

11 years ago
11 years ago
11 years ago
10 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
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
10 years ago
11 years ago
10 years ago
  1. package daemon
  2. import (
  3. "os"
  4. "os/signal"
  5. "github.com/ebuchman/debora"
  6. bc "github.com/tendermint/tendermint/blockchain"
  7. . "github.com/tendermint/tendermint/common"
  8. "github.com/tendermint/tendermint/config"
  9. "github.com/tendermint/tendermint/consensus"
  10. dbm "github.com/tendermint/tendermint/db"
  11. mempl "github.com/tendermint/tendermint/mempool"
  12. "github.com/tendermint/tendermint/p2p"
  13. "github.com/tendermint/tendermint/rpc"
  14. "github.com/tendermint/tendermint/rpc/core"
  15. sm "github.com/tendermint/tendermint/state"
  16. )
  17. type Node struct {
  18. sw *p2p.Switch
  19. book *p2p.AddrBook
  20. blockStore *bc.BlockStore
  21. pexReactor *p2p.PEXReactor
  22. bcReactor *bc.BlockchainReactor
  23. mempoolReactor *mempl.MempoolReactor
  24. consensusState *consensus.ConsensusState
  25. consensusReactor *consensus.ConsensusReactor
  26. privValidator *sm.PrivValidator
  27. }
  28. func NewNode() *Node {
  29. // Get BlockStore
  30. blockStoreDB := dbm.GetDB("blockstore")
  31. blockStore := bc.NewBlockStore(blockStoreDB)
  32. // Get State
  33. stateDB := dbm.GetDB("state")
  34. state := sm.LoadState(stateDB)
  35. if state == nil {
  36. state = sm.MakeGenesisStateFromFile(stateDB, config.App().GetString("GenesisFile"))
  37. state.Save()
  38. }
  39. // Get PrivValidator
  40. var privValidator *sm.PrivValidator
  41. if _, err := os.Stat(config.App().GetString("PrivValidatorFile")); err == nil {
  42. privValidator = sm.LoadPrivValidator(config.App().GetString("PrivValidatorFile"))
  43. log.Info("Loaded PrivValidator", "file", config.App().GetString("PrivValidatorFile"), "privValidator", privValidator)
  44. } else {
  45. log.Info("No PrivValidator found", "file", config.App().GetString("PrivValidatorFile"))
  46. }
  47. // Get PEXReactor
  48. book := p2p.NewAddrBook(config.App().GetString("AddrBookFile"))
  49. pexReactor := p2p.NewPEXReactor(book)
  50. // Get BlockchainReactor
  51. bcReactor := bc.NewBlockchainReactor(state, blockStore, config.App().GetBool("FastSync"))
  52. // Get MempoolReactor
  53. mempool := mempl.NewMempool(state.Copy())
  54. mempoolReactor := mempl.NewMempoolReactor(mempool)
  55. // Get ConsensusReactor
  56. consensusState := consensus.NewConsensusState(state, blockStore, mempoolReactor)
  57. consensusReactor := consensus.NewConsensusReactor(consensusState, blockStore)
  58. if privValidator != nil {
  59. consensusReactor.SetPrivValidator(privValidator)
  60. }
  61. sw := p2p.NewSwitch()
  62. sw.SetNetwork(config.App().GetString("Network"))
  63. sw.AddReactor("PEX", pexReactor)
  64. sw.AddReactor("MEMPOOL", mempoolReactor)
  65. sw.AddReactor("BLOCKCHAIN", bcReactor)
  66. sw.AddReactor("CONSENSUS", consensusReactor)
  67. return &Node{
  68. sw: sw,
  69. book: book,
  70. blockStore: blockStore,
  71. pexReactor: pexReactor,
  72. bcReactor: bcReactor,
  73. mempoolReactor: mempoolReactor,
  74. consensusState: consensusState,
  75. consensusReactor: consensusReactor,
  76. privValidator: privValidator,
  77. }
  78. }
  79. func (n *Node) Start() {
  80. log.Info("Starting Node")
  81. n.book.Start()
  82. n.sw.Reactor("PEX").Start(n.sw)
  83. n.sw.Reactor("MEMPOOL").Start(n.sw)
  84. n.sw.Reactor("BLOCKCHAIN").Start(n.sw)
  85. if !config.App().GetBool("FastSync") {
  86. n.sw.Reactor("CONSENSUS").Start(n.sw)
  87. }
  88. }
  89. func (n *Node) Stop() {
  90. log.Info("Stopping Node")
  91. // TODO: gracefully disconnect from peers.
  92. n.sw.Stop()
  93. n.book.Stop()
  94. }
  95. // Add a Listener to accept inbound peer connections.
  96. func (n *Node) AddListener(l p2p.Listener) {
  97. log.Info(Fmt("Added %v", l))
  98. n.sw.AddListener(l)
  99. n.book.AddOurAddress(l.ExternalAddress())
  100. }
  101. func (n *Node) inboundConnectionRoutine(l p2p.Listener) {
  102. for {
  103. inConn, ok := <-l.Connections()
  104. if !ok {
  105. break
  106. }
  107. // New inbound connection!
  108. peer, err := n.sw.AddPeerWithConnection(inConn, false)
  109. if err != nil {
  110. log.Info("Ignoring error from inbound connection: %v\n%v",
  111. peer, err)
  112. continue
  113. }
  114. // NOTE: We don't yet have the external address of the
  115. // remote (if they have a listener at all).
  116. // PEXReactor's pexRoutine will handle that.
  117. }
  118. // cleanup
  119. }
  120. func (n *Node) DialSeed() {
  121. addr := p2p.NewNetAddressString(config.App().GetString("SeedNode"))
  122. peer, err := n.sw.DialPeerWithAddress(addr)
  123. if err != nil {
  124. log.Error("Error dialing seed", "error", err)
  125. //n.book.MarkAttempt(addr)
  126. return
  127. } else {
  128. log.Info("Connected to seed", "peer", peer)
  129. n.book.AddAddress(addr, addr)
  130. }
  131. }
  132. func (n *Node) StartRPC() {
  133. core.SetBlockStore(n.blockStore)
  134. core.SetConsensusState(n.consensusState)
  135. core.SetMempoolReactor(n.mempoolReactor)
  136. core.SetSwitch(n.sw)
  137. rpc.StartHTTPServer()
  138. }
  139. func (n *Node) Switch() *p2p.Switch {
  140. return n.sw
  141. }
  142. func (n *Node) ConsensusState() *consensus.ConsensusState {
  143. return n.consensusState
  144. }
  145. func (n *Node) MempoolReactor() *mempl.MempoolReactor {
  146. return n.mempoolReactor
  147. }
  148. //------------------------------------------------------------------------------
  149. // debora variables
  150. var (
  151. AppName = "tendermint"
  152. SrcPath = "github.com/tendermint/tendermint/cmd"
  153. PublicKey = "30820122300d06092a864886f70d01010105000382010f003082010a0282010100d1ffab251e05c0cae7bdd5f94c1b9644d4eb66847ee2e9a622b09e0228f2e70e6fecd1dfe6b3dc59fefab1abf0ff4e5d9657541cbe697ab1cf23fb26c9b857f6b6db8b67a0223b514ca77c8f1e049eaf9477d1a5f8041d045eeb0253a3c1ff7b90150d9b5c814a8d05fb707dd35aac118d5457334a557a82579f727a8bed521b0895b73da2458ffd1fc4be91adb624cc25731194d491f23ed47bf9a7265d28b23885e8a70625772eeeaf8e56ff3a1a2f33934668cc3a874042711f8b386da7842c117441a4d6ed29a182a00499ed5d4b6ce9532c5468d3976991f66d595a6f361e29cdf7750cf1c21e583e4c2207334c8d33ead731bf1172793b176089978b110203010001"
  154. DeboraCallPort = 56565
  155. )
  156. type DeboraMode int
  157. const (
  158. DeboraNullMode = iota // debora off by default
  159. DeboraPeerMode // upgradeable
  160. DeboraDevMode // upgrader
  161. )
  162. func deboraBroadcast(n *Node) func([]byte) {
  163. return func(payload []byte) {
  164. msg := &p2p.PexDeboraMessage{Payload: payload}
  165. n.sw.Broadcast(p2p.PexChannel, msg)
  166. }
  167. }
  168. func Daemon(deborable DeboraMode) {
  169. // Add to debora
  170. if deborable == DeboraPeerMode {
  171. // TODO: support debora.logfile
  172. if err := debora.Add(PublicKey, SrcPath, AppName, config.App().GetString("Debora.LogFile")); err != nil {
  173. log.Info("Failed to add program to debora", "error", err)
  174. }
  175. }
  176. // Create & start node
  177. n := NewNode()
  178. l := p2p.NewDefaultListener("tcp", config.App().GetString("ListenAddr"), false)
  179. n.AddListener(l)
  180. n.Start()
  181. if deborable == DeboraDevMode {
  182. log.Info("Running debora-dev server (listen to call)")
  183. debora.DebListenAndServe("tendermint", DeboraCallPort, deboraBroadcast(n))
  184. }
  185. // If seedNode is provided by config, dial out.
  186. if config.App().GetString("SeedNode") != "" {
  187. n.DialSeed()
  188. }
  189. // Run the RPC server.
  190. if config.App().GetString("RPC.HTTP.ListenAddr") != "" {
  191. n.StartRPC()
  192. }
  193. // Sleep forever and then...
  194. trapSignal(func() {
  195. n.Stop()
  196. })
  197. }
  198. func trapSignal(cb func()) {
  199. c := make(chan os.Signal, 1)
  200. signal.Notify(c, os.Interrupt)
  201. go func() {
  202. for sig := range c {
  203. log.Info(Fmt("captured %v, exiting..", sig))
  204. cb()
  205. os.Exit(1)
  206. }
  207. }()
  208. select {}
  209. }