diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 4f637c3aa5..3b89e71560 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -680,11 +680,13 @@ func CalcDifficulty(snap *Snapshot, signer common.Address) *big.Int { // Start implements consensus.Engine, starting the clique consensus engine. func (c *Clique) Start() { + log.Info("Start clique consensus engine") atomic.StoreInt32(&c.running, 1) } // Stop implements consensus.Engine, stopping the clique consensus engine. func (c *Clique) Stop() { + log.Info("Stop clique consensus engine") atomic.StoreInt32(&c.running, 0) } diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 094085aa8c..2cb72676e9 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -32,6 +32,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" ) @@ -556,11 +557,13 @@ func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header // Start implements consensus.Engine, starting the ethash engine. func (ethash *Ethash) Start() { + log.Info("Start ethash consensus engine") atomic.StoreInt32(ðash.running, 1) } // Stop implements consensus.Engine, stopping the ethash engine. func (ethash *Ethash) Stop() { + log.Info("Stop ethash consensus engine") atomic.StoreInt32(ðash.running, 0) } diff --git a/core/tx_pool.go b/core/tx_pool.go index 7007f85ddf..0fb5ca52b2 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -465,6 +465,9 @@ func (pool *TxPool) SetGasPrice(price *big.Int) { pool.mu.Lock() defer pool.mu.Unlock() + if pool.gasPrice == price { + return + } pool.gasPrice = price for _, tx := range pool.priced.Cap(price, pool.locals) { pool.removeTx(tx.Hash(), false) diff --git a/eth/api.go b/eth/api.go index ef66e99cbf..a6b4319872 100644 --- a/eth/api.go +++ b/eth/api.go @@ -96,7 +96,8 @@ func NewPrivateMinerAPI(e *Ethereum) *PrivateMinerAPI { // Start the miner with the given number of threads. If threads is nil the number // of workers started is equal to the number of logical CPUs that are usable by // this process. If mining is already running, this method adjust the number of -// threads allowed to use. +// threads allowed to use and updates the minimum price required by the transaction +// pool. func (api *PrivateMinerAPI) Start(threads *int) error { // Set the number of threads if the seal engine supports it if threads == nil { @@ -111,17 +112,14 @@ func (api *PrivateMinerAPI) Start(threads *int) error { log.Info("Updated mining threads", "threads", *threads) th.SetThreads(*threads) } - // Start the miner and return - if !api.e.IsMining() { - // Propagate the initial price point to the transaction pool - api.e.lock.RLock() - price := api.e.gasPrice - api.e.lock.RUnlock() + // Propagate the initial price point to the transaction pool + api.e.lock.RLock() + price := api.e.gasPrice + api.e.lock.RUnlock() + api.e.txPool.SetGasPrice(price) - api.e.txPool.SetGasPrice(price) - return api.e.StartMining(true) - } - return nil + // Start the miner and return + return api.e.StartMining(true) } // Stop the miner @@ -162,7 +160,7 @@ func (api *PrivateMinerAPI) SetEtherbase(etherbase common.Address) bool { // GetHashrate returns the current hashrate of the miner. func (api *PrivateMinerAPI) GetHashrate() uint64 { - return uint64(api.e.miner.HashRate()) + return api.e.miner.HashRate() } // PrivateAdminAPI is the collection of Ethereum full node-related APIs diff --git a/eth/backend.go b/eth/backend.go index 62a85f3fcb..a41adebcfd 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -166,7 +166,13 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { if eth.protocolManager, err = NewProtocolManager(eth.chainConfig, config.SyncMode, config.NetworkId, eth.eventMux, eth.txPool, eth.engine, eth.blockchain, chainDb); err != nil { return nil, err } - eth.miner = miner.New(eth, eth.chainConfig, eth.EventMux(), eth.engine) + + // Specify etherbase explicitly. + var etherbase common.Address + if addr, err := eth.Etherbase(); err == nil { + etherbase = addr + } + eth.miner = miner.New(eth, eth.chainConfig, eth.EventMux(), eth.engine, etherbase) eth.miner.SetExtra(makeExtraData(config.ExtraData)) eth.APIBackend = &EthAPIBackend{eth, nil} @@ -338,7 +344,7 @@ func (s *Ethereum) StartMining(local bool) error { log.Error("Cannot start mining without etherbase", "err", err) return fmt.Errorf("etherbase missing: %v", err) } - if clique, ok := s.engine.(*clique.Clique); ok { + if clique, ok := s.engine.(*clique.Clique); ok && !clique.IsRunning() { wallet, err := s.accountManager.Find(accounts.Account{Address: eb}) if wallet == nil || err != nil { log.Error("Etherbase account unavailable locally", "err", err) diff --git a/miner/miner.go b/miner/miner.go index 9cfc8fd64f..0da233dd74 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -54,12 +54,13 @@ type Miner struct { shouldStart int32 // should start indicates whether we should start after sync } -func New(eth Backend, config *params.ChainConfig, mux *event.TypeMux, engine consensus.Engine) *Miner { +func New(eth Backend, config *params.ChainConfig, mux *event.TypeMux, engine consensus.Engine, coinbase common.Address) *Miner { miner := &Miner{ eth: eth, mux: mux, engine: engine, - worker: newWorker(config, engine, common.Address{}, eth, mux), + coinbase: coinbase, + worker: newWorker(config, engine, coinbase, eth, mux), canStart: 1, } miner.Register(NewCpuAgent(eth.BlockChain(), engine)) @@ -108,15 +109,22 @@ func (self *Miner) Start(coinbase common.Address) { log.Info("Network syncing, will start miner afterwards") return } - log.Info("Starting mining operation") - self.engine.Start() - self.worker.start() - self.worker.commitNewWork() + if !self.engine.IsRunning() { + self.engine.Start() + } + if !self.worker.isRunning() { + self.worker.start() + self.worker.commitNewWork() + } } func (self *Miner) Stop() { - self.engine.Stop() - self.worker.stop() + if self.engine.IsRunning() { + self.engine.Stop() + } + if self.worker.isRunning() { + self.worker.stop() + } atomic.StoreInt32(&self.shouldStart, 0) } @@ -132,9 +140,9 @@ func (self *Miner) Mining() bool { return self.engine.IsRunning() } -func (self *Miner) HashRate() (tot int64) { +func (self *Miner) HashRate() (tot uint64) { if pow, ok := self.engine.(consensus.PoW); ok { - tot += int64(pow.Hashrate()) + tot += uint64(pow.Hashrate()) } return } diff --git a/miner/worker.go b/miner/worker.go index 3d2a99a5be..1dcf2c9b1e 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -127,8 +127,8 @@ type worker struct { unconfirmed *unconfirmedBlocks // set of locally mined blocks pending canonicalness confirmations // atomic status counters - mining int32 - atWork int32 + running int32 + atWork int32 } func newWorker(config *params.ChainConfig, engine consensus.Engine, coinbase common.Address, eth Backend, mux *event.TypeMux) *worker { @@ -175,7 +175,7 @@ func (self *worker) setExtra(extra []byte) { } func (self *worker) pending() (*types.Block, *state.StateDB) { - if atomic.LoadInt32(&self.mining) == 0 { + if atomic.LoadInt32(&self.running) == 0 { // return a snapshot to avoid contention on currentMu mutex self.snapshotMu.RLock() defer self.snapshotMu.RUnlock() @@ -188,7 +188,7 @@ func (self *worker) pending() (*types.Block, *state.StateDB) { } func (self *worker) pendingBlock() *types.Block { - if atomic.LoadInt32(&self.mining) == 0 { + if atomic.LoadInt32(&self.running) == 0 { // return a snapshot to avoid contention on currentMu mutex self.snapshotMu.RLock() defer self.snapshotMu.RUnlock() @@ -204,7 +204,7 @@ func (self *worker) start() { self.mu.Lock() defer self.mu.Unlock() - atomic.StoreInt32(&self.mining, 1) + atomic.StoreInt32(&self.running, 1) // spin up agents for agent := range self.agents { @@ -217,15 +217,20 @@ func (self *worker) stop() { self.mu.Lock() defer self.mu.Unlock() - if atomic.LoadInt32(&self.mining) == 1 { + if atomic.LoadInt32(&self.running) == 1 { for agent := range self.agents { agent.Stop() } } - atomic.StoreInt32(&self.mining, 0) + atomic.StoreInt32(&self.running, 0) atomic.StoreInt32(&self.atWork, 0) } +// isRunning returns an indicator whether worker is currently running or not. +func (self *worker) isRunning() bool { + return atomic.LoadInt32(&self.running) > 0 +} + func (self *worker) register(agent Agent) { self.mu.Lock() defer self.mu.Unlock() @@ -266,7 +271,7 @@ func (self *worker) update() { // Note all transactions received may not be continuous with transactions // already included in the current mining block. These transactions will // be automatically eliminated. - if atomic.LoadInt32(&self.mining) == 0 { + if atomic.LoadInt32(&self.running) == 0 { self.currentMu.Lock() txs := make(map[common.Address]types.Transactions) for _, tx := range ev.Txs {