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.

417 lines
12 KiB

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
10 years ago
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
  1. package node
  2. import (
  3. "bytes"
  4. "io/ioutil"
  5. "math/rand"
  6. "net"
  7. "net/http"
  8. "strings"
  9. "sync"
  10. "time"
  11. . "github.com/tendermint/go-common"
  12. "github.com/tendermint/go-crypto"
  13. dbm "github.com/tendermint/go-db"
  14. "github.com/tendermint/go-events"
  15. "github.com/tendermint/go-p2p"
  16. "github.com/tendermint/go-rpc"
  17. "github.com/tendermint/go-rpc/server"
  18. "github.com/tendermint/go-wire"
  19. bc "github.com/tendermint/tendermint/blockchain"
  20. "github.com/tendermint/tendermint/consensus"
  21. mempl "github.com/tendermint/tendermint/mempool"
  22. "github.com/tendermint/tendermint/proxy"
  23. "github.com/tendermint/tendermint/rpc/core"
  24. sm "github.com/tendermint/tendermint/state"
  25. "github.com/tendermint/tendermint/types"
  26. "github.com/tendermint/tmsp/example/golang"
  27. )
  28. import _ "net/http/pprof"
  29. type Node struct {
  30. sw *p2p.Switch
  31. evsw *events.EventSwitch
  32. blockStore *bc.BlockStore
  33. bcReactor *bc.BlockchainReactor
  34. mempoolReactor *mempl.MempoolReactor
  35. consensusState *consensus.ConsensusState
  36. consensusReactor *consensus.ConsensusReactor
  37. privValidator *types.PrivValidator
  38. genesisDoc *types.GenesisDoc
  39. privKey crypto.PrivKeyEd25519
  40. }
  41. func NewNode(privValidator *types.PrivValidator) *Node {
  42. // Get BlockStore
  43. blockStoreDB := dbm.GetDB("blockstore")
  44. blockStore := bc.NewBlockStore(blockStoreDB)
  45. // Get State
  46. state := getState()
  47. // Create two proxyAppConn connections,
  48. // one for the consensus and one for the mempool.
  49. proxyAddr := config.GetString("proxy_app")
  50. proxyAppConnMempool := getProxyApp(proxyAddr, state.AppHash)
  51. proxyAppConnConsensus := getProxyApp(proxyAddr, state.AppHash)
  52. // add the chainid to the global config
  53. config.Set("chain_id", state.ChainID)
  54. // Generate node PrivKey
  55. privKey := crypto.GenPrivKeyEd25519()
  56. // Make event switch
  57. eventSwitch := events.NewEventSwitch()
  58. _, err := eventSwitch.Start()
  59. if err != nil {
  60. Exit(Fmt("Failed to start switch: %v", err))
  61. }
  62. // Make BlockchainReactor
  63. bcReactor := bc.NewBlockchainReactor(state.Copy(), proxyAppConnConsensus, blockStore, config.GetBool("fast_sync"))
  64. // Make MempoolReactor
  65. mempool := mempl.NewMempool(proxyAppConnMempool)
  66. mempoolReactor := mempl.NewMempoolReactor(mempool)
  67. // Make ConsensusReactor
  68. consensusState := consensus.NewConsensusState(state.Copy(), proxyAppConnConsensus, blockStore, mempool)
  69. consensusReactor := consensus.NewConsensusReactor(consensusState, blockStore, config.GetBool("fast_sync"))
  70. if privValidator != nil {
  71. consensusReactor.SetPrivValidator(privValidator)
  72. }
  73. // deterministic accountability
  74. err = consensusState.OpenFileForMessageLog(config.GetString("cs_msg_log"))
  75. if err != nil {
  76. log.Error("Failed to open cs_msg_log", "error", err.Error())
  77. }
  78. // Make p2p network switch
  79. sw := p2p.NewSwitch()
  80. sw.AddReactor("MEMPOOL", mempoolReactor)
  81. sw.AddReactor("BLOCKCHAIN", bcReactor)
  82. sw.AddReactor("CONSENSUS", consensusReactor)
  83. // add the event switch to all services
  84. // they should all satisfy events.Eventable
  85. SetEventSwitch(eventSwitch, bcReactor, mempoolReactor, consensusReactor)
  86. // run the profile server
  87. profileHost := config.GetString("prof_laddr")
  88. if profileHost != "" {
  89. go func() {
  90. log.Warn("Profile server", "error", http.ListenAndServe(profileHost, nil))
  91. }()
  92. }
  93. return &Node{
  94. sw: sw,
  95. evsw: eventSwitch,
  96. blockStore: blockStore,
  97. bcReactor: bcReactor,
  98. mempoolReactor: mempoolReactor,
  99. consensusState: consensusState,
  100. consensusReactor: consensusReactor,
  101. privValidator: privValidator,
  102. genesisDoc: state.GenesisDoc,
  103. privKey: privKey,
  104. }
  105. }
  106. // Call Start() after adding the listeners.
  107. func (n *Node) Start() error {
  108. n.sw.SetNodeInfo(makeNodeInfo(n.sw, n.privKey))
  109. n.sw.SetNodePrivKey(n.privKey)
  110. _, err := n.sw.Start()
  111. return err
  112. }
  113. func (n *Node) Stop() {
  114. log.Notice("Stopping Node")
  115. // TODO: gracefully disconnect from peers.
  116. n.sw.Stop()
  117. }
  118. // Add the event switch to reactors, mempool, etc.
  119. func SetEventSwitch(evsw *events.EventSwitch, eventables ...events.Eventable) {
  120. for _, e := range eventables {
  121. e.SetEventSwitch(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.Notice(Fmt("Added %v", l))
  129. n.sw.AddListener(l)
  130. }
  131. // Dial a list of seeds in random order
  132. // Spawns a go routine for each dial
  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. return
  151. } else {
  152. log.Notice("Connected to seed", "peer", peer)
  153. }
  154. }
  155. func (n *Node) StartRPC() (net.Listener, error) {
  156. core.SetBlockStore(n.blockStore)
  157. core.SetConsensusState(n.consensusState)
  158. core.SetConsensusReactor(n.consensusReactor)
  159. core.SetMempoolReactor(n.mempoolReactor)
  160. core.SetSwitch(n.sw)
  161. core.SetPrivValidator(n.privValidator)
  162. core.SetGenesisDoc(n.genesisDoc)
  163. listenAddr := config.GetString("rpc_laddr")
  164. mux := http.NewServeMux()
  165. wm := rpcserver.NewWebsocketManager(core.Routes, n.evsw)
  166. mux.HandleFunc("/websocket", wm.WebsocketHandler)
  167. rpcserver.RegisterRPCFuncs(mux, core.Routes)
  168. return 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, privKey crypto.PrivKeyEd25519) *p2p.NodeInfo {
  186. nodeInfo := &p2p.NodeInfo{
  187. PubKey: privKey.PubKey().(crypto.PubKeyEd25519),
  188. Moniker: config.GetString("moniker"),
  189. Network: config.GetString("chain_id"),
  190. Version: Version,
  191. Other: []string{
  192. Fmt("p2p_version=%v", p2p.Version),
  193. Fmt("rpc_version=%v", rpc.Version),
  194. Fmt("wire_version=%v", wire.Version),
  195. },
  196. }
  197. // include git hash in the nodeInfo if available
  198. if rev, err := ReadFile(config.GetString("revision_file")); err == nil {
  199. nodeInfo.Other = append(nodeInfo.Other, Fmt("revision=%v", string(rev)))
  200. }
  201. if !sw.IsListening() {
  202. return nodeInfo
  203. }
  204. p2pListener := sw.Listeners()[0]
  205. p2pHost := p2pListener.ExternalAddress().IP.String()
  206. p2pPort := p2pListener.ExternalAddress().Port
  207. rpcListenAddr := config.GetString("rpc_laddr")
  208. // We assume that the rpcListener has the same ExternalAddress.
  209. // This is probably true because both P2P and RPC listeners use UPnP,
  210. // except of course if the rpc is only bound to localhost
  211. nodeInfo.ListenAddr = Fmt("%v:%v", p2pHost, p2pPort)
  212. nodeInfo.Other = append(nodeInfo.Other, Fmt("rpc_addr=%v", rpcListenAddr))
  213. return nodeInfo
  214. }
  215. //------------------------------------------------------------------------------
  216. // Users wishing to use an external signer for their validators
  217. // should fork tendermint/tendermint and implement RunNode to
  218. // load their custom priv validator and call NewNode(privVal)
  219. func RunNode() {
  220. // Wait until the genesis doc becomes available
  221. genDocFile := config.GetString("genesis_file")
  222. if !FileExists(genDocFile) {
  223. log.Notice(Fmt("Waiting for genesis file %v...", genDocFile))
  224. for {
  225. time.Sleep(time.Second)
  226. if !FileExists(genDocFile) {
  227. continue
  228. }
  229. jsonBlob, err := ioutil.ReadFile(genDocFile)
  230. if err != nil {
  231. Exit(Fmt("Couldn't read GenesisDoc file: %v", err))
  232. }
  233. genDoc := types.GenesisDocFromJSON(jsonBlob)
  234. if genDoc.ChainID == "" {
  235. PanicSanity(Fmt("Genesis doc %v must include non-empty chain_id", genDocFile))
  236. }
  237. config.Set("chain_id", genDoc.ChainID)
  238. config.Set("genesis_doc", genDoc)
  239. }
  240. }
  241. // Get PrivValidator
  242. privValidatorFile := config.GetString("priv_validator_file")
  243. privValidator := types.LoadOrGenPrivValidator(privValidatorFile)
  244. // Create & start node
  245. n := NewNode(privValidator)
  246. l := p2p.NewDefaultListener("tcp", config.GetString("node_laddr"), config.GetBool("skip_upnp"))
  247. n.AddListener(l)
  248. err := n.Start()
  249. if err != nil {
  250. Exit(Fmt("Failed to start node: %v", err))
  251. }
  252. log.Notice("Started node", "nodeInfo", n.sw.NodeInfo())
  253. // If seedNode is provided by config, dial out.
  254. if config.GetString("seeds") != "" {
  255. n.DialSeed()
  256. }
  257. // Run the RPC server.
  258. if config.GetString("rpc_laddr") != "" {
  259. _, err := n.StartRPC()
  260. if err != nil {
  261. PanicCrisis(err)
  262. }
  263. }
  264. // Sleep forever and then...
  265. TrapSignal(func() {
  266. n.Stop()
  267. })
  268. }
  269. func newConsensusState() *consensus.ConsensusState {
  270. // Get BlockStore
  271. blockStoreDB := dbm.GetDB("blockstore")
  272. blockStore := bc.NewBlockStore(blockStoreDB)
  273. // Get State
  274. stateDB := dbm.GetDB("state")
  275. state := sm.MakeGenesisStateFromFile(stateDB, config.GetString("genesis_file"))
  276. // Create two proxyAppCtx connections,
  277. // one for the consensus and one for the mempool.
  278. proxyAddr := config.GetString("proxy_app")
  279. proxyAppCtxMempool := getProxyApp(proxyAddr, state.LastAppHash)
  280. proxyAppCtxConsensus := getProxyApp(proxyAddr, state.LastAppHash)
  281. // add the chainid to the global config
  282. config.Set("chain_id", state.ChainID)
  283. // Make event switch
  284. eventSwitch := events.NewEventSwitch()
  285. _, err := eventSwitch.Start()
  286. if err != nil {
  287. Exit(Fmt("Failed to start event switch: %v", err))
  288. }
  289. mempool := mempl.NewMempool(proxyAppCtxMempool)
  290. consensusState := consensus.NewConsensusState(state.Copy(), proxyAppCtxConsensus, blockStore, mempool)
  291. consensusState.SetEventSwitch(eventSwitch)
  292. return consensusState
  293. }
  294. func RunReplayConsole() {
  295. msgLogFile := config.GetString("cs_msg_log")
  296. if msgLogFile == "" {
  297. Exit("cs_msg_log file name not set in tendermint config")
  298. }
  299. consensusState := newConsensusState()
  300. if err := consensusState.ReplayConsole(msgLogFile); err != nil {
  301. Exit(Fmt("Error during consensus replay: %v", err))
  302. }
  303. }
  304. func RunReplay() {
  305. msgLogFile := config.GetString("cs_msg_log")
  306. if msgLogFile == "" {
  307. Exit("cs_msg_log file name not set in tendermint config")
  308. }
  309. consensusState := newConsensusState()
  310. if err := consensusState.ReplayMessages(msgLogFile); err != nil {
  311. Exit(Fmt("Error during consensus replay: %v", err))
  312. }
  313. log.Notice("Replay run successfully")
  314. }
  315. // Load the most recent state from "state" db,
  316. // or create a new one (and save) from genesis.
  317. func getState() *sm.State {
  318. stateDB := dbm.GetDB("state")
  319. state := sm.LoadState(stateDB)
  320. if state == nil {
  321. state = sm.MakeGenesisStateFromFile(stateDB, config.GetString("genesis_file"))
  322. state.Save()
  323. }
  324. return state
  325. }
  326. // Get a connection to the proxyAppConn addr.
  327. // Check the current hash, and panic if it doesn't match.
  328. func getProxyApp(addr string, hash []byte) (proxyAppConn proxy.AppConn) {
  329. // use local app (for testing)
  330. if addr == "local" {
  331. app := example.NewCounterApplication(true)
  332. mtx := new(sync.Mutex)
  333. proxyAppConn = proxy.NewLocalAppConn(mtx, app)
  334. } else {
  335. proxyConn, err := Connect(addr)
  336. if err != nil {
  337. Exit(Fmt("Failed to connect to proxy for mempool: %v", err))
  338. }
  339. remoteApp := proxy.NewRemoteAppConn(proxyConn, 1024)
  340. remoteApp.Start()
  341. proxyAppConn = remoteApp
  342. }
  343. // Check the hash
  344. currentHash, err := proxyAppConn.GetHashSync()
  345. if err != nil {
  346. PanicCrisis(Fmt("Error in getting proxyAppConn hash: %v", err))
  347. }
  348. if !bytes.Equal(hash, currentHash) {
  349. PanicCrisis(Fmt("ProxyApp hash does not match. Expected %X, got %X", hash, currentHash))
  350. }
  351. return proxyAppConn
  352. }