|
|
|
@ -1574,13 +1574,14 @@ func (d *Downloader) importBlockResults(results []*fetchResult) error { |
|
|
|
|
func (d *Downloader) processFastSyncContent(latest *types.Header) error { |
|
|
|
|
// Start syncing state of the reported head block. This should get us most of
|
|
|
|
|
// the state of the pivot block.
|
|
|
|
|
stateSync := d.syncState(latest.Root) |
|
|
|
|
defer stateSync.Cancel() |
|
|
|
|
go func() { |
|
|
|
|
if err := stateSync.Wait(); err != nil && err != errCancelStateFetch && err != errCanceled { |
|
|
|
|
sync := d.syncState(latest.Root) |
|
|
|
|
defer sync.Cancel() |
|
|
|
|
closeOnErr := func(s *stateSync) { |
|
|
|
|
if err := s.Wait(); err != nil && err != errCancelStateFetch && err != errCanceled { |
|
|
|
|
d.queue.Close() // wake up Results
|
|
|
|
|
} |
|
|
|
|
}() |
|
|
|
|
} |
|
|
|
|
go closeOnErr(sync) |
|
|
|
|
// Figure out the ideal pivot block. Note, that this goalpost may move if the
|
|
|
|
|
// sync takes long enough for the chain head to move significantly.
|
|
|
|
|
pivot := uint64(0) |
|
|
|
@ -1600,12 +1601,12 @@ func (d *Downloader) processFastSyncContent(latest *types.Header) error { |
|
|
|
|
if len(results) == 0 { |
|
|
|
|
// If pivot sync is done, stop
|
|
|
|
|
if oldPivot == nil { |
|
|
|
|
return stateSync.Cancel() |
|
|
|
|
return sync.Cancel() |
|
|
|
|
} |
|
|
|
|
// If sync failed, stop
|
|
|
|
|
select { |
|
|
|
|
case <-d.cancelCh: |
|
|
|
|
stateSync.Cancel() |
|
|
|
|
sync.Cancel() |
|
|
|
|
return errCanceled |
|
|
|
|
default: |
|
|
|
|
} |
|
|
|
@ -1625,28 +1626,24 @@ func (d *Downloader) processFastSyncContent(latest *types.Header) error { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
P, beforeP, afterP := splitAroundPivot(pivot, results) |
|
|
|
|
if err := d.commitFastSyncData(beforeP, stateSync); err != nil { |
|
|
|
|
if err := d.commitFastSyncData(beforeP, sync); err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
if P != nil { |
|
|
|
|
// If new pivot block found, cancel old state retrieval and restart
|
|
|
|
|
if oldPivot != P { |
|
|
|
|
stateSync.Cancel() |
|
|
|
|
sync.Cancel() |
|
|
|
|
|
|
|
|
|
stateSync = d.syncState(P.Header.Root) |
|
|
|
|
defer stateSync.Cancel() |
|
|
|
|
go func() { |
|
|
|
|
if err := stateSync.Wait(); err != nil && err != errCancelStateFetch && err != errCanceled { |
|
|
|
|
d.queue.Close() // wake up Results
|
|
|
|
|
} |
|
|
|
|
}() |
|
|
|
|
sync = d.syncState(P.Header.Root) |
|
|
|
|
defer sync.Cancel() |
|
|
|
|
go closeOnErr(sync) |
|
|
|
|
oldPivot = P |
|
|
|
|
} |
|
|
|
|
// Wait for completion, occasionally checking for pivot staleness
|
|
|
|
|
select { |
|
|
|
|
case <-stateSync.done: |
|
|
|
|
if stateSync.err != nil { |
|
|
|
|
return stateSync.err |
|
|
|
|
case <-sync.done: |
|
|
|
|
if sync.err != nil { |
|
|
|
|
return sync.err |
|
|
|
|
} |
|
|
|
|
if err := d.commitPivotBlock(P); err != nil { |
|
|
|
|
return err |
|
|
|
|