Skip to content

Commit 28d30b5

Browse files
holimanfjl
andauthored
eth: close miner on exit (instead of just stopping) (ethereum#21992)
This ensures that all miner goroutines have exited before stopping the blockchain. Co-authored-by: Felix Lange <[email protected]>
1 parent 2fe0c65 commit 28d30b5

File tree

3 files changed

+16
-2
lines changed

3 files changed

+16
-2
lines changed

eth/backend.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -554,7 +554,7 @@ func (s *Ethereum) Stop() error {
554554
s.bloomIndexer.Close()
555555
close(s.closeBloomHandler)
556556
s.txPool.Stop()
557-
s.miner.Stop()
557+
s.miner.Close()
558558
s.blockchain.Stop()
559559
s.engine.Close()
560560
rawdb.PopUncleanShutdownMarker(s.chainDb)

miner/miner.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ package miner
2020
import (
2121
"fmt"
2222
"math/big"
23+
"sync"
2324
"time"
2425

2526
"github.com/ethereum/go-ethereum/common"
@@ -63,6 +64,8 @@ type Miner struct {
6364
exitCh chan struct{}
6465
startCh chan common.Address
6566
stopCh chan struct{}
67+
68+
wg sync.WaitGroup
6669
}
6770

6871
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
7578
stopCh: make(chan struct{}),
7679
worker: newWorker(config, chainConfig, engine, eth, mux, isLocalBlock, true),
7780
}
81+
miner.wg.Add(1)
7882
go miner.update()
79-
8083
return miner
8184
}
8285

@@ -85,6 +88,8 @@ func New(eth Backend, config *Config, chainConfig *params.ChainConfig, mux *even
8588
// the loop is exited. This to prevent a major security vuln where external parties can DOS you with blocks
8689
// and halt your mining operation for as long as the DOS continues.
8790
func (miner *Miner) update() {
91+
defer miner.wg.Done()
92+
8893
events := miner.mux.Subscribe(downloader.StartEvent{}, downloader.DoneEvent{}, downloader.FailedEvent{})
8994
defer func() {
9095
if !events.Closed() {
@@ -154,6 +159,7 @@ func (miner *Miner) Stop() {
154159

155160
func (miner *Miner) Close() {
156161
close(miner.exitCh)
162+
miner.wg.Wait()
157163
}
158164

159165
func (miner *Miner) Mining() bool {

miner/worker.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,8 @@ type worker struct {
150150
resubmitIntervalCh chan time.Duration
151151
resubmitAdjustCh chan *intervalAdjust
152152

153+
wg sync.WaitGroup
154+
153155
current *environment // An environment for current running cycle.
154156
localUncles map[common.Hash]*types.Block // A set of side blocks generated locally as the possible uncle blocks.
155157
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
225227
recommit = minRecommitInterval
226228
}
227229

230+
worker.wg.Add(4)
228231
go worker.mainLoop()
229232
go worker.newWorkLoop(recommit)
230233
go worker.resultLoop()
@@ -323,6 +326,7 @@ func (w *worker) close() {
323326
}
324327
atomic.StoreInt32(&w.running, 0)
325328
close(w.exitCh)
329+
w.wg.Wait()
326330
}
327331

328332
// recalcRecommit recalculates the resubmitting interval upon feedback.
@@ -349,6 +353,7 @@ func recalcRecommit(minRecommit, prev time.Duration, target float64, inc bool) t
349353

350354
// newWorkLoop is a standalone goroutine to submit new mining work upon received events.
351355
func (w *worker) newWorkLoop(recommit time.Duration) {
356+
defer w.wg.Done()
352357
var (
353358
interrupt *int32
354359
minRecommit = recommit // minimal resubmit interval specified by user.
@@ -446,6 +451,7 @@ func (w *worker) newWorkLoop(recommit time.Duration) {
446451

447452
// mainLoop is a standalone goroutine to regenerate the sealing task based on the received event.
448453
func (w *worker) mainLoop() {
454+
defer w.wg.Done()
449455
defer w.txsSub.Unsubscribe()
450456
defer w.chainHeadSub.Unsubscribe()
451457
defer w.chainSideSub.Unsubscribe()
@@ -548,6 +554,7 @@ func (w *worker) mainLoop() {
548554
// taskLoop is a standalone goroutine to fetch sealing task from the generator and
549555
// push them to consensus engine.
550556
func (w *worker) taskLoop() {
557+
defer w.wg.Done()
551558
var (
552559
stopCh chan struct{}
553560
prev common.Hash
@@ -595,6 +602,7 @@ func (w *worker) taskLoop() {
595602
// resultLoop is a standalone goroutine to handle sealing result submitting
596603
// and flush relative data to the database.
597604
func (w *worker) resultLoop() {
605+
defer w.wg.Done()
598606
for {
599607
select {
600608
case block := <-w.resultCh:

0 commit comments

Comments
 (0)