Unverified Commit 28d30b51 authored by Martin Holst Swende's avatar Martin Holst Swende Committed by GitHub

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: 's avatarFelix Lange <fjl@twurst.com>
parent 2fe0c65f
...@@ -554,7 +554,7 @@ func (s *Ethereum) Stop() error { ...@@ -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 ...@@ -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 { ...@@ -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 ...@@ -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 ...@@ -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() { ...@@ -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 { ...@@ -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 ...@@ -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() { ...@@ -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 ...@@ -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) { ...@@ -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() { ...@@ -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() { ...@@ -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:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment