diff --git i/eth/downloader/downloader.go w/eth/downloader/downloader.go index 43f0e3db9..b337f95c9 100644 --- i/eth/downloader/downloader.go +++ w/eth/downloader/downloader.go @@ -143,6 +143,8 @@ type Downloader struct { quitCh chan struct{} // Quit channel to signal termination quitLock sync.RWMutex // Lock to prevent double closes + downloads sync.WaitGroup // Keeps track of the currently active downloads + // Testing hooks syncInitHook func(uint64, uint64) // Method to call upon initiating a new sync run bodyFetchHook func([]*types.Header) // Method to call upon starting a block body fetch @@ -403,7 +405,9 @@ func (d *Downloader) synchronise(id string, hash common.Hash, td *big.Int, mode // specified peer and head hash. func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td *big.Int) (err error) { d.mux.Post(StartEvent{}) + d.downloads.Add(1) defer func() { + d.downloads.Done() // reset on error if err != nil { d.mux.Post(FailedEvent{err}) @@ -471,14 +475,22 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td *big.I } else if d.mode == FullSync { fetchers = append(fetchers, d.processFullSyncContent) } - return d.spawnSync(fetchers) + return d.spawnSync(errCancelHeaderFetch, fetchers) } // spawnSync runs d.process and all given fetcher functions to completion in // separate goroutines, returning the first error that appears. -func (d *Downloader) spawnSync(fetchers []func() error) error { +func (d *Downloader) spawnSync(errCancel error, fetchers []func() error) error { + d.cancelLock.Lock() + select { + case <-d.cancelCh: + d.cancelLock.Unlock() + return errCancel + default: + } errc := make(chan error, len(fetchers)) d.cancelWg.Add(len(fetchers)) + d.cancelLock.Unlock() for _, fn := range fetchers { fn := fn go func() { defer d.cancelWg.Done(); errc <- fn() }() @@ -539,6 +551,10 @@ func (d *Downloader) Terminate() { // Cancel any pending download requests d.Cancel() + + // Wait, so external dependencies aren't destroyed + // until the download processing is done. + d.downloads.Wait() } // fetchHeight retrieves the head header of the remote peer to aid in estimating diff --git i/eth/handler.go w/eth/handler.go index 4069359c9..da9ebb243 100644 --- i/eth/handler.go +++ w/eth/handler.go @@ -230,6 +230,9 @@ func (pm *ProtocolManager) Stop() { // Quit fetcher, txsyncLoop. close(pm.quitSync) + // Stop downloader and make sure that all the running downloads are complete. + pm.downloader.Terminate() + // Disconnect existing sessions. // This also closes the gate for any new registrations on the peer set. // sessions which are already established but not added to pm.peers yet diff --git i/eth/sync.go w/eth/sync.go index e49e40087..4367434a6 100644 --- i/eth/sync.go +++ w/eth/sync.go @@ -135,7 +135,6 @@ func (pm *ProtocolManager) syncer() { // Start and ensure cleanup of sync mechanisms pm.fetcher.Start() defer pm.fetcher.Stop() - defer pm.downloader.Terminate() // Wait for different events to fire synchronisation operations forceSync := time.NewTicker(forceSyncCycle) diff --git i/les/backend.go w/les/backend.go index 6a324cb04..e3844bf84 100644 --- i/les/backend.go +++ w/les/backend.go @@ -20,7 +20,6 @@ package les import ( "fmt" "sync" - "time" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" @@ -250,7 +249,6 @@ func (s *LightEthereum) Stop() error { s.eventMux.Stop() - time.Sleep(time.Millisecond * 200) s.chainDb.Close() close(s.shutdownChan) diff --git i/les/handler.go w/les/handler.go index 9627f392b..f2bbe899f 100644 --- i/les/handler.go +++ w/les/handler.go @@ -241,6 +241,9 @@ func (pm *ProtocolManager) Stop() { close(pm.quitSync) // quits syncer, fetcher + // Stop downloader and make sure that all the running downloads are complete. + pm.downloader.Terminate() + // Disconnect existing sessions. // This also closes the gate for any new registrations on the peer set. // sessions which are already established but not added to pm.peers yet diff --git i/les/sync.go w/les/sync.go index c3d37e2f3..fc1f076c7 100644 --- i/les/sync.go +++ w/les/sync.go @@ -31,7 +31,6 @@ func (pm *ProtocolManager) syncer() { // Start and ensure cleanup of sync mechanisms //pm.fetcher.Start() //defer pm.fetcher.Stop() - defer pm.downloader.Terminate() // Wait for different events to fire synchronisation operations //forceSync := time.Tick(forceSyncCycle)