backend.go 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. package eth
  2. import (
  3. "crypto/ecdsa"
  4. "fmt"
  5. "strings"
  6. "github.com/ethereum/go-ethereum/core"
  7. "github.com/ethereum/go-ethereum/crypto"
  8. "github.com/ethereum/go-ethereum/ethdb"
  9. "github.com/ethereum/go-ethereum/ethutil"
  10. "github.com/ethereum/go-ethereum/event"
  11. ethlogger "github.com/ethereum/go-ethereum/logger"
  12. "github.com/ethereum/go-ethereum/p2p"
  13. "github.com/ethereum/go-ethereum/p2p/discover"
  14. "github.com/ethereum/go-ethereum/p2p/nat"
  15. "github.com/ethereum/go-ethereum/pow/ezp"
  16. "github.com/ethereum/go-ethereum/rpc"
  17. "github.com/ethereum/go-ethereum/whisper"
  18. )
  19. var logger = ethlogger.NewLogger("SERV")
  20. var jsonlogger = ethlogger.NewJsonLogger()
  21. type Config struct {
  22. Name string
  23. KeyStore string
  24. DataDir string
  25. LogFile string
  26. LogLevel int
  27. KeyRing string
  28. LogFormat string
  29. MaxPeers int
  30. Port string
  31. // This should be a space-separated list of
  32. // discovery node URLs.
  33. BootNodes string
  34. // This key is used to identify the node on the network.
  35. // If nil, an ephemeral key is used.
  36. NodeKey *ecdsa.PrivateKey
  37. NAT nat.Interface
  38. Shh bool
  39. Dial bool
  40. KeyManager *crypto.KeyManager
  41. }
  42. func (cfg *Config) parseBootNodes() []*discover.Node {
  43. var ns []*discover.Node
  44. for _, url := range strings.Split(cfg.BootNodes, " ") {
  45. if url == "" {
  46. continue
  47. }
  48. n, err := discover.ParseNode(url)
  49. if err != nil {
  50. logger.Errorf("Bootstrap URL %s: %v\n", url, err)
  51. continue
  52. }
  53. ns = append(ns, n)
  54. }
  55. return ns
  56. }
  57. type Ethereum struct {
  58. // Channel for shutting down the ethereum
  59. shutdownChan chan bool
  60. quit chan bool
  61. // DB interface
  62. db ethutil.Database
  63. blacklist p2p.Blacklist
  64. //*** SERVICES ***
  65. // State manager for processing new blocks and managing the over all states
  66. blockProcessor *core.BlockProcessor
  67. txPool *core.TxPool
  68. chainManager *core.ChainManager
  69. blockPool *BlockPool
  70. whisper *whisper.Whisper
  71. net *p2p.Server
  72. eventMux *event.TypeMux
  73. txSub event.Subscription
  74. blockSub event.Subscription
  75. RpcServer rpc.RpcServer
  76. WsServer rpc.RpcServer
  77. keyManager *crypto.KeyManager
  78. logger ethlogger.LogSystem
  79. Mining bool
  80. }
  81. func New(config *Config) (*Ethereum, error) {
  82. // Boostrap database
  83. logger := ethlogger.New(config.DataDir, config.LogFile, config.LogLevel, config.LogFormat)
  84. db, err := ethdb.NewLDBDatabase("blockchain")
  85. if err != nil {
  86. return nil, err
  87. }
  88. // Perform database sanity checks
  89. d, _ := db.Get([]byte("ProtocolVersion"))
  90. protov := ethutil.NewValue(d).Uint()
  91. if protov != ProtocolVersion && protov != 0 {
  92. return nil, fmt.Errorf("Database version mismatch. Protocol(%d / %d). `rm -rf %s`", protov, ProtocolVersion, ethutil.Config.ExecPath+"/database")
  93. }
  94. // Create new keymanager
  95. var keyManager *crypto.KeyManager
  96. switch config.KeyStore {
  97. case "db":
  98. keyManager = crypto.NewDBKeyManager(db)
  99. case "file":
  100. keyManager = crypto.NewFileKeyManager(config.DataDir)
  101. default:
  102. return nil, fmt.Errorf("unknown keystore type: %s", config.KeyStore)
  103. }
  104. // Initialise the keyring
  105. keyManager.Init(config.KeyRing, 0, false)
  106. saveProtocolVersion(db)
  107. //ethutil.Config.Db = db
  108. eth := &Ethereum{
  109. shutdownChan: make(chan bool),
  110. quit: make(chan bool),
  111. db: db,
  112. keyManager: keyManager,
  113. blacklist: p2p.NewBlacklist(),
  114. eventMux: &event.TypeMux{},
  115. logger: logger,
  116. }
  117. eth.chainManager = core.NewChainManager(db, eth.EventMux())
  118. eth.txPool = core.NewTxPool(eth.EventMux())
  119. eth.blockProcessor = core.NewBlockProcessor(db, eth.txPool, eth.chainManager, eth.EventMux())
  120. eth.chainManager.SetProcessor(eth.blockProcessor)
  121. eth.whisper = whisper.New()
  122. hasBlock := eth.chainManager.HasBlock
  123. insertChain := eth.chainManager.InsertChain
  124. eth.blockPool = NewBlockPool(hasBlock, insertChain, ezp.Verify)
  125. ethProto := EthProtocol(eth.txPool, eth.chainManager, eth.blockPool)
  126. protocols := []p2p.Protocol{ethProto, eth.whisper.Protocol()}
  127. netprv := config.NodeKey
  128. if netprv == nil {
  129. if netprv, err = crypto.GenerateKey(); err != nil {
  130. return nil, fmt.Errorf("could not generate server key: %v", err)
  131. }
  132. }
  133. eth.net = &p2p.Server{
  134. PrivateKey: netprv,
  135. Name: config.Name,
  136. MaxPeers: config.MaxPeers,
  137. Protocols: protocols,
  138. Blacklist: eth.blacklist,
  139. NAT: config.NAT,
  140. NoDial: !config.Dial,
  141. BootstrapNodes: config.parseBootNodes(),
  142. }
  143. if len(config.Port) > 0 {
  144. eth.net.ListenAddr = ":" + config.Port
  145. }
  146. return eth, nil
  147. }
  148. func (s *Ethereum) KeyManager() *crypto.KeyManager {
  149. return s.keyManager
  150. }
  151. func (s *Ethereum) Logger() ethlogger.LogSystem {
  152. return s.logger
  153. }
  154. func (s *Ethereum) Name() string {
  155. return s.net.Name
  156. }
  157. func (s *Ethereum) ChainManager() *core.ChainManager {
  158. return s.chainManager
  159. }
  160. func (s *Ethereum) BlockProcessor() *core.BlockProcessor {
  161. return s.blockProcessor
  162. }
  163. func (s *Ethereum) TxPool() *core.TxPool {
  164. return s.txPool
  165. }
  166. func (s *Ethereum) BlockPool() *BlockPool {
  167. return s.blockPool
  168. }
  169. func (s *Ethereum) Whisper() *whisper.Whisper {
  170. return s.whisper
  171. }
  172. func (s *Ethereum) EventMux() *event.TypeMux {
  173. return s.eventMux
  174. }
  175. func (self *Ethereum) Db() ethutil.Database {
  176. return self.db
  177. }
  178. func (s *Ethereum) IsMining() bool {
  179. return s.Mining
  180. }
  181. func (s *Ethereum) IsListening() bool {
  182. // XXX TODO
  183. return false
  184. }
  185. func (s *Ethereum) PeerCount() int {
  186. return s.net.PeerCount()
  187. }
  188. func (s *Ethereum) Peers() []*p2p.Peer {
  189. return s.net.Peers()
  190. }
  191. func (s *Ethereum) MaxPeers() int {
  192. return s.net.MaxPeers
  193. }
  194. func (s *Ethereum) Coinbase() []byte {
  195. return nil // TODO
  196. }
  197. // Start the ethereum
  198. func (s *Ethereum) Start() error {
  199. jsonlogger.LogJson(&ethlogger.LogStarting{
  200. ClientString: s.net.Name,
  201. Coinbase: ethutil.Bytes2Hex(s.KeyManager().Address()),
  202. ProtocolVersion: ProtocolVersion,
  203. LogEvent: ethlogger.LogEvent{Guid: ethutil.Bytes2Hex(crypto.FromECDSAPub(&s.net.PrivateKey.PublicKey))},
  204. })
  205. err := s.net.Start()
  206. if err != nil {
  207. return err
  208. }
  209. // Start services
  210. s.txPool.Start()
  211. s.blockPool.Start()
  212. if s.whisper != nil {
  213. s.whisper.Start()
  214. }
  215. // broadcast transactions
  216. s.txSub = s.eventMux.Subscribe(core.TxPreEvent{})
  217. go s.txBroadcastLoop()
  218. // broadcast mined blocks
  219. s.blockSub = s.eventMux.Subscribe(core.NewMinedBlockEvent{})
  220. go s.blockBroadcastLoop()
  221. logger.Infoln("Server started")
  222. return nil
  223. }
  224. func (self *Ethereum) SuggestPeer(nodeURL string) error {
  225. n, err := discover.ParseNode(nodeURL)
  226. if err != nil {
  227. return fmt.Errorf("invalid node URL: %v", err)
  228. }
  229. self.net.SuggestPeer(n)
  230. return nil
  231. }
  232. func (s *Ethereum) Stop() {
  233. // Close the database
  234. defer s.db.Close()
  235. close(s.quit)
  236. s.txSub.Unsubscribe() // quits txBroadcastLoop
  237. s.blockSub.Unsubscribe() // quits blockBroadcastLoop
  238. if s.RpcServer != nil {
  239. s.RpcServer.Stop()
  240. }
  241. if s.WsServer != nil {
  242. s.WsServer.Stop()
  243. }
  244. s.txPool.Stop()
  245. s.eventMux.Stop()
  246. s.blockPool.Stop()
  247. if s.whisper != nil {
  248. s.whisper.Stop()
  249. }
  250. logger.Infoln("Server stopped")
  251. close(s.shutdownChan)
  252. }
  253. // This function will wait for a shutdown and resumes main thread execution
  254. func (s *Ethereum) WaitForShutdown() {
  255. <-s.shutdownChan
  256. }
  257. // now tx broadcasting is taken out of txPool
  258. // handled here via subscription, efficiency?
  259. func (self *Ethereum) txBroadcastLoop() {
  260. // automatically stops if unsubscribe
  261. for obj := range self.txSub.Chan() {
  262. event := obj.(core.TxPreEvent)
  263. self.net.Broadcast("eth", TxMsg, event.Tx.RlpData())
  264. }
  265. }
  266. func (self *Ethereum) blockBroadcastLoop() {
  267. // automatically stops if unsubscribe
  268. for obj := range self.blockSub.Chan() {
  269. switch ev := obj.(type) {
  270. case core.NewMinedBlockEvent:
  271. self.net.Broadcast("eth", NewBlockMsg, ev.Block.RlpData(), ev.Block.Td)
  272. }
  273. }
  274. }
  275. func saveProtocolVersion(db ethutil.Database) {
  276. d, _ := db.Get([]byte("ProtocolVersion"))
  277. protocolVersion := ethutil.NewValue(d).Uint()
  278. if protocolVersion == 0 {
  279. db.Put([]byte("ProtocolVersion"), ethutil.NewValue(ProtocolVersion).Bytes())
  280. }
  281. }