aboutsummaryrefslogtreecommitdiffstats
path: root/eth/backend.go
diff options
context:
space:
mode:
Diffstat (limited to 'eth/backend.go')
-rw-r--r--eth/backend.go114
1 files changed, 111 insertions, 3 deletions
diff --git a/eth/backend.go b/eth/backend.go
index a7107f8d8..938071fc7 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -14,6 +14,7 @@ import (
"github.com/ethereum/ethash"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/compiler"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
@@ -30,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()
@@ -59,6 +68,7 @@ type Config struct {
LogJSON string
VmDebug bool
NatSpec bool
+ AutoDAG bool
MaxPeers int
MaxPendingPeers int
@@ -79,6 +89,7 @@ type Config struct {
GasPrice *big.Int
MinerThreads int
AccountManager *accounts.Manager
+ SolcPath string
// NewDB is used to create databases.
// If nil, the default is to create leveldb databases on disk.
@@ -181,6 +192,8 @@ type Ethereum struct {
pow *ethash.Ethash
protocolManager *ProtocolManager
downloader *downloader.Downloader
+ SolcPath string
+ solc *compiler.Solidity
net *p2p.Server
eventMux *event.TypeMux
@@ -193,6 +206,8 @@ type Ethereum struct {
MinerThreads int
NatSpec bool
DataDir string
+ AutoDAG bool
+ autodagquit chan bool
etherbase common.Address
clientVersion string
ethVersionId int
@@ -209,7 +224,7 @@ func New(config *Config) (*Ethereum, error) {
// 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)
const dbCount = 3
- ethdb.OpenFileLimit = 256 / (dbCount + 1)
+ ethdb.OpenFileLimit = 128 / (dbCount + 1)
newdb := config.NewDB
if newdb == nil {
@@ -264,11 +279,13 @@ func New(config *Config) (*Ethereum, error) {
netVersionId: config.NetworkId,
NatSpec: config.NatSpec,
MinerThreads: config.MinerThreads,
+ SolcPath: config.SolcPath,
+ AutoDAG: config.AutoDAG,
}
- eth.chainManager = core.NewChainManager(blockDb, stateDb, eth.EventMux())
- eth.downloader = downloader.New(eth.EventMux(), eth.chainManager.HasBlock, eth.chainManager.GetBlock)
eth.pow = ethash.New()
+ eth.chainManager = core.NewChainManager(blockDb, stateDb, eth.pow, eth.EventMux())
+ eth.downloader = downloader.New(eth.EventMux(), eth.chainManager.HasBlock, eth.chainManager.GetBlock)
eth.txPool = core.NewTxPool(eth.EventMux(), eth.chainManager.State, eth.chainManager.GasLimit)
eth.blockProcessor = core.NewBlockProcessor(stateDb, extraDb, eth.pow, eth.txPool, eth.chainManager, eth.EventMux())
eth.chainManager.SetProcessor(eth.blockProcessor)
@@ -443,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()
@@ -521,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)
@@ -554,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()
@@ -571,3 +664,18 @@ func saveBlockchainVersion(db common.Database, bcVersion int) {
db.Put([]byte("BlockchainVersion"), common.NewValue(bcVersion).Bytes())
}
}
+
+func (self *Ethereum) Solc() (*compiler.Solidity, error) {
+ var err error
+ if self.solc == nil {
+ self.solc, err = compiler.New(self.SolcPath)
+ }
+ return self.solc, err
+}
+
+// set in js console via admin interface or wrapper from cli flags
+func (self *Ethereum) SetSolc(solcPath string) (*compiler.Solidity, error) {
+ self.SolcPath = solcPath
+ self.solc = nil
+ return self.Solc()
+}