Skip to content

Commit 972a75f

Browse files
authored
Merge pull request #596 from etclabscore/fix/miner-downloader-pause-alt3
Fix/miner downloader autopause
2 parents 957e0cb + 8ca1030 commit 972a75f

File tree

4 files changed

+76
-6
lines changed

4 files changed

+76
-6
lines changed

eth/fetcher/block_fetcher.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@ import (
3232
"github.com/ethereum/go-ethereum/trie"
3333
)
3434

35+
// InsertChainEvent is posted by the handler when a propagated block is successfully imported.
36+
// The block may have been propagated via announcement (hashes) or broadcast (full block, via its miner).
37+
// The event should not be posted if the insert function returns any error.
38+
type InsertChainEvent struct {
39+
Blocks types.Blocks
40+
}
41+
3542
const (
3643
lightTimeout = time.Millisecond // Time allowance before an announced header is explicitly requested
3744
arriveTimeout = 500 * time.Millisecond // Time allowance before an announced block/transaction is explicitly requested

eth/handler.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,9 @@ func newHandler(config *handlerConfig) (*handler, error) {
293293
}
294294
n, err := h.chain.InsertChain(blocks)
295295
if err == nil {
296-
h.acceptTxs.Store(true) // Mark initial sync done on any fetcher import
296+
// Mark initial sync done on any fetcher import
297+
h.acceptTxs.Store(true)
298+
h.eventMux.Post(fetcher.InsertChainEvent{Blocks: blocks})
297299
}
298300
return n, err
299301
}

miner/miner.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
"github.com/ethereum/go-ethereum/core/txpool"
3232
"github.com/ethereum/go-ethereum/core/types"
3333
"github.com/ethereum/go-ethereum/eth/downloader"
34+
"github.com/ethereum/go-ethereum/eth/fetcher"
3435
"github.com/ethereum/go-ethereum/event"
3536
"github.com/ethereum/go-ethereum/log"
3637
"github.com/ethereum/go-ethereum/params/types/ctypes"
@@ -107,7 +108,7 @@ func New(eth Backend, config *Config, chainConfig ctypes.ChainConfigurator, mux
107108
func (miner *Miner) update() {
108109
defer miner.wg.Done()
109110

110-
events := miner.mux.Subscribe(downloader.StartEvent{}, downloader.DoneEvent{}, downloader.FailedEvent{})
111+
events := miner.mux.Subscribe(downloader.StartEvent{}, downloader.DoneEvent{}, downloader.FailedEvent{}, fetcher.InsertChainEvent{})
111112
defer func() {
112113
if !events.Closed() {
113114
events.Unsubscribe()
@@ -116,13 +117,13 @@ func (miner *Miner) update() {
116117

117118
shouldStart := false
118119
canStart := true
119-
dlEventCh := events.Chan()
120+
eventCh := events.Chan()
120121
for {
121122
select {
122-
case ev := <-dlEventCh:
123+
case ev := <-eventCh:
123124
if ev == nil {
124125
// Unsubscription done, stop listening
125-
dlEventCh = nil
126+
eventCh = nil
126127
continue
127128
}
128129
switch ev.Data.(type) {
@@ -142,7 +143,12 @@ func (miner *Miner) update() {
142143
miner.worker.start()
143144
}
144145
miner.worker.syncing.Store(false)
145-
case downloader.DoneEvent:
146+
case downloader.DoneEvent, fetcher.InsertChainEvent:
147+
// InsertBlockEvents are posted by the block fetcher, which handles the fetching and importing
148+
// of network head blocks.
149+
// This event should be treated by the miner equivalently to the downloader.DoneEvent;
150+
// both events indicate that the local node should be treated as fully synced
151+
// and thus ready to mine.
146152
canStart = true
147153
if shouldStart {
148154
miner.worker.start()

miner/miner_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import (
3434
"github.com/ethereum/go-ethereum/core/vm"
3535
"github.com/ethereum/go-ethereum/crypto"
3636
"github.com/ethereum/go-ethereum/eth/downloader"
37+
"github.com/ethereum/go-ethereum/eth/fetcher"
3738
"github.com/ethereum/go-ethereum/event"
3839
"github.com/ethereum/go-ethereum/params"
3940
"github.com/ethereum/go-ethereum/params/types/ctypes"
@@ -182,6 +183,60 @@ func TestMinerStartStopAfterDownloaderEvents(t *testing.T) {
182183
waitForMiningState(t, miner, false)
183184
}
184185

186+
// TestMinerStartAfterFetcherInsertEvent tests that the miner resumes mining during a downloader sync attempt
187+
// if a propagated block (announce, broadcast) is inserted successfully to the local chain.
188+
func TestMinerStartAfterFetcherInsertEvent(t *testing.T) {
189+
miner, mux, cleanup := createMiner(t)
190+
defer cleanup(false)
191+
192+
miner.Start()
193+
waitForMiningState(t, miner, true)
194+
// Start the downloader
195+
mux.Post(downloader.StartEvent{})
196+
waitForMiningState(t, miner, false)
197+
198+
// During the sync, import a block via the fetcher.
199+
// Miner should resume mining, inferring that we're at or near-enough (<32 block) the head of the network canonical chain.
200+
mux.Post(fetcher.InsertChainEvent{})
201+
waitForMiningState(t, miner, true)
202+
203+
mux.Post(downloader.FailedEvent{})
204+
waitForMiningState(t, miner, true)
205+
206+
mux.Post(downloader.StartEvent{})
207+
waitForMiningState(t, miner, true) // Has not autopaused mining.
208+
209+
// Downloader finally succeeds.
210+
mux.Post(downloader.DoneEvent{})
211+
waitForMiningState(t, miner, true) // Still mining.
212+
}
213+
214+
// TestMinerStartAfterFetcherInsertEvent2 tests that the miner does not autopause if outside any downloader sync attempt
215+
// a propagated block (announce, broadcast) is inserted successfully to the local chain; that is,
216+
// a fetcher->import event disables the downloader event listener and autopause mechanism.
217+
func TestMinerStartAfterFetcherInsertEvent2(t *testing.T) {
218+
miner, mux, cleanup := createMiner(t)
219+
defer cleanup(false)
220+
221+
miner.Start()
222+
waitForMiningState(t, miner, true)
223+
224+
// Before we've started the downloader, import a block via the fetcher.
225+
// This should disable subsequent autopausing for downloader events thereafter, since
226+
// we consider the local chain sufficiently synced.
227+
mux.Post(fetcher.InsertChainEvent{})
228+
waitForMiningState(t, miner, true)
229+
230+
// Start the downloader
231+
mux.Post(downloader.StartEvent{})
232+
// Still mining; we've inferred by a successful import of a propagated block
233+
// that we're already synced, and we're no longer treating downloader events as autopause-able.
234+
waitForMiningState(t, miner, true)
235+
236+
mux.Post(downloader.FailedEvent{})
237+
waitForMiningState(t, miner, true)
238+
}
239+
185240
func TestStartWhileDownload(t *testing.T) {
186241
miner, mux, cleanup := createMiner(t)
187242
defer cleanup(false)

0 commit comments

Comments
 (0)