backend.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
  1. package eth
  2. import (
  3. "crypto/ecdsa"
  4. "encoding/json"
  5. "fmt"
  6. "io/ioutil"
  7. "math/big"
  8. "os"
  9. "path/filepath"
  10. "strings"
  11. "time"
  12. "github.com/ethereum/ethash"
  13. "github.com/ethereum/go-ethereum/accounts"
  14. "github.com/ethereum/go-ethereum/common"
  15. "github.com/ethereum/go-ethereum/common/compiler"
  16. "github.com/ethereum/go-ethereum/core"
  17. "github.com/ethereum/go-ethereum/core/types"
  18. "github.com/ethereum/go-ethereum/core/vm"
  19. "github.com/ethereum/go-ethereum/crypto"
  20. "github.com/ethereum/go-ethereum/eth/downloader"
  21. "github.com/ethereum/go-ethereum/ethdb"
  22. "github.com/ethereum/go-ethereum/event"
  23. "github.com/ethereum/go-ethereum/logger"
  24. "github.com/ethereum/go-ethereum/logger/glog"
  25. "github.com/ethereum/go-ethereum/miner"
  26. "github.com/ethereum/go-ethereum/p2p"
  27. "github.com/ethereum/go-ethereum/p2p/discover"
  28. "github.com/ethereum/go-ethereum/p2p/nat"
  29. "github.com/ethereum/go-ethereum/whisper"
  30. "github.com/rcrowley/go-metrics"
  31. )
  32. const (
  33. epochLength = 30000
  34. ethashRevision = 23
  35. autoDAGcheckInterval = 10 * time.Hour
  36. autoDAGepochHeight = epochLength / 2
  37. )
  38. var (
  39. jsonlogger = logger.NewJsonLogger()
  40. defaultBootNodes = []*discover.Node{
  41. // ETH/DEV Go Bootnodes
  42. discover.MustParseNode("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303"),
  43. discover.MustParseNode("enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303"),
  44. // ETH/DEV cpp-ethereum (poc-9.ethdev.com)
  45. discover.MustParseNode("enode://487611428e6c99a11a9795a6abe7b529e81315ca6aad66e2a2fc76e3adf263faba0d35466c2f8f68d561dbefa8878d4df5f1f2ddb1fbeab7f42ffb8cd328bd4a@5.1.83.226:30303"),
  46. }
  47. staticNodes = "static-nodes.json" // Path within <datadir> to search for the static node list
  48. trustedNodes = "trusted-nodes.json" // Path within <datadir> to search for the trusted node list
  49. )
  50. type Config struct {
  51. Name string
  52. ProtocolVersion int
  53. NetworkId int
  54. GenesisNonce int
  55. BlockChainVersion int
  56. SkipBcVersionCheck bool // e.g. blockchain export
  57. DataDir string
  58. LogFile string
  59. Verbosity int
  60. LogJSON string
  61. VmDebug bool
  62. NatSpec bool
  63. AutoDAG bool
  64. MaxPeers int
  65. MaxPendingPeers int
  66. Discovery bool
  67. Port string
  68. // Space-separated list of discovery node URLs
  69. BootNodes string
  70. // This key is used to identify the node on the network.
  71. // If nil, an ephemeral key is used.
  72. NodeKey *ecdsa.PrivateKey
  73. NAT nat.Interface
  74. Shh bool
  75. Dial bool
  76. Etherbase string
  77. GasPrice *big.Int
  78. MinerThreads int
  79. AccountManager *accounts.Manager
  80. SolcPath string
  81. GpoMinGasPrice *big.Int
  82. GpoMaxGasPrice *big.Int
  83. GpoFullBlockRatio int
  84. GpobaseStepDown int
  85. GpobaseStepUp int
  86. GpobaseCorrectionFactor int
  87. // NewDB is used to create databases.
  88. // If nil, the default is to create leveldb databases on disk.
  89. NewDB func(path string) (common.Database, error)
  90. }
  91. func (cfg *Config) parseBootNodes() []*discover.Node {
  92. if cfg.BootNodes == "" {
  93. return defaultBootNodes
  94. }
  95. var ns []*discover.Node
  96. for _, url := range strings.Split(cfg.BootNodes, " ") {
  97. if url == "" {
  98. continue
  99. }
  100. n, err := discover.ParseNode(url)
  101. if err != nil {
  102. glog.V(logger.Error).Infof("Bootstrap URL %s: %v\n", url, err)
  103. continue
  104. }
  105. ns = append(ns, n)
  106. }
  107. return ns
  108. }
  109. // parseNodes parses a list of discovery node URLs loaded from a .json file.
  110. func (cfg *Config) parseNodes(file string) []*discover.Node {
  111. // Short circuit if no node config is present
  112. path := filepath.Join(cfg.DataDir, file)
  113. if _, err := os.Stat(path); err != nil {
  114. return nil
  115. }
  116. // Load the nodes from the config file
  117. blob, err := ioutil.ReadFile(path)
  118. if err != nil {
  119. glog.V(logger.Error).Infof("Failed to access nodes: %v", err)
  120. return nil
  121. }
  122. nodelist := []string{}
  123. if err := json.Unmarshal(blob, &nodelist); err != nil {
  124. glog.V(logger.Error).Infof("Failed to load nodes: %v", err)
  125. return nil
  126. }
  127. // Interpret the list as a discovery node array
  128. var nodes []*discover.Node
  129. for _, url := range nodelist {
  130. if url == "" {
  131. continue
  132. }
  133. node, err := discover.ParseNode(url)
  134. if err != nil {
  135. glog.V(logger.Error).Infof("Node URL %s: %v\n", url, err)
  136. continue
  137. }
  138. nodes = append(nodes, node)
  139. }
  140. return nodes
  141. }
  142. func (cfg *Config) nodeKey() (*ecdsa.PrivateKey, error) {
  143. // use explicit key from command line args if set
  144. if cfg.NodeKey != nil {
  145. return cfg.NodeKey, nil
  146. }
  147. // use persistent key if present
  148. keyfile := filepath.Join(cfg.DataDir, "nodekey")
  149. key, err := crypto.LoadECDSA(keyfile)
  150. if err == nil {
  151. return key, nil
  152. }
  153. // no persistent key, generate and store a new one
  154. if key, err = crypto.GenerateKey(); err != nil {
  155. return nil, fmt.Errorf("could not generate server key: %v", err)
  156. }
  157. if err := crypto.SaveECDSA(keyfile, key); err != nil {
  158. glog.V(logger.Error).Infoln("could not persist nodekey: ", err)
  159. }
  160. return key, nil
  161. }
  162. type Ethereum struct {
  163. // Channel for shutting down the ethereum
  164. shutdownChan chan bool
  165. // DB interfaces
  166. blockDb common.Database // Block chain database
  167. stateDb common.Database // State changes database
  168. extraDb common.Database // Extra database (txs, etc)
  169. // Closed when databases are flushed and closed
  170. databasesClosed chan bool
  171. //*** SERVICES ***
  172. // State manager for processing new blocks and managing the over all states
  173. blockProcessor *core.BlockProcessor
  174. txPool *core.TxPool
  175. chainManager *core.ChainManager
  176. accountManager *accounts.Manager
  177. whisper *whisper.Whisper
  178. pow *ethash.Ethash
  179. protocolManager *ProtocolManager
  180. SolcPath string
  181. solc *compiler.Solidity
  182. GpoMinGasPrice *big.Int
  183. GpoMaxGasPrice *big.Int
  184. GpoFullBlockRatio int
  185. GpobaseStepDown int
  186. GpobaseStepUp int
  187. GpobaseCorrectionFactor int
  188. net *p2p.Server
  189. eventMux *event.TypeMux
  190. miner *miner.Miner
  191. // logger logger.LogSystem
  192. Mining bool
  193. MinerThreads int
  194. NatSpec bool
  195. DataDir string
  196. AutoDAG bool
  197. autodagquit chan bool
  198. etherbase common.Address
  199. clientVersion string
  200. ethVersionId int
  201. netVersionId int
  202. shhVersionId int
  203. }
  204. func New(config *Config) (*Ethereum, error) {
  205. // Bootstrap database
  206. logger.New(config.DataDir, config.LogFile, config.Verbosity)
  207. if len(config.LogJSON) > 0 {
  208. logger.NewJSONsystem(config.DataDir, config.LogJSON)
  209. }
  210. // Let the database take 3/4 of the max open files (TODO figure out a way to get the actual limit of the open files)
  211. const dbCount = 3
  212. ethdb.OpenFileLimit = 128 / (dbCount + 1)
  213. newdb := config.NewDB
  214. if newdb == nil {
  215. newdb = func(path string) (common.Database, error) { return ethdb.NewLDBDatabase(path) }
  216. }
  217. blockDb, err := newdb(filepath.Join(config.DataDir, "blockchain"))
  218. if err != nil {
  219. return nil, fmt.Errorf("blockchain db err: %v", err)
  220. }
  221. if db, ok := blockDb.(*ethdb.LDBDatabase); ok {
  222. db.GetTimer = metrics.GetOrRegisterTimer("eth/db/block/user/gets", metrics.DefaultRegistry)
  223. db.PutTimer = metrics.GetOrRegisterTimer("eth/db/block/user/puts", metrics.DefaultRegistry)
  224. db.MissMeter = metrics.GetOrRegisterMeter("eth/db/block/user/misses", metrics.DefaultRegistry)
  225. db.ReadMeter = metrics.GetOrRegisterMeter("eth/db/block/user/reads", metrics.DefaultRegistry)
  226. db.WriteMeter = metrics.GetOrRegisterMeter("eth/db/block/user/writes", metrics.DefaultRegistry)
  227. db.CompTimeMeter = metrics.GetOrRegisterMeter("eth/db/block/compact/time", metrics.DefaultRegistry)
  228. db.CompReadMeter = metrics.GetOrRegisterMeter("eth/db/block/compact/input", metrics.DefaultRegistry)
  229. db.CompWriteMeter = metrics.GetOrRegisterMeter("eth/db/block/compact/output", metrics.DefaultRegistry)
  230. }
  231. stateDb, err := newdb(filepath.Join(config.DataDir, "state"))
  232. if err != nil {
  233. return nil, fmt.Errorf("state db err: %v", err)
  234. }
  235. if db, ok := stateDb.(*ethdb.LDBDatabase); ok {
  236. db.GetTimer = metrics.GetOrRegisterTimer("eth/db/state/user/gets", metrics.DefaultRegistry)
  237. db.PutTimer = metrics.GetOrRegisterTimer("eth/db/state/user/puts", metrics.DefaultRegistry)
  238. db.MissMeter = metrics.GetOrRegisterMeter("eth/db/state/user/misses", metrics.DefaultRegistry)
  239. db.ReadMeter = metrics.GetOrRegisterMeter("eth/db/state/user/reads", metrics.DefaultRegistry)
  240. db.WriteMeter = metrics.GetOrRegisterMeter("eth/db/state/user/writes", metrics.DefaultRegistry)
  241. db.CompTimeMeter = metrics.GetOrRegisterMeter("eth/db/state/compact/time", metrics.DefaultRegistry)
  242. db.CompReadMeter = metrics.GetOrRegisterMeter("eth/db/state/compact/input", metrics.DefaultRegistry)
  243. db.CompWriteMeter = metrics.GetOrRegisterMeter("eth/db/state/compact/output", metrics.DefaultRegistry)
  244. }
  245. extraDb, err := newdb(filepath.Join(config.DataDir, "extra"))
  246. if err != nil {
  247. return nil, fmt.Errorf("extra db err: %v", err)
  248. }
  249. if db, ok := extraDb.(*ethdb.LDBDatabase); ok {
  250. db.GetTimer = metrics.GetOrRegisterTimer("eth/db/extra/user/gets", metrics.DefaultRegistry)
  251. db.PutTimer = metrics.GetOrRegisterTimer("eth/db/extra/user/puts", metrics.DefaultRegistry)
  252. db.MissMeter = metrics.GetOrRegisterMeter("eth/db/extra/user/misses", metrics.DefaultRegistry)
  253. db.ReadMeter = metrics.GetOrRegisterMeter("eth/db/extra/user/reads", metrics.DefaultRegistry)
  254. db.WriteMeter = metrics.GetOrRegisterMeter("eth/db/extra/user/writes", metrics.DefaultRegistry)
  255. db.CompTimeMeter = metrics.GetOrRegisterMeter("eth/db/extra/compact/time", metrics.DefaultRegistry)
  256. db.CompReadMeter = metrics.GetOrRegisterMeter("eth/db/extra/compact/input", metrics.DefaultRegistry)
  257. db.CompWriteMeter = metrics.GetOrRegisterMeter("eth/db/extra/compact/output", metrics.DefaultRegistry)
  258. }
  259. nodeDb := filepath.Join(config.DataDir, "nodes")
  260. // Perform database sanity checks
  261. d, _ := blockDb.Get([]byte("ProtocolVersion"))
  262. protov := int(common.NewValue(d).Uint())
  263. if protov != config.ProtocolVersion && protov != 0 {
  264. path := filepath.Join(config.DataDir, "blockchain")
  265. return nil, fmt.Errorf("Database version mismatch. Protocol(%d / %d). `rm -rf %s`", protov, config.ProtocolVersion, path)
  266. }
  267. saveProtocolVersion(blockDb, config.ProtocolVersion)
  268. glog.V(logger.Info).Infof("Protocol Version: %v, Network Id: %v", config.ProtocolVersion, config.NetworkId)
  269. if !config.SkipBcVersionCheck {
  270. b, _ := blockDb.Get([]byte("BlockchainVersion"))
  271. bcVersion := int(common.NewValue(b).Uint())
  272. if bcVersion != config.BlockChainVersion && bcVersion != 0 {
  273. return nil, fmt.Errorf("Blockchain DB version mismatch (%d / %d). Run geth upgradedb.\n", bcVersion, config.BlockChainVersion)
  274. }
  275. saveBlockchainVersion(blockDb, config.BlockChainVersion)
  276. }
  277. glog.V(logger.Info).Infof("Blockchain DB Version: %d", config.BlockChainVersion)
  278. eth := &Ethereum{
  279. shutdownChan: make(chan bool),
  280. databasesClosed: make(chan bool),
  281. blockDb: blockDb,
  282. stateDb: stateDb,
  283. extraDb: extraDb,
  284. eventMux: &event.TypeMux{},
  285. accountManager: config.AccountManager,
  286. DataDir: config.DataDir,
  287. etherbase: common.HexToAddress(config.Etherbase),
  288. clientVersion: config.Name, // TODO should separate from Name
  289. ethVersionId: config.ProtocolVersion,
  290. netVersionId: config.NetworkId,
  291. NatSpec: config.NatSpec,
  292. MinerThreads: config.MinerThreads,
  293. SolcPath: config.SolcPath,
  294. AutoDAG: config.AutoDAG,
  295. GpoMinGasPrice: config.GpoMinGasPrice,
  296. GpoMaxGasPrice: config.GpoMaxGasPrice,
  297. GpoFullBlockRatio: config.GpoFullBlockRatio,
  298. GpobaseStepDown: config.GpobaseStepDown,
  299. GpobaseStepUp: config.GpobaseStepUp,
  300. GpobaseCorrectionFactor: config.GpobaseCorrectionFactor,
  301. }
  302. eth.pow = ethash.New()
  303. genesis := core.GenesisBlock(uint64(config.GenesisNonce), stateDb)
  304. eth.chainManager, err = core.NewChainManager(genesis, blockDb, stateDb, eth.pow, eth.EventMux())
  305. if err != nil {
  306. return nil, err
  307. }
  308. eth.txPool = core.NewTxPool(eth.EventMux(), eth.chainManager.State, eth.chainManager.GasLimit)
  309. eth.blockProcessor = core.NewBlockProcessor(stateDb, extraDb, eth.pow, eth.chainManager, eth.EventMux())
  310. eth.chainManager.SetProcessor(eth.blockProcessor)
  311. eth.protocolManager = NewProtocolManager(config.ProtocolVersion, config.NetworkId, eth.eventMux, eth.txPool, eth.pow, eth.chainManager)
  312. eth.miner = miner.New(eth, eth.EventMux(), eth.pow)
  313. eth.miner.SetGasPrice(config.GasPrice)
  314. if config.Shh {
  315. eth.whisper = whisper.New()
  316. eth.shhVersionId = int(eth.whisper.Version())
  317. }
  318. netprv, err := config.nodeKey()
  319. if err != nil {
  320. return nil, err
  321. }
  322. protocols := []p2p.Protocol{eth.protocolManager.SubProtocol}
  323. if config.Shh {
  324. protocols = append(protocols, eth.whisper.Protocol())
  325. }
  326. eth.net = &p2p.Server{
  327. PrivateKey: netprv,
  328. Name: config.Name,
  329. MaxPeers: config.MaxPeers,
  330. MaxPendingPeers: config.MaxPendingPeers,
  331. Discovery: config.Discovery,
  332. Protocols: protocols,
  333. NAT: config.NAT,
  334. NoDial: !config.Dial,
  335. BootstrapNodes: config.parseBootNodes(),
  336. StaticNodes: config.parseNodes(staticNodes),
  337. TrustedNodes: config.parseNodes(trustedNodes),
  338. NodeDatabase: nodeDb,
  339. }
  340. if len(config.Port) > 0 {
  341. eth.net.ListenAddr = ":" + config.Port
  342. }
  343. vm.Debug = config.VmDebug
  344. return eth, nil
  345. }
  346. type NodeInfo struct {
  347. Name string
  348. NodeUrl string
  349. NodeID string
  350. IP string
  351. DiscPort int // UDP listening port for discovery protocol
  352. TCPPort int // TCP listening port for RLPx
  353. Td string
  354. ListenAddr string
  355. }
  356. func (s *Ethereum) NodeInfo() *NodeInfo {
  357. node := s.net.Self()
  358. return &NodeInfo{
  359. Name: s.Name(),
  360. NodeUrl: node.String(),
  361. NodeID: node.ID.String(),
  362. IP: node.IP.String(),
  363. DiscPort: int(node.UDP),
  364. TCPPort: int(node.TCP),
  365. ListenAddr: s.net.ListenAddr,
  366. Td: s.ChainManager().Td().String(),
  367. }
  368. }
  369. type PeerInfo struct {
  370. ID string
  371. Name string
  372. Caps string
  373. RemoteAddress string
  374. LocalAddress string
  375. }
  376. func newPeerInfo(peer *p2p.Peer) *PeerInfo {
  377. var caps []string
  378. for _, cap := range peer.Caps() {
  379. caps = append(caps, cap.String())
  380. }
  381. return &PeerInfo{
  382. ID: peer.ID().String(),
  383. Name: peer.Name(),
  384. Caps: strings.Join(caps, ", "),
  385. RemoteAddress: peer.RemoteAddr().String(),
  386. LocalAddress: peer.LocalAddr().String(),
  387. }
  388. }
  389. // PeersInfo returns an array of PeerInfo objects describing connected peers
  390. func (s *Ethereum) PeersInfo() (peersinfo []*PeerInfo) {
  391. for _, peer := range s.net.Peers() {
  392. if peer != nil {
  393. peersinfo = append(peersinfo, newPeerInfo(peer))
  394. }
  395. }
  396. return
  397. }
  398. func (s *Ethereum) ResetWithGenesisBlock(gb *types.Block) {
  399. s.chainManager.ResetWithGenesisBlock(gb)
  400. }
  401. func (s *Ethereum) StartMining(threads int) error {
  402. eb, err := s.Etherbase()
  403. if err != nil {
  404. err = fmt.Errorf("Cannot start mining without etherbase address: %v", err)
  405. glog.V(logger.Error).Infoln(err)
  406. return err
  407. }
  408. go s.miner.Start(eb, threads)
  409. return nil
  410. }
  411. func (s *Ethereum) Etherbase() (eb common.Address, err error) {
  412. eb = s.etherbase
  413. if (eb == common.Address{}) {
  414. primary, err := s.accountManager.Primary()
  415. if err != nil {
  416. return eb, err
  417. }
  418. if (primary == common.Address{}) {
  419. err = fmt.Errorf("no accounts found")
  420. return eb, err
  421. }
  422. eb = primary
  423. }
  424. return eb, nil
  425. }
  426. func (s *Ethereum) StopMining() { s.miner.Stop() }
  427. func (s *Ethereum) IsMining() bool { return s.miner.Mining() }
  428. func (s *Ethereum) Miner() *miner.Miner { return s.miner }
  429. // func (s *Ethereum) Logger() logger.LogSystem { return s.logger }
  430. func (s *Ethereum) Name() string { return s.net.Name }
  431. func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager }
  432. func (s *Ethereum) ChainManager() *core.ChainManager { return s.chainManager }
  433. func (s *Ethereum) BlockProcessor() *core.BlockProcessor { return s.blockProcessor }
  434. func (s *Ethereum) TxPool() *core.TxPool { return s.txPool }
  435. func (s *Ethereum) Whisper() *whisper.Whisper { return s.whisper }
  436. func (s *Ethereum) EventMux() *event.TypeMux { return s.eventMux }
  437. func (s *Ethereum) BlockDb() common.Database { return s.blockDb }
  438. func (s *Ethereum) StateDb() common.Database { return s.stateDb }
  439. func (s *Ethereum) ExtraDb() common.Database { return s.extraDb }
  440. func (s *Ethereum) IsListening() bool { return true } // Always listening
  441. func (s *Ethereum) PeerCount() int { return s.net.PeerCount() }
  442. func (s *Ethereum) Peers() []*p2p.Peer { return s.net.Peers() }
  443. func (s *Ethereum) MaxPeers() int { return s.net.MaxPeers }
  444. func (s *Ethereum) ClientVersion() string { return s.clientVersion }
  445. func (s *Ethereum) EthVersion() int { return s.ethVersionId }
  446. func (s *Ethereum) NetVersion() int { return s.netVersionId }
  447. func (s *Ethereum) ShhVersion() int { return s.shhVersionId }
  448. func (s *Ethereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader }
  449. // Start the ethereum
  450. func (s *Ethereum) Start() error {
  451. jsonlogger.LogJson(&logger.LogStarting{
  452. ClientString: s.net.Name,
  453. ProtocolVersion: ProtocolVersion,
  454. })
  455. err := s.net.Start()
  456. if err != nil {
  457. return err
  458. }
  459. // periodically flush databases
  460. go s.syncDatabases()
  461. if s.AutoDAG {
  462. s.StartAutoDAG()
  463. }
  464. s.protocolManager.Start()
  465. if s.whisper != nil {
  466. s.whisper.Start()
  467. }
  468. glog.V(logger.Info).Infoln("Server started")
  469. return nil
  470. }
  471. // sync databases every minute. If flushing fails we exit immediatly. The system
  472. // may not continue under any circumstances.
  473. func (s *Ethereum) syncDatabases() {
  474. ticker := time.NewTicker(1 * time.Minute)
  475. done:
  476. for {
  477. select {
  478. case <-ticker.C:
  479. // don't change the order of database flushes
  480. if err := s.extraDb.Flush(); err != nil {
  481. glog.Fatalf("fatal error: flush extraDb: %v (Restart your node. We are aware of this issue)\n", err)
  482. }
  483. if err := s.stateDb.Flush(); err != nil {
  484. glog.Fatalf("fatal error: flush stateDb: %v (Restart your node. We are aware of this issue)\n", err)
  485. }
  486. if err := s.blockDb.Flush(); err != nil {
  487. glog.Fatalf("fatal error: flush blockDb: %v (Restart your node. We are aware of this issue)\n", err)
  488. }
  489. case <-s.shutdownChan:
  490. break done
  491. }
  492. }
  493. s.blockDb.Close()
  494. s.stateDb.Close()
  495. s.extraDb.Close()
  496. close(s.databasesClosed)
  497. }
  498. func (s *Ethereum) StartForTest() {
  499. jsonlogger.LogJson(&logger.LogStarting{
  500. ClientString: s.net.Name,
  501. ProtocolVersion: ProtocolVersion,
  502. })
  503. }
  504. // AddPeer connects to the given node and maintains the connection until the
  505. // server is shut down. If the connection fails for any reason, the server will
  506. // attempt to reconnect the peer.
  507. func (self *Ethereum) AddPeer(nodeURL string) error {
  508. n, err := discover.ParseNode(nodeURL)
  509. if err != nil {
  510. return fmt.Errorf("invalid node URL: %v", err)
  511. }
  512. self.net.AddPeer(n)
  513. return nil
  514. }
  515. func (s *Ethereum) Stop() {
  516. s.net.Stop()
  517. s.chainManager.Stop()
  518. s.protocolManager.Stop()
  519. s.txPool.Stop()
  520. s.eventMux.Stop()
  521. if s.whisper != nil {
  522. s.whisper.Stop()
  523. }
  524. s.StopAutoDAG()
  525. close(s.shutdownChan)
  526. }
  527. // This function will wait for a shutdown and resumes main thread execution
  528. func (s *Ethereum) WaitForShutdown() {
  529. <-s.databasesClosed
  530. <-s.shutdownChan
  531. }
  532. // StartAutoDAG() spawns a go routine that checks the DAG every autoDAGcheckInterval
  533. // by default that is 10 times per epoch
  534. // in epoch n, if we past autoDAGepochHeight within-epoch blocks,
  535. // it calls ethash.MakeDAG to pregenerate the DAG for the next epoch n+1
  536. // if it does not exist yet as well as remove the DAG for epoch n-1
  537. // the loop quits if autodagquit channel is closed, it can safely restart and
  538. // stop any number of times.
  539. // For any more sophisticated pattern of DAG generation, use CLI subcommand
  540. // makedag
  541. func (self *Ethereum) StartAutoDAG() {
  542. if self.autodagquit != nil {
  543. return // already started
  544. }
  545. go func() {
  546. glog.V(logger.Info).Infof("Automatic pregeneration of ethash DAG ON (ethash dir: %s)", ethash.DefaultDir)
  547. var nextEpoch uint64
  548. timer := time.After(0)
  549. self.autodagquit = make(chan bool)
  550. for {
  551. select {
  552. case <-timer:
  553. glog.V(logger.Info).Infof("checking DAG (ethash dir: %s)", ethash.DefaultDir)
  554. currentBlock := self.ChainManager().CurrentBlock().NumberU64()
  555. thisEpoch := currentBlock / epochLength
  556. if nextEpoch <= thisEpoch {
  557. if currentBlock%epochLength > autoDAGepochHeight {
  558. if thisEpoch > 0 {
  559. previousDag, previousDagFull := dagFiles(thisEpoch - 1)
  560. os.Remove(filepath.Join(ethash.DefaultDir, previousDag))
  561. os.Remove(filepath.Join(ethash.DefaultDir, previousDagFull))
  562. glog.V(logger.Info).Infof("removed DAG for epoch %d (%s)", thisEpoch-1, previousDag)
  563. }
  564. nextEpoch = thisEpoch + 1
  565. dag, _ := dagFiles(nextEpoch)
  566. if _, err := os.Stat(dag); os.IsNotExist(err) {
  567. glog.V(logger.Info).Infof("Pregenerating DAG for epoch %d (%s)", nextEpoch, dag)
  568. err := ethash.MakeDAG(nextEpoch*epochLength, "") // "" -> ethash.DefaultDir
  569. if err != nil {
  570. glog.V(logger.Error).Infof("Error generating DAG for epoch %d (%s)", nextEpoch, dag)
  571. return
  572. }
  573. } else {
  574. glog.V(logger.Error).Infof("DAG for epoch %d (%s)", nextEpoch, dag)
  575. }
  576. }
  577. }
  578. timer = time.After(autoDAGcheckInterval)
  579. case <-self.autodagquit:
  580. return
  581. }
  582. }
  583. }()
  584. }
  585. // dagFiles(epoch) returns the two alternative DAG filenames (not a path)
  586. // 1) <revision>-<hex(seedhash[8])> 2) full-R<revision>-<hex(seedhash[8])>
  587. func dagFiles(epoch uint64) (string, string) {
  588. seedHash, _ := ethash.GetSeedHash(epoch * epochLength)
  589. dag := fmt.Sprintf("full-R%d-%x", ethashRevision, seedHash[:8])
  590. return dag, "full-R" + dag
  591. }
  592. // stopAutoDAG stops automatic DAG pregeneration by quitting the loop
  593. func (self *Ethereum) StopAutoDAG() {
  594. if self.autodagquit != nil {
  595. close(self.autodagquit)
  596. self.autodagquit = nil
  597. }
  598. glog.V(logger.Info).Infof("Automatic pregeneration of ethash DAG OFF (ethash dir: %s)", ethash.DefaultDir)
  599. }
  600. func saveProtocolVersion(db common.Database, protov int) {
  601. d, _ := db.Get([]byte("ProtocolVersion"))
  602. protocolVersion := common.NewValue(d).Uint()
  603. if protocolVersion == 0 {
  604. db.Put([]byte("ProtocolVersion"), common.NewValue(protov).Bytes())
  605. }
  606. }
  607. func saveBlockchainVersion(db common.Database, bcVersion int) {
  608. d, _ := db.Get([]byte("BlockchainVersion"))
  609. blockchainVersion := common.NewValue(d).Uint()
  610. if blockchainVersion == 0 {
  611. db.Put([]byte("BlockchainVersion"), common.NewValue(bcVersion).Bytes())
  612. }
  613. }
  614. func (self *Ethereum) Solc() (*compiler.Solidity, error) {
  615. var err error
  616. if self.solc == nil {
  617. self.solc, err = compiler.New(self.SolcPath)
  618. }
  619. return self.solc, err
  620. }
  621. // set in js console via admin interface or wrapper from cli flags
  622. func (self *Ethereum) SetSolc(solcPath string) (*compiler.Solidity, error) {
  623. self.SolcPath = solcPath
  624. self.solc = nil
  625. return self.Solc()
  626. }