backend.go 22 KB

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