automatic DAG pregeneration for smooth epoch transitions
- backend: AutoDAG bool flag passed from cli/eth.Config to ethereum, autoDAG loop started if true - backend: autoDAG loop start/stop, remove previous DAG - cli: AutoDAG bool flag, off by default, but automatically ON if mining - admin jsre: add startAutoDAG stopAutoDAG and makeDAG in miner section - switch on/off DAG autogeneration when miner started/stopped on console
This commit is contained in:
@ -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()
|
||||
|
Reference in New Issue
Block a user