eth: close miner on exit (instead of just stopping) (#21992)
This ensures that all miner goroutines have exited before stopping the blockchain. Co-authored-by: Felix Lange <fjl@twurst.com>
This commit is contained in:
parent
2fe0c65f4b
commit
28d30b51f8
@ -554,7 +554,7 @@ func (s *Ethereum) Stop() error {
|
|||||||
s.bloomIndexer.Close()
|
s.bloomIndexer.Close()
|
||||||
close(s.closeBloomHandler)
|
close(s.closeBloomHandler)
|
||||||
s.txPool.Stop()
|
s.txPool.Stop()
|
||||||
s.miner.Stop()
|
s.miner.Close()
|
||||||
s.blockchain.Stop()
|
s.blockchain.Stop()
|
||||||
s.engine.Close()
|
s.engine.Close()
|
||||||
rawdb.PopUncleanShutdownMarker(s.chainDb)
|
rawdb.PopUncleanShutdownMarker(s.chainDb)
|
||||||
|
@ -20,6 +20,7 @@ package miner
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
@ -63,6 +64,8 @@ type Miner struct {
|
|||||||
exitCh chan struct{}
|
exitCh chan struct{}
|
||||||
startCh chan common.Address
|
startCh chan common.Address
|
||||||
stopCh chan struct{}
|
stopCh chan struct{}
|
||||||
|
|
||||||
|
wg sync.WaitGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(eth Backend, config *Config, chainConfig *params.ChainConfig, mux *event.TypeMux, engine consensus.Engine, isLocalBlock func(block *types.Block) bool) *Miner {
|
func New(eth Backend, config *Config, chainConfig *params.ChainConfig, mux *event.TypeMux, engine consensus.Engine, isLocalBlock func(block *types.Block) bool) *Miner {
|
||||||
@ -75,8 +78,8 @@ func New(eth Backend, config *Config, chainConfig *params.ChainConfig, mux *even
|
|||||||
stopCh: make(chan struct{}),
|
stopCh: make(chan struct{}),
|
||||||
worker: newWorker(config, chainConfig, engine, eth, mux, isLocalBlock, true),
|
worker: newWorker(config, chainConfig, engine, eth, mux, isLocalBlock, true),
|
||||||
}
|
}
|
||||||
|
miner.wg.Add(1)
|
||||||
go miner.update()
|
go miner.update()
|
||||||
|
|
||||||
return miner
|
return miner
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,6 +88,8 @@ func New(eth Backend, config *Config, chainConfig *params.ChainConfig, mux *even
|
|||||||
// the loop is exited. This to prevent a major security vuln where external parties can DOS you with blocks
|
// the loop is exited. This to prevent a major security vuln where external parties can DOS you with blocks
|
||||||
// and halt your mining operation for as long as the DOS continues.
|
// and halt your mining operation for as long as the DOS continues.
|
||||||
func (miner *Miner) update() {
|
func (miner *Miner) update() {
|
||||||
|
defer miner.wg.Done()
|
||||||
|
|
||||||
events := miner.mux.Subscribe(downloader.StartEvent{}, downloader.DoneEvent{}, downloader.FailedEvent{})
|
events := miner.mux.Subscribe(downloader.StartEvent{}, downloader.DoneEvent{}, downloader.FailedEvent{})
|
||||||
defer func() {
|
defer func() {
|
||||||
if !events.Closed() {
|
if !events.Closed() {
|
||||||
@ -154,6 +159,7 @@ func (miner *Miner) Stop() {
|
|||||||
|
|
||||||
func (miner *Miner) Close() {
|
func (miner *Miner) Close() {
|
||||||
close(miner.exitCh)
|
close(miner.exitCh)
|
||||||
|
miner.wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (miner *Miner) Mining() bool {
|
func (miner *Miner) Mining() bool {
|
||||||
|
@ -150,6 +150,8 @@ type worker struct {
|
|||||||
resubmitIntervalCh chan time.Duration
|
resubmitIntervalCh chan time.Duration
|
||||||
resubmitAdjustCh chan *intervalAdjust
|
resubmitAdjustCh chan *intervalAdjust
|
||||||
|
|
||||||
|
wg sync.WaitGroup
|
||||||
|
|
||||||
current *environment // An environment for current running cycle.
|
current *environment // An environment for current running cycle.
|
||||||
localUncles map[common.Hash]*types.Block // A set of side blocks generated locally as the possible uncle blocks.
|
localUncles map[common.Hash]*types.Block // A set of side blocks generated locally as the possible uncle blocks.
|
||||||
remoteUncles map[common.Hash]*types.Block // A set of side blocks as the possible uncle blocks.
|
remoteUncles map[common.Hash]*types.Block // A set of side blocks as the possible uncle blocks.
|
||||||
@ -225,6 +227,7 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus
|
|||||||
recommit = minRecommitInterval
|
recommit = minRecommitInterval
|
||||||
}
|
}
|
||||||
|
|
||||||
|
worker.wg.Add(4)
|
||||||
go worker.mainLoop()
|
go worker.mainLoop()
|
||||||
go worker.newWorkLoop(recommit)
|
go worker.newWorkLoop(recommit)
|
||||||
go worker.resultLoop()
|
go worker.resultLoop()
|
||||||
@ -323,6 +326,7 @@ func (w *worker) close() {
|
|||||||
}
|
}
|
||||||
atomic.StoreInt32(&w.running, 0)
|
atomic.StoreInt32(&w.running, 0)
|
||||||
close(w.exitCh)
|
close(w.exitCh)
|
||||||
|
w.wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
// recalcRecommit recalculates the resubmitting interval upon feedback.
|
// recalcRecommit recalculates the resubmitting interval upon feedback.
|
||||||
@ -349,6 +353,7 @@ func recalcRecommit(minRecommit, prev time.Duration, target float64, inc bool) t
|
|||||||
|
|
||||||
// newWorkLoop is a standalone goroutine to submit new mining work upon received events.
|
// newWorkLoop is a standalone goroutine to submit new mining work upon received events.
|
||||||
func (w *worker) newWorkLoop(recommit time.Duration) {
|
func (w *worker) newWorkLoop(recommit time.Duration) {
|
||||||
|
defer w.wg.Done()
|
||||||
var (
|
var (
|
||||||
interrupt *int32
|
interrupt *int32
|
||||||
minRecommit = recommit // minimal resubmit interval specified by user.
|
minRecommit = recommit // minimal resubmit interval specified by user.
|
||||||
@ -446,6 +451,7 @@ func (w *worker) newWorkLoop(recommit time.Duration) {
|
|||||||
|
|
||||||
// mainLoop is a standalone goroutine to regenerate the sealing task based on the received event.
|
// mainLoop is a standalone goroutine to regenerate the sealing task based on the received event.
|
||||||
func (w *worker) mainLoop() {
|
func (w *worker) mainLoop() {
|
||||||
|
defer w.wg.Done()
|
||||||
defer w.txsSub.Unsubscribe()
|
defer w.txsSub.Unsubscribe()
|
||||||
defer w.chainHeadSub.Unsubscribe()
|
defer w.chainHeadSub.Unsubscribe()
|
||||||
defer w.chainSideSub.Unsubscribe()
|
defer w.chainSideSub.Unsubscribe()
|
||||||
@ -548,6 +554,7 @@ func (w *worker) mainLoop() {
|
|||||||
// taskLoop is a standalone goroutine to fetch sealing task from the generator and
|
// taskLoop is a standalone goroutine to fetch sealing task from the generator and
|
||||||
// push them to consensus engine.
|
// push them to consensus engine.
|
||||||
func (w *worker) taskLoop() {
|
func (w *worker) taskLoop() {
|
||||||
|
defer w.wg.Done()
|
||||||
var (
|
var (
|
||||||
stopCh chan struct{}
|
stopCh chan struct{}
|
||||||
prev common.Hash
|
prev common.Hash
|
||||||
@ -595,6 +602,7 @@ func (w *worker) taskLoop() {
|
|||||||
// resultLoop is a standalone goroutine to handle sealing result submitting
|
// resultLoop is a standalone goroutine to handle sealing result submitting
|
||||||
// and flush relative data to the database.
|
// and flush relative data to the database.
|
||||||
func (w *worker) resultLoop() {
|
func (w *worker) resultLoop() {
|
||||||
|
defer w.wg.Done()
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case block := <-w.resultCh:
|
case block := <-w.resultCh:
|
||||||
|
Loading…
Reference in New Issue
Block a user