diff options
author | Jeffrey Wilcke <jeffrey@ethereum.org> | 2015-05-22 00:01:57 +0800 |
---|---|---|
committer | Jeffrey Wilcke <jeffrey@ethereum.org> | 2015-05-22 00:01:57 +0800 |
commit | f1cc3619f5bed55d803532f65f80b38fa760664b (patch) | |
tree | b59099b5e3527b7e478aaf08c48ace8a4c67d6f8 /eth | |
parent | af28736bd0f01176fa95b715e48476dd8269b942 (diff) | |
parent | bed80133e0573ebeefa201a15b20188198adf0ac (diff) | |
download | go-tangerine-f1cc3619f5bed55d803532f65f80b38fa760664b.tar go-tangerine-f1cc3619f5bed55d803532f65f80b38fa760664b.tar.gz go-tangerine-f1cc3619f5bed55d803532f65f80b38fa760664b.tar.bz2 go-tangerine-f1cc3619f5bed55d803532f65f80b38fa760664b.tar.lz go-tangerine-f1cc3619f5bed55d803532f65f80b38fa760664b.tar.xz go-tangerine-f1cc3619f5bed55d803532f65f80b38fa760664b.tar.zst go-tangerine-f1cc3619f5bed55d803532f65f80b38fa760664b.zip |
Merge pull request #1055 from ethersphere/autodag
automatic DAG pregeneration for smooth epoch transitions
Diffstat (limited to 'eth')
-rw-r--r-- | eth/backend.go | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/eth/backend.go b/eth/backend.go index 69504fd94..938071fc7 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -31,6 +31,14 @@ import ( "github.com/ethereum/go-ethereum/whisper" ) +const ( + epochLength = 30000 + ethashRevision = 23 + + autoDAGcheckInterval = 10 * time.Hour + autoDAGepochHeight = epochLength / 2 +) + var ( jsonlogger = logger.NewJsonLogger() @@ -60,6 +68,7 @@ type Config struct { LogJSON string VmDebug bool NatSpec bool + AutoDAG bool MaxPeers int MaxPendingPeers int @@ -197,6 +206,8 @@ type Ethereum struct { MinerThreads int NatSpec bool DataDir string + AutoDAG bool + autodagquit chan bool etherbase common.Address clientVersion string ethVersionId int @@ -269,6 +280,7 @@ func New(config *Config) (*Ethereum, error) { NatSpec: config.NatSpec, MinerThreads: config.MinerThreads, SolcPath: config.SolcPath, + AutoDAG: config.AutoDAG, } eth.pow = ethash.New() @@ -448,6 +460,10 @@ func (s *Ethereum) Start() error { // periodically flush databases go s.syncDatabases() + if s.AutoDAG { + s.StartAutoDAG() + } + // Start services go s.txPool.Start() s.protocolManager.Start() @@ -526,6 +542,7 @@ func (s *Ethereum) Stop() { if s.whisper != nil { s.whisper.Stop() } + s.StopAutoDAG() glog.V(logger.Info).Infoln("Server stopped") close(s.shutdownChan) @@ -559,6 +576,77 @@ func (self *Ethereum) syncAccounts(tx *types.Transaction) { } } +// StartAutoDAG() spawns a go routine that checks the DAG every autoDAGcheckInterval +// by default that is 10 times per epoch +// in epoch n, if we past autoDAGepochHeight within-epoch blocks, +// it calls ethash.MakeDAG to pregenerate the DAG for the next epoch n+1 +// if it does not exist yet as well as remove the DAG for epoch n-1 +// the loop quits if autodagquit channel is closed, it can safely restart and +// stop any number of times. +// For any more sophisticated pattern of DAG generation, use CLI subcommand +// makedag +func (self *Ethereum) StartAutoDAG() { + if self.autodagquit != nil { + return // already started + } + go func() { + glog.V(logger.Info).Infof("Automatic pregeneration of ethash DAG ON (ethash dir: %s)", ethash.DefaultDir) + var nextEpoch uint64 + timer := time.After(0) + self.autodagquit = make(chan bool) + for { + select { + case <-timer: + glog.V(logger.Info).Infof("checking DAG (ethash dir: %s)", ethash.DefaultDir) + currentBlock := self.ChainManager().CurrentBlock().NumberU64() + thisEpoch := currentBlock / epochLength + if nextEpoch <= thisEpoch { + if currentBlock%epochLength > autoDAGepochHeight { + if thisEpoch > 0 { + previousDag, previousDagFull := dagFiles(thisEpoch - 1) + os.Remove(filepath.Join(ethash.DefaultDir, previousDag)) + os.Remove(filepath.Join(ethash.DefaultDir, previousDagFull)) + glog.V(logger.Info).Infof("removed DAG for epoch %d (%s)", thisEpoch-1, previousDag) + } + nextEpoch = thisEpoch + 1 + dag, _ := dagFiles(nextEpoch) + if _, err := os.Stat(dag); os.IsNotExist(err) { + glog.V(logger.Info).Infof("Pregenerating DAG for epoch %d (%s)", nextEpoch, dag) + err := ethash.MakeDAG(nextEpoch*epochLength, "") // "" -> ethash.DefaultDir + if err != nil { + glog.V(logger.Error).Infof("Error generating DAG for epoch %d (%s)", nextEpoch, dag) + return + } + } else { + glog.V(logger.Error).Infof("DAG for epoch %d (%s)", nextEpoch, dag) + } + } + } + timer = time.After(autoDAGcheckInterval) + case <-self.autodagquit: + return + } + } + }() +} + +// dagFiles(epoch) returns the two alternative DAG filenames (not a path) +// 1) <revision>-<hex(seedhash[8])> 2) full-R<revision>-<hex(seedhash[8])> +func dagFiles(epoch uint64) (string, string) { + seedHash, _ := ethash.GetSeedHash(epoch * epochLength) + dag := fmt.Sprintf("full-R%d-%x", ethashRevision, seedHash[:8]) + return dag, "full-R" + dag +} + +// stopAutoDAG stops automatic DAG pregeneration by quitting the loop +func (self *Ethereum) StopAutoDAG() { + if self.autodagquit != nil { + close(self.autodagquit) + self.autodagquit = nil + } + glog.V(logger.Info).Infof("Automatic pregeneration of ethash DAG OFF (ethash dir: %s)", ethash.DefaultDir) +} + func saveProtocolVersion(db common.Database, protov int) { d, _ := db.Get([]byte("ProtocolVersion")) protocolVersion := common.NewValue(d).Uint() |