@ -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 ( )